6aecbdc9b7
The support chat showed 'Tänker' and then went quiet with no answer and no error. Root cause: the 2026-08-21 RIP-3 cutover moved general.help to the single-call POST /api/agent/ask, whose 1500-token default cap made stop_reason max_tokens routine on tool-loop turns. The empty answer then passed unlogged through the service, the route answered 200 with an empty string, and the console appended an invisible empty bubble. Fixes, single-call path: - ask-service: default maxTokens 1500 -> 5400 (the streaming chat's reply ceiling); an empty final answer now logs model + usage and throws the typed EmptyModelAnswerError instead of passing through. - /api/agent/ask: maxDuration 300, logger, empty answer maps to 502 with 'Assistenten gav inget svar. Försök igen.'; an empty assistant turn is never persisted (the question stays, so retry works). - AskConsole: a 200 with an empty answer shows the error box instead of appending an invisible bubble. - anthropic-family: serialized tool results are bounded at 40000 chars (mirrors run-turn) so one big read cannot eat the output budget; the step-exhausted fallback keeps tools declared with tool_choice none, because replaying tool_use/tool_result without tools is an API 400. Fixes, streaming path (same silent class): - /api/agent/invoke: maxDuration 300 so deep thinking turns are not killed mid-stream at the platform default cap. - run-turn: stop_reason max_tokens with no visible text emits an error event, not a bare turn_complete. - AgentChat: an NDJSON stream that ends without turn_complete or error (and was not aborted) shows 'Anslutningen bröts innan svaret blev klart. Försök igen.' The lib/ai request-shape tests were updated deliberately for the fallback change; general.help stays on the single-call runtime (founder decision, not reverted). Claude-Session: https://claude.ai/code/session_01SyDuePXxUFowaPBKpAv8SF Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
19 lines
687 B
TypeScript
19 lines
687 B
TypeScript
/**
|
|
* Typed failure for "the model returned no visible text": stop_reason
|
|
* max_tokens with the whole budget spent before the first text block, or a
|
|
* refusal with an empty body. Before this existed, an empty answer flowed
|
|
* through /api/agent/ask as a 200 and rendered as an invisible bubble
|
|
* ("Tänker", then silence).
|
|
*
|
|
* Lives in its own module so the API route and its tests can match on it
|
|
* without importing ask-service's full dependency graph.
|
|
*/
|
|
export class EmptyModelAnswerError extends Error {
|
|
readonly code = 'empty_model_answer'
|
|
|
|
constructor(model: string) {
|
|
super(`Model ${model} returned an empty answer`)
|
|
this.name = 'EmptyModelAnswerError'
|
|
}
|
|
}
|