[FEATURE] Add set_effort and set_thinking as control-protocol subtypes

Resolved 💬 3 comments Opened May 21, 2026 by ritu456286 Closed May 24, 2026

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

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.
  • null resets to whatever was passed via --effort / --thinking at launch (or the model default if nothing was passed).
  • Writes to the runtime layer, same precedence as --effort, so the value isn't shadowed by userSettings.effortLevel or 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: ... }) updates state.effortValue in memory but is stripped before persistence (the flagSettings source serialises as {}).
  • /effort <level> is a local-jsx slash command that mutates state.effortValue directly, 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_

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗