#6685: fix: suppress thinking leak for Synthetic reasoning models
agents
Cluster:
Model Reasoning Fixes
## Summary
Fixes #6442
When using Synthetic provider with reasoning-capable models (e.g. Kimi K2.5), thinking text leaks into user-facing output as plain text. This happens because pi-ai's Anthropic provider sends no `thinking` parameter when `thinkLevel` is `"off"` (the default), and Synthetic/Kimi defaults to emitting thinking as plain text content blocks.
- Adds `createThinkingDisabledWrapper()` in `extra-params.ts` that injects `thinking: { type: "disabled" }` into the Anthropic API payload via the `onPayload` callback
- Only applies when: `thinkLevel === "off"`, `model.reasoning === true`, and `model.api === "anthropic-messages"`
- No effect on actual Anthropic models (Claude already handles absent `thinking` param correctly; `disabled` is a valid no-op)
- No effect on non-anthropic-messages providers (Venice, OpenRouter, Ollama all use `openai-completions`/`openai-responses`)
## Test plan
- [x] New unit tests for `createThinkingDisabledWrapper` (4 tests covering inject, no-overwrite, non-reasoning skip, non-anthropic skip)
- [x] `pnpm lint && pnpm build && pnpm test` pass
- [x] Manual test: sent messages via Synthetic/Kimi K2.5 with `thinkLevel: "off"` — thinking no longer leaks into user output
- [x] Manual test: sent messages with `--thinking medium` — model reasons, structured thinking blocks properly filtered from output
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR prevents “thinking” text from leaking into user-visible output when using Anthropic-compatible providers (notably Synthetic/Kimi) with reasoning-capable models and `thinkLevel: "off"`. It does so by adding a `createThinkingDisabledWrapper()` stream wrapper that injects `thinking: { type: "disabled" }` into the Anthropic Messages payload (via `onPayload`) when the model is marked `reasoning: true` and uses the `anthropic-messages` API, and then applying that wrapper during embedded runs when thinking is disabled. Unit tests cover injection, non-overwrite, and skip conditions for non-reasoning / non-anthropic APIs.
<h3>Confidence Score: 4/5</h3>
- This PR is likely safe to merge; it’s a small, targeted payload mutation with tests.
- The change is narrowly scoped (only wraps streamFn when thinkLevel is off and model is reasoning + anthropic-messages) and has unit tests for core behavior. Main remaining risk is subtle onPayload chaining/ordering or models/providers where forcing `thinking: disabled` has unintended effects, but the wrapper avoids overwriting existing thinking settings.
- src/agents/pi-embedded-runner/extra-params.ts and src/agents/pi-embedded-runner/run/attempt.ts
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#10097: fix: add empty thinking blocks to tool call messages when thinking is…
by cyxer000 · 2026-02-06
80.5%
#19407: fix(agents): strip thinking blocks on cross-provider model switch (...
by lailoo · 2026-02-17
80.1%
#20620: feat: add anthropic/claude-opus-4-6 to XHIGH_MODEL_REFS
by chungjchris · 2026-02-19
79.1%
#16100: fix: convert unsigned thinking blocks to text to prevent signature ...
by claw-sylphx · 2026-02-14
78.7%
#18935: fix(agents): suppress reasoning blocks from channel delivery
by BinHPdev · 2026-02-17
78.2%
#17455: fix: strip content before orphan closing think tags
by jwt625 · 2026-02-15
78.1%
#18926: fix(agents): preserve thinking signatures for direct Anthropic API
by BinHPdev · 2026-02-17
77.3%
#13235: feat: stream reasoning_content via /v1/chat/completions SSE
by mode80 · 2026-02-10
77.2%
#20945: fix: strip thinking blocks with field-name signatures from OpenAI-c...
by austenstone · 2026-02-19
77.1%
#13361: fix(google-antigravity): add Opus 4.6 support and fix thinking.sign...
by SovranAMR · 2026-02-10
77.0%