Accept Claude Code's command_lifecycle stream events

This commit is contained in:
Ian Gulliver
2026-10-22 21:30:17 -07:00
parent 73291f7c35
commit 0233e2c310
2 changed files with 3 additions and 1 deletions
+1
View File
@@ -27,6 +27,7 @@ NDJSON both ways: one JSON object per line on stdin and stdout. Non-JSON stdout
- User turn, written to stdin: `{"type":"user","message":{"role":"user","content":"..."},"parent_tool_use_id":null,"session_id":"..."}`. With images, `content` is an array of Anthropic content blocks instead: `{"type":"image","source":{"type":"base64","media_type":"image/png","data":"..."}}` for each image, then `{"type":"text","text":"..."}`. - User turn, written to stdin: `{"type":"user","message":{"role":"user","content":"..."},"parent_tool_use_id":null,"session_id":"..."}`. With images, `content` is an array of Anthropic content blocks instead: `{"type":"image","source":{"type":"base64","media_type":"image/png","data":"..."}}` for each image, then `{"type":"text","text":"..."}`.
- Stdout events: `system` (subtype `init` carries `session_id`, `model`, tools, MCP server status), `assistant` and `user` (Anthropic message content blocks: `text`, `tool_use`, `tool_result`), `result` (ends a turn; `subtype` is `success` or `error_during_execution` after an interrupt, with cost, duration, turn count). - Stdout events: `system` (subtype `init` carries `session_id`, `model`, tools, MCP server status), `assistant` and `user` (Anthropic message content blocks: `text`, `tool_use`, `tool_result`), `result` (ends a turn; `subtype` is `success` or `error_during_execution` after an interrupt, with cost, duration, turn count).
- `--include-partial-messages` adds `stream_event` lines wrapping the raw API stream (`message_start`, `content_block_start`, `content_block_delta` with `text_delta`, `content_block_stop`, `message_delta`, `message_stop`), each with `parent_tool_use_id` (set inside subagents). The complete `assistant` event for a block still arrives, before that block's `content_block_stop`. - `--include-partial-messages` adds `stream_event` lines wrapping the raw API stream (`message_start`, `content_block_start`, `content_block_delta` with `text_delta`, `content_block_stop`, `message_delta`, `message_stop`), each with `parent_tool_use_id` (set inside subagents). The complete `assistant` event for a block still arrives, before that block's `content_block_stop`.
- Newer CLIs also send `command_lifecycle` lines (`command_uuid`, `state` such as `completed`). byre drops them, as it does `keep_alive`.
- The `init` event arrives with the first turn, not at launch, so the session ID is unknown until the first message is sent. - The `init` event arrives with the first turn, not at launch, so the session ID is unknown until the first message is sent.
- While a tool runs, `tool_progress` lines with `"heartbeat": true`, the tool's `elapsed_time_seconds`, and a `parent_tool_use_id` naming the tool call arrive every 30 seconds. A Bash call also brings `system` `task_started` and `task_notification` lines around it. - While a tool runs, `tool_progress` lines with `"heartbeat": true`, the tool's `elapsed_time_seconds`, and a `parent_tool_use_id` naming the tool call arrive every 30 seconds. A Bash call also brings `system` `task_started` and `task_notification` lines around it.
- Subagents (the `Agent` tool, listed in `init` tools as `Task`): `system` `task_started` (`task_type` `local_agent`, `tool_use_id` naming the `Agent` call, `subagent_type`, `description`, `prompt`, `is_backgrounded`), `task_progress` (`description` of what it is doing), `task_updated` (by `task_id` only), and `task_notification` (`status`, `summary`). `assistant` and `user` lines from inside the subagent carry `parent_tool_use_id` set to the `Agent` call's ID, plus `agent_id`, `subagent_type` and `task_description`. A foreground subagent (`run_in_background: false`) sends only its prompt this way, as a `user` text block, and its final report arrives as the `Agent` call's `tool_result`. A background one (the default) streams all its assistant and tool-result lines; the `Agent` call's `tool_result` comes back at once saying it launched, the turn can end with its own `result` while the subagent runs, and when the subagent finishes the CLI starts another turn by itself, ending in a second `result` carrying `origin.kind` `task-notification`. - Subagents (the `Agent` tool, listed in `init` tools as `Task`): `system` `task_started` (`task_type` `local_agent`, `tool_use_id` naming the `Agent` call, `subagent_type`, `description`, `prompt`, `is_backgrounded`), `task_progress` (`description` of what it is doing), `task_updated` (by `task_id` only), and `task_notification` (`status`, `summary`). `assistant` and `user` lines from inside the subagent carry `parent_tool_use_id` set to the `Agent` call's ID, plus `agent_id`, `subagent_type` and `task_description`. A foreground subagent (`run_in_background: false`) sends only its prompt this way, as a `user` text block, and its final report arrives as the `Agent` call's `tool_result`. A background one (the default) streams all its assistant and tool-result lines; the `Agent` call's `tool_result` comes back at once saying it launched, the turn can end with its own `result` while the subagent runs, and when the subagent finishes the CLI starts another turn by itself, ending in a second `result` carrying `origin.kind` `task-notification`.
+2 -1
View File
@@ -56,6 +56,7 @@ var knownTypes = map[string]bool{
"control_response": true, "control_response": true,
"control_cancel_request": true, "control_cancel_request": true,
"keep_alive": true, "keep_alive": true,
"command_lifecycle": true,
} }
type Event struct { type Event struct {
@@ -585,7 +586,7 @@ func (s *Session) handleLine(line []byte) {
} }
return return
case "keep_alive": case "keep_alive", "command_lifecycle":
return return
} }