fix: reviewer mode model auto selection
This commit is contained in:
28
AGENTS.md
Normal file
28
AGENTS.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
AGENTS GUIDE FOR THIS REPO
|
||||||
|
|
||||||
|
Build, lint, test
|
||||||
|
- Install: flutter pub get
|
||||||
|
- Generate code (required for freezed/json): flutter pub run build_runner build --delete-conflicting-outputs
|
||||||
|
- Analyze (lints): flutter analyze
|
||||||
|
- Format: dart format . --fix
|
||||||
|
- Run app: flutter run -d ios | -d android
|
||||||
|
- Build release: flutter build apk --release; flutter build appbundle --release; flutter build ios --release
|
||||||
|
- Run all tests: flutter test
|
||||||
|
- Run single test file: flutter test path/to/test.dart
|
||||||
|
- Run single test by name: flutter test path/to/test.dart --name "test name substring"
|
||||||
|
|
||||||
|
Code style
|
||||||
|
- Use Flutter lints (analysis_options.yaml includes package:flutter_lints/flutter.yaml); avoid print, prefer logging/services. Fix analyzer warnings before merging.
|
||||||
|
- Imports: prefer relative imports within lib/, package:conduit for cross-feature access. Group as: dart:*, package:*, third-party, project; alphabetize within groups; no unused imports.
|
||||||
|
- Formatting: run dart format .; keep lines readable (< 100–120 cols). No trailing whitespace. Use const where possible.
|
||||||
|
- Types and null safety: use sound null-safety; avoid dynamic; prefer explicit types for public APIs; use final for immutables.
|
||||||
|
- Naming: lowerCamelCase for variables/functions, UpperCamelCase for classes/types; file names snake_case.dart; private members with leading _.
|
||||||
|
- State management: use Riverpod providers in features/* and core/providers; avoid global singletons except services injected via providers.
|
||||||
|
- Data models: use freezed/json_serializable where applicable; regenerate with build_runner after model changes.
|
||||||
|
- Error handling: never swallow errors; convert Dio/network/storage errors into domain errors via core/error/* (api_error_handler.dart, user_friendly_error_handler.dart). Surface user-safe messages; log details via services.
|
||||||
|
- Async/streams: cancel subscriptions; handle connectivity changes via core/services; prefer Future<void> return for async methods.
|
||||||
|
- UI: keep widgets small and pure; move side effects to controllers/providers; respect theme in shared/theme/*; follow design tokens in shared/theme/app_theme.dart and shared/theme/theme_extensions.dart (Spacing, AppBorderRadius, Elevation, ConduitShadows, AppTypography).
|
||||||
|
|
||||||
|
Repo conventions
|
||||||
|
- Follow CI versions from .github/workflows/release.yml (Flutter stable 3.32.5, Java 21). Keep pubspec constraints aligned.
|
||||||
|
- No Cursor/Copilot rule files present. If added later (.cursor/rules or .github/copilot-instructions.md), mirror their guidance here.
|
||||||
@@ -141,7 +141,9 @@ final apiServiceProvider = Provider<ApiService?>((ref) {
|
|||||||
// Keep legacy callback for backward compatibility during transition
|
// Keep legacy callback for backward compatibility during transition
|
||||||
apiService.onAuthTokenInvalid = () {
|
apiService.onAuthTokenInvalid = () {
|
||||||
// This will be removed once migration is complete
|
// This will be removed once migration is complete
|
||||||
foundation.debugPrint('DEBUG: Legacy auth invalidation callback triggered');
|
foundation.debugPrint(
|
||||||
|
'DEBUG: Legacy auth invalidation callback triggered',
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize with any existing token immediately
|
// Initialize with any existing token immediately
|
||||||
@@ -178,7 +180,9 @@ final apiTokenUpdaterProvider = Provider<void>((ref) {
|
|||||||
final api = ref.read(apiServiceProvider);
|
final api = ref.read(apiServiceProvider);
|
||||||
if (api != null && next != null && next.isNotEmpty) {
|
if (api != null && next != null && next.isNotEmpty) {
|
||||||
api.updateAuthToken(next);
|
api.updateAuthToken(next);
|
||||||
foundation.debugPrint('DEBUG: Updated API service with unified auth token');
|
foundation.debugPrint(
|
||||||
|
'DEBUG: Updated API service with unified auth token',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -233,7 +237,9 @@ final modelsProvider = FutureProvider<List<Model>>((ref) async {
|
|||||||
try {
|
try {
|
||||||
foundation.debugPrint('DEBUG: Fetching models from server');
|
foundation.debugPrint('DEBUG: Fetching models from server');
|
||||||
final models = await api.getModels();
|
final models = await api.getModels();
|
||||||
foundation.debugPrint('DEBUG: Successfully fetched ${models.length} models');
|
foundation.debugPrint(
|
||||||
|
'DEBUG: Successfully fetched ${models.length} models',
|
||||||
|
);
|
||||||
return models;
|
return models;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
foundation.debugPrint('ERROR: Failed to fetch models: $e');
|
foundation.debugPrint('ERROR: Failed to fetch models: $e');
|
||||||
@@ -260,7 +266,9 @@ final conversationsProvider = FutureProvider<List<Conversation>>((ref) async {
|
|||||||
// Check if we have a recent cache (within 5 seconds)
|
// Check if we have a recent cache (within 5 seconds)
|
||||||
final lastFetch = ref.read(_conversationsCacheTimestamp);
|
final lastFetch = ref.read(_conversationsCacheTimestamp);
|
||||||
if (lastFetch != null && DateTime.now().difference(lastFetch).inSeconds < 5) {
|
if (lastFetch != null && DateTime.now().difference(lastFetch).inSeconds < 5) {
|
||||||
foundation.debugPrint('DEBUG: Using cached conversations (fetched ${DateTime.now().difference(lastFetch).inSeconds}s ago)');
|
foundation.debugPrint(
|
||||||
|
'DEBUG: Using cached conversations (fetched ${DateTime.now().difference(lastFetch).inSeconds}s ago)',
|
||||||
|
);
|
||||||
// Note: Can't read our own provider here, would cause a cycle
|
// Note: Can't read our own provider here, would cause a cycle
|
||||||
// The caching is handled by Riverpod's built-in mechanism
|
// The caching is handled by Riverpod's built-in mechanism
|
||||||
}
|
}
|
||||||
@@ -277,7 +285,8 @@ final conversationsProvider = FutureProvider<List<Conversation>>((ref) async {
|
|||||||
ChatMessage(
|
ChatMessage(
|
||||||
id: 'demo-msg-1',
|
id: 'demo-msg-1',
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
content: '**Welcome to Conduit Demo Mode**\n\nThis is a demo for app review - responses are pre-written, not from real AI.\n\nTry these features:\n• Send messages\n• Attach images\n• Use voice input\n• Switch models (tap header)\n• Create new chats (menu)\n\nAll features work offline. No server needed.',
|
content:
|
||||||
|
'**Welcome to Conduit Demo Mode**\n\nThis is a demo for app review - responses are pre-written, not from real AI.\n\nTry these features:\n• Send messages\n• Attach images\n• Use voice input\n• Switch models (tap header)\n• Create new chats (menu)\n\nAll features work offline. No server needed.',
|
||||||
timestamp: DateTime.now().subtract(const Duration(minutes: 10)),
|
timestamp: DateTime.now().subtract(const Duration(minutes: 10)),
|
||||||
model: 'Gemma 2 Mini (Demo)',
|
model: 'Gemma 2 Mini (Demo)',
|
||||||
isStreaming: false,
|
isStreaming: false,
|
||||||
@@ -293,129 +302,164 @@ final conversationsProvider = FutureProvider<List<Conversation>>((ref) async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
foundation.debugPrint('DEBUG: Fetching conversations from OpenWebUI API...');
|
foundation.debugPrint(
|
||||||
final conversations = await api.getConversations(); // Fetch all conversations
|
'DEBUG: Fetching conversations from OpenWebUI API...',
|
||||||
|
);
|
||||||
|
final conversations = await api
|
||||||
|
.getConversations(); // Fetch all conversations
|
||||||
foundation.debugPrint(
|
foundation.debugPrint(
|
||||||
'DEBUG: Successfully fetched ${conversations.length} conversations',
|
'DEBUG: Successfully fetched ${conversations.length} conversations',
|
||||||
);
|
);
|
||||||
|
|
||||||
// Also fetch folder information and update conversations with folder IDs
|
|
||||||
try {
|
|
||||||
final foldersData = await api.getFolders();
|
|
||||||
foundation.debugPrint('DEBUG: Fetched ${foldersData.length} folders for conversation mapping');
|
|
||||||
|
|
||||||
// Parse folder data into Folder objects
|
|
||||||
final folders = foldersData.map((folderData) => Folder.fromJson(folderData)).toList();
|
|
||||||
|
|
||||||
// Create a map of conversation ID to folder ID
|
|
||||||
final conversationToFolder = <String, String>{};
|
|
||||||
for (final folder in folders) {
|
|
||||||
foundation.debugPrint('DEBUG: Folder "${folder.name}" (${folder.id}) has ${folder.conversationIds.length} conversations');
|
|
||||||
for (final conversationId in folder.conversationIds) {
|
|
||||||
conversationToFolder[conversationId] = folder.id;
|
|
||||||
foundation.debugPrint('DEBUG: Mapping conversation $conversationId to folder ${folder.id}');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update conversations with folder IDs, preferring explicit folder_id from chat if present
|
|
||||||
// Use a map to ensure uniqueness by ID throughout the merge process
|
|
||||||
final conversationMap = <String, Conversation>{};
|
|
||||||
|
|
||||||
for (final conversation in conversations) {
|
|
||||||
// Prefer server-provided folderId on the chat itself
|
|
||||||
final explicitFolderId = conversation.folderId;
|
|
||||||
final mappedFolderId = conversationToFolder[conversation.id];
|
|
||||||
final folderIdToUse = explicitFolderId ?? mappedFolderId;
|
|
||||||
if (folderIdToUse != null) {
|
|
||||||
conversationMap[conversation.id] = conversation.copyWith(folderId: folderIdToUse);
|
|
||||||
foundation.debugPrint('DEBUG: Updated conversation ${conversation.id.substring(0, 8)} with folderId: $folderIdToUse (explicit: ${explicitFolderId != null})');
|
|
||||||
} else {
|
|
||||||
conversationMap[conversation.id] = conversation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge conversations that are in folders but missing from the main list
|
|
||||||
// Build a set of existing IDs from the fetched list
|
|
||||||
final existingIds = conversationMap.keys.toSet();
|
|
||||||
|
|
||||||
// Diagnostics: count how many folder-mapped IDs are missing from the main list
|
// Also fetch folder information and update conversations with folder IDs
|
||||||
final missingInBase = conversationToFolder.keys.where((id) => !existingIds.contains(id)).toList();
|
try {
|
||||||
if (missingInBase.isNotEmpty) {
|
final foldersData = await api.getFolders();
|
||||||
foundation.debugPrint('DEBUG: ${missingInBase.length} conversations referenced by folders are missing from base list');
|
foundation.debugPrint(
|
||||||
final preview = missingInBase.take(10).toList();
|
'DEBUG: Fetched ${foldersData.length} folders for conversation mapping',
|
||||||
foundation.debugPrint('DEBUG: Missing IDs sample: $preview${missingInBase.length > 10 ? ' ...' : ''}');
|
);
|
||||||
|
|
||||||
|
// Parse folder data into Folder objects
|
||||||
|
final folders = foldersData
|
||||||
|
.map((folderData) => Folder.fromJson(folderData))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
// Create a map of conversation ID to folder ID
|
||||||
|
final conversationToFolder = <String, String>{};
|
||||||
|
for (final folder in folders) {
|
||||||
|
foundation.debugPrint(
|
||||||
|
'DEBUG: Folder "${folder.name}" (${folder.id}) has ${folder.conversationIds.length} conversations',
|
||||||
|
);
|
||||||
|
for (final conversationId in folder.conversationIds) {
|
||||||
|
conversationToFolder[conversationId] = folder.id;
|
||||||
|
foundation.debugPrint(
|
||||||
|
'DEBUG: Mapping conversation $conversationId to folder ${folder.id}',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update conversations with folder IDs, preferring explicit folder_id from chat if present
|
||||||
|
// Use a map to ensure uniqueness by ID throughout the merge process
|
||||||
|
final conversationMap = <String, Conversation>{};
|
||||||
|
|
||||||
|
for (final conversation in conversations) {
|
||||||
|
// Prefer server-provided folderId on the chat itself
|
||||||
|
final explicitFolderId = conversation.folderId;
|
||||||
|
final mappedFolderId = conversationToFolder[conversation.id];
|
||||||
|
final folderIdToUse = explicitFolderId ?? mappedFolderId;
|
||||||
|
if (folderIdToUse != null) {
|
||||||
|
conversationMap[conversation.id] = conversation.copyWith(
|
||||||
|
folderId: folderIdToUse,
|
||||||
|
);
|
||||||
|
foundation.debugPrint(
|
||||||
|
'DEBUG: Updated conversation ${conversation.id.substring(0, 8)} with folderId: $folderIdToUse (explicit: ${explicitFolderId != null})',
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
foundation.debugPrint('DEBUG: All folder-referenced conversations are present in base list');
|
conversationMap[conversation.id] = conversation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge conversations that are in folders but missing from the main list
|
||||||
|
// Build a set of existing IDs from the fetched list
|
||||||
|
final existingIds = conversationMap.keys.toSet();
|
||||||
|
|
||||||
|
// Diagnostics: count how many folder-mapped IDs are missing from the main list
|
||||||
|
final missingInBase = conversationToFolder.keys
|
||||||
|
.where((id) => !existingIds.contains(id))
|
||||||
|
.toList();
|
||||||
|
if (missingInBase.isNotEmpty) {
|
||||||
|
foundation.debugPrint(
|
||||||
|
'DEBUG: ${missingInBase.length} conversations referenced by folders are missing from base list',
|
||||||
|
);
|
||||||
|
final preview = missingInBase.take(10).toList();
|
||||||
|
foundation.debugPrint(
|
||||||
|
'DEBUG: Missing IDs sample: $preview${missingInBase.length > 10 ? ' ...' : ''}',
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
foundation.debugPrint(
|
||||||
|
'DEBUG: All folder-referenced conversations are present in base list',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to fetch missing conversations per-folder to construct accurate entries
|
||||||
|
// If per-folder fetch fails, fall back to creating minimal placeholder entries
|
||||||
|
final apiSvc = ref.read(apiServiceProvider);
|
||||||
|
for (final folder in folders) {
|
||||||
|
// Collect IDs in this folder that are missing
|
||||||
|
final missingIds = folder.conversationIds
|
||||||
|
.where((id) => !existingIds.contains(id))
|
||||||
|
.toList();
|
||||||
|
if (missingIds.isEmpty) continue;
|
||||||
|
|
||||||
|
List<Conversation> folderConvs = const [];
|
||||||
|
try {
|
||||||
|
if (apiSvc != null) {
|
||||||
|
folderConvs = await apiSvc.getConversationsInFolder(folder.id);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
foundation.debugPrint(
|
||||||
|
'DEBUG: getConversationsInFolder failed for ${folder.id}: $e',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to fetch missing conversations per-folder to construct accurate entries
|
// Index fetched folder conversations for quick lookup
|
||||||
// If per-folder fetch fails, fall back to creating minimal placeholder entries
|
final fetchedMap = {for (final c in folderConvs) c.id: c};
|
||||||
final apiSvc = ref.read(apiServiceProvider);
|
|
||||||
for (final folder in folders) {
|
|
||||||
// Collect IDs in this folder that are missing
|
|
||||||
final missingIds = folder.conversationIds.where((id) => !existingIds.contains(id)).toList();
|
|
||||||
if (missingIds.isEmpty) continue;
|
|
||||||
|
|
||||||
List<Conversation> folderConvs = const [];
|
for (final convId in missingIds) {
|
||||||
try {
|
final fetched = fetchedMap[convId];
|
||||||
if (apiSvc != null) {
|
if (fetched != null) {
|
||||||
folderConvs = await apiSvc.getConversationsInFolder(folder.id);
|
final toAdd = fetched.folderId == null
|
||||||
}
|
? fetched.copyWith(folderId: folder.id)
|
||||||
} catch (e) {
|
: fetched;
|
||||||
foundation.debugPrint('DEBUG: getConversationsInFolder failed for ${folder.id}: $e');
|
// Use map to prevent duplicates - this will overwrite if ID already exists
|
||||||
}
|
conversationMap[toAdd.id] = toAdd;
|
||||||
|
existingIds.add(toAdd.id);
|
||||||
// Index fetched folder conversations for quick lookup
|
foundation.debugPrint(
|
||||||
final fetchedMap = {for (final c in folderConvs) c.id: c};
|
'DEBUG: Added missing conversation from folder fetch: ${toAdd.id.substring(0, 8)} -> folder ${folder.id}',
|
||||||
|
);
|
||||||
for (final convId in missingIds) {
|
} else {
|
||||||
final fetched = fetchedMap[convId];
|
// Create a minimal placeholder if not returned by folder API
|
||||||
if (fetched != null) {
|
final placeholder = Conversation(
|
||||||
final toAdd = fetched.folderId == null
|
id: convId,
|
||||||
? fetched.copyWith(folderId: folder.id)
|
title: 'Chat',
|
||||||
: fetched;
|
createdAt: DateTime.now(),
|
||||||
// Use map to prevent duplicates - this will overwrite if ID already exists
|
updatedAt: DateTime.now(),
|
||||||
conversationMap[toAdd.id] = toAdd;
|
messages: const [],
|
||||||
existingIds.add(toAdd.id);
|
folderId: folder.id,
|
||||||
foundation.debugPrint('DEBUG: Added missing conversation from folder fetch: ${toAdd.id.substring(0, 8)} -> folder ${folder.id}');
|
);
|
||||||
} else {
|
// Use map to prevent duplicates
|
||||||
// Create a minimal placeholder if not returned by folder API
|
conversationMap[convId] = placeholder;
|
||||||
final placeholder = Conversation(
|
existingIds.add(convId);
|
||||||
id: convId,
|
foundation.debugPrint(
|
||||||
title: 'Chat',
|
'DEBUG: Added placeholder conversation for missing ID: ${convId.substring(0, 8)} -> folder ${folder.id}',
|
||||||
createdAt: DateTime.now(),
|
);
|
||||||
updatedAt: DateTime.now(),
|
|
||||||
messages: const [],
|
|
||||||
folderId: folder.id,
|
|
||||||
);
|
|
||||||
// Use map to prevent duplicates
|
|
||||||
conversationMap[convId] = placeholder;
|
|
||||||
existingIds.add(convId);
|
|
||||||
foundation.debugPrint('DEBUG: Added placeholder conversation for missing ID: ${convId.substring(0, 8)} -> folder ${folder.id}');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Convert map back to list - this ensures no duplicates by ID
|
// Convert map back to list - this ensures no duplicates by ID
|
||||||
final sortedConversations = conversationMap.values.toList();
|
final sortedConversations = conversationMap.values.toList();
|
||||||
|
|
||||||
// Sort conversations by updatedAt in descending order (most recent first)
|
// Sort conversations by updatedAt in descending order (most recent first)
|
||||||
sortedConversations.sort((a, b) => b.updatedAt.compareTo(a.updatedAt));
|
sortedConversations.sort((a, b) => b.updatedAt.compareTo(a.updatedAt));
|
||||||
foundation.debugPrint('DEBUG: Sorted conversations by updatedAt (most recent first)');
|
foundation.debugPrint(
|
||||||
|
'DEBUG: Sorted conversations by updatedAt (most recent first)',
|
||||||
|
);
|
||||||
|
|
||||||
// Update cache timestamp
|
// Update cache timestamp
|
||||||
ref.read(_conversationsCacheTimestamp.notifier).state = DateTime.now();
|
ref.read(_conversationsCacheTimestamp.notifier).state = DateTime.now();
|
||||||
|
|
||||||
return sortedConversations;
|
return sortedConversations;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
foundation.debugPrint('DEBUG: Failed to fetch folder information: $e');
|
foundation.debugPrint('DEBUG: Failed to fetch folder information: $e');
|
||||||
// Sort conversations even when folder fetch fails
|
// Sort conversations even when folder fetch fails
|
||||||
conversations.sort((a, b) => b.updatedAt.compareTo(a.updatedAt));
|
conversations.sort((a, b) => b.updatedAt.compareTo(a.updatedAt));
|
||||||
foundation.debugPrint('DEBUG: Sorted conversations by updatedAt (fallback case)');
|
foundation.debugPrint(
|
||||||
|
'DEBUG: Sorted conversations by updatedAt (fallback case)',
|
||||||
|
);
|
||||||
|
|
||||||
// Update cache timestamp
|
// Update cache timestamp
|
||||||
ref.read(_conversationsCacheTimestamp.notifier).state = DateTime.now();
|
ref.read(_conversationsCacheTimestamp.notifier).state = DateTime.now();
|
||||||
|
|
||||||
return conversations; // Return original conversations if folder fetch fails
|
return conversations; // Return original conversations if folder fetch fails
|
||||||
}
|
}
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
@@ -458,6 +502,35 @@ final loadConversationProvider = FutureProvider.family<Conversation, String>((
|
|||||||
|
|
||||||
// Provider to automatically load and set the default model from OpenWebUI
|
// Provider to automatically load and set the default model from OpenWebUI
|
||||||
final defaultModelProvider = FutureProvider<Model?>((ref) async {
|
final defaultModelProvider = FutureProvider<Model?>((ref) async {
|
||||||
|
// Handle reviewer mode first
|
||||||
|
final reviewerMode = ref.watch(reviewerModeProvider);
|
||||||
|
if (reviewerMode) {
|
||||||
|
// Check if a model is already selected
|
||||||
|
final currentSelected = ref.read(selectedModelProvider);
|
||||||
|
if (currentSelected != null) {
|
||||||
|
foundation.debugPrint(
|
||||||
|
'DEBUG: Model already selected in reviewer mode: ${currentSelected.name}',
|
||||||
|
);
|
||||||
|
return currentSelected;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get demo models and select the first one
|
||||||
|
final models = await ref.read(modelsProvider.future);
|
||||||
|
if (models.isNotEmpty) {
|
||||||
|
final defaultModel = models.first;
|
||||||
|
Future.microtask(() {
|
||||||
|
if (ref.read(selectedModelProvider) == null) {
|
||||||
|
ref.read(selectedModelProvider.notifier).state = defaultModel;
|
||||||
|
foundation.debugPrint(
|
||||||
|
'DEBUG: Auto-selected demo model: ${defaultModel.name}',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return defaultModel;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
final api = ref.watch(apiServiceProvider);
|
final api = ref.watch(apiServiceProvider);
|
||||||
if (api == null) return null;
|
if (api == null) return null;
|
||||||
|
|
||||||
@@ -465,7 +538,9 @@ final defaultModelProvider = FutureProvider<Model?>((ref) async {
|
|||||||
// Check if a model is already selected
|
// Check if a model is already selected
|
||||||
final currentSelected = ref.read(selectedModelProvider);
|
final currentSelected = ref.read(selectedModelProvider);
|
||||||
if (currentSelected != null) {
|
if (currentSelected != null) {
|
||||||
foundation.debugPrint('DEBUG: Model already selected: ${currentSelected.name}');
|
foundation.debugPrint(
|
||||||
|
'DEBUG: Model already selected: ${currentSelected.name}',
|
||||||
|
);
|
||||||
return currentSelected;
|
return currentSelected;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,7 +554,9 @@ final defaultModelProvider = FutureProvider<Model?>((ref) async {
|
|||||||
// Double-check if a model was selected while we were loading
|
// Double-check if a model was selected while we were loading
|
||||||
final checkSelected = ref.read(selectedModelProvider);
|
final checkSelected = ref.read(selectedModelProvider);
|
||||||
if (checkSelected != null) {
|
if (checkSelected != null) {
|
||||||
foundation.debugPrint('DEBUG: Model was selected during loading: ${checkSelected.name}');
|
foundation.debugPrint(
|
||||||
|
'DEBUG: Model was selected during loading: ${checkSelected.name}',
|
||||||
|
);
|
||||||
return checkSelected;
|
return checkSelected;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,7 +593,9 @@ final defaultModelProvider = FutureProvider<Model?>((ref) async {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (apiError) {
|
} catch (apiError) {
|
||||||
foundation.debugPrint('DEBUG: Failed to get default model from server: $apiError');
|
foundation.debugPrint(
|
||||||
|
'DEBUG: Failed to get default model from server: $apiError',
|
||||||
|
);
|
||||||
// Use first available model as fallback
|
// Use first available model as fallback
|
||||||
selectedModel = models.first;
|
selectedModel = models.first;
|
||||||
foundation.debugPrint(
|
foundation.debugPrint(
|
||||||
@@ -555,7 +634,9 @@ final defaultModelProvider = FutureProvider<Model?>((ref) async {
|
|||||||
return fallbackModel;
|
return fallbackModel;
|
||||||
}
|
}
|
||||||
} catch (fallbackError) {
|
} catch (fallbackError) {
|
||||||
foundation.debugPrint('DEBUG: Error in fallback model selection: $fallbackError');
|
foundation.debugPrint(
|
||||||
|
'DEBUG: Error in fallback model selection: $fallbackError',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -625,7 +706,9 @@ final serverSearchProvider = FutureProvider.family<List<Conversation>, String>((
|
|||||||
return Conversation.fromJson(data as Map<String, dynamic>);
|
return Conversation.fromJson(data as Map<String, dynamic>);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
foundation.debugPrint('DEBUG: Server search returned ${conversations.length} results');
|
foundation.debugPrint(
|
||||||
|
'DEBUG: Server search returned ${conversations.length} results',
|
||||||
|
);
|
||||||
return conversations;
|
return conversations;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
foundation.debugPrint('DEBUG: Server search failed, fallback to local: $e');
|
foundation.debugPrint('DEBUG: Server search failed, fallback to local: $e');
|
||||||
@@ -773,8 +856,6 @@ final userSettingsProvider = FutureProvider<UserSettings>((ref) async {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Conversation Suggestions provider
|
// Conversation Suggestions provider
|
||||||
final conversationSuggestionsProvider = FutureProvider<List<String>>((
|
final conversationSuggestionsProvider = FutureProvider<List<String>>((
|
||||||
ref,
|
ref,
|
||||||
|
|||||||
Reference in New Issue
Block a user