main
dart 90 lines 3.35 KB
Raw
1 import 'package:flutter_riverpod/flutter_riverpod.dart';
2 import 'package:localmind/core/providers/app_providers.dart';
3 import 'package:localmind/features/conversations/providers/conversation_providers.dart'
4 as conv;
5 import 'package:localmind/features/personas/providers/personas_providers.dart';
6 import 'package:localmind/features/personas/utils/persona_prompt_utils.dart';
7 import '../data/models/chat_parameters.dart';
8 import 'chat_reasoning_providers.dart';
9 import 'model_selection_providers.dart';
10
11 final chatParamsProvider = Provider<ChatParameters>((ref) {
12 final settings = ref.watch(settingsProvider);
13 final activeConv = ref.watch(conv.activeConversationProvider);
14 final selectedModel = ref.watch(selectedModelProvider);
15 final reasoningConfig = ref.watch(chatReasoningConfigProvider);
16 final modelSupportsReasoning = selectedModel?.supportsReasoning ?? false;
17 // Mandatory-reasoning models can't run with thinking off, so force it on
18 // regardless of the toggle state.
19 final reasoningEnabled = modelSupportsReasoning
20 ? (selectedModel!.reasoningMandatory ? true : reasoningConfig.enabled)
21 : null;
22
23 double temperature = settings.temperature;
24 double topP = settings.topP;
25 int maxTokens = settings.maxTokens;
26 int contextLength = settings.contextLength;
27
28 if (activeConv?.temperature != null) {
29 temperature = activeConv!.temperature!;
30 }
31 if (activeConv?.topP != null) {
32 topP = activeConv!.topP!;
33 }
34 if (activeConv?.maxTokens != null) {
35 maxTokens = activeConv!.maxTokens!;
36 }
37 if (activeConv?.contextLength != null) {
38 contextLength = activeConv!.contextLength!;
39 }
40
41 String? systemPrompt;
42 if (activeConv?.systemPrompt != null &&
43 activeConv!.systemPrompt!.trim().isNotEmpty) {
44 systemPrompt = activeConv.systemPrompt;
45 } else if (activeConv?.personaId != null) {
46 final personasAsync = ref.read(personasNotifierProvider);
47 final personas = personasAsync.value ?? [];
48 final selected = PersonaPromptUtils.resolvePersonas(
49 activeConv!.personaId,
50 personas,
51 );
52 if (selected.isNotEmpty) {
53 systemPrompt = PersonaPromptUtils.combineSystemPrompts(selected);
54 final persona = selected.first;
55 if (persona.preferredParams != null) {
56 final params = persona.preferredParams as Map<String, dynamic>;
57 if (params['temperature'] != null) {
58 temperature = (params['temperature'] as num).toDouble();
59 }
60 if (params['topP'] != null) topP = (params['topP'] as num).toDouble();
61 if (params['maxTokens'] != null) {
62 maxTokens = (params['maxTokens'] as num).toInt();
63 }
64 }
65 }
66 }
67
68 // Fallback-only: never stacks with a chat prompt or persona (#81).
69 final defaultSystemPrompt = settings.defaultSystemPrompt.trim();
70 if (systemPrompt == null && defaultSystemPrompt.isNotEmpty) {
71 systemPrompt = defaultSystemPrompt;
72 }
73
74 return ChatParameters(
75 temperature: temperature,
76 topP: topP,
77 sendTemperature: settings.sendTemperature,
78 sendTopP: settings.sendTopP,
79 maxTokens: maxTokens,
80 contextLength: contextLength,
81 systemPrompt: systemPrompt,
82 reasoningEnabled: reasoningEnabled,
83 reasoningEffort: resolveEffortForModel(
84 selectedModel,
85 reasoningConfig.effort,
86 ),
87 reasoningAllowedOptions: selectedModel?.supportedReasoningEfforts,
88 reasoningDefaultOption: selectedModel?.defaultReasoningEffort,
89 );
90 });