project-nomad/admin/app
Jake Turner 5c97bf605a fix(AI): stop <think> output leaking into titles, chips, and the RAG query (#1254)
ThinkTagSplitter was wired into both streaming paths but neither
non-streaming one, and every ancillary call goes through non-streaming
chat(). So a reasoning tasks model put its reasoning transcript into the
sidebar title, into the suggestion chips, and — worst — into the string
that gets embedded and sent to Qdrant, silently corrupting retrieval for
the rest of the conversation. splitThinkTags() already existed and was
already unit tested; it just had no production callers.

Fixed in three layers:

1. Strip at the transport. New normalizeNonStreamed() in think_stream.ts
   merges structured reasoning (native `thinking`, /v1 `reasoning`) with
   anything the splitter pulls out of inline tags, and both _chatNative
   and _chatCompat now return through it. That covers every caller at
   once, including the legacy controller path and the eval harness.

2. Suppress at the source. _chatNative and _chatStreamNative forwarded
   `think` only when truthy, so `think: false` was never sent and Ollama
   left reasoning on for capable models. Guard is now definedness. This
   also fixes the ai.autoThinking=off setting, which had no effect on
   the native streaming transport.

3. Guard the call sites. Title, suggestions, and query rewrite now pass
   think:false plus thinkingCapable (from the memoized capability check,
   so no extra round-trip), and handle an empty-after-strip result. The
   rewrite matters most: QUERY_REWRITE_MAX_TOKENS caps it at 120, which
   a reasoning model burns entirely on thinking, so stripping alone
   would have turned a corrupt query into an empty one. It now falls
   back to the raw user message instead of embedding "".

Verified: think_stream.spec.ts 17/17 (6 new cases, including the
truncated-mid-thought case that drives the fallback), typecheck clean,
full test:unit failures byte-identical to the pre-change baseline.
2026-09-29 15:54:41 -07:00
..
controllers feat(AI): budget the prompt and actually set the context window (#1253) 2026-09-29 15:54:41 -07:00
data refactor(drug-reference): make collections JSON the single source for curated data (#1130) 2026-08-04 03:38:35 +00:00
exceptions fix(Docs): documentation renderer fixes 2025-12-23 16:00:33 -08:00
jobs fix(downloads): don't retry a rejected entitlement for four hours (#1205) 2026-08-04 03:40:02 +00:00
middleware fix(API): skip compression for Server-Sent Events (#798) 2026-05-20 10:16:00 -07:00
models feat(benchmark): official multi-arch sysbench, resolved digest, platform metadata (#1158) 2026-08-04 03:39:53 +00:00
services fix(AI): stop <think> output leaking into titles, chips, and the RAG query (#1254) 2026-09-29 15:54:41 -07:00
utils fix(AI): stop <think> output leaking into titles, chips, and the RAG query (#1254) 2026-09-29 15:54:41 -07:00
validators feat(AI): budget the prompt and actually set the context window (#1253) 2026-09-29 15:54:41 -07:00