Gap
Think.toUIMessageStream(...) is called with no options on both the WebSocket path (_streamResult) and the sub-agent chat() path, so subclasses have no override point for the AI SDK's sendReasoning flag. Reasoning chunks reach clients because the SDK default is true, but that's an implicit dependency on an SDK default and there's no scoped control for subclasses that want to suppress reasoning, or vary it per turn.
Proposal
Two-level control, matching how the rest of TurnConfig flows over Think's class-field defaults:
sendReasoning: boolean = true on Think — subclass-wide default.
- Optional
sendReasoning?: boolean on TurnConfig returned from beforeTurn — per-turn override that wins for that turn only.
The resolved value (config.sendReasoning ?? this.sendReasoning) snapshots in a closure that wraps the StreamableResult returned from _runInferenceLoop, so neither stream path re-reads this.sendReasoning and the instance field can't drift between turns.
// Subclass-wide:
export class MyAgent extends Think<Env> {
override sendReasoning = false;
}
// Per-turn:
override beforeTurn(ctx: TurnContext) {
return { sendReasoning: ctx.continuation };
}
Use case
Running Claude 4.6 with adaptive thinking on a chat surface that streams both internal tool-use continuations and the final user-facing assistant message over the same WebSocket. We want reasoning visible on the final turn and hidden on the internal loop turns. Currently only "always on" or "always off" is expressible.
Reference implementation
A branch with the change is at https://github.com/cgrdavies/agents/tree/feat/think-send-reasoning. It includes:
- The two-level knob + per-turn snapshot in
_runInferenceLoop
- Four test cases in
packages/think/src/tests/hooks.test.ts covering default behavior, instance-field override, and both directions of TurnConfig precedence
- Changeset (
@cloudflare/think: patch)
- README +
docs/think/index.md Configuration tables updated
Local verification: 274/274 tests passing in packages/think; oxfmt --check, oxlint, and tsc --noEmit all clean on the modified files; package builds clean. Happy to revise the API shape if a different design fits the package better.
References
Gap
Think.toUIMessageStream(...)is called with no options on both the WebSocket path (_streamResult) and the sub-agentchat()path, so subclasses have no override point for the AI SDK'ssendReasoningflag. Reasoning chunks reach clients because the SDK default istrue, but that's an implicit dependency on an SDK default and there's no scoped control for subclasses that want to suppress reasoning, or vary it per turn.Proposal
Two-level control, matching how the rest of
TurnConfigflows overThink's class-field defaults:sendReasoning: boolean = trueonThink— subclass-wide default.sendReasoning?: booleanonTurnConfigreturned frombeforeTurn— per-turn override that wins for that turn only.The resolved value (
config.sendReasoning ?? this.sendReasoning) snapshots in a closure that wraps theStreamableResultreturned from_runInferenceLoop, so neither stream path re-readsthis.sendReasoningand the instance field can't drift between turns.Use case
Running Claude 4.6 with adaptive thinking on a chat surface that streams both internal tool-use continuations and the final user-facing assistant message over the same WebSocket. We want reasoning visible on the final turn and hidden on the internal loop turns. Currently only "always on" or "always off" is expressible.
Reference implementation
A branch with the change is at https://github.com/cgrdavies/agents/tree/feat/think-send-reasoning. It includes:
_runInferenceLooppackages/think/src/tests/hooks.test.tscovering default behavior, instance-field override, and both directions ofTurnConfigprecedence@cloudflare/think: patch)docs/think/index.mdConfiguration tables updatedLocal verification: 274/274 tests passing in
packages/think;oxfmt --check,oxlint, andtsc --noEmitall clean on the modified files; package builds clean. Happy to revise the API shape if a different design fits the package better.References
UIMessageStreamOptions.sendReasoning: https://ai-sdk.dev/docs/reference/ai-sdk-ui/append-message-to-ui-stream