You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Every Anthropic-backed chat reply is capped at 1024 output tokens, and nothing says when it hits
user-ai.ts:108:
max_tokens: body.maxTokens??1024,
The chat loop never passes one.grep maxTokens workers/api/src/agent-think.ts → nothing; both runUserWorkersAi calls in the chat path send { messages, tools } and take the default.
Every other call site sets its own, deliberately: loop-orchestrator 300, coding-copilot 160/600, coding-brains 700, resume-parse 2000, the pipeline ai_generate step 500. Chat — the surface
that produces by far the longest text, and the only one a human reads end to end — is the single
caller that never chose, and it inherits ~1024 tokens ≈ 4,000 characters.
And a truncated reply is indistinguishable from a finished one
runAnthropic reads content and usage off the response (:183-197). stop_reason is never
looked at — grep -rn stop_reason workers/api/src finds it only in the loop-run store and instance-work, both about a different thing entirely (a run's outcome).
So when a reply is cut at the cap the platform has the fact, in the response body, and discards it.
Nothing marks the message, nothing warns the user, nothing logs it.
Seen in the wild, in the transcript that prompted #395
The Chess coder message of 2026-08-07 23:24:31 ends, mid-file, mid-import:
"use client"
import { useState } from "react"
import { useRouter } from "next/navigation"
import
That is not a formatting artefact. The message stops on import because the generation stopped
there. It is a long reply, it hit the cap, and it was stored and displayed as though it were the
whole answer.
Why it matters more on this product than on a chatbot
The agents most likely to exceed 4,000 characters are the technical ones — a Repo Coder explaining
a file, an agent listing issues with bodies, anything quoting code — and guardrails.responseStyle: "technical" explicitly asks them to cite files and functions. The cap bites hardest exactly where
the product is trying to be most useful.
The codebase already learned this lesson once, one directory away
(routes/instances-translation.ts:280): "Explicit max_tokens: the Workers AI default is small
enough to TRUNCATE". Chat never got the same treatment.
Suggested fix
Set an explicit cap for chat, sized for a reply a person reads — 4k is a reasonable starting
point for claude-sonnet-4-6 — rather than inheriting a default that was chosen for nothing in
particular.
Consider making the cap a per-agent setting: a terse operator agent and a code-explaining Repo
Coder do not want the same ceiling, and settingsSchema already exists for exactly this kind of
per-agent number.
Files: workers/api/src/lib/user-ai.ts:108,183-197, workers/api/src/agent-think.ts:700-706.
Related: #395, #397 (the same loop's tool-result protocol).
Every Anthropic-backed chat reply is capped at 1024 output tokens, and nothing says when it hits
user-ai.ts:108:The chat loop never passes one.
grep maxTokens workers/api/src/agent-think.ts→ nothing; bothrunUserWorkersAicalls in the chat path send{ messages, tools }and take the default.Every other call site sets its own, deliberately:
loop-orchestrator300,coding-copilot160/600,coding-brains700,resume-parse2000, the pipelineai_generatestep 500. Chat — the surfacethat produces by far the longest text, and the only one a human reads end to end — is the single
caller that never chose, and it inherits ~1024 tokens ≈ 4,000 characters.
And a truncated reply is indistinguishable from a finished one
runAnthropicreadscontentandusageoff the response (:183-197).stop_reasonis neverlooked at —
grep -rn stop_reason workers/api/srcfinds it only in the loop-run store andinstance-work, both about a different thing entirely (a run's outcome).So when a reply is cut at the cap the platform has the fact, in the response body, and discards it.
Nothing marks the message, nothing warns the user, nothing logs it.
Seen in the wild, in the transcript that prompted #395
The Chess coder message of 2026-08-07 23:24:31 ends, mid-file, mid-import:
That is not a formatting artefact. The message stops on
importbecause the generation stoppedthere. It is a long reply, it hit the cap, and it was stored and displayed as though it were the
whole answer.
Why it matters more on this product than on a chatbot
The agents most likely to exceed 4,000 characters are the technical ones — a Repo Coder explaining
a file, an agent listing issues with bodies, anything quoting code — and
guardrails.responseStyle: "technical"explicitly asks them to cite files and functions. The cap bites hardest exactly wherethe product is trying to be most useful.
The codebase already learned this lesson once, one directory away
(
routes/instances-translation.ts:280): "Explicit max_tokens: the Workers AI default is smallenough to TRUNCATE". Chat never got the same treatment.
Suggested fix
point for
claude-sonnet-4-6— rather than inheriting a default that was chosen for nothing inparticular.
stop_reason. When it ismax_tokens, say so: mark the message, and log it, so"the agent stopped mid-sentence" is a fact on the record instead of a user's impression. This is
the same rule the voice stack now follows for a turn it could not transcribe ([bug] A voice turn rejected as noise is erased along with the live capture — nothing survives, nothing is logged #377) and the loop
for a cancel it accepted ([bug] Stop on a loop looks like it does nothing — the server records the cancel and no UI ever reads cancelRequested #376) — the platform knows, so the user should.
Coder do not want the same ceiling, and
settingsSchemaalready exists for exactly this kind ofper-agent number.
Files:
workers/api/src/lib/user-ai.ts:108,183-197,workers/api/src/agent-think.ts:700-706.Related: #395, #397 (the same loop's tool-result protocol).