anthropics / anthropics/claude-agent-sdk-python
[FEATURE] : Add set_effort and set_thinking to ClaudeSDKClient
- 主要语言
- Python
- 星标
- 8.1k
- 派生
- 1.3k
- 平均合并
- 2 天 31 分钟
- 30 天内合并 PR
- 1
描述
## Problem
`ClaudeSDKClient` exposes `set_model` and `set_permission_mode` as public, mid-conversation setters backed by control-protocol subtypes. `effort` and `thinking` are first-class fields on `ClaudeAgentOptions` , but the Python SDK exposes no equivalent setter - both are launch-only, mapped to `--effort` / `--thinking` on the CLI command line.
The TypeScript SDK exposes `applyFlagSettings` on its `Query` interface as a partial workaround. The Python SDK does not surface it at all.
There is no public mid-conversation knob in the Python SDK for either effort or thinking.
## Reproduction
- SDK: `claude-agent-sdk` `0.1.60`
- Bundled CLI: `cli.js` `2.1.111`
- Python 3.11.13, Linux
```python
import asyncio
from claude_agent_sdk import ClaudeAgentOptions, ClaudeSDKClient
async def main():
options = ClaudeAgentOptions(model="claude-opus-4-7", effort="low")
async with ClaudeSDKClient(options=options) as client:
await client.query("Quick exploratory question.")
async for _ in client.receive_response():
pass
# Want to bump effort before the next turn — no public method exists.
# client.set_effort("max") # AttributeError
# client.set_thinking({"type": "adaptive"}) # AttributeError
await client.query("Now give a deep planning answer.")
# ...still running at effort=low.
asyncio.run(main())
```
The only mid-conversation setters on `ClaudeSDKClient` are:
```python
await client.set_model(...)
await client.set_permission_mode(...)
```
## Workaround
Send the raw control request through the private `Query._send_control_request`:
```python
await client._query._send_control_request({
"subtype": "apply_flag_settings",
"settings": {"effortLevel": "max"},
})
```
This is not a clean substitute for dedicated setters:
- `_send_control_request` is private. `apply_flag_settings` has no `TypedDict` in `SDKControlRequest`.
- `{ effortLevel: "max" }` updates the in-memory `state.effortValue` but is **stripped before persistence** — `flagSettings` source serialises as `{}`.
CLI versions inspected for a dedicated subtype: cli.js 2.1.19 → 2.1.111 and native binaries 2.1.114 → 2.1.143. No `set_effort` or `set_thinking` subtype exists in any of them.
## What we'd like
1. Confirm whether there's a public API we missed for changing effort or thinking mid-conversation. We checked the methods on `ClaudeSDKClient` (`set_model`, `set_permission_mode`, `set_effort?`, `set_thinking?`) and the public exports, and didn't find one.
2. If not, please add public `client.set_effort()` and `client.set_thinking()` methods, symmetric with `set_model`:
```python
class ClaudeSDKClient:
async def set_effort(self, effort: EffortLevel | None) -> None: ...
async def set_thinking(self, thinking: ThinkingConfig | None) -> None: ...
```
`EffortLevel = Literal["low", "medium", "high", "xhigh", "max"]` and `ThinkingConfig` are already in `types.py`. Semantics matching `set_model`: streaming-mode only; effective on next turn; `None` resets to the value supplied at launch.
3. Backed by new control-protocol subtypes on `@anthropic-ai/claude-code`:
```jsonc
{ "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
}
}
```
Add corresponding `TypedDict` variants (`SDKControlSetEffortRequest`, `SDKControlSetThinkingRequest`) to the `SDKControlRequest` union in `types.py`. Also add the missing `SDKControlSetModelRequest` for parity — `set_model` is currently dispatched as an untyped dict.
4. Once the CLI subtypes land, the Python SDK PR is a forwarder identical in shape to `set_model`:
```python
async def set_effort(self, effort: EffortLevel | None) -> None:
await self._send_control_request({"subtype": "set_effort", "effort": effort})
async def set_thinking(self, thinking: ThinkingConfig | None) -> None:
await self._send_control_request({"subtype": "set_thinking", "thinking": thinking})
```
贡献指南
这个仓库没有索引到贡献指南
评估
这个 Issue 还没有评估数据。