fix: model name inconsistencies
This commit is contained in:
@@ -333,7 +333,7 @@ final defaultModelAutoSelectionProvider = Provider<void>((ref) {
|
|||||||
final desired = next.defaultModel;
|
final desired = next.defaultModel;
|
||||||
if (desired == null || desired.isEmpty) return;
|
if (desired == null || desired.isEmpty) return;
|
||||||
|
|
||||||
// Resolve the desired model against available models
|
// Resolve the desired model against available models (by ID only)
|
||||||
Future(() async {
|
Future(() async {
|
||||||
try {
|
try {
|
||||||
// Prefer already-loaded models to avoid unnecessary fetches
|
// Prefer already-loaded models to avoid unnecessary fetches
|
||||||
@@ -346,14 +346,10 @@ final defaultModelAutoSelectionProvider = Provider<void>((ref) {
|
|||||||
}
|
}
|
||||||
Model? selected;
|
Model? selected;
|
||||||
try {
|
try {
|
||||||
selected = models.firstWhere(
|
selected = models.firstWhere((model) => model.id == desired);
|
||||||
(model) =>
|
} catch (_) {
|
||||||
model.id == desired ||
|
selected = null;
|
||||||
model.name == desired ||
|
}
|
||||||
model.id.contains(desired) ||
|
|
||||||
model.name.contains(desired),
|
|
||||||
);
|
|
||||||
} catch (_) {}
|
|
||||||
|
|
||||||
// Fallback: keep current selection or pick first available
|
// Fallback: keep current selection or pick first available
|
||||||
selected ??= ref.read(selectedModelProvider) ??
|
selected ??= ref.read(selectedModelProvider) ??
|
||||||
@@ -362,7 +358,7 @@ final defaultModelAutoSelectionProvider = Provider<void>((ref) {
|
|||||||
if (selected != null) {
|
if (selected != null) {
|
||||||
ref.read(selectedModelProvider.notifier).state = selected;
|
ref.read(selectedModelProvider.notifier).state = selected;
|
||||||
foundation.debugPrint(
|
foundation.debugPrint(
|
||||||
'DEBUG: Auto-applied default model from settings: ${selected.name}',
|
'DEBUG: Auto-applied default model (by ID): ${selected.name}',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -669,29 +665,43 @@ final defaultModelProvider = FutureProvider<Model?>((ref) async {
|
|||||||
|
|
||||||
Model? selectedModel;
|
Model? selectedModel;
|
||||||
|
|
||||||
// First check user's preferred default model
|
// First check user's preferred default model (ID only). If an older
|
||||||
|
// name-based value is found, migrate it once to the correct ID.
|
||||||
final userSettings = ref.read(appSettingsProvider);
|
final userSettings = ref.read(appSettingsProvider);
|
||||||
final userDefaultModelId = userSettings.defaultModel;
|
final userDefaultModelId = userSettings.defaultModel;
|
||||||
|
|
||||||
if (userDefaultModelId != null && userDefaultModelId.isNotEmpty) {
|
if (userDefaultModelId != null && userDefaultModelId.isNotEmpty) {
|
||||||
try {
|
try {
|
||||||
selectedModel = models.firstWhere(
|
// Exact ID match only
|
||||||
(model) =>
|
selectedModel =
|
||||||
model.id == userDefaultModelId ||
|
models.firstWhere((model) => model.id == userDefaultModelId);
|
||||||
model.name == userDefaultModelId ||
|
|
||||||
model.id.contains(userDefaultModelId) ||
|
|
||||||
model.name.contains(userDefaultModelId),
|
|
||||||
);
|
|
||||||
foundation.debugPrint(
|
foundation.debugPrint(
|
||||||
'DEBUG: Found user default model: ${selectedModel.name}',
|
'DEBUG: Found user default model by ID: ${selectedModel.name}',
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
// Attempt a one-time migration if the stored value was a model name
|
||||||
|
// from older versions. Only migrate on exact, unique name match.
|
||||||
|
final nameMatches =
|
||||||
|
models.where((m) => m.name == userDefaultModelId).toList();
|
||||||
|
if (nameMatches.length == 1) {
|
||||||
|
selectedModel = nameMatches.first;
|
||||||
foundation.debugPrint(
|
foundation.debugPrint(
|
||||||
'DEBUG: User default model "$userDefaultModelId" not found in available models',
|
'DEBUG: Migrating user default model name to ID: '
|
||||||
|
'${nameMatches.first.name} -> ${nameMatches.first.id}',
|
||||||
|
);
|
||||||
|
// Persist the migrated ID
|
||||||
|
await ref
|
||||||
|
.read(appSettingsProvider.notifier)
|
||||||
|
.setDefaultModel(nameMatches.first.id);
|
||||||
|
} else {
|
||||||
|
foundation.debugPrint(
|
||||||
|
'DEBUG: User default model "$userDefaultModelId" not found by ID and '
|
||||||
|
'no unique name match. Ignoring.',
|
||||||
);
|
);
|
||||||
selectedModel = null; // Will fall back to server default or first model
|
selectedModel = null; // Will fall back to server default or first model
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If no user default or user default not found, try server's default model
|
// If no user default or user default not found, try server's default model
|
||||||
if (selectedModel == null) {
|
if (selectedModel == null) {
|
||||||
@@ -699,24 +709,30 @@ final defaultModelProvider = FutureProvider<Model?>((ref) async {
|
|||||||
final defaultModelId = await api.getDefaultModel();
|
final defaultModelId = await api.getDefaultModel();
|
||||||
|
|
||||||
if (defaultModelId != null && defaultModelId.isNotEmpty) {
|
if (defaultModelId != null && defaultModelId.isNotEmpty) {
|
||||||
// Find the model that matches the default model ID
|
// Find the model that matches the default model ID (ID only)
|
||||||
try {
|
try {
|
||||||
selectedModel = models.firstWhere(
|
selectedModel =
|
||||||
(model) =>
|
models.firstWhere((model) => model.id == defaultModelId);
|
||||||
model.id == defaultModelId ||
|
|
||||||
model.name == defaultModelId ||
|
|
||||||
model.id.contains(defaultModelId) ||
|
|
||||||
model.name.contains(defaultModelId),
|
|
||||||
);
|
|
||||||
foundation.debugPrint(
|
foundation.debugPrint(
|
||||||
'DEBUG: Found server default model: ${selectedModel.name}',
|
'DEBUG: Found server default model by ID: ${selectedModel.name}',
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
// If server returned a name instead of ID, attempt exact name match.
|
||||||
|
final byName = models.where((m) => m.name == defaultModelId).toList();
|
||||||
|
if (byName.length == 1) {
|
||||||
|
selectedModel = byName.first;
|
||||||
foundation.debugPrint(
|
foundation.debugPrint(
|
||||||
'DEBUG: Server default model "$defaultModelId" not found in available models',
|
'DEBUG: Server default "$defaultModelId" matched by name; '
|
||||||
|
'selected ${selectedModel.name} (${selectedModel.id})',
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
foundation.debugPrint(
|
||||||
|
'DEBUG: Server default model "$defaultModelId" not found by ID; '
|
||||||
|
'falling back to first available',
|
||||||
);
|
);
|
||||||
selectedModel = models.first;
|
selectedModel = models.first;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// No server default, use first available model
|
// No server default, use first available model
|
||||||
selectedModel = models.first;
|
selectedModel = models.first;
|
||||||
|
|||||||
@@ -406,7 +406,7 @@ Future<void> regenerateMessage(
|
|||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: '',
|
content: '',
|
||||||
timestamp: DateTime.now(),
|
timestamp: DateTime.now(),
|
||||||
model: selectedModel.name,
|
model: selectedModel.id,
|
||||||
isStreaming: true,
|
isStreaming: true,
|
||||||
);
|
);
|
||||||
ref.read(chatMessagesProvider.notifier).addMessage(assistantMessage);
|
ref.read(chatMessagesProvider.notifier).addMessage(assistantMessage);
|
||||||
@@ -477,7 +477,7 @@ Future<void> regenerateMessage(
|
|||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: '',
|
content: '',
|
||||||
timestamp: DateTime.now(),
|
timestamp: DateTime.now(),
|
||||||
model: selectedModel.name,
|
model: selectedModel.id,
|
||||||
isStreaming: true,
|
isStreaming: true,
|
||||||
);
|
);
|
||||||
ref.read(chatMessagesProvider.notifier).addMessage(assistantMessage);
|
ref.read(chatMessagesProvider.notifier).addMessage(assistantMessage);
|
||||||
@@ -547,6 +547,7 @@ Future<void> _sendMessageInternal(
|
|||||||
role: 'user',
|
role: 'user',
|
||||||
content: message,
|
content: message,
|
||||||
timestamp: DateTime.now(),
|
timestamp: DateTime.now(),
|
||||||
|
model: selectedModel.id,
|
||||||
attachmentIds: attachments,
|
attachmentIds: attachments,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -649,7 +650,7 @@ Future<void> _sendMessageInternal(
|
|||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: '',
|
content: '',
|
||||||
timestamp: DateTime.now(),
|
timestamp: DateTime.now(),
|
||||||
model: selectedModel.name,
|
model: selectedModel.id,
|
||||||
isStreaming: true,
|
isStreaming: true,
|
||||||
);
|
);
|
||||||
ref.read(chatMessagesProvider.notifier).addMessage(assistantMessage);
|
ref.read(chatMessagesProvider.notifier).addMessage(assistantMessage);
|
||||||
@@ -883,7 +884,7 @@ Future<void> _sendMessageInternal(
|
|||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: '',
|
content: '',
|
||||||
timestamp: DateTime.now(),
|
timestamp: DateTime.now(),
|
||||||
model: selectedModel.name,
|
model: selectedModel.id,
|
||||||
isStreaming: true,
|
isStreaming: true,
|
||||||
);
|
);
|
||||||
ref.read(chatMessagesProvider.notifier).addMessage(imageOnlyAssistant);
|
ref.read(chatMessagesProvider.notifier).addMessage(imageOnlyAssistant);
|
||||||
@@ -1063,7 +1064,7 @@ Future<void> _sendMessageInternal(
|
|||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: '',
|
content: '',
|
||||||
timestamp: DateTime.now(),
|
timestamp: DateTime.now(),
|
||||||
model: selectedModel.name,
|
model: selectedModel.id,
|
||||||
isStreaming: true,
|
isStreaming: true,
|
||||||
);
|
);
|
||||||
ref.read(chatMessagesProvider.notifier).addMessage(assistantMessage);
|
ref.read(chatMessagesProvider.notifier).addMessage(assistantMessage);
|
||||||
@@ -2378,7 +2379,7 @@ final regenerateLastMessageProvider = Provider<Future<void> Function()>((ref) {
|
|||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: '',
|
content: '',
|
||||||
timestamp: DateTime.now(),
|
timestamp: DateTime.now(),
|
||||||
model: selectedModel.name,
|
model: selectedModel.id,
|
||||||
isStreaming: true,
|
isStreaming: true,
|
||||||
);
|
);
|
||||||
ref.read(chatMessagesProvider.notifier).addMessage(placeholder);
|
ref.read(chatMessagesProvider.notifier).addMessage(placeholder);
|
||||||
|
|||||||
@@ -688,6 +688,29 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
|
|
||||||
final isSelected = _selectedMessageIds.contains(message.id);
|
final isSelected = _selectedMessageIds.contains(message.id);
|
||||||
|
|
||||||
|
// Resolve a friendly model display name for message headers
|
||||||
|
String? displayModelName;
|
||||||
|
final rawModel = message.model;
|
||||||
|
if (rawModel != null && rawModel.isNotEmpty) {
|
||||||
|
final modelsAsync = ref.watch(modelsProvider);
|
||||||
|
if (modelsAsync.hasValue) {
|
||||||
|
final models = modelsAsync.value!;
|
||||||
|
try {
|
||||||
|
// Prefer exact ID match; fall back to exact name match
|
||||||
|
final match = models.firstWhere(
|
||||||
|
(m) => m.id == rawModel || m.name == rawModel,
|
||||||
|
);
|
||||||
|
displayModelName = match.name;
|
||||||
|
} catch (_) {
|
||||||
|
// As a fallback, format the raw value to be more readable
|
||||||
|
displayModelName = _formatModelDisplayName(rawModel);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Models not loaded yet; format raw value for readability
|
||||||
|
displayModelName = _formatModelDisplayName(rawModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Wrap message in selection container if in selection mode
|
// Wrap message in selection container if in selection mode
|
||||||
Widget messageWidget;
|
Widget messageWidget;
|
||||||
|
|
||||||
@@ -698,7 +721,7 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
message: message,
|
message: message,
|
||||||
isUser: isUser,
|
isUser: isUser,
|
||||||
isStreaming: isStreaming,
|
isStreaming: isStreaming,
|
||||||
modelName: message.model,
|
modelName: displayModelName,
|
||||||
onCopy: () => _copyMessage(message.content),
|
onCopy: () => _copyMessage(message.content),
|
||||||
onEdit: () => _editMessage(message),
|
onEdit: () => _editMessage(message),
|
||||||
onRegenerate: () => _regenerateMessage(message),
|
onRegenerate: () => _regenerateMessage(message),
|
||||||
@@ -710,7 +733,7 @@ class _ChatPageState extends ConsumerState<ChatPage> {
|
|||||||
key: ValueKey('assistant-${message.id}'),
|
key: ValueKey('assistant-${message.id}'),
|
||||||
message: message,
|
message: message,
|
||||||
isStreaming: isStreaming,
|
isStreaming: isStreaming,
|
||||||
modelName: message.model,
|
modelName: displayModelName,
|
||||||
onCopy: () => _copyMessage(message.content),
|
onCopy: () => _copyMessage(message.content),
|
||||||
onRegenerate: () => _regenerateMessage(message),
|
onRegenerate: () => _regenerateMessage(message),
|
||||||
onLike: () => _likeMessage(message),
|
onLike: () => _likeMessage(message),
|
||||||
|
|||||||
Reference in New Issue
Block a user