@tduncan / Cortana / commits / ae8195c

feat(chat): let users stop sending temperature/top_p and set a default system prompt #81

Some providers and reasoning models reject temperature and top_p, and every remote request always sent both. - Add "Send temperature" / "Send Top P" switches (Settings > Behavior and the chat parameters sheet). When off, OpenAI-compatible, OpenRouter, LM Studio and Ollama requests omit the field. - Add a default system prompt setting used only when a chat has no prompt of its own and no persona, so it never stacks with a persona. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

abdulmominsakib committed Sep 28, 2026 at 20:10 UTC ae8195ca12dd9072abf7b503258d8307de088aae
41 files changed +901 -28
lib/core/providers/app_providers.dart
+5
@@ -143,6 +143,11 @@ class SettingsNotifier extends Notifier<AppSettings> {
143 _update(state.copyWith(locationToolsEnabled: value));
144 void setAutoCollapseThinking(bool value) =>
145 _update(state.copyWith(autoCollapseThinking: value));
146 + void setSendTemperature(bool value) =>
147 + _update(state.copyWith(sendTemperature: value));
148 + void setSendTopP(bool value) => _update(state.copyWith(sendTopP: value));
149 + void setDefaultSystemPrompt(String value) =>
150 + _update(state.copyWith(defaultSystemPrompt: value.trim()));
151
152 void addSavedMcpIntegration(McpIntegration integration) {
153 final current = List<McpIntegration>.from(state.savedMcpIntegrations);
lib/features/chat/data/chat_service.dart
+8 -8
@@ -217,8 +217,8 @@ class LMStudioChatService implements ChatService {
217 'model': modelId,
218 'input': input,
219 if (systemPrompt.isNotEmpty) 'system_prompt': systemPrompt,
220 - 'temperature': params.temperature,
221 - 'top_p': params.topP,
220 + if (params.sendTemperature) 'temperature': params.temperature,
221 + if (params.sendTopP) 'top_p': params.topP,
222 'max_output_tokens': params.maxTokens,
223 'stream': true,
224 };
@@ -670,8 +670,8 @@ class OpenAICompatibleChatService implements ChatService {
670 final body = <String, dynamic>{
671 'model': modelId,
672 'messages': apiMessages,
673 - 'temperature': params.temperature,
674 - 'top_p': params.topP,
673 + if (params.sendTemperature) 'temperature': params.temperature,
674 + if (params.sendTopP) 'top_p': params.topP,
675 'max_tokens': params.maxTokens,
676 'stream': true,
677 };
@@ -940,8 +940,8 @@ class OllamaChatService implements ChatService {
940 'messages': apiMessages,
941 'stream': true,
942 'options': {
943 - 'temperature': params.temperature,
944 - 'top_p': params.topP,
943 + if (params.sendTemperature) 'temperature': params.temperature,
944 + if (params.sendTopP) 'top_p': params.topP,
945 'num_predict': params.maxTokens,
946 },
947 };
@@ -1215,8 +1215,8 @@ class OpenRouterChatService implements ChatService {
1215 final body = <String, dynamic>{
1216 'model': modelId,
1217 'messages': apiMessages,
1218 - 'temperature': params.temperature,
1219 - 'top_p': params.topP,
1218 + if (params.sendTemperature) 'temperature': params.temperature,
1219 + if (params.sendTopP) 'top_p': params.topP,
1220 'max_tokens': params.maxTokens,
1221 'stream': true,
1222 };
lib/features/chat/data/models/chat_parameters.dart
+11
@@ -11,6 +11,11 @@ class ChatParameters {
11 final double? minP;
12 final double? repeatPenalty;
13
14 + /// When false, remote chat services omit the field from the request body.
15 + /// Local runtimes always use the value.
16 + final bool sendTemperature;
17 + final bool sendTopP;
18 +
19 /// Null when the active model doesn't support reasoning (no reasoning
20 /// control fields should be sent); otherwise reflects the Think toggle.
21 final bool? reasoningEnabled;
@@ -37,6 +42,8 @@ class ChatParameters {
42 this.topK,
43 this.minP,
44 this.repeatPenalty,
45 + this.sendTemperature = true,
46 + this.sendTopP = true,
47 this.reasoningEnabled,
48 this.reasoningEffort = ReasoningEffort.low,
49 this.reasoningAllowedOptions,
@@ -59,6 +66,8 @@ class ChatParameters {
66 int? topK,
67 double? minP,
68 double? repeatPenalty,
69 + bool? sendTemperature,
70 + bool? sendTopP,
71 bool? reasoningEnabled,
72 ReasoningEffort? reasoningEffort,
73 List<String>? reasoningAllowedOptions,
@@ -73,6 +82,8 @@ class ChatParameters {
82 topK: topK ?? this.topK,
83 minP: minP ?? this.minP,
84 repeatPenalty: repeatPenalty ?? this.repeatPenalty,
85 + sendTemperature: sendTemperature ?? this.sendTemperature,
86 + sendTopP: sendTopP ?? this.sendTopP,
87 reasoningEnabled: reasoningEnabled ?? this.reasoningEnabled,
88 reasoningEffort: reasoningEffort ?? this.reasoningEffort,
89 reasoningAllowedOptions:
lib/features/chat/providers/chat_notifier.dart
+12 -3
@@ -1596,16 +1596,25 @@ class ChatNotifier extends Notifier<ChatState> {
1596 }
1597
1598 final personaIds = conversation?.personaId;
1599 - if (personaIds == null || personaIds.isEmpty) return null;
1599 + if (personaIds == null || personaIds.isEmpty) {
1600 + return _defaultSystemPrompt();
1601 + }
1602
1603 try {
1604 final personas = ref.read(personasNotifierProvider).value ?? [];
1605 final selected = PersonaPromptUtils.resolvePersonas(personaIds, personas);
1604 - if (selected.isEmpty) return null;
1606 + if (selected.isEmpty) return _defaultSystemPrompt();
1607 return PersonaPromptUtils.combineSystemPrompts(selected);
1608 } catch (_) {}
1609
1608 - return null;
1610 + return _defaultSystemPrompt();
1611 + }
1612 +
1613 + /// Settings fallback, used only when the chat has no prompt of its own and
1614 + /// no persona (#81).
1615 + String? _defaultSystemPrompt() {
1616 + final prompt = ref.read(settingsProvider).defaultSystemPrompt.trim();
1617 + return prompt.isEmpty ? null : prompt;
1618 }
1619
1620 List<Message> _truncateToContextWindow(
lib/features/chat/providers/chat_params_providers.dart
+8
@@ -65,9 +65,17 @@ final chatParamsProvider = Provider<ChatParameters>((ref) {
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,
lib/features/chat/views/components/chat_settings_sheet.dart
+36 -2
@@ -123,6 +123,8 @@ class _ChatSettingsSheetState extends ConsumerState<ChatSettingsSheet> {
123 maxTokens,
124 activeConv?.id,
125 isDark,
126 + sendTemperature: settings.sendTemperature,
127 + sendTopP: settings.sendTopP,
128 ),
129 child: Row(
130 children: [
@@ -170,8 +172,11 @@ class _ChatSettingsSheetState extends ConsumerState<ChatSettingsSheet> {
172 double topP,
173 int maxTokens,
174 String? conversationId,
173 - bool isDark,
174 - ) {
175 + bool isDark, {
176 + required bool sendTemperature,
177 + required bool sendTopP,
178 + }) {
179 + final settingsNotifier = ref.read(settingsProvider.notifier);
180 return Padding(
181 padding: const EdgeInsets.symmetric(vertical: 16),
182 child: Column(
@@ -185,6 +190,9 @@ class _ChatSettingsSheetState extends ConsumerState<ChatSettingsSheet> {
190 description: l10n.temperature_desc,
191 onChanged: (v) => _updateParam(ref, conversationId, temperature: v),
192 isDark: isDark,
193 + sendToApi: sendTemperature,
194 + sendToApiLabel: l10n.send_temperature_to_api,
195 + onSendToApiChanged: settingsNotifier.setSendTemperature,
196 ),
197 const SizedBox(height: 24),
198 _ParamSlider(
@@ -196,6 +204,9 @@ class _ChatSettingsSheetState extends ConsumerState<ChatSettingsSheet> {
204 description: l10n.top_p_desc,
205 onChanged: (v) => _updateParam(ref, conversationId, topP: v),
206 isDark: isDark,
207 + sendToApi: sendTopP,
208 + sendToApiLabel: l10n.send_top_p_to_api,
209 + onSendToApiChanged: settingsNotifier.setSendTopP,
210 ),
211 const SizedBox(height: 24),
212 _ParamInput(
@@ -613,6 +624,9 @@ class _ParamSlider extends StatelessWidget {
624 required this.description,
625 required this.onChanged,
626 required this.isDark,
627 + required this.sendToApi,
628 + required this.sendToApiLabel,
629 + required this.onSendToApiChanged,
630 });
631
632 final String label;
@@ -624,6 +638,11 @@ class _ParamSlider extends StatelessWidget {
638 final ValueChanged<double> onChanged;
639 final bool isDark;
640
641 + /// Global switch: when off the value isn't sent to remote APIs (#81).
642 + final bool sendToApi;
643 + final String sendToApiLabel;
644 + final ValueChanged<bool> onSendToApiChanged;
645 +
646 @override
647 Widget build(BuildContext context) {
648 return Column(
@@ -650,6 +669,7 @@ class _ParamSlider extends StatelessWidget {
669 initialValue: value,
670 min: min,
671 max: max,
672 + enabled: sendToApi,
673 onChanged: onChanged,
674 ),
675 const SizedBox(height: 4),
@@ -660,6 +680,20 @@ class _ParamSlider extends StatelessWidget {
680 color: isDark ? Colors.white54 : Colors.black54,
681 ),
682 ),
683 + Row(
684 + children: [
685 + Expanded(
686 + child: Text(
687 + sendToApiLabel,
688 + style: TextStyle(
689 + fontSize: 12,
690 + color: isDark ? Colors.white70 : Colors.black87,
691 + ),
692 + ),
693 + ),
694 + Switch.adaptive(value: sendToApi, onChanged: onSendToApiChanged),
695 + ],
696 + ),
697 ],
698 );
699 }
lib/features/settings/data/models/app_settings.dart
+24
@@ -60,6 +60,15 @@ class AppSettings {
60 final bool calendarToolsEnabled;
61 final bool locationToolsEnabled;
62 final bool autoCollapseThinking;
63 +
64 + /// Whether `temperature` / `top_p` are sent to remote APIs. Some providers
65 + /// (e.g. reasoning models) reject them (#81).
66 + final bool sendTemperature;
67 + final bool sendTopP;
68 +
69 + /// Fallback system prompt used when a chat has neither its own prompt nor
70 + /// a persona.
71 + final String defaultSystemPrompt;
72 final List<McpIntegration> savedMcpIntegrations;
73
74 AppSettings({
@@ -110,6 +119,9 @@ class AppSettings {
119 this.calendarToolsEnabled = false,
120 this.locationToolsEnabled = false,
121 this.autoCollapseThinking = false,
122 + this.sendTemperature = true,
123 + this.sendTopP = true,
124 + this.defaultSystemPrompt = '',
125 this.savedMcpIntegrations = const [],
126 });
127
@@ -161,6 +173,9 @@ class AppSettings {
173 bool? calendarToolsEnabled,
174 bool? locationToolsEnabled,
175 bool? autoCollapseThinking,
176 + bool? sendTemperature,
177 + bool? sendTopP,
178 + String? defaultSystemPrompt,
179 List<McpIntegration>? savedMcpIntegrations,
180 }) {
181 return AppSettings(
@@ -234,6 +249,9 @@ class AppSettings {
249 calendarToolsEnabled: calendarToolsEnabled ?? this.calendarToolsEnabled,
250 locationToolsEnabled: locationToolsEnabled ?? this.locationToolsEnabled,
251 autoCollapseThinking: autoCollapseThinking ?? this.autoCollapseThinking,
252 + sendTemperature: sendTemperature ?? this.sendTemperature,
253 + sendTopP: sendTopP ?? this.sendTopP,
254 + defaultSystemPrompt: defaultSystemPrompt ?? this.defaultSystemPrompt,
255 savedMcpIntegrations: savedMcpIntegrations ?? this.savedMcpIntegrations,
256 );
257 }
@@ -287,6 +305,9 @@ class AppSettings {
305 'calendarToolsEnabled': calendarToolsEnabled,
306 'locationToolsEnabled': locationToolsEnabled,
307 'autoCollapseThinking': autoCollapseThinking,
308 + 'sendTemperature': sendTemperature,
309 + 'sendTopP': sendTopP,
310 + 'defaultSystemPrompt': defaultSystemPrompt,
311 'savedMcpIntegrations': savedMcpIntegrations
312 .map((i) => i.toJson())
313 .toList(),
@@ -344,6 +365,9 @@ class AppSettings {
365 calendarToolsEnabled: map['calendarToolsEnabled'] ?? false,
366 locationToolsEnabled: map['locationToolsEnabled'] ?? false,
367 autoCollapseThinking: map['autoCollapseThinking'] ?? false,
368 + sendTemperature: map['sendTemperature'] ?? true,
369 + sendTopP: map['sendTopP'] ?? true,
370 + defaultSystemPrompt: map['defaultSystemPrompt'] as String? ?? '',
371 savedMcpIntegrations: _parseSavedMcpIntegrations(
372 map['savedMcpIntegrations'],
373 ),
lib/features/settings/views/settings_screen.dart
+129
@@ -272,6 +272,27 @@ class SettingsViews extends ConsumerWidget {
272 .read(settingsProvider.notifier)
273 .setAutoCollapseThinking(value),
274 ),
275 + _ToggleSetting(
276 + label: l10n.send_temperature_to_api,
277 + description: l10n.send_sampling_params_desc,
278 + value: settings.sendTemperature,
279 + onChanged: (value) => ref
280 + .read(settingsProvider.notifier)
281 + .setSendTemperature(value),
282 + ),
283 + _ToggleSetting(
284 + label: l10n.send_top_p_to_api,
285 + description: l10n.send_sampling_params_desc,
286 + value: settings.sendTopP,
287 + onChanged: (value) =>
288 + ref.read(settingsProvider.notifier).setSendTopP(value),
289 + ),
290 + _DefaultSystemPromptSetting(
291 + currentPrompt: settings.defaultSystemPrompt,
292 + onSave: (value) => ref
293 + .read(settingsProvider.notifier)
294 + .setDefaultSystemPrompt(value),
295 + ),
296 _ToggleSetting(
297 label: l10n.haptic_feedback,
298 value: settings.hapticFeedbackEnabled,
@@ -2524,6 +2545,114 @@ class _HuggingFaceTokenSetting extends StatelessWidget {
2545 }
2546 }
2547
2548 +class _DefaultSystemPromptSetting extends StatelessWidget {
2549 + const _DefaultSystemPromptSetting({
2550 + required this.currentPrompt,
2551 + required this.onSave,
2552 + });
2553 +
2554 + final String currentPrompt;
2555 + final ValueChanged<String> onSave;
2556 +
2557 + Future<void> _editPrompt(BuildContext context) async {
2558 + final l10n = AppLocalizations.of(context)!;
2559 + final controller = TextEditingController(text: currentPrompt);
2560 + final result = await showDialog<String?>(
2561 + context: context,
2562 + builder: (ctx) {
2563 + return AlertDialog(
2564 + title: Text(l10n.default_system_prompt),
2565 + content: TextField(
2566 + controller: controller,
2567 + autofocus: true,
2568 + minLines: 4,
2569 + maxLines: 10,
2570 + decoration: InputDecoration(
2571 + hintText: l10n.default_system_prompt_hint,
2572 + border: const OutlineInputBorder(),
2573 + ),
2574 + ),
2575 + actions: [
2576 + TextButton(
2577 + onPressed: () => Navigator.of(ctx).pop(),
2578 + child: Text(l10n.cancel),
2579 + ),
2580 + TextButton(
2581 + onPressed: () => Navigator.of(ctx).pop(controller.text),
2582 + child: Text(l10n.save),
2583 + ),
2584 + ],
2585 + );
2586 + },
2587 + );
2588 +
2589 + controller.dispose();
2590 + if (result == null) return;
2591 + onSave(result);
2592 + }
2593 +
2594 + @override
2595 + Widget build(BuildContext context) {
2596 + final l10n = AppLocalizations.of(context)!;
2597 + final theme = Theme.of(context);
2598 + final hasPrompt = currentPrompt.trim().isNotEmpty;
2599 +
2600 + return _SettingPanel(
2601 + child: Column(
2602 + crossAxisAlignment: CrossAxisAlignment.start,
2603 + children: [
2604 + _SettingHeader(label: l10n.default_system_prompt),
2605 + const SizedBox(height: 6),
2606 + Text(
2607 + l10n.default_system_prompt_desc,
2608 + style: theme.textTheme.bodySmall?.copyWith(
2609 + color: _mutedColor(context),
2610 + height: 1.4,
2611 + ),
2612 + ),
2613 + const SizedBox(height: 10),
2614 + Row(
2615 + children: [
2616 + Expanded(
2617 + child: _InputShell(
2618 + child: Padding(
2619 + padding: const EdgeInsets.symmetric(
2620 + horizontal: 14,
2621 + vertical: 12,
2622 + ),
2623 + child: Text(
2624 + hasPrompt ? currentPrompt : '—',
2625 + maxLines: 2,
2626 + overflow: TextOverflow.ellipsis,
2627 + style: theme.textTheme.bodyMedium?.copyWith(
2628 + color: hasPrompt
2629 + ? theme.colorScheme.onSurface
2630 + : _mutedColor(context),
2631 + ),
2632 + ),
2633 + ),
2634 + ),
2635 + ),
2636 + const SizedBox(width: 10),
2637 + ShadButton.outline(
2638 + onPressed: () => _editPrompt(context),
2639 + child: Text(l10n.edit),
2640 + ),
2641 + if (hasPrompt) ...[
2642 + const SizedBox(width: 6),
2643 + ShadButton.outline(
2644 + onPressed: () => onSave(''),
2645 + child: Text(l10n.clear),
2646 + ),
2647 + ],
2648 + ],
2649 + ),
2650 + ],
2651 + ),
2652 + );
2653 + }
2654 +}
2655 +
2656 class _PrivacyPolicyLink extends StatelessWidget {
2657 static final Uri _privacyUrl = Uri.parse(
2658 'https://momin.pro/privacy-policy-localmind/',
lib/l10n/app_ar.arb
+7 -1
@@ -946,5 +946,11 @@
946 "stt_error_client": "تعذر بدء خدمة التعرف على الكلام. تأكد من تثبيت تطبيق إدخال صوتي وتعيينه كأداة التعرف على الكلام الافتراضية، ثم حاول مرة أخرى.",
947 "stt_error_language": "أداة التعرف على الكلام على هذا الجهاز لا تدعم لغتك.",
948 "stt_error_unavailable": "لم يتم العثور على خدمة للتعرف على الكلام على هذا الجهاز. ثبّت تطبيق إدخال صوتي (مثل FUTO Voice Input) وعيّنه كأداة التعرف على الكلام الافتراضية.",
949 - "stt_error_generic": "خطأ في التعرف على الكلام: {code}"
949 + "stt_error_generic": "خطأ في التعرف على الكلام: {code}",
950 + "send_temperature_to_api": "إرسال درجة الحرارة",
951 + "send_top_p_to_api": "إرسال Top P",
952 + "send_sampling_params_desc": "أوقفه لمزوّدي الخدمة أو النماذج التي ترفض هذه المعلمة (مثل بعض نماذج الاستدلال). ينطبق على كل المحادثات مع الخوادم البعيدة.",
953 + "default_system_prompt": "موجّه النظام الافتراضي",
954 + "default_system_prompt_desc": "يُستخدم في المحادثات التي لا تحتوي على شخصية ولا موجّه نظام خاص بها.",
955 + "default_system_prompt_hint": "أنت مساعد مفيد…"
956 }
lib/l10n/app_bn.arb
+7 -1
@@ -942,5 +942,11 @@
942 "stt_error_client": "স্পিচ রিকগনিশন সার্ভিস চালু হয়নি। একটি ভয়েস ইনপুট অ্যাপ ইনস্টল করে ডিফল্ট স্পিচ রিকগনাইজার হিসেবে সেট করুন, তারপর আবার চেষ্টা করুন।",
943 "stt_error_language": "এই ডিভাইসের স্পিচ রিকগনাইজার আপনার ভাষা সমর্থন করে না।",
944 "stt_error_unavailable": "এই ডিভাইসে কোনো স্পিচ রিকগনিশন সার্ভিস পাওয়া যায়নি। একটি ভয়েস ইনপুট অ্যাপ (যেমন FUTO Voice Input) ইনস্টল করে ডিফল্ট স্পিচ রিকগনাইজার হিসেবে সেট করুন।",
945 - "stt_error_generic": "স্পিচ রিকগনিশন ত্রুটি: {code}"
945 + "stt_error_generic": "স্পিচ রিকগনিশন ত্রুটি: {code}",
946 + "send_temperature_to_api": "টেম্পারেচার পাঠান",
947 + "send_top_p_to_api": "Top P পাঠান",
948 + "send_sampling_params_desc": "যে প্রোভাইডার বা মডেল এই প্যারামিটার গ্রহণ করে না (যেমন কিছু রিজনিং মডেল) তাদের জন্য বন্ধ করুন। রিমোট সার্ভারের সব চ্যাটে প্রযোজ্য।",
949 + "default_system_prompt": "ডিফল্ট সিস্টেম প্রম্পট",
950 + "default_system_prompt_desc": "যে চ্যাটে কোনো পারসোনা বা নিজস্ব সিস্টেম প্রম্পট নেই সেখানে ব্যবহৃত হয়।",
951 + "default_system_prompt_hint": "তুমি একজন সহায়ক অ্যাসিস্ট্যান্ট…"
952 }
lib/l10n/app_de.arb
+7 -1
@@ -939,5 +939,11 @@
939 "stt_error_client": "Der Spracherkennungsdienst konnte nicht gestartet werden. Stelle sicher, dass eine Spracheingabe-App installiert und als Standard-Spracherkennung festgelegt ist, und versuche es erneut.",
940 "stt_error_language": "Die Spracherkennung auf diesem Gerät unterstützt deine Sprache nicht.",
941 "stt_error_unavailable": "Auf diesem Gerät wurde kein Spracherkennungsdienst gefunden. Installiere eine Spracheingabe-App (zum Beispiel FUTO Voice Input) und lege sie als Standard-Spracherkennung fest.",
942 - "stt_error_generic": "Fehler bei der Spracherkennung: {code}"
942 + "stt_error_generic": "Fehler bei der Spracherkennung: {code}",
943 + "send_temperature_to_api": "Temperatur senden",
944 + "send_top_p_to_api": "Top P senden",
945 + "send_sampling_params_desc": "Für Anbieter oder Modelle deaktivieren, die diesen Parameter ablehnen (z. B. einige Reasoning-Modelle). Gilt für alle Chats mit Remote-Servern.",
946 + "default_system_prompt": "Standard-Systemprompt",
947 + "default_system_prompt_desc": "Wird für Chats ohne Persona und ohne eigenen Systemprompt verwendet.",
948 + "default_system_prompt_hint": "Du bist ein hilfreicher Assistent…"
949 }
lib/l10n/app_en.arb
+7 -1
@@ -3463,5 +3463,11 @@
3463 "stt_error_language": "The speech recognizer on this device doesn't support your language.",
3464 "stt_error_unavailable": "No speech recognition service found on this device. Install a voice input app (for example FUTO Voice Input) and set it as the default speech recognizer.",
3465 "stt_error_generic": "Speech recognition error: {code}",
3466 - "@stt_error_generic": {"description": "Fallback speech recognition error with the platform error name", "placeholders": {"code": {"type": "String"}}}
3466 + "@stt_error_generic": {"description": "Fallback speech recognition error with the platform error name", "placeholders": {"code": {"type": "String"}}},
3467 + "send_temperature_to_api": "Send temperature",
3468 + "send_top_p_to_api": "Send Top P",
3469 + "send_sampling_params_desc": "Turn off for providers or models that reject this parameter (for example some reasoning models). Applies to all chats with remote servers.",
3470 + "default_system_prompt": "Default system prompt",
3471 + "default_system_prompt_desc": "Used for chats that have no persona and no chat-specific system prompt.",
3472 + "default_system_prompt_hint": "You are a helpful assistant…"
3473 }
lib/l10n/app_es.arb
+7 -1
@@ -942,5 +942,11 @@
942 "stt_error_client": "No se pudo iniciar el servicio de reconocimiento de voz. Asegúrate de tener instalada una app de entrada de voz configurada como reconocedor predeterminado e inténtalo de nuevo.",
943 "stt_error_language": "El reconocedor de voz de este dispositivo no admite tu idioma.",
944 "stt_error_unavailable": "No se encontró ningún servicio de reconocimiento de voz en este dispositivo. Instala una app de entrada de voz (por ejemplo FUTO Voice Input) y configúrala como reconocedor predeterminado.",
945 - "stt_error_generic": "Error de reconocimiento de voz: {code}"
945 + "stt_error_generic": "Error de reconocimiento de voz: {code}",
946 + "send_temperature_to_api": "Enviar temperatura",
947 + "send_top_p_to_api": "Enviar Top P",
948 + "send_sampling_params_desc": "Desactívalo para proveedores o modelos que rechazan este parámetro (por ejemplo, algunos modelos de razonamiento). Se aplica a todos los chats con servidores remotos.",
949 + "default_system_prompt": "Prompt de sistema predeterminado",
950 + "default_system_prompt_desc": "Se usa en chats sin persona ni prompt de sistema propio.",
951 + "default_system_prompt_hint": "Eres un asistente útil…"
952 }
lib/l10n/app_fr.arb
+7 -1
@@ -939,5 +939,11 @@
939 "stt_error_client": "Le service de reconnaissance vocale n'a pas pu démarrer. Vérifiez qu'une application de saisie vocale est installée et définie comme reconnaissance vocale par défaut, puis réessayez.",
940 "stt_error_language": "La reconnaissance vocale de cet appareil ne prend pas en charge votre langue.",
941 "stt_error_unavailable": "Aucun service de reconnaissance vocale trouvé sur cet appareil. Installez une application de saisie vocale (par exemple FUTO Voice Input) et définissez-la comme reconnaissance vocale par défaut.",
942 - "stt_error_generic": "Erreur de reconnaissance vocale : {code}"
942 + "stt_error_generic": "Erreur de reconnaissance vocale : {code}",
943 + "send_temperature_to_api": "Envoyer la température",
944 + "send_top_p_to_api": "Envoyer Top P",
945 + "send_sampling_params_desc": "Désactivez-le pour les fournisseurs ou modèles qui refusent ce paramètre (par exemple certains modèles de raisonnement). S'applique à toutes les discussions avec des serveurs distants.",
946 + "default_system_prompt": "Prompt système par défaut",
947 + "default_system_prompt_desc": "Utilisé pour les discussions sans persona ni prompt système spécifique.",
948 + "default_system_prompt_hint": "Tu es un assistant serviable…"
949 }
lib/l10n/app_hi.arb
+7 -1
@@ -942,5 +942,11 @@
942 "stt_error_client": "वॉइस पहचान सेवा शुरू नहीं हो सकी। सुनिश्चित करें कि कोई वॉइस इनपुट ऐप इंस्टॉल है और डिफ़ॉल्ट स्पीच रिकग्नाइज़र के रूप में सेट है, फिर कोशिश करें।",
943 "stt_error_language": "इस डिवाइस का स्पीच रिकग्नाइज़र आपकी भाषा का समर्थन नहीं करता।",
944 "stt_error_unavailable": "इस डिवाइस पर कोई वॉइस पहचान सेवा नहीं मिली। कोई वॉइस इनपुट ऐप (जैसे FUTO Voice Input) इंस्टॉल करें और उसे डिफ़ॉल्ट स्पीच रिकग्नाइज़र के रूप में सेट करें।",
945 - "stt_error_generic": "वॉइस पहचान त्रुटि: {code}"
945 + "stt_error_generic": "वॉइस पहचान त्रुटि: {code}",
946 + "send_temperature_to_api": "टेम्परेचर भेजें",
947 + "send_top_p_to_api": "Top P भेजें",
948 + "send_sampling_params_desc": "जो प्रोवाइडर या मॉडल इस पैरामीटर को अस्वीकार करते हैं (जैसे कुछ रीज़निंग मॉडल), उनके लिए बंद करें। रिमोट सर्वर वाली सभी चैट पर लागू।",
949 + "default_system_prompt": "डिफ़ॉल्ट सिस्टम प्रॉम्प्ट",
950 + "default_system_prompt_desc": "उन चैट के लिए उपयोग होता है जिनमें न कोई पर्सोना है और न ही अपना सिस्टम प्रॉम्प्ट।",
951 + "default_system_prompt_hint": "आप एक सहायक असिस्टेंट हैं…"
952 }
lib/l10n/app_it.arb
+7 -1
@@ -942,5 +942,11 @@
942 "stt_error_client": "Impossibile avviare il servizio di riconoscimento vocale. Assicurati che un'app di input vocale sia installata e impostata come riconoscimento vocale predefinito, poi riprova.",
943 "stt_error_language": "Il riconoscimento vocale di questo dispositivo non supporta la tua lingua.",
944 "stt_error_unavailable": "Nessun servizio di riconoscimento vocale trovato su questo dispositivo. Installa un'app di input vocale (ad esempio FUTO Voice Input) e impostala come riconoscimento vocale predefinito.",
945 - "stt_error_generic": "Errore di riconoscimento vocale: {code}"
945 + "stt_error_generic": "Errore di riconoscimento vocale: {code}",
946 + "send_temperature_to_api": "Invia temperatura",
947 + "send_top_p_to_api": "Invia Top P",
948 + "send_sampling_params_desc": "Disattivalo per provider o modelli che rifiutano questo parametro (ad esempio alcuni modelli di ragionamento). Vale per tutte le chat con server remoti.",
949 + "default_system_prompt": "Prompt di sistema predefinito",
950 + "default_system_prompt_desc": "Usato per le chat senza persona e senza un prompt di sistema proprio.",
951 + "default_system_prompt_hint": "Sei un assistente disponibile…"
952 }
lib/l10n/app_ja.arb
+7 -1
@@ -942,5 +942,11 @@
942 "stt_error_client": "音声認識サービスを開始できませんでした。音声入力アプリがインストールされ、既定の音声認識に設定されていることを確認して、もう一度お試しください。",
943 "stt_error_language": "このデバイスの音声認識はお使いの言語に対応していません。",
944 "stt_error_unavailable": "このデバイスに音声認識サービスが見つかりません。音声入力アプリ(例: FUTO Voice Input)をインストールし、既定の音声認識に設定してください。",
945 - "stt_error_generic": "音声認識エラー: {code}"
945 + "stt_error_generic": "音声認識エラー: {code}",
946 + "send_temperature_to_api": "Temperature を送信",
947 + "send_top_p_to_api": "Top P を送信",
948 + "send_sampling_params_desc": "このパラメーターを受け付けないプロバイダーやモデル(一部の推論モデルなど)ではオフにしてください。リモートサーバーとのすべてのチャットに適用されます。",
949 + "default_system_prompt": "デフォルトのシステムプロンプト",
950 + "default_system_prompt_desc": "ペルソナもチャット固有のシステムプロンプトもないチャットで使用されます。",
951 + "default_system_prompt_hint": "あなたは親切なアシスタントです…"
952 }
lib/l10n/app_ko.arb
+7 -1
@@ -953,5 +953,11 @@
953 "stt_error_client": "음성 인식 서비스를 시작하지 못했습니다. 음성 입력 앱이 설치되어 있고 기본 음성 인식기로 설정되어 있는지 확인한 후 다시 시도하세요.",
954 "stt_error_language": "이 기기의 음성 인식기가 사용자의 언어를 지원하지 않습니다.",
955 "stt_error_unavailable": "이 기기에서 음성 인식 서비스를 찾을 수 없습니다. 음성 입력 앱(예: FUTO Voice Input)을 설치하고 기본 음성 인식기로 설정하세요.",
956 - "stt_error_generic": "음성 인식 오류: {code}"
956 + "stt_error_generic": "음성 인식 오류: {code}",
957 + "send_temperature_to_api": "Temperature 전송",
958 + "send_top_p_to_api": "Top P 전송",
959 + "send_sampling_params_desc": "이 매개변수를 거부하는 제공업체나 모델(예: 일부 추론 모델)에서는 끄세요. 원격 서버와의 모든 채팅에 적용됩니다.",
960 + "default_system_prompt": "기본 시스템 프롬프트",
961 + "default_system_prompt_desc": "페르소나와 채팅별 시스템 프롬프트가 없는 채팅에 사용됩니다.",
962 + "default_system_prompt_hint": "당신은 도움이 되는 어시스턴트입니다…"
963 }
lib/l10n/app_localizations.dart
+36
@@ -5912,6 +5912,42 @@ abstract class AppLocalizations {
5912 /// In en, this message translates to:
5913 /// **'Speech recognition error: {code}'**
5914 String stt_error_generic(String code);
5915 +
5916 + /// No description provided for @send_temperature_to_api.
5917 + ///
5918 + /// In en, this message translates to:
5919 + /// **'Send temperature'**
5920 + String get send_temperature_to_api;
5921 +
5922 + /// No description provided for @send_top_p_to_api.
5923 + ///
5924 + /// In en, this message translates to:
5925 + /// **'Send Top P'**
5926 + String get send_top_p_to_api;
5927 +
5928 + /// No description provided for @send_sampling_params_desc.
5929 + ///
5930 + /// In en, this message translates to:
5931 + /// **'Turn off for providers or models that reject this parameter (for example some reasoning models). Applies to all chats with remote servers.'**
5932 + String get send_sampling_params_desc;
5933 +
5934 + /// No description provided for @default_system_prompt.
5935 + ///
5936 + /// In en, this message translates to:
5937 + /// **'Default system prompt'**
5938 + String get default_system_prompt;
5939 +
5940 + /// No description provided for @default_system_prompt_desc.
5941 + ///
5942 + /// In en, this message translates to:
5943 + /// **'Used for chats that have no persona and no chat-specific system prompt.'**
5944 + String get default_system_prompt_desc;
5945 +
5946 + /// No description provided for @default_system_prompt_hint.
5947 + ///
5948 + /// In en, this message translates to:
5949 + /// **'You are a helpful assistant…'**
5950 + String get default_system_prompt_hint;
5951 }
5952
5953 class _AppLocalizationsDelegate
lib/l10n/app_localizations_ar.dart
+20
@@ -3178,4 +3178,24 @@ class AppLocalizationsAr extends AppLocalizations {
3178 String stt_error_generic(String code) {
3179 return 'خطأ في التعرف على الكلام: $code';
3180 }
3181 +
3182 + @override
3183 + String get send_temperature_to_api => 'إرسال درجة الحرارة';
3184 +
3185 + @override
3186 + String get send_top_p_to_api => 'إرسال Top P';
3187 +
3188 + @override
3189 + String get send_sampling_params_desc =>
3190 + 'أوقفه لمزوّدي الخدمة أو النماذج التي ترفض هذه المعلمة (مثل بعض نماذج الاستدلال). ينطبق على كل المحادثات مع الخوادم البعيدة.';
3191 +
3192 + @override
3193 + String get default_system_prompt => 'موجّه النظام الافتراضي';
3194 +
3195 + @override
3196 + String get default_system_prompt_desc =>
3197 + 'يُستخدم في المحادثات التي لا تحتوي على شخصية ولا موجّه نظام خاص بها.';
3198 +
3199 + @override
3200 + String get default_system_prompt_hint => 'أنت مساعد مفيد…';
3201 }
lib/l10n/app_localizations_bn.dart
+20
@@ -3203,4 +3203,24 @@ class AppLocalizationsBn extends AppLocalizations {
3203 String stt_error_generic(String code) {
3204 return 'স্পিচ রিকগনিশন ত্রুটি: $code';
3205 }
3206 +
3207 + @override
3208 + String get send_temperature_to_api => 'টেম্পারেচার পাঠান';
3209 +
3210 + @override
3211 + String get send_top_p_to_api => 'Top P পাঠান';
3212 +
3213 + @override
3214 + String get send_sampling_params_desc =>
3215 + 'যে প্রোভাইডার বা মডেল এই প্যারামিটার গ্রহণ করে না (যেমন কিছু রিজনিং মডেল) তাদের জন্য বন্ধ করুন। রিমোট সার্ভারের সব চ্যাটে প্রযোজ্য।';
3216 +
3217 + @override
3218 + String get default_system_prompt => 'ডিফল্ট সিস্টেম প্রম্পট';
3219 +
3220 + @override
3221 + String get default_system_prompt_desc =>
3222 + 'যে চ্যাটে কোনো পারসোনা বা নিজস্ব সিস্টেম প্রম্পট নেই সেখানে ব্যবহৃত হয়।';
3223 +
3224 + @override
3225 + String get default_system_prompt_hint => 'তুমি একজন সহায়ক অ্যাসিস্ট্যান্ট…';
3226 }
lib/l10n/app_localizations_de.dart
+20
@@ -3193,4 +3193,24 @@ class AppLocalizationsDe extends AppLocalizations {
3193 String stt_error_generic(String code) {
3194 return 'Fehler bei der Spracherkennung: $code';
3195 }
3196 +
3197 + @override
3198 + String get send_temperature_to_api => 'Temperatur senden';
3199 +
3200 + @override
3201 + String get send_top_p_to_api => 'Top P senden';
3202 +
3203 + @override
3204 + String get send_sampling_params_desc =>
3205 + 'Für Anbieter oder Modelle deaktivieren, die diesen Parameter ablehnen (z. B. einige Reasoning-Modelle). Gilt für alle Chats mit Remote-Servern.';
3206 +
3207 + @override
3208 + String get default_system_prompt => 'Standard-Systemprompt';
3209 +
3210 + @override
3211 + String get default_system_prompt_desc =>
3212 + 'Wird für Chats ohne Persona und ohne eigenen Systemprompt verwendet.';
3213 +
3214 + @override
3215 + String get default_system_prompt_hint => 'Du bist ein hilfreicher Assistent…';
3216 }
lib/l10n/app_localizations_en.dart
+20
@@ -3181,4 +3181,24 @@ class AppLocalizationsEn extends AppLocalizations {
3181 String stt_error_generic(String code) {
3182 return 'Speech recognition error: $code';
3183 }
3184 +
3185 + @override
3186 + String get send_temperature_to_api => 'Send temperature';
3187 +
3188 + @override
3189 + String get send_top_p_to_api => 'Send Top P';
3190 +
3191 + @override
3192 + String get send_sampling_params_desc =>
3193 + 'Turn off for providers or models that reject this parameter (for example some reasoning models). Applies to all chats with remote servers.';
3194 +
3195 + @override
3196 + String get default_system_prompt => 'Default system prompt';
3197 +
3198 + @override
3199 + String get default_system_prompt_desc =>
3200 + 'Used for chats that have no persona and no chat-specific system prompt.';
3201 +
3202 + @override
3203 + String get default_system_prompt_hint => 'You are a helpful assistant…';
3204 }
lib/l10n/app_localizations_es.dart
+20
@@ -3207,4 +3207,24 @@ class AppLocalizationsEs extends AppLocalizations {
3207 String stt_error_generic(String code) {
3208 return 'Error de reconocimiento de voz: $code';
3209 }
3210 +
3211 + @override
3212 + String get send_temperature_to_api => 'Enviar temperatura';
3213 +
3214 + @override
3215 + String get send_top_p_to_api => 'Enviar Top P';
3216 +
3217 + @override
3218 + String get send_sampling_params_desc =>
3219 + 'Desactívalo para proveedores o modelos que rechazan este parámetro (por ejemplo, algunos modelos de razonamiento). Se aplica a todos los chats con servidores remotos.';
3220 +
3221 + @override
3222 + String get default_system_prompt => 'Prompt de sistema predeterminado';
3223 +
3224 + @override
3225 + String get default_system_prompt_desc =>
3226 + 'Se usa en chats sin persona ni prompt de sistema propio.';
3227 +
3228 + @override
3229 + String get default_system_prompt_hint => 'Eres un asistente útil…';
3230 }
lib/l10n/app_localizations_fr.dart
+20
@@ -3196,4 +3196,24 @@ class AppLocalizationsFr extends AppLocalizations {
3196 String stt_error_generic(String code) {
3197 return 'Erreur de reconnaissance vocale : $code';
3198 }
3199 +
3200 + @override
3201 + String get send_temperature_to_api => 'Envoyer la température';
3202 +
3203 + @override
3204 + String get send_top_p_to_api => 'Envoyer Top P';
3205 +
3206 + @override
3207 + String get send_sampling_params_desc =>
3208 + 'Désactivez-le pour les fournisseurs ou modèles qui refusent ce paramètre (par exemple certains modèles de raisonnement). S\'applique à toutes les discussions avec des serveurs distants.';
3209 +
3210 + @override
3211 + String get default_system_prompt => 'Prompt système par défaut';
3212 +
3213 + @override
3214 + String get default_system_prompt_desc =>
3215 + 'Utilisé pour les discussions sans persona ni prompt système spécifique.';
3216 +
3217 + @override
3218 + String get default_system_prompt_hint => 'Tu es un assistant serviable…';
3219 }
lib/l10n/app_localizations_hi.dart
+20
@@ -3193,4 +3193,24 @@ class AppLocalizationsHi extends AppLocalizations {
3193 String stt_error_generic(String code) {
3194 return 'वॉइस पहचान त्रुटि: $code';
3195 }
3196 +
3197 + @override
3198 + String get send_temperature_to_api => 'टेम्परेचर भेजें';
3199 +
3200 + @override
3201 + String get send_top_p_to_api => 'Top P भेजें';
3202 +
3203 + @override
3204 + String get send_sampling_params_desc =>
3205 + 'जो प्रोवाइडर या मॉडल इस पैरामीटर को अस्वीकार करते हैं (जैसे कुछ रीज़निंग मॉडल), उनके लिए बंद करें। रिमोट सर्वर वाली सभी चैट पर लागू।';
3206 +
3207 + @override
3208 + String get default_system_prompt => 'डिफ़ॉल्ट सिस्टम प्रॉम्प्ट';
3209 +
3210 + @override
3211 + String get default_system_prompt_desc =>
3212 + 'उन चैट के लिए उपयोग होता है जिनमें न कोई पर्सोना है और न ही अपना सिस्टम प्रॉम्प्ट।';
3213 +
3214 + @override
3215 + String get default_system_prompt_hint => 'आप एक सहायक असिस्टेंट हैं…';
3216 }
lib/l10n/app_localizations_it.dart
+20
@@ -3209,4 +3209,24 @@ class AppLocalizationsIt extends AppLocalizations {
3209 String stt_error_generic(String code) {
3210 return 'Errore di riconoscimento vocale: $code';
3211 }
3212 +
3213 + @override
3214 + String get send_temperature_to_api => 'Invia temperatura';
3215 +
3216 + @override
3217 + String get send_top_p_to_api => 'Invia Top P';
3218 +
3219 + @override
3220 + String get send_sampling_params_desc =>
3221 + 'Disattivalo per provider o modelli che rifiutano questo parametro (ad esempio alcuni modelli di ragionamento). Vale per tutte le chat con server remoti.';
3222 +
3223 + @override
3224 + String get default_system_prompt => 'Prompt di sistema predefinito';
3225 +
3226 + @override
3227 + String get default_system_prompt_desc =>
3228 + 'Usato per le chat senza persona e senza un prompt di sistema proprio.';
3229 +
3230 + @override
3231 + String get default_system_prompt_hint => 'Sei un assistente disponibile…';
3232 }
lib/l10n/app_localizations_ja.dart
+20
@@ -3126,4 +3126,24 @@ class AppLocalizationsJa extends AppLocalizations {
3126 String stt_error_generic(String code) {
3127 return '音声認識エラー: $code';
3128 }
3129 +
3130 + @override
3131 + String get send_temperature_to_api => 'Temperature を送信';
3132 +
3133 + @override
3134 + String get send_top_p_to_api => 'Top P を送信';
3135 +
3136 + @override
3137 + String get send_sampling_params_desc =>
3138 + 'このパラメーターを受け付けないプロバイダーやモデル(一部の推論モデルなど)ではオフにしてください。リモートサーバーとのすべてのチャットに適用されます。';
3139 +
3140 + @override
3141 + String get default_system_prompt => 'デフォルトのシステムプロンプト';
3142 +
3143 + @override
3144 + String get default_system_prompt_desc =>
3145 + 'ペルソナもチャット固有のシステムプロンプトもないチャットで使用されます。';
3146 +
3147 + @override
3148 + String get default_system_prompt_hint => 'あなたは親切なアシスタントです…';
3149 }
lib/l10n/app_localizations_ko.dart
+19
@@ -3109,4 +3109,23 @@ class AppLocalizationsKo extends AppLocalizations {
3109 String stt_error_generic(String code) {
3110 return '음성 인식 오류: $code';
3111 }
3112 +
3113 + @override
3114 + String get send_temperature_to_api => 'Temperature 전송';
3115 +
3116 + @override
3117 + String get send_top_p_to_api => 'Top P 전송';
3118 +
3119 + @override
3120 + String get send_sampling_params_desc =>
3121 + '이 매개변수를 거부하는 제공업체나 모델(예: 일부 추론 모델)에서는 끄세요. 원격 서버와의 모든 채팅에 적용됩니다.';
3122 +
3123 + @override
3124 + String get default_system_prompt => '기본 시스템 프롬프트';
3125 +
3126 + @override
3127 + String get default_system_prompt_desc => '페르소나와 채팅별 시스템 프롬프트가 없는 채팅에 사용됩니다.';
3128 +
3129 + @override
3130 + String get default_system_prompt_hint => '당신은 도움이 되는 어시스턴트입니다…';
3131 }
lib/l10n/app_localizations_pt.dart
+20
@@ -3224,4 +3224,24 @@ class AppLocalizationsPt extends AppLocalizations {
3224 String stt_error_generic(String code) {
3225 return 'Erro de reconhecimento de voz: $code';
3226 }
3227 +
3228 + @override
3229 + String get send_temperature_to_api => 'Enviar temperatura';
3230 +
3231 + @override
3232 + String get send_top_p_to_api => 'Enviar Top P';
3233 +
3234 + @override
3235 + String get send_sampling_params_desc =>
3236 + 'Desative para provedores ou modelos que rejeitam este parâmetro (por exemplo, alguns modelos de raciocínio). Aplica-se a todos os chats com servidores remotos.';
3237 +
3238 + @override
3239 + String get default_system_prompt => 'Prompt de sistema padrão';
3240 +
3241 + @override
3242 + String get default_system_prompt_desc =>
3243 + 'Usado em chats sem persona e sem prompt de sistema próprio.';
3244 +
3245 + @override
3246 + String get default_system_prompt_hint => 'Você é um assistente prestativo…';
3247 }
lib/l10n/app_localizations_ru.dart
+20
@@ -3206,4 +3206,24 @@ class AppLocalizationsRu extends AppLocalizations {
3206 String stt_error_generic(String code) {
3207 return 'Ошибка распознавания речи: $code';
3208 }
3209 +
3210 + @override
3211 + String get send_temperature_to_api => 'Отправлять температуру';
3212 +
3213 + @override
3214 + String get send_top_p_to_api => 'Отправлять Top P';
3215 +
3216 + @override
3217 + String get send_sampling_params_desc =>
3218 + 'Отключите для провайдеров или моделей, которые не принимают этот параметр (например, некоторых моделей рассуждения). Действует для всех чатов с удалёнными серверами.';
3219 +
3220 + @override
3221 + String get default_system_prompt => 'Системный промпт по умолчанию';
3222 +
3223 + @override
3224 + String get default_system_prompt_desc =>
3225 + 'Используется в чатах без персоны и без собственного системного промпта.';
3226 +
3227 + @override
3228 + String get default_system_prompt_hint => 'Ты полезный ассистент…';
3229 }
lib/l10n/app_localizations_tr.dart
+20
@@ -3213,4 +3213,24 @@ class AppLocalizationsTr extends AppLocalizations {
3213 String stt_error_generic(String code) {
3214 return 'Konuşma tanıma hatası: $code';
3215 }
3216 +
3217 + @override
3218 + String get send_temperature_to_api => 'Sıcaklığı gönder';
3219 +
3220 + @override
3221 + String get send_top_p_to_api => 'Top P gönder';
3222 +
3223 + @override
3224 + String get send_sampling_params_desc =>
3225 + 'Bu parametreyi reddeden sağlayıcılar veya modeller için kapatın (örneğin bazı akıl yürütme modelleri). Uzak sunuculardaki tüm sohbetler için geçerlidir.';
3226 +
3227 + @override
3228 + String get default_system_prompt => 'Varsayılan sistem istemi';
3229 +
3230 + @override
3231 + String get default_system_prompt_desc =>
3232 + 'Personası ve sohbete özel sistem istemi olmayan sohbetlerde kullanılır.';
3233 +
3234 + @override
3235 + String get default_system_prompt_hint => 'Yardımsever bir asistansın…';
3236 }
lib/l10n/app_localizations_zh.dart
+38
@@ -3100,6 +3100,25 @@ class AppLocalizationsZh extends AppLocalizations {
3100 String stt_error_generic(String code) {
3101 return '语音识别错误:$code';
3102 }
3103 +
3104 + @override
3105 + String get send_temperature_to_api => '发送 Temperature';
3106 +
3107 + @override
3108 + String get send_top_p_to_api => '发送 Top P';
3109 +
3110 + @override
3111 + String get send_sampling_params_desc =>
3112 + '对于拒绝此参数的服务商或模型(例如部分推理模型)请关闭。适用于所有远程服务器的对话。';
3113 +
3114 + @override
3115 + String get default_system_prompt => '默认系统提示词';
3116 +
3117 + @override
3118 + String get default_system_prompt_desc => '用于没有角色且没有专属系统提示词的对话。';
3119 +
3120 + @override
3121 + String get default_system_prompt_hint => '你是一个乐于助人的助手……';
3122 }
3123
3124 /// The translations for Chinese, as used in Taiwan (`zh_TW`).
@@ -6104,4 +6123,23 @@ class AppLocalizationsZhTw extends AppLocalizationsZh {
6123 String stt_error_generic(String code) {
6124 return '語音辨識錯誤:$code';
6125 }
6126 +
6127 + @override
6128 + String get send_temperature_to_api => '傳送 Temperature';
6129 +
6130 + @override
6131 + String get send_top_p_to_api => '傳送 Top P';
6132 +
6133 + @override
6134 + String get send_sampling_params_desc =>
6135 + '對於拒絕此參數的服務商或模型(例如部分推理模型)請關閉。適用於所有遠端伺服器的對話。';
6136 +
6137 + @override
6138 + String get default_system_prompt => '預設系統提示詞';
6139 +
6140 + @override
6141 + String get default_system_prompt_desc => '用於沒有角色且沒有專屬系統提示詞的對話。';
6142 +
6143 + @override
6144 + String get default_system_prompt_hint => '你是一個樂於助人的助理……';
6145 }
lib/l10n/app_pt.arb
+7 -1
@@ -953,5 +953,11 @@
953 "stt_error_client": "Não foi possível iniciar o serviço de reconhecimento de voz. Verifique se um app de entrada por voz está instalado e definido como reconhecedor de fala padrão e tente novamente.",
954 "stt_error_language": "O reconhecedor de fala deste dispositivo não suporta seu idioma.",
955 "stt_error_unavailable": "Nenhum serviço de reconhecimento de voz encontrado neste dispositivo. Instale um app de entrada por voz (por exemplo FUTO Voice Input) e defina-o como reconhecedor de fala padrão.",
956 - "stt_error_generic": "Erro de reconhecimento de voz: {code}"
956 + "stt_error_generic": "Erro de reconhecimento de voz: {code}",
957 + "send_temperature_to_api": "Enviar temperatura",
958 + "send_top_p_to_api": "Enviar Top P",
959 + "send_sampling_params_desc": "Desative para provedores ou modelos que rejeitam este parâmetro (por exemplo, alguns modelos de raciocínio). Aplica-se a todos os chats com servidores remotos.",
960 + "default_system_prompt": "Prompt de sistema padrão",
961 + "default_system_prompt_desc": "Usado em chats sem persona e sem prompt de sistema próprio.",
962 + "default_system_prompt_hint": "Você é um assistente prestativo…"
963 }
lib/l10n/app_ru.arb
+7 -1
@@ -939,5 +939,11 @@
939 "stt_error_client": "Не удалось запустить службу распознавания речи. Убедитесь, что установлено приложение голосового ввода и оно выбрано распознавателем речи по умолчанию, затем попробуйте снова.",
940 "stt_error_language": "Распознаватель речи на этом устройстве не поддерживает ваш язык.",
941 "stt_error_unavailable": "На устройстве не найдена служба распознавания речи. Установите приложение голосового ввода (например, FUTO Voice Input) и выберите его распознавателем речи по умолчанию.",
942 - "stt_error_generic": "Ошибка распознавания речи: {code}"
942 + "stt_error_generic": "Ошибка распознавания речи: {code}",
943 + "send_temperature_to_api": "Отправлять температуру",
944 + "send_top_p_to_api": "Отправлять Top P",
945 + "send_sampling_params_desc": "Отключите для провайдеров или моделей, которые не принимают этот параметр (например, некоторых моделей рассуждения). Действует для всех чатов с удалёнными серверами.",
946 + "default_system_prompt": "Системный промпт по умолчанию",
947 + "default_system_prompt_desc": "Используется в чатах без персоны и без собственного системного промпта.",
948 + "default_system_prompt_hint": "Ты полезный ассистент…"
949 }
lib/l10n/app_tr.arb
+7 -1
@@ -939,5 +939,11 @@
939 "stt_error_client": "Konuşma tanıma hizmeti başlatılamadı. Bir sesli giriş uygulamasının yüklü ve varsayılan konuşma tanıyıcı olarak ayarlı olduğundan emin olup tekrar deneyin.",
940 "stt_error_language": "Bu cihazdaki konuşma tanıyıcı dilinizi desteklemiyor.",
941 "stt_error_unavailable": "Bu cihazda konuşma tanıma hizmeti bulunamadı. Bir sesli giriş uygulaması (örneğin FUTO Voice Input) yükleyip varsayılan konuşma tanıyıcı olarak ayarlayın.",
942 - "stt_error_generic": "Konuşma tanıma hatası: {code}"
942 + "stt_error_generic": "Konuşma tanıma hatası: {code}",
943 + "send_temperature_to_api": "Sıcaklığı gönder",
944 + "send_top_p_to_api": "Top P gönder",
945 + "send_sampling_params_desc": "Bu parametreyi reddeden sağlayıcılar veya modeller için kapatın (örneğin bazı akıl yürütme modelleri). Uzak sunuculardaki tüm sohbetler için geçerlidir.",
946 + "default_system_prompt": "Varsayılan sistem istemi",
947 + "default_system_prompt_desc": "Personası ve sohbete özel sistem istemi olmayan sohbetlerde kullanılır.",
948 + "default_system_prompt_hint": "Yardımsever bir asistansın…"
949 }
lib/l10n/app_zh.arb
+7 -1
@@ -942,5 +942,11 @@
942 "stt_error_client": "语音识别服务无法启动。请确认已安装语音输入应用并将其设为默认语音识别器,然后重试。",
943 "stt_error_language": "此设备上的语音识别器不支持你的语言。",
944 "stt_error_unavailable": "此设备上未找到语音识别服务。请安装语音输入应用(例如 FUTO Voice Input)并将其设为默认语音识别器。",
945 - "stt_error_generic": "语音识别错误:{code}"
945 + "stt_error_generic": "语音识别错误:{code}",
946 + "send_temperature_to_api": "发送 Temperature",
947 + "send_top_p_to_api": "发送 Top P",
948 + "send_sampling_params_desc": "对于拒绝此参数的服务商或模型(例如部分推理模型)请关闭。适用于所有远程服务器的对话。",
949 + "default_system_prompt": "默认系统提示词",
950 + "default_system_prompt_desc": "用于没有角色且没有专属系统提示词的对话。",
951 + "default_system_prompt_hint": "你是一个乐于助人的助手……"
952 }
lib/l10n/app_zh_TW.arb
+7 -1
@@ -942,5 +942,11 @@
942 "stt_error_client": "語音辨識服務無法啟動。請確認已安裝語音輸入 App 並設為預設語音辨識器,然後重試。",
943 "stt_error_language": "此裝置上的語音辨識器不支援你的語言。",
944 "stt_error_unavailable": "此裝置上找不到語音辨識服務。請安裝語音輸入 App(例如 FUTO Voice Input)並設為預設語音辨識器。",
945 - "stt_error_generic": "語音辨識錯誤:{code}"
945 + "stt_error_generic": "語音辨識錯誤:{code}",
946 + "send_temperature_to_api": "傳送 Temperature",
947 + "send_top_p_to_api": "傳送 Top P",
948 + "send_sampling_params_desc": "對於拒絕此參數的服務商或模型(例如部分推理模型)請關閉。適用於所有遠端伺服器的對話。",
949 + "default_system_prompt": "預設系統提示詞",
950 + "default_system_prompt_desc": "用於沒有角色且沒有專屬系統提示詞的對話。",
951 + "default_system_prompt_hint": "你是一個樂於助人的助理……"
952 }
test/features/chat/data/sampling_params_request_test.dart new
+135
@@ -0,0 +1,135 @@
1 +import 'dart:async';
2 +import 'dart:convert';
3 +import 'dart:typed_data';
4 +
5 +import 'package:dio/dio.dart';
6 +import 'package:flutter_test/flutter_test.dart';
7 +import 'package:localmind/core/models/enums.dart';
8 +import 'package:localmind/features/chat/data/chat_service.dart';
9 +import 'package:localmind/features/chat/data/models/chat_parameters.dart';
10 +import 'package:localmind/features/chat/data/models/message.dart';
11 +import 'package:localmind/features/servers/data/models/server.dart';
12 +
13 +/// Captures the request body and answers with an empty stream.
14 +class _CapturingInterceptor extends Interceptor {
15 + _CapturingInterceptor(this.lines);
16 +
17 + final List<String> lines;
18 + Map<String, dynamic>? body;
19 +
20 + @override
21 + void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
22 + final data = options.data;
23 + body = data is String
24 + ? jsonDecode(data) as Map<String, dynamic>
25 + : Map<String, dynamic>.from(data as Map);
26 + final controller = StreamController<Uint8List>();
27 + handler.resolve(
28 + Response(
29 + requestOptions: options,
30 + statusCode: 200,
31 + data: ResponseBody(controller.stream, 200),
32 + ),
33 + );
34 + Future.microtask(() async {
35 + for (final line in lines) {
36 + controller.add(Uint8List.fromList(utf8.encode('$line\n')));
37 + }
38 + await controller.close();
39 + });
40 + }
41 +}
42 +
43 +Server _server(ServerType type) => Server(
44 + id: 'test-${type.name}',
45 + name: 'Test',
46 + type: type,
47 + host: 'localhost',
48 + port: 8080,
49 + createdAt: DateTime.utc(2026, 9, 28),
50 + lastConnectedAt: DateTime.utc(2026, 9, 28),
51 +);
52 +
53 +final _messages = [
54 + Message(
55 + id: 'm1',
56 + conversationId: 'c1',
57 + role: MessageRole.user,
58 + content: 'hi',
59 + createdAt: DateTime.utc(2026, 9, 28),
60 + ),
61 +];
62 +
63 +Future<Map<String, dynamic>> _captureBody(
64 + ChatService Function(Dio dio) build,
65 + ServerType type,
66 + ChatParameters params, {
67 + List<String> lines = const ['data: [DONE]'],
68 +}) async {
69 + final interceptor = _CapturingInterceptor(lines);
70 + final service = build(Dio()..interceptors.add(interceptor));
71 + await service
72 + .sendMessage(
73 + server: _server(type),
74 + modelId: 'test-model',
75 + messages: _messages,
76 + params: params,
77 + )
78 + .toList();
79 + return interceptor.body!;
80 +}
81 +
82 +void main() {
83 + final omitBoth = ChatParameters.defaults().copyWith(
84 + sendTemperature: false,
85 + sendTopP: false,
86 + );
87 +
88 + test('OpenAI-compatible sends sampling params by default', () async {
89 + final body = await _captureBody(
90 + OpenAICompatibleChatService.new,
91 + ServerType.openAICompatible,
92 + ChatParameters.defaults(),
93 + );
94 + expect(body, containsPair('temperature', isA<num>()));
95 + expect(body, containsPair('top_p', isA<num>()));
96 + });
97 +
98 + test('OpenAI-compatible omits disabled sampling params (#81)', () async {
99 + final body = await _captureBody(
100 + OpenAICompatibleChatService.new,
101 + ServerType.openAICompatible,
102 + omitBoth,
103 + );
104 + expect(body.containsKey('temperature'), isFalse);
105 + expect(body.containsKey('top_p'), isFalse);
106 + });
107 +
108 + test('OpenRouter omits disabled sampling params (#81)', () async {
109 + final body = await _captureBody(
110 + OpenRouterChatService.new,
111 + ServerType.openRouter,
112 + ChatParameters.defaults().copyWith(sendTopP: false),
113 + );
114 + expect(body.containsKey('temperature'), isTrue);
115 + expect(body.containsKey('top_p'), isFalse);
116 + });
117 +
118 + test('Ollama omits disabled sampling params from options (#81)', () async {
119 + final body = await _captureBody(
120 + OllamaChatService.new,
121 + ServerType.ollama,
122 + omitBoth,
123 + lines: [
124 + jsonEncode({
125 + 'message': {'content': ''},
126 + 'done': true,
127 + }),
128 + ],
129 + );
130 + final options = body['options'] as Map<String, dynamic>;
131 + expect(options.containsKey('temperature'), isFalse);
132 + expect(options.containsKey('top_p'), isFalse);
133 + expect(options.containsKey('num_predict'), isTrue);
134 + });
135 +}
test/features/chat/providers/chat_params_default_prompt_test.dart new
+69
@@ -0,0 +1,69 @@
1 +import 'package:flutter_riverpod/flutter_riverpod.dart';
2 +import 'package:flutter_test/flutter_test.dart';
3 +import 'package:localmind/core/providers/app_providers.dart';
4 +import 'package:localmind/core/providers/storage_providers.dart';
5 +import 'package:localmind/features/chat/providers/chat_params_providers.dart';
6 +import 'package:localmind/features/conversations/data/models/conversation.dart';
7 +import 'package:localmind/features/conversations/providers/conversation_providers.dart'
8 + as conv;
9 +import 'package:localmind/features/settings/data/models/app_settings.dart';
10 +import 'package:shared_preferences/shared_preferences.dart';
11 +
12 +void main() {
13 + TestWidgetsFlutterBinding.ensureInitialized();
14 +
15 + Future<ProviderContainer> container({Conversation? conversation}) async {
16 + SharedPreferences.setMockInitialValues({});
17 + final prefs = await SharedPreferences.getInstance();
18 + final c = ProviderContainer(
19 + overrides: [
20 + sharedPreferencesProvider.overrideWithValue(prefs),
21 + settingsProvider.overrideWith(_SettingsNotifier.new),
22 + conv.activeConversationProvider.overrideWith(
23 + () => _ActiveConversation(conversation),
24 + ),
25 + ],
26 + );
27 + addTearDown(c.dispose);
28 + return c;
29 + }
30 +
31 + test('uses the default system prompt when the chat has none (#81)', () async {
32 + final c = await container();
33 + final params = c.read(chatParamsProvider);
34 +
35 + expect(params.systemPrompt, 'Default prompt');
36 + expect(params.sendTemperature, isFalse);
37 + expect(params.sendTopP, isTrue);
38 + });
39 +
40 + test('a chat-specific prompt wins over the default', () async {
41 + final c = await container(
42 + conversation: Conversation(
43 + id: 'c1',
44 + title: 'Chat',
45 + createdAt: DateTime.utc(2026, 9, 28),
46 + updatedAt: DateTime.utc(2026, 9, 28),
47 + systemPrompt: 'Chat prompt',
48 + ),
49 + );
50 +
51 + expect(c.read(chatParamsProvider).systemPrompt, 'Chat prompt');
52 + });
53 +}
54 +
55 +class _SettingsNotifier extends SettingsNotifier {
56 + @override
57 + AppSettings build() => AppSettings(
58 + defaultSystemPrompt: 'Default prompt',
59 + sendTemperature: false,
60 + );
61 +}
62 +
63 +class _ActiveConversation extends conv.ActiveConversationNotifier {
64 + _ActiveConversation(this._conversation);
65 + final Conversation? _conversation;
66 +
67 + @override
68 + Conversation? build() => _conversation;
69 +}
test/features/settings/app_settings_sampling_test.dart new
+26
@@ -0,0 +1,26 @@
1 +import 'package:flutter_test/flutter_test.dart';
2 +import 'package:localmind/features/settings/data/models/app_settings.dart';
3 +
4 +void main() {
5 + test('sampling send flags and default system prompt round-trip', () {
6 + final settings = AppSettings(
7 + sendTemperature: false,
8 + sendTopP: false,
9 + defaultSystemPrompt: 'Be brief.',
10 + );
11 +
12 + final restored = AppSettings.fromMap(settings.toMap());
13 +
14 + expect(restored.sendTemperature, isFalse);
15 + expect(restored.sendTopP, isFalse);
16 + expect(restored.defaultSystemPrompt, 'Be brief.');
17 + });
18 +
19 + test('older saved settings default to sending both params', () {
20 + final restored = AppSettings.fromMap(const <String, dynamic>{});
21 +
22 + expect(restored.sendTemperature, isTrue);
23 + expect(restored.sendTopP, isTrue);
24 + expect(restored.defaultSystemPrompt, isEmpty);
25 + });
26 +}