[FEATURE] Add set_effort and set_thinking as control-protocol subtypes
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
The Claude Code CLI has mid-conversation control-protocol subtypes for set_model, set_permission_mode, and set_max_thinking_tokens, but no equivalent for effort or for the richer thinking config. SDK consumers can't change these between turns — they're locked to whatever was passed via --effort / --thinking when the CLI started.
What we checked
Checked every available Claude Code CLI build:
- JavaScript (
cli.js) versions: 2.1.19, 2.1.50, 2.1.71, 2.1.92, 2.1.101, 2.1.107, 2.1.111 - Native binary (
claude.exe) versions: 2.1.114, 2.1.119, 2.1.126, 2.1.138, 2.1.139, 2.1.143
In all 13 versions, set_model, set_permission_mode, and set_max_thinking_tokens are present. set_effort and set_thinking are absent in every version.
Downstream tracking
- claude-agent-sdk-python: issue #981
Proposed Solution
Add two new control-protocol subtypes — set_effort and set_thinking — modeled directly on the existing set_model.
{ "type": "control_request", "request_id": "...",
"request": {
"subtype": "set_effort",
"effort": "low" | "medium" | "high" | "xhigh" | "max" | null
}
}
{ "type": "control_request", "request_id": "...",
"request": {
"subtype": "set_thinking",
"thinking":
{ "type": "adaptive", "display": "summarized" | "omitted" } |
{ "type": "enabled", "budget_tokens": number, "display": "summarized" | "omitted" } |
{ "type": "disabled" } |
null
}
}
Semantics matching set_model:
- Takes effect on the next turn; the current turn is unaffected.
nullresets to whatever was passed via--effort/--thinkingat launch (or the model default if nothing was passed).- Writes to the runtime layer, same precedence as
--effort, so the value isn't shadowed byuserSettings.effortLevelor silently clamped by the resolver.
This closes the gap where effort and thinking are first-class options at launch but can't be changed afterwards, and lets the Python and TypeScript SDKs expose clean set_effort / set_thinking methods instead of routing through apply_flag_settings.
Alternative Solutions
The two existing paths aren't viable substitutes:
apply_flag_settings({ effortLevel: ... })updatesstate.effortValuein memory but is stripped before persistence (theflagSettingssource serialises as{})./effort <level>is alocal-jsxslash command that mutatesstate.effortValuedirectly, but only runs in the interactive terminal UI — it isn't dispatched from headless / SDK / stream-JSON mode.
Priority
Critical - Blocking my work
Feature Category
Developer tools/SDK
Use Case Example
_No response_
Additional Context
_No response_
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗