feat(llm): user-controlled think mode (default off); remove qwen3 hardcode
The chat generation pipeline previously forced think=True unconditionally to match qwen3's combined think+tools template, locking the system into that model family. Bench data (2026-05-21, qwen3:30b-a3b/qwen3:32b on CPU) showed thinking adds 1-2 minutes per turn for unclear quality benefit — qwen3:30b-a3b even produced more rambling with think on. This decouples think from the model family by reading a per-user `think_enabled` setting (default `false`). Non-qwen3 models can now run through the same pipeline without the silent-generation failure mode that content-gated thinking would have caused — they just don't think. qwen3 users who still want thinking can opt in via the Settings UI. Settings UI: - New "Enable model thinking" checkbox in General → Assistant section. - Help text explains the default-off rationale and when to opt in. - Persists via the existing settings API; no schema migration needed (Setting is key/value text). Telemetry to confirm whether this regresses tool-call reliability on qwen3 (the current model) is in a follow-up commit (generation_tool_log). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,8 @@ const savingTimezone = ref(false);
|
|||||||
const timezoneSaved = ref(false);
|
const timezoneSaved = ref(false);
|
||||||
const autoConsolidateTasks = ref(true);
|
const autoConsolidateTasks = ref(true);
|
||||||
const savingAutoConsolidate = ref(false);
|
const savingAutoConsolidate = ref(false);
|
||||||
|
const thinkEnabled = ref(false);
|
||||||
|
const savingThinkEnabled = ref(false);
|
||||||
|
|
||||||
async function saveAutoConsolidate() {
|
async function saveAutoConsolidate() {
|
||||||
savingAutoConsolidate.value = true;
|
savingAutoConsolidate.value = true;
|
||||||
@@ -35,6 +37,19 @@ async function saveAutoConsolidate() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function saveThinkEnabled() {
|
||||||
|
savingThinkEnabled.value = true;
|
||||||
|
try {
|
||||||
|
await apiPut('/api/settings', {
|
||||||
|
think_enabled: thinkEnabled.value ? "true" : "false",
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
toastStore.show('Failed to save setting', 'error');
|
||||||
|
} finally {
|
||||||
|
savingThinkEnabled.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function detectTimezone() {
|
function detectTimezone() {
|
||||||
userTimezone.value = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
userTimezone.value = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||||
}
|
}
|
||||||
@@ -771,6 +786,9 @@ onMounted(async () => {
|
|||||||
userTimezone.value = allSettings.user_timezone ?? "";
|
userTimezone.value = allSettings.user_timezone ?? "";
|
||||||
// Default true if unset; explicit "false" disables auto-consolidation.
|
// Default true if unset; explicit "false" disables auto-consolidation.
|
||||||
autoConsolidateTasks.value = (allSettings.auto_consolidate_tasks ?? "true") !== "false";
|
autoConsolidateTasks.value = (allSettings.auto_consolidate_tasks ?? "true") !== "false";
|
||||||
|
// Default false: think mode is opt-in. Bench showed it costs 1-2 min/turn
|
||||||
|
// for unclear benefit; qwen3 users can re-enable if tool calls regress.
|
||||||
|
thinkEnabled.value = (allSettings.think_enabled ?? "false") === "true";
|
||||||
chatRetentionDays.value = allSettings.chat_retention_days !== undefined
|
chatRetentionDays.value = allSettings.chat_retention_days !== undefined
|
||||||
? Number(allSettings.chat_retention_days)
|
? Number(allSettings.chat_retention_days)
|
||||||
: 90;
|
: 90;
|
||||||
@@ -1518,6 +1536,22 @@ function formatUserDate(iso: string): string {
|
|||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label class="checkbox-label">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
v-model="thinkEnabled"
|
||||||
|
:disabled="savingThinkEnabled"
|
||||||
|
@change="saveThinkEnabled"
|
||||||
|
/>
|
||||||
|
Enable model thinking
|
||||||
|
</label>
|
||||||
|
<p class="field-hint">
|
||||||
|
When on, the chat model runs in reasoning mode before responding.
|
||||||
|
Default off — bench data showed thinking adds 1–2 minutes per turn for unclear quality benefit.
|
||||||
|
Turn on for qwen3-family models if tool-call reliability drops without it.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button class="btn-save" @click="saveAssistant" :disabled="saving">
|
<button class="btn-save" @click="saveAssistant" :disabled="saving">
|
||||||
|
|||||||
@@ -231,12 +231,15 @@ async def run_generation(
|
|||||||
# Emit context event
|
# Emit context event
|
||||||
buf.append_event("context", {"context": context_meta})
|
buf.append_event("context", {"context": context_meta})
|
||||||
|
|
||||||
# Always think on qwen3-class models: reasoning mode is the only reliable
|
# Think mode is per-user-setting (default off). Historically forced on for
|
||||||
# path for the tool-call template. Content-based gating was tried in 87fcaa6
|
# qwen3 because content-gated thinking (87fcaa6) exposed silent-generation
|
||||||
# but exposed silent-generation failures on short tool-intent prompts, since
|
# failures on short tool-intent prompts. After moving to a model-family
|
||||||
# the classifier had no way to tell that "create a task" needs a tool call.
|
# decoupled architecture, the bench data (May 2026) showed think costs
|
||||||
|
# 1-2 min/turn for unclear quality benefit; default off, opt in via
|
||||||
|
# the Settings UI. The generation_tool_log captures per-turn outcomes
|
||||||
|
# so reliability regressions surface empirically.
|
||||||
think_requested = think
|
think_requested = think
|
||||||
think = True
|
think = (await get_setting(user_id, "think_enabled", "false")).lower() == "true"
|
||||||
|
|
||||||
t_start = time.monotonic()
|
t_start = time.monotonic()
|
||||||
timing: dict = {
|
timing: dict = {
|
||||||
|
|||||||
Reference in New Issue
Block a user