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:
2026-05-21 22:00:44 -04:00
parent 2d5d3ffdff
commit d345b32856
2 changed files with 42 additions and 5 deletions
@@ -231,12 +231,15 @@ async def run_generation(
# Emit context event
buf.append_event("context", {"context": context_meta})
# Always think on qwen3-class models: reasoning mode is the only reliable
# path for the tool-call template. Content-based gating was tried in 87fcaa6
# but exposed silent-generation failures on short tool-intent prompts, since
# the classifier had no way to tell that "create a task" needs a tool call.
# Think mode is per-user-setting (default off). Historically forced on for
# qwen3 because content-gated thinking (87fcaa6) exposed silent-generation
# failures on short tool-intent prompts. After moving to a model-family
# 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 = True
think = (await get_setting(user_id, "think_enabled", "false")).lower() == "true"
t_start = time.monotonic()
timing: dict = {