fix: model name inconsistencies

This commit is contained in:
cogwheel0
2025-09-01 18:49:43 +05:30
parent 2c263cf866
commit 047a67a0c5
3 changed files with 84 additions and 44 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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),