mirror of
https://github.com/alphaXiv/OpenResearch.git
synced 2026-11-11 09:59:34 +08:00
* Persistent Claude Code child per chat session
Replace the spawn-per-turn + --resume fork with one long-lived
`claude --print --input-format stream-json` child per chat session
(new src/local/claude.rs ClaudeHost/ClaudeClient, mirroring codex.rs),
collapsing ~3-6s of per-turn spawn/config/MCP-handshake overhead.
- Respawn policy: child keyed by SpawnConfig; permission-mode/effort/
bridge change or a cleared model -> kill + respawn with --resume;
model-only change -> set_model control request; identical -> reuse.
- run_turn rewritten around a pure, store-free apply_event(ctx, state,
event) folded over the child's stream-json output; native-session-id
and flush stay in the caller.
- Gate token minted only at spawn (re-minting would strand a live
bridge child); process_group(0) so terminal SIGINT can't kill a
resident child mid-turn.
- ChatHost gains a claude host; interrupt/delete/shutdown and up.rs's
project-delete loop kill the resident child (it survives task-abort).
- Tests: child_action matrix, classify_line variants, apply_event
fixture tests over hand-written stream-json.
* Review round 1 fixes: drop ClaudeHost back-ref, fix achieved bridge_active, prune dead code
- spawn_client: force config.bridge_active = false before the plan block so a
failed bridge write records false (was inheriting wanted=true, which both
suppressed plan cards with no bridge to hold them and defeated the
respawn-to-retry recovery)
- SpawnSpec carries the ChatHost directly (transient, no cycle); deletes the
Weak attach/OnceLock apparatus and the duplicated up_port
- drop dead ClaudeHost::client_for; claude_effort back to private
- truthful docs: write_mcp_config and gate_tokens are per-spawn/per-child now
- new fixture tests: result without is_error falls back to subtype; errored
tool_result flips the tool part to error
* Comment nit from clean review round: gate token is per-child, not per-turn
* Stream partial text/thinking deltas into the transcript
Without --include-partial-messages the CLI only emits complete assistant
messages, so each text block landed at once instead of streaming. Deltas
build the part under the same {mid}-{index} id the final assistant event
upserts, so the authoritative text overwrites the accumulated one; a
subagent's nested stream (parent_tool_use_id) is ignored.
* Note the stream-protocol invariants the delta overwrite leans on