anthropics / anthropics/claude-agent-sdk-python
Feature request: `clear()` and runtime `resume` for warm subprocess reuse
- Linguagem predominante
- Python
- Estrelas
- 8.1k
- Forks
- 1.3k
- Métricas de merge de PRs
- Métricas de PR pendentes
Descrição
## Summary
Request two new **control protocol subtypes** on an already-connected `ClaudeSDKClient` subprocess:
1. **`clear`** — reset in-process conversation state without tearing down the subprocess (MCP, permissions, model, env preserved)
2. **Runtime `resume`** — load an existing session's history into the **running** subprocess (equivalent to CLI `--resume`, but without `disconnect()` / `connect()`), from a `SessionStore` or local `.jsonl`
Together these enable a **generic subprocess slot pool** instead of today's **one-subprocess-per-session** binding in multi-tenant server deployments.
> **Distinct from existing work:** This is not a request to restore the `/clear` slash command ([#493](https://github.com/anthropics/claude-agent-sdk-python/issues/493)), nor is it satisfied by SessionStore resume at `connect()` time ([#837](https://github.com/anthropics/claude-agent-sdk-python/pull/837)) or external history seeding into a fresh client ([#848](https://github.com/anthropics/claude-agent-sdk-python/issues/848)). We need a **runtime control plane** on a warm subprocess.
## Motivation
We run a multi-tenant **FastAPI + uvicorn** service on Kubernetes. Each pod maintains a `SessionPool` of long-lived `ClaudeSDKClient` instances backed by a **Postgres `SessionStore`** and distributed leases for cross-pod coordination.
Today's architecture forces **one subprocess per active session** because:
1. There is no supported way to **clear conversation state** on a running subprocess. The interactive CLI's `/clear` maps to internal `clearConversation` logic, but SDK mode does not expose it ([#493](https://github.com/anthropics/claude-agent-sdk-python/issues/493) closed as expected behavior; [#120](https://github.com/anthropics/claude-agent-sdk-python/issues/120) confirms `/clear` via `query()` does not actually reset context).
2. **CLI `resume` only works at `connect()` time** (`ClaudeAgentOptions(resume=...)` → `--resume` on subprocess spawn). There is no way to **resume a different session on an already-running CLI subprocess**. SessionStore ([#837](https://github.com/anthropics/claude-agent-sdk-python/pull/837)) materializes history for a **new** connection — it does not resume on a warm subprocess.
3. **`query(session_id=...)` does not isolate context** in a single long-lived client ([#560](https://github.com/anthropics/claude-agent-sdk-python/issues/560)), so we cannot multiplex sessions on one subprocess without a real reset primitive.
Idle subprocesses stay locked to their original session and cannot serve new users, causing:
- Higher memory (many idle subprocesses holding session state + MCP servers)
- Repeated cold-start cost (subprocess spawn, CLI init, MCP handshake) for new sessions
- Poor pool utilization in multi-tenant deployments
### FastAPI / asyncio note
We are aware that `ClaudeSDKClient` cannot be used across different asyncio tasks ([#576](https://github.com/anthropics/claude-agent-sdk-python/issues/576), [#925](https://github.com/anthropics/claude-agent-sdk-python/issues/925)). We already run each pooled client inside a **dedicated owner task** (queue bridge pattern from #576). **This issue does not ask to remove `TaskContextError`** — only for `clear` / runtime `resume` operations callable from that owner task on a warm subprocess.
## Proposed API
### 1. `ClaudeSDKClient.clear()`
Clear conversation history while preserving process-level state (MCP connections, permission mode, model, settings, process env).
```python
# After a conversation ends, reuse the subprocess slot for a new session
await client.clear()
await client.query("New conversation starts here")
```
Implementation sketch: a new `clear` control request subtype invoking the same `clearConversation` path as the interactive CLI `/clear` command. Based on CLI behavior, this should:
- Reset in-memory messages to `[]`
- Generate a new session ID
- Clear per-session caches (file state, web fetch cache, prompt cache, etc.)
- **Preserve** MCP server connections, permission mode, model selection, and process-level env
Optional sugar:
```python
await client.clear(resume="uuid-of-existing-session") # clear + load in one step
```
### 2. Runtime `resume` (a.k.a. `load_session()`)
Expose CLI resume semantics on a **warm subprocess** — the same behavior as `connect(options=ClaudeAgentOptions(resume=session_id))`, but callable mid-flight:
```python
# Option A: explicit resume after clear (slot reuse → restore prior session)
await client.clear()
await client.resume(session_id="uuid-of-existing-session")
await client.query("Continue from where we left off")
# Option B: alias name (either is fine)
await client.load_session(session_id="uuid-of-existing-session")
```
This is the critical half of the request: **`clear()` alone only starts a blank session**; **runtime `resume` restores history on the same subprocess** so a pool slot can switch between sessions without cold start.
`resume()` / `load_session()` should accept the same sources as connect-time `--resume`:
- Local `~/.claude/projects/.../*.jsonl` (default)
- `ClaudeAgentOptions.session_store` when configured (materialize + inject in-process, no full reconnect)
Emit a `SystemMessage(subtype="init", ...)` (or equivalent) with the resumed `session_id` so callers can confirm the active session after load.
## Use case: generic subprocess slot pool
```
Current (per-session binding):
Session A → Subprocess 1 (locked)
Session B → Subprocess 2 (locked)
Session C → cold start (new subprocess)
With clear + runtime resume (generic slot pool):
Slot 1: serve A → clear() → serve C → clear() → resume(B) → serve B → ...
Slot 2: serve D → clear() → ...
```
Pool size becomes bounded by **concurrency**, not by **distinct session count**.
## What existing issues do NOT solve
| Issue | What it addresses | What it leaves open |
|-------|-------------------|---------------------|
| [#560](https://github.com/anthropics/claude-agent-sdk-python/issues/560) | Context leak in long-lived client; asks for `clear_context` | No API design, no SessionStore, no pool architecture |
| [#493](https://github.com/anthropics/claude-agent-sdk-python/issues/493) | `/clear` unavailable in SDK mode | Official answer: use new session ID — still implies reconnect/cold start |
| [#837](https://github.com/anthropics/claude-agent-sdk-python/pull/837) | SessionStore + resume at `connect()` | No runtime switch on warm subprocess |
| [#848](https://github.com/anthropics/claude-agent-sdk-python/issues/848) | Seed external history into **fresh** client | No in-process load; no slot reuse |
| [#576](https://github.com/anthropics/claude-agent-sdk-python/issues/576) | Cross-task hang → `TaskContextError` | No session lifecycle on warm process |
## Related issues
- #560 — in-process context reset motivation (same latency-sensitive use case)
- #493, #120 — `/clear` not available / ineffective via SDK; motivates control-protocol `clear`
- #576, #925 — owner-task constraint (we comply; documented here)
- #837 — SessionStore resume at connect only
- #848 — external history seeding on fresh client (complementary)
## Environment
- `claude-agent-sdk` version: 0.2.87
- Claude CLI version: 2.1.153
- Python: 3.12
- Deployment: FastAPI + uvicorn, multi-pod (Kubernetes), Postgres SessionStore
Guia de contribuição
Nenhum guia de contribuição indexado para este repositório
Avaliação
Esta issue ainda não foi avaliada.