self: silent-stop kinds cover every kind the CLI queues nothing for on our stop; capture fixtures killshell and deadline-race; tests kill hand mutants H2 and H5
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
21f92068fb
commit
c5a2c68cb8
6 changed files with 67 additions and 4 deletions
|
|
@ -266,6 +266,10 @@ const STOP_TOOLS: [&str; 3] = ["TaskStop", "KillShell", "KillBash"];
|
|||
/// The model name on the CLI's own assistant lines, which no request produced.
|
||||
const SYNTHETIC_MODEL: &str = "<synthetic>";
|
||||
|
||||
/// The kinds (`task_type`) whose stop by the session queues nothing for the model, so their stopped notification owes no turn: `local_bash` (a Bash task or a Monitor) is captured, the rest are read from the bundle's kill code
|
||||
/// (Soul verdict `eureka-body:verdict:cut-self-reply-conversation.s6`). `local_agent`, `monitor_mcp`, `monitor_ws` and any kind not listed or unread queue a message when stopped, so they owe their turn.
|
||||
const SILENT_STOP_KINDS: [&str; 8] = ["local_bash", "local_workflow", "remote_agent", "mcp_task", "in_process_teammate", "dream", "auto_mode_scan", "local_memory_import"];
|
||||
|
||||
/// One line of the child's stream, as far as the actuator reads it.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Usage {
|
||||
|
|
@ -320,8 +324,8 @@ pub fn read_usage(line: &str) -> Usage {
|
|||
let task_id = |object: &serde_json::Map<String, Value>| object.get("task_id").and_then(Value::as_str).map(String::from);
|
||||
// A task of the main session that nobody awaits: no parent task, `awaited` not true.
|
||||
let main = |object: &serde_json::Map<String, Value>| object.get("parent_task_id").is_none_or(Value::is_null) && object.get("awaited").and_then(Value::as_bool) != Some(true);
|
||||
// The kind the CLI gives a task, `task_type`: only `local_bash` (a Bash task or a Monitor) is captured to get no turn when we stop it.
|
||||
let shell = |object: &serde_json::Map<String, Value>| object.get("task_type").and_then(Value::as_str) == Some("local_bash");
|
||||
// The kind the CLI gives a task, `task_type`: only a kind in `SILENT_STOP_KINDS` is known to get no turn when we stop it.
|
||||
let shell = |object: &serde_json::Map<String, Value>| object.get("task_type").and_then(Value::as_str).is_some_and(|kind| SILENT_STOP_KINDS.contains(&kind));
|
||||
match event.get("subtype").and_then(Value::as_str) {
|
||||
Some("init") => Usage::TurnBegan,
|
||||
Some("background_tasks_changed") => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
{"t": 0.0, "sent": "PLAN turn A."}
|
||||
{"t": 0.36, "line": "{\"type\":\"system\",\"subtype\":\"init\",\"cwd\":\"/probe/work\",\"session_id\":\"408a422a-df1e-4791-840c-9378578b03db\",\"tools\":[\"Task\",\"Bash\",\"CronCreate\",\"CronDelete\",\"CronList\",\"Edit\",\"EnterWorktree\",\"ExitWorktree\",\"ListAgents\",\"Monitor\",\"NotebookEdit\",\"Read\",\"ReportFindings\",\"ScheduleWakeup\",\"SendMessage\",\"Skill\",\"TaskStop\",\"ToolSearch\",\"WebFetch\",\"WebSearch\",\"Workflow\",\"Write\"],\"mcp_servers\":[],\"model\":\"claude-opus-5-5\",\"permissionMode\":\"bypassPermissions\",\"slash_commands\":[\"deep-research\",\"dataviz\",\"update-config\",\"verify\",\"debug\",\"code-review\",\"simplify\",\"batch\",\"fewer-permission-prompts\",\"doctor\",\"loop\",\"claude-api\",\"workflow-authoring\",\"run\",\"run-skill-generator\",\"plugin-authoring\",\"agents\",\"auto-mode-setup\",\"autocompact\",\"clear\",\"color\",\"config\",\"output-style\",\"context\",\"effort\",\"fast\",\"focus\",\"heapdump\",\"init\",\"mcp\",\"model\",\"__remote-workflow\",\"workflow-launch-exec\",\"reload-plugins\",\"reload-skills\",\"rename\",\"security-review\",\"usage\",\"insights\",\"recap\",\"goal\",\"list-agents\",\"team-onboarding\"],\"terminal_slash_commands\":[\"doctor\",\"color\",\"focus\",\"reload-plugins\"],\"apiKeySource\":\"ANTHROPIC_API_KEY\",\"claude_code_version\":\"2.1.312\",\"output_style\":\"default\",\"agents\":[\"claude\",\"Explore\",\"general-purpose\",\"Plan\",\"statusline-setup\"],\"skills\":[\"deep-research\",\"dataviz\",\"update-config\",\"verify\",\"debug\",\"code-review\",\"simplify\",\"batch\",\"fewer-permission-prompts\",\"doctor\",\"loop\",\"claude-api\",\"workflow-authoring\",\"run\",\"run-skill-generator\",\"plugin-authoring\"],\"plugins\":[{\"name\":\"cc-plugin-sec-default\",\"path\":\"builtin\",\"source\":\"cc-plugin-sec-default@builtin\"},{\"name\":\"cc-plugin-agents-md\",\"path\":\"builtin\",\"source\":\"cc-plugin-agents-md@builtin\"},{\"name\":\"cc-plugin-plugin-authoring\",\"path\":\"builtin\",\"source\":\"cc-plugin-plugin-authoring@builtin\"}],\"capabilities\":[\"interrupt_receipt_v1\",\"interrupt_cancel_queued_v1\",\"interrupt_send_now_v1\",\"interrupt_requeue_taken_v1\",\"msg_lifecycle_v1\",\"request_marker_lists_v1\",\"ask_user_question_unanswered_v1\",\"lifecycle_wakeup_source_v1\",\"sdk_mcp_tools_list_changed\",\"sdk_mcp_manifests\",\"mcp_read_resource_v1\",\"mcp_tool_ui_meta_v1\",\"ui_surface_v1\",\"mcp_call_result_not_for_model_v1\"],\"analytics_disabled\":true,\"product_feedback_disabled\":true,\"uuid\":\"4a4e64ae-f961-4e76-97c2-db379130c1d0\",\"memory_paths\":{\"auto\":\"/probe/cfg/projects/-probe-work/memory/\"},\"original_cwd\":\"/probe/work\",\"additional_directories\":[],\"messaging_socket_path\":\"/tmp/cc-socks/819313.sock\",\"fast_mode_state\":\"off\",\"fast_mode_disabled_reason\":\"sdk_opt_in_required\",\"per_turn_effort_active\":true,\"view_mode\":\"default\"}"}
|
||||
{"t": 0.43, "line": "{\"type\":\"user\",\"message\":{\"role\":\"user\",\"content\":\"PLAN turn A.\"},\"session_id\":\"408a422a-df1e-4791-840c-9378578b03db\",\"parent_tool_use_id\":null,\"uuid\":\"3b973add-311d-45ba-afc6-2857d0f20045\",\"timestamp\":\"2026-11-07T07:15:36.658Z\",\"isReplay\":true}"}
|
||||
{"t": 0.43, "line": "{\"type\":\"assistant\",\"message\":{\"id\":\"msg_0001\",\"type\":\"message\",\"role\":\"assistant\",\"model\":\"claude-opus-5-5\",\"content\":[{\"type\":\"tool_use\",\"id\":\"toolu_0001\",\"name\":\"Bash\",\"input\":{\"command\":\"sleep 30; echo late\",\"description\":\"probe deadline\",\"timeout\":3000,\"run_in_background\":true,\"dangerouslyDisableSandbox\":true}}],\"stop_reason\":null,\"stop_sequence\":null,\"usage\":{\"input_tokens\":10,\"output_tokens\":5,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0},\"context_management\":null},\"parent_tool_use_id\":null,\"session_id\":\"408a422a-df1e-4791-840c-9378578b03db\",\"uuid\":\"f2f50dd3-9e7d-4345-bff1-93238ddb9526\",\"timestamp\":\"2026-11-07T07:15:36.731Z\"}"}
|
||||
{"t": 0.49, "line": "{\"type\":\"system\",\"subtype\":\"background_tasks_changed\",\"tasks\":[{\"task_id\":\"bebo6xkjg\",\"run_id\":\"0mw62k1y3-7daba487\",\"task_type\":\"local_bash\",\"description\":\"probe deadline\"}],\"uuid\":\"2c0a6756-171b-4ff0-9bda-4fbe8a7df03f\",\"session_id\":\"408a422a-df1e-4791-840c-9378578b03db\"}"}
|
||||
{"t": 0.49, "line": "{\"type\":\"system\",\"subtype\":\"task_started\",\"task_id\":\"bebo6xkjg\",\"run_id\":\"0mw62k1y3-7daba487\",\"tool_use_id\":\"toolu_0001\",\"description\":\"probe deadline\",\"is_backgrounded\":true,\"task_type\":\"local_bash\",\"uuid\":\"0ea4bcba-f504-4848-bcbe-14679d3a8c80\",\"session_id\":\"408a422a-df1e-4791-840c-9378578b03db\"}"}
|
||||
{"t": 0.5, "line": "{\"type\":\"user\",\"message\":{\"role\":\"user\",\"content\":[{\"tool_use_id\":\"toolu_0001\",\"type\":\"tool_result\",\"content\":\"Command running in background with ID: bebo6xkjg. Output is being written to: /tmp/claude-1000/-probe-work/408a422a-df1e-4791-840c-9378578b03db/tasks/bebo6xkjg.output. You will be notified when it completes. To check interim output, use Read on that file path.\",\"is_error\":false}]},\"parent_tool_use_id\":null,\"session_id\":\"408a422a-df1e-4791-840c-9378578b03db\",\"uuid\":\"c2abf70d-69c1-4f8f-8b23-fb0a3e2c1726\",\"timestamp\":\"2026-11-07T07:15:36.807Z\",\"tool_use_result\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":false,\"isImage\":false,\"noOutputExpected\":false,\"backgroundTaskId\":\"bebo6xkjg\",\"dangerouslyDisableSandbox\":true},\"tool_result_meta\":[{\"id\":\"toolu_0001\",\"permission_decision\":{\"decision\":\"accept\",\"source\":\"config\",\"reason_type\":\"mode\"}}]}"}
|
||||
{"t": 0.53, "line": "{\"type\":\"assistant\",\"message\":{\"id\":\"msg_0002\",\"type\":\"message\",\"role\":\"assistant\",\"model\":\"claude-opus-5-5\",\"content\":[{\"type\":\"tool_use\",\"id\":\"toolu_0002_0\",\"name\":\"Bash\",\"input\":{\"command\":\"python3 -c \\\"import time; time.sleep(5)\\\"; echo fgdone\",\"description\":\"probe fg\",\"dangerouslyDisableSandbox\":true}}],\"stop_reason\":null,\"stop_sequence\":null,\"usage\":{\"input_tokens\":10,\"output_tokens\":5,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0},\"context_management\":null},\"parent_tool_use_id\":null,\"session_id\":\"408a422a-df1e-4791-840c-9378578b03db\",\"uuid\":\"a731cd17-6318-4d8c-8047-c5f9119da859\",\"timestamp\":\"2026-11-07T07:15:36.834Z\"}"}
|
||||
{"t": 0.54, "line": "{\"type\":\"assistant\",\"message\":{\"id\":\"msg_0002\",\"type\":\"message\",\"role\":\"assistant\",\"model\":\"claude-opus-5-5\",\"content\":[{\"type\":\"tool_use\",\"id\":\"toolu_0002_1\",\"name\":\"TaskStop\",\"input\":{\"task_id\":\"bebo6xkjg\"}}],\"stop_reason\":null,\"stop_sequence\":null,\"usage\":{\"input_tokens\":10,\"output_tokens\":5,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0},\"context_management\":null},\"parent_tool_use_id\":null,\"session_id\":\"408a422a-df1e-4791-840c-9378578b03db\",\"uuid\":\"32c62d31-ae4e-482e-a59e-f4f7fa85e786\",\"timestamp\":\"2026-11-07T07:15:36.845Z\"}"}
|
||||
{"t": 3.49, "line": "{\"type\":\"system\",\"subtype\":\"task_updated\",\"task_id\":\"bebo6xkjg\",\"run_id\":\"0mw62k1y3-7daba487\",\"patch\":{\"status\":\"killed\",\"end_time\":1794035739799},\"uuid\":\"3d7cfc21-2e35-434f-9f64-1bd113f5a8ce\",\"session_id\":\"408a422a-df1e-4791-840c-9378578b03db\"}"}
|
||||
{"t": 3.49, "line": "{\"type\":\"system\",\"subtype\":\"task_notification\",\"task_id\":\"bebo6xkjg\",\"run_id\":\"0mw62k1y3-7daba487\",\"tool_use_id\":\"toolu_0001\",\"status\":\"stopped\",\"output_file\":\"/tmp/claude-1000/-probe-work/408a422a-df1e-4791-840c-9378578b03db/tasks/bebo6xkjg.output\",\"summary\":\"Background command \\\"probe deadline\\\" was stopped after reaching its background time limit\",\"uuid\":\"60731d39-fa3f-475b-adeb-9244121bf865\",\"session_id\":\"408a422a-df1e-4791-840c-9378578b03db\"}"}
|
||||
{"t": 3.49, "line": "{\"type\":\"system\",\"subtype\":\"background_tasks_changed\",\"tasks\":[],\"uuid\":\"31c0a64c-cecd-4482-8c02-cef1baa30343\",\"session_id\":\"408a422a-df1e-4791-840c-9378578b03db\"}"}
|
||||
{"t": 3.55, "line": "{\"type\":\"system\",\"subtype\":\"task_started\",\"task_id\":\"bpom69hzy\",\"run_id\":\"0mw62k4b1-8b00ca4b\",\"tool_use_id\":\"toolu_0002_0\",\"description\":\"probe fg\",\"is_backgrounded\":false,\"task_type\":\"local_bash\",\"uuid\":\"f72ba4c8-e784-448b-9580-ffd94e38b2d7\",\"session_id\":\"408a422a-df1e-4791-840c-9378578b03db\"}"}
|
||||
{"t": 5.56, "line": "{\"type\":\"system\",\"subtype\":\"task_notification\",\"task_id\":\"bpom69hzy\",\"run_id\":\"0mw62k4b1-8b00ca4b\",\"tool_use_id\":\"toolu_0002_0\",\"status\":\"completed\",\"output_file\":\"\",\"summary\":\"probe fg\",\"uuid\":\"a151840d-3cae-4e98-9dcb-8327089bdb11\",\"session_id\":\"408a422a-df1e-4791-840c-9378578b03db\"}"}
|
||||
{"t": 5.57, "line": "{\"type\":\"user\",\"message\":{\"role\":\"user\",\"content\":[{\"tool_use_id\":\"toolu_0002_0\",\"type\":\"tool_result\",\"content\":\"fgdone\",\"is_error\":false}]},\"parent_tool_use_id\":null,\"session_id\":\"408a422a-df1e-4791-840c-9378578b03db\",\"uuid\":\"25715c6d-a131-4686-a6b7-f674d280a1c0\",\"timestamp\":\"2026-11-07T07:15:41.872Z\",\"tool_use_result\":{\"stdout\":\"fgdone\",\"stderr\":\"\",\"interrupted\":false,\"isImage\":false,\"noOutputExpected\":false,\"dangerouslyDisableSandbox\":true},\"tool_result_meta\":[{\"id\":\"toolu_0002_0\",\"permission_decision\":{\"decision\":\"accept\",\"source\":\"config\",\"reason_type\":\"mode\"}}]}"}
|
||||
{"t": 5.57, "line": "{\"type\":\"user\",\"message\":{\"role\":\"user\",\"content\":[{\"type\":\"tool_result\",\"content\":\"<tool_use_error>Task bebo6xkjg is not running (status: killed)</tool_use_error>\",\"is_error\":true,\"tool_use_id\":\"toolu_0002_1\"}]},\"parent_tool_use_id\":null,\"session_id\":\"408a422a-df1e-4791-840c-9378578b03db\",\"uuid\":\"51ef7078-d280-4d04-bfb8-f15e36586f9a\",\"timestamp\":\"2026-11-07T07:15:41.875Z\",\"tool_use_result\":\"Error: Task bebo6xkjg is not running (status: killed)\"}"}
|
||||
{"t": 5.58, "line": "{\"type\":\"user\",\"message\":{\"role\":\"user\",\"content\":\"<task-notification>\\n<task-id>bebo6xkjg</task-id>\\n<tool-use-id>toolu_0001</tool-use-id>\\n<output-file>/tmp/claude-1000/-probe-work/408a422a-df1e-4791-840c-9378578b03db/tasks/bebo6xkjg.output</output-file>\\n<status>killed</status>\\n<summary>Background command \\\"probe deadline\\\" was stopped after reaching its background time limit</summary>\\n<note>If the work in progress still needs it, start it again with `run_in_background` and a longer `timeout`. If it already had the longest `timeout` allowed, do not restart it. Either way, report that it was stopped.</note>\\n</task-notification>\"},\"session_id\":\"408a422a-df1e-4791-840c-9378578b03db\",\"parent_tool_use_id\":null,\"uuid\":\"2664fb01-59b3-486b-bd69-8aeb3f536077\",\"timestamp\":\"2026-11-07T07:15:39.797Z\",\"isReplay\":true,\"origin\":{\"kind\":\"task-notification\",\"producer\":\"session-task\",\"runId\":\"0mw62k1y3-7daba487\"}}"}
|
||||
{"t": 5.59, "line": "{\"type\":\"assistant\",\"message\":{\"id\":\"msg_0003\",\"type\":\"message\",\"role\":\"assistant\",\"model\":\"claude-opus-5-5\",\"content\":[{\"type\":\"text\",\"text\":\"ANSWER to request 3\"}],\"stop_reason\":null,\"stop_sequence\":null,\"usage\":{\"input_tokens\":10,\"output_tokens\":5,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0},\"context_management\":null},\"parent_tool_use_id\":null,\"session_id\":\"408a422a-df1e-4791-840c-9378578b03db\",\"uuid\":\"8c33d0f9-05c0-4999-9166-4d93581090b3\",\"timestamp\":\"2026-11-07T07:15:41.897Z\"}"}
|
||||
{"t": 5.6, "line": "{\"duration_api_ms\":74,\"stop_reason\":\"end_turn\",\"session_id\":\"408a422a-df1e-4791-840c-9378578b03db\",\"total_cost_usd\":0.00042,\"usage\":{\"input_tokens\":30,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0,\"output_tokens\":15,\"output_tokens_details\":{\"thinking_tokens\":0},\"server_tool_use\":{\"web_search_requests\":0,\"web_fetch_requests\":0},\"service_tier\":\"standard\",\"cache_creation\":{\"ephemeral_1h_input_tokens\":0,\"ephemeral_5m_input_tokens\":0},\"inference_geo\":\"\",\"iterations\":[],\"speed\":\"standard\",\"fallback_credit\":null},\"modelUsage\":{\"claude-opus-5-5\":{\"inputTokens\":30,\"outputTokens\":15,\"cacheReadInputTokens\":0,\"cacheCreationInputTokens\":0,\"webSearchRequests\":0,\"costUSD\":0.00042,\"contextWindow\":1000000,\"maxOutputTokens\":128000,\"thinkingTokens\":0,\"cacheCreationEphemeral5mInputTokens\":0,\"cacheCreationEphemeral1hInputTokens\":0,\"canonicalModel\":\"claude-opus-5-5\",\"provider\":\"firstParty\",\"costBasis\":\"list\"}},\"permission_denials\":[],\"terminal_reason\":\"completed\",\"fast_mode_state\":\"off\",\"fast_mode_disabled_reason\":\"sdk_opt_in_required\",\"subagent_stats\":{\"spawned\":0,\"requested\":{\"background\":0,\"foreground\":0,\"unset\":0},\"started_in_background\":0,\"max_depth\":0,\"spawned_by_subagents\":0,\"completed\":0,\"failed\":0,\"killed\":{\"parent\":0,\"user\":0,\"system\":0},\"refused\":{\"depth_limit\":0,\"concurrency_limit\":0,\"budget\":0},\"by_type\":{}},\"safety_stops\":0,\"is_error\":false,\"num_turns\":4,\"subtype\":\"success\",\"api_error_status\":null,\"result\":\"ANSWER to request 3\",\"ttft_ms\":100,\"type\":\"result\",\"duration_ms\":5272,\"uuid\":\"0a6174e4-d3b5-4983-ba64-f5748df72f82\",\"ttft_stream_ms\":98,\"time_to_request_ms\":89,\"first_content_frame_ms\":98,\"queued_turn_count\":0,\"result_index\":0,\"model_usage_since_last_result\":{\"claude-opus-5-5\":{\"inputTokens\":30,\"outputTokens\":15,\"cacheReadInputTokens\":0,\"cacheCreationInputTokens\":0,\"webSearchRequests\":0,\"costUSD\":0.00042,\"contextWindow\":1000000,\"maxOutputTokens\":128000,\"thinkingTokens\":0,\"cacheCreationEphemeral5mInputTokens\":0,\"cacheCreationEphemeral1hInputTokens\":0,\"canonicalModel\":\"claude-opus-5-5\",\"provider\":\"firstParty\",\"costBasis\":\"list\"}}}"}
|
||||
{"t": 25.07, "exit": 0}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
{"t": 0.0, "sent": "PLAN turn A."}
|
||||
{"t": 0.45, "line": "{\"type\":\"system\",\"subtype\":\"init\",\"cwd\":\"/probe/work\",\"session_id\":\"d6090dff-59a2-4308-bc89-63774d11a1fb\",\"tools\":[\"Task\",\"Bash\",\"CronCreate\",\"CronDelete\",\"CronList\",\"Edit\",\"EnterWorktree\",\"ExitWorktree\",\"ListAgents\",\"Monitor\",\"NotebookEdit\",\"Read\",\"ReportFindings\",\"ScheduleWakeup\",\"SendMessage\",\"Skill\",\"TaskStop\",\"ToolSearch\",\"WebFetch\",\"WebSearch\",\"Workflow\",\"Write\"],\"mcp_servers\":[],\"model\":\"claude-opus-5-5\",\"permissionMode\":\"bypassPermissions\",\"slash_commands\":[\"deep-research\",\"dataviz\",\"update-config\",\"verify\",\"debug\",\"code-review\",\"simplify\",\"batch\",\"fewer-permission-prompts\",\"doctor\",\"loop\",\"claude-api\",\"workflow-authoring\",\"run\",\"run-skill-generator\",\"plugin-authoring\",\"agents\",\"auto-mode-setup\",\"autocompact\",\"clear\",\"color\",\"config\",\"output-style\",\"context\",\"effort\",\"fast\",\"focus\",\"heapdump\",\"init\",\"mcp\",\"model\",\"__remote-workflow\",\"workflow-launch-exec\",\"reload-plugins\",\"reload-skills\",\"rename\",\"security-review\",\"usage\",\"insights\",\"recap\",\"goal\",\"list-agents\",\"team-onboarding\"],\"terminal_slash_commands\":[\"doctor\",\"color\",\"focus\",\"reload-plugins\"],\"apiKeySource\":\"ANTHROPIC_API_KEY\",\"claude_code_version\":\"2.1.312\",\"output_style\":\"default\",\"agents\":[\"claude\",\"Explore\",\"general-purpose\",\"Plan\",\"statusline-setup\"],\"skills\":[\"deep-research\",\"dataviz\",\"update-config\",\"verify\",\"debug\",\"code-review\",\"simplify\",\"batch\",\"fewer-permission-prompts\",\"doctor\",\"loop\",\"claude-api\",\"workflow-authoring\",\"run\",\"run-skill-generator\",\"plugin-authoring\"],\"plugins\":[{\"name\":\"cc-plugin-sec-default\",\"path\":\"builtin\",\"source\":\"cc-plugin-sec-default@builtin\"},{\"name\":\"cc-plugin-agents-md\",\"path\":\"builtin\",\"source\":\"cc-plugin-agents-md@builtin\"},{\"name\":\"cc-plugin-plugin-authoring\",\"path\":\"builtin\",\"source\":\"cc-plugin-plugin-authoring@builtin\"}],\"capabilities\":[\"interrupt_receipt_v1\",\"interrupt_cancel_queued_v1\",\"interrupt_send_now_v1\",\"interrupt_requeue_taken_v1\",\"msg_lifecycle_v1\",\"request_marker_lists_v1\",\"ask_user_question_unanswered_v1\",\"lifecycle_wakeup_source_v1\",\"sdk_mcp_tools_list_changed\",\"sdk_mcp_manifests\",\"mcp_read_resource_v1\",\"mcp_tool_ui_meta_v1\",\"ui_surface_v1\",\"mcp_call_result_not_for_model_v1\"],\"analytics_disabled\":true,\"product_feedback_disabled\":true,\"uuid\":\"5aea4fe1-dace-4f2e-ba3e-71eeaee9f80c\",\"memory_paths\":{\"auto\":\"/probe/cfg/projects/-probe-work/memory/\"},\"original_cwd\":\"/probe/work\",\"additional_directories\":[],\"messaging_socket_path\":\"/tmp/cc-socks/822857.sock\",\"fast_mode_state\":\"off\",\"fast_mode_disabled_reason\":\"sdk_opt_in_required\",\"per_turn_effort_active\":true,\"view_mode\":\"default\"}"}
|
||||
{"t": 0.51, "line": "{\"type\":\"user\",\"message\":{\"role\":\"user\",\"content\":\"PLAN turn A.\"},\"session_id\":\"d6090dff-59a2-4308-bc89-63774d11a1fb\",\"parent_tool_use_id\":null,\"uuid\":\"b37d6ee9-4320-4f36-b90a-09dbd9e5ac8d\",\"timestamp\":\"2026-11-07T07:16:01.872Z\",\"isReplay\":true}"}
|
||||
{"t": 0.52, "line": "{\"type\":\"assistant\",\"message\":{\"id\":\"msg_0001\",\"type\":\"message\",\"role\":\"assistant\",\"model\":\"claude-opus-5-5\",\"content\":[{\"type\":\"tool_use\",\"id\":\"toolu_0001\",\"name\":\"Bash\",\"input\":{\"command\":\"python3 -c 'import time; time.sleep(30)'; echo probe-done\",\"description\":\"probe bg\",\"run_in_background\":true,\"dangerouslyDisableSandbox\":true}}],\"stop_reason\":null,\"stop_sequence\":null,\"usage\":{\"input_tokens\":10,\"output_tokens\":5,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0},\"context_management\":null},\"parent_tool_use_id\":null,\"session_id\":\"d6090dff-59a2-4308-bc89-63774d11a1fb\",\"uuid\":\"32127ee2-aef1-41b9-a2d3-f6c334819161\",\"timestamp\":\"2026-11-07T07:16:01.953Z\"}"}
|
||||
{"t": 0.58, "line": "{\"type\":\"system\",\"subtype\":\"background_tasks_changed\",\"tasks\":[{\"task_id\":\"bvo8lvtx8\",\"run_id\":\"0mw62klem-e6539923\",\"task_type\":\"local_bash\",\"description\":\"probe bg\"}],\"uuid\":\"d0cc1e0d-c677-4b18-9695-ed90cda6fb9a\",\"session_id\":\"d6090dff-59a2-4308-bc89-63774d11a1fb\"}"}
|
||||
{"t": 0.59, "line": "{\"type\":\"system\",\"subtype\":\"task_started\",\"task_id\":\"bvo8lvtx8\",\"run_id\":\"0mw62klem-e6539923\",\"tool_use_id\":\"toolu_0001\",\"description\":\"probe bg\",\"is_backgrounded\":true,\"task_type\":\"local_bash\",\"uuid\":\"cf225ef3-bffa-4c09-be80-c9c6caea074c\",\"session_id\":\"d6090dff-59a2-4308-bc89-63774d11a1fb\"}"}
|
||||
{"t": 0.6, "line": "{\"type\":\"user\",\"message\":{\"role\":\"user\",\"content\":[{\"tool_use_id\":\"toolu_0001\",\"type\":\"tool_result\",\"content\":\"Command running in background with ID: bvo8lvtx8. Output is being written to: /tmp/claude-1000/-probe-work/d6090dff-59a2-4308-bc89-63774d11a1fb/tasks/bvo8lvtx8.output. You will be notified when it completes. To check interim output, use Read on that file path.\",\"is_error\":false}]},\"parent_tool_use_id\":null,\"session_id\":\"d6090dff-59a2-4308-bc89-63774d11a1fb\",\"uuid\":\"dd13af8f-28ab-406c-878f-928a16970cca\",\"timestamp\":\"2026-11-07T07:16:02.036Z\",\"tool_use_result\":{\"stdout\":\"\",\"stderr\":\"\",\"interrupted\":false,\"isImage\":false,\"noOutputExpected\":false,\"backgroundTaskId\":\"bvo8lvtx8\",\"dangerouslyDisableSandbox\":true},\"tool_result_meta\":[{\"id\":\"toolu_0001\",\"permission_decision\":{\"decision\":\"accept\",\"source\":\"config\",\"reason_type\":\"mode\"}}]}"}
|
||||
{"t": 0.62, "line": "{\"type\":\"assistant\",\"message\":{\"id\":\"msg_0002\",\"type\":\"message\",\"role\":\"assistant\",\"model\":\"claude-opus-5-5\",\"content\":[{\"type\":\"tool_use\",\"id\":\"toolu_0002\",\"name\":\"KillShell\",\"input\":{\"shell_id\":\"bvo8lvtx8\"}}],\"stop_reason\":null,\"stop_sequence\":null,\"usage\":{\"input_tokens\":10,\"output_tokens\":5,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0},\"context_management\":null},\"parent_tool_use_id\":null,\"session_id\":\"d6090dff-59a2-4308-bc89-63774d11a1fb\",\"uuid\":\"56fb10ce-a362-4d84-aed7-88be47dc9cbc\",\"timestamp\":\"2026-11-07T07:16:02.063Z\"}"}
|
||||
{"t": 0.63, "line": "{\"type\":\"system\",\"subtype\":\"task_updated\",\"task_id\":\"bvo8lvtx8\",\"run_id\":\"0mw62klem-e6539923\",\"patch\":{\"status\":\"killed\",\"end_time\":1794035762069},\"uuid\":\"c02da7d6-5ba6-444e-8e34-9d86f793bbe9\",\"session_id\":\"d6090dff-59a2-4308-bc89-63774d11a1fb\"}"}
|
||||
{"t": 0.63, "line": "{\"type\":\"system\",\"subtype\":\"task_notification\",\"task_id\":\"bvo8lvtx8\",\"run_id\":\"0mw62klem-e6539923\",\"tool_use_id\":\"toolu_0001\",\"status\":\"stopped\",\"output_file\":\"/tmp/claude-1000/-probe-work/d6090dff-59a2-4308-bc89-63774d11a1fb/tasks/bvo8lvtx8.output\",\"summary\":\"probe bg\",\"uuid\":\"04dcf7b2-bccc-40a7-99f9-a314bf882716\",\"session_id\":\"d6090dff-59a2-4308-bc89-63774d11a1fb\"}"}
|
||||
{"t": 0.63, "line": "{\"type\":\"system\",\"subtype\":\"background_tasks_changed\",\"tasks\":[],\"uuid\":\"6d3619a3-5534-441f-9140-745fb0c9a788\",\"session_id\":\"d6090dff-59a2-4308-bc89-63774d11a1fb\"}"}
|
||||
{"t": 0.63, "line": "{\"type\":\"user\",\"message\":{\"role\":\"user\",\"content\":[{\"tool_use_id\":\"toolu_0002\",\"type\":\"tool_result\",\"content\":\"{\\\"message\\\":\\\"Successfully stopped task: bvo8lvtx8 (python3 -c 'import time; time.sleep(30)'; echo probe-done)\\\",\\\"task_id\\\":\\\"bvo8lvtx8\\\",\\\"task_type\\\":\\\"local_bash\\\",\\\"command\\\":\\\"python3 -c 'import time; time.sleep(30)'; echo probe-done\\\"}\"}]},\"parent_tool_use_id\":null,\"session_id\":\"d6090dff-59a2-4308-bc89-63774d11a1fb\",\"uuid\":\"73bfdcac-eb35-4422-858c-d2d225a9c960\",\"timestamp\":\"2026-11-07T07:16:02.072Z\",\"tool_use_result\":{\"message\":\"Successfully stopped task: bvo8lvtx8 (python3 -c 'import time; time.sleep(30)'; echo probe-done)\",\"task_id\":\"bvo8lvtx8\",\"task_type\":\"local_bash\",\"command\":\"python3 -c 'import time; time.sleep(30)'; echo probe-done\"},\"tool_result_meta\":[{\"id\":\"toolu_0002\",\"permission_decision\":{\"decision\":\"accept\",\"source\":\"config\",\"reason_type\":\"mode\"}}]}"}
|
||||
{"t": 0.66, "line": "{\"type\":\"assistant\",\"message\":{\"id\":\"msg_0003\",\"type\":\"message\",\"role\":\"assistant\",\"model\":\"claude-opus-5-5\",\"content\":[{\"type\":\"text\",\"text\":\"ANSWER to request 3\"}],\"stop_reason\":null,\"stop_sequence\":null,\"usage\":{\"input_tokens\":10,\"output_tokens\":5,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0},\"context_management\":null},\"parent_tool_use_id\":null,\"session_id\":\"d6090dff-59a2-4308-bc89-63774d11a1fb\",\"uuid\":\"e713a3bc-b83a-44c3-b3a2-f7de2efcce7d\",\"timestamp\":\"2026-11-07T07:16:02.094Z\"}"}
|
||||
{"t": 0.66, "line": "{\"duration_api_ms\":85,\"stop_reason\":\"end_turn\",\"session_id\":\"d6090dff-59a2-4308-bc89-63774d11a1fb\",\"total_cost_usd\":0.00042,\"usage\":{\"input_tokens\":30,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0,\"output_tokens\":15,\"output_tokens_details\":{\"thinking_tokens\":0},\"server_tool_use\":{\"web_search_requests\":0,\"web_fetch_requests\":0},\"service_tier\":\"standard\",\"cache_creation\":{\"ephemeral_1h_input_tokens\":0,\"ephemeral_5m_input_tokens\":0},\"inference_geo\":\"\",\"iterations\":[],\"speed\":\"standard\",\"fallback_credit\":null},\"modelUsage\":{\"claude-opus-5-5\":{\"inputTokens\":30,\"outputTokens\":15,\"cacheReadInputTokens\":0,\"cacheCreationInputTokens\":0,\"webSearchRequests\":0,\"costUSD\":0.00042,\"contextWindow\":1000000,\"maxOutputTokens\":128000,\"thinkingTokens\":0,\"cacheCreationEphemeral5mInputTokens\":0,\"cacheCreationEphemeral1hInputTokens\":0,\"canonicalModel\":\"claude-opus-5-5\",\"provider\":\"firstParty\",\"costBasis\":\"list\"}},\"permission_denials\":[],\"terminal_reason\":\"completed\",\"fast_mode_state\":\"off\",\"fast_mode_disabled_reason\":\"sdk_opt_in_required\",\"subagent_stats\":{\"spawned\":0,\"requested\":{\"background\":0,\"foreground\":0,\"unset\":0},\"started_in_background\":0,\"max_depth\":0,\"spawned_by_subagents\":0,\"completed\":0,\"failed\":0,\"killed\":{\"parent\":0,\"user\":0,\"system\":0},\"refused\":{\"depth_limit\":0,\"concurrency_limit\":0,\"budget\":0},\"by_type\":{}},\"safety_stops\":0,\"is_error\":false,\"num_turns\":3,\"subtype\":\"success\",\"api_error_status\":null,\"result\":\"ANSWER to request 3\",\"ttft_ms\":112,\"type\":\"result\",\"duration_ms\":259,\"uuid\":\"0bf20120-888c-465b-99d8-a8eeb1166aa3\",\"ttft_stream_ms\":111,\"time_to_request_ms\":101,\"first_content_frame_ms\":111,\"queued_turn_count\":0,\"result_index\":0,\"model_usage_since_last_result\":{\"claude-opus-5-5\":{\"inputTokens\":30,\"outputTokens\":15,\"cacheReadInputTokens\":0,\"cacheCreationInputTokens\":0,\"webSearchRequests\":0,\"costUSD\":0.00042,\"contextWindow\":1000000,\"maxOutputTokens\":128000,\"thinkingTokens\":0,\"cacheCreationEphemeral5mInputTokens\":0,\"cacheCreationEphemeral1hInputTokens\":0,\"canonicalModel\":\"claude-opus-5-5\",\"provider\":\"firstParty\",\"costBasis\":\"list\"}}}"}
|
||||
{"t": 15.03, "exit": 0}
|
||||
|
|
@ -155,7 +155,7 @@ pub(super) struct State {
|
|||
running: BTreeSet<String>,
|
||||
/// Tasks the main session ever backgrounded (the CLI's own SDK consumer's rule), by `task_id`: a monotone cache of the stream.
|
||||
backgrounded: BTreeSet<String>,
|
||||
/// Tasks the CLI's `task_type` calls `local_bash` (a Bash task or a Monitor), by `task_id`: the only kinds captured to get no turn when we stop them.
|
||||
/// Tasks of a kind whose stop by the session queues nothing for the model (`SILENT_STOP_KINDS`), by `task_id`: the only kinds that owe no turn when we stop them.
|
||||
shell: BTreeSet<String>,
|
||||
/// Tasks a `TaskStop` call of ours named: the CLI's stop tells the model nothing, so such a notification owes no turn.
|
||||
stopped_by_us: BTreeSet<String>,
|
||||
|
|
@ -340,7 +340,7 @@ pub(super) fn decide(mut state: State, event: Event, now: DateTime<Utc>) -> (Sta
|
|||
}
|
||||
state.backgrounded.insert(id);
|
||||
}
|
||||
// The CLI's rule: a backgrounded task's notification is given a turn, except that of a stop the model asked for itself of a shell task (any other kind, or an unread one, gets its turn when stopped as when ended). A foreground,
|
||||
// The CLI's rule: a backgrounded task's notification is given a turn, except that of a stop the model asked for itself of a silent-stop kind (any other kind, or an unread one, gets its turn when stopped as when ended). A foreground,
|
||||
// subagent-owned, awaited or unknown task owes nothing; a stop the CLI made on its own (a deadline, memory pressure) owes its turn.
|
||||
Event::TaskNotified { id, stopped } => {
|
||||
if state.backgrounded.contains(&id) && !(stopped && state.stopped_by_us.contains(&id) && state.shell.contains(&id)) {
|
||||
|
|
|
|||
|
|
@ -644,6 +644,7 @@ fn a_notification_owes_a_turn_when_the_task_was_backgrounded_unless_the_session_
|
|||
assert!(owes(vec![(backgrounded("t"), 3), (stopped("t"), 4)]), "a stop the session did not ask for owes its turn");
|
||||
assert!(owes(vec![(backgrounded("t"), 3), (stops_of("b", &["other"]), 3), (stopped("t"), 4)]));
|
||||
assert!(owes(vec![(backgrounded_other("t"), 3), (stops_of("b", &["t"]), 3), (stopped("t"), 4)]), "a stop of ours owes nothing only for a shell task: any other kind gets its turn");
|
||||
assert!(!owes(vec![(Event::BackgroundTasks { live: vec!["t".into()], main: vec!["t".into()], shell: vec!["t".into()] }, 3), (stops_of("b", &["t"]), 3), (stopped("t"), 4)]), "a kind read only from the level's entry is as silent as one read from the start line");
|
||||
assert!(owes(vec![(Event::BackgroundTasks { live: vec!["t".into()], main: vec!["t".into()], shell: vec![] }, 3), (stops_of("b", &["t"]), 3), (stopped("t"), 4)]), "a level entry of another or unread kind gets its turn");
|
||||
assert!(owes(vec![(backgrounded("t"), 3), (stops_of("b", &["t"]), 3), (notified("t"), 4)]), "a task that completed is told in its own turn: only a status of stopped is ours");
|
||||
// The stop is read from any line of the turn, including a request line already seen.
|
||||
|
|
|
|||
|
|
@ -1616,6 +1616,8 @@ mod live_session {
|
|||
const BG_FGTO: &str = include_str!("claude-2.1.312-live-session-bg-fgto.jsonl");
|
||||
const BG_KILL: &str = include_str!("claude-2.1.312-live-session-bg-kill.jsonl");
|
||||
const BG_MONITOR: &str = include_str!("claude-2.1.312-live-session-bg-monitor.jsonl");
|
||||
const BG_KILLSHELL: &str = include_str!("claude-2.1.312-live-session-bg-killshell.jsonl");
|
||||
const BG_DEADLINE_RACE: &str = include_str!("claude-2.1.312-live-session-bg-deadline-race.jsonl");
|
||||
|
||||
#[test]
|
||||
fn a_line_written_during_a_tool_call_is_folded_one_result_and_its_echo_before_the_request_that_carries_it() {
|
||||
|
|
@ -1768,6 +1770,16 @@ mod live_session {
|
|||
assert_eq!(started(json!({})), Usage::TaskBackgrounded { id: "t".into(), shell: false }, "no task_type is no shell");
|
||||
assert_eq!(started(json!({"task_type": "local_bash"})), Usage::TaskBackgrounded { id: "t".into(), shell: true });
|
||||
assert_eq!(started(json!({"task_type": "local_agent"})), Usage::TaskBackgrounded { id: "t".into(), shell: false });
|
||||
// Every kind the CLI source shows queues nothing for the model when the session stops it is silent; the kinds that queue a message, and any unknown one, are not.
|
||||
for kind in ["local_bash", "local_workflow", "remote_agent", "mcp_task", "in_process_teammate", "dream", "auto_mode_scan", "local_memory_import"] {
|
||||
assert_eq!(started(json!({"task_type": kind})), Usage::TaskBackgrounded { id: "t".into(), shell: true }, "{kind}");
|
||||
}
|
||||
for kind in ["local_agent", "monitor_mcp", "monitor_ws", "some_new_kind"] {
|
||||
assert_eq!(started(json!({"task_type": kind})), Usage::TaskBackgrounded { id: "t".into(), shell: false }, "{kind}");
|
||||
}
|
||||
// The move to the background read from `task_updated` names no kind, so it claims no silence.
|
||||
let updated = json!({"type": "system", "subtype": "task_updated", "task_id": "t", "patch": {"is_backgrounded": true}}).to_string();
|
||||
assert_eq!(read_usage(&updated), Usage::TaskBackgrounded { id: "t".into(), shell: false });
|
||||
assert_eq!(started(json!({"is_backgrounded": false})), Usage::Other, "a foreground task is no reading");
|
||||
assert_eq!(started(json!({"parent_task_id": "p"})), Usage::Other);
|
||||
assert_eq!(started(json!({"awaited": true})), Usage::Other);
|
||||
|
|
@ -1789,6 +1801,17 @@ mod live_session {
|
|||
assert!(call("Bash", json!({"task_id": "t"})).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_shell_task_stopped_by_killshell_or_by_a_deadline_that_beat_our_taskstop_gives_no_cli_turn_and_leaves_the_session_idle() {
|
||||
for capture in [BG_KILLSHELL, BG_DEADLINE_RACE] {
|
||||
let usages = usages(capture);
|
||||
assert!(usages.iter().any(|usage| matches!(usage, Usage::TaskNotified { stopped: true, .. })), "{usages:?}");
|
||||
assert!(usages.iter().any(|usage| matches!(usage, Usage::Request { stops, .. } if !stops.is_empty())), "{usages:?}");
|
||||
assert_eq!(kinds(&replay(capture)).iter().filter(|kind| **kind == "turn").count(), 1, "no turn begins after ours");
|
||||
assert!(idleness(capture).last().unwrap().1, "nothing is owed after the stop");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_background_agent_announces_itself_as_a_backgrounded_task_and_the_session_is_not_idle_until_its_notification_turn_ends() {
|
||||
let usages = usages(BG_AGENT);
|
||||
|
|
|
|||
Loading…
Reference in a new issue