← Back to PRs

#14323: feat: add forcePrependThinkTag option for reasoning models

by LisaMacintosh open 2026-02-11 23:38 View on GitHub →
agents stale size: M
## Summary Adds a user-configurable option to force-prepend an opening `<think>` tag to model responses. This is useful for reasoning models that do not reliably emit think tags (e.g., GLM-4.7-Flash, MiniMax-M2.1, step-3.5-flash). ## Changes - Added `forcePrependThinkTag` option to `AgentModelEntryConfig` (per-model) and `AgentDefaultsConfig` (global) - Added Zod schema validation for the new config option - Implemented force prepend logic in `handleMessageUpdate` that runs before reasoning parser - Added state flag `thinkTagPrepended` to track when tag has been prepended - Includes unit tests ## Configuration ```yaml # Global setting (applies to all models) forcePrependThinkTag: true # Per-model override models: glm-4.7-flash: forcePrependThinkTag: true ``` ## Behavior - Default: `false` (OFF) - When enabled, prepends `<think>` tag to the first chunk of the assistant message - Only prepends once per assistant message - Runs before reasoning parser processes the content - Works with streaming responses Closes #14151 <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> Adds `forcePrependThinkTag` config option and subscribe-level implementation for prepending `<think>` tags to model responses for reasoning models that don't reliably emit them. Config types, Zod schema validation, state tracking, and unit tests are all present. - **Missing wiring**: The option is defined in config types and the subscribe function accepts it, but the runner layer (`pi-embedded-runner/run/attempt.ts`, `run/types.ts`, `run/params.ts`) doesn't thread it through. The `subscribeEmbeddedPiSession()` call never receives `forcePrependThinkTag`, so the feature won't activate from user configuration — only tests (which call subscribe directly) exercise this code path. - **Double-tag risk**: No guard against models that intermittently emit `<think>` tags. If the model does emit one, the prepend produces `<think><think>...` which causes the tag parser's state machine to leak a raw `<think>` tag into visible output. <h3>Confidence Score: 2/5</h3> - Feature is non-functional in production due to missing parameter threading through the runner layer. - The subscribe-level implementation and tests are sound, but the config-to-subscribe wiring is completely absent. The feature will silently do nothing when users enable it via configuration. Additionally, there's no guard against double-prepending when a model already emits a think tag. - `src/agents/pi-embedded-runner/run/attempt.ts` (missing `forcePrependThinkTag` passthrough), `src/agents/pi-embedded-runner/run/types.ts` and `run/params.ts` (missing type definitions), and `src/agents/pi-embedded-subscribe.handlers.messages.ts` (double-tag guard needed). <!-- 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