Refine course progression and runtime safety

This commit is contained in:
Haoran
2026-08-11 15:13:13 +08:00
parent b36dbcd84f
commit ab35e59672
83 changed files with 5291 additions and 2267 deletions

View File

@@ -4,43 +4,43 @@
{
"id": "fresh-subagent-context",
"title": "Subagents Start with Fresh Messages",
"description": "The child agent receives only the delegated prompt. This isolates exploratory work and prevents the parent context from filling with every intermediate tool result.",
"alternatives": "Sharing the full parent history gives more context, but it defeats the purpose of delegation as context isolation.",
"description": "The subagent receives only the delegated prompt. Its intermediate tool calls stay in a separate message list instead of being copied into the parent conversation.",
"alternatives": "Passing the parent history would give the subagent more context, but would no longer demonstrate a fresh-message boundary.",
"zh": {
"title": "子代理从全新 Messages 开始",
"description": "子代理只收到被委派的 prompt。这样探索性工作被隔离,父上下文不会塞满每个中间工具结果。"
"description": "子 Agent 只收到被委派的 prompt。中间工具调用留在另一份消息列表中,不复制到父对话。"
},
"ja": {
"title": "サブエージェントは新しい messages で始まる",
"description": "エージェントは委任された prompt だけを受け取ります。探索作業を隔離し、親コンテキストが中間 tool result で膨らむのを防ぎます。"
"description": "サブエージェントは委任された prompt だけを受け取る。中間ツール呼び出しは別のメッセージリストに残り、親会話へコピーされない。"
}
},
{
"id": "summary-only-return",
"title": "Only the Summary Returns to the Parent",
"description": "The parent receives a compact final answer, not the child's full transcript. That gives delegation a predictable context cost.",
"alternatives": "Returning the full transcript can help debugging, but it makes large subagent runs expensive to continue.",
"title": "Only the Final Text Returns to the Parent",
"description": "The parent receives the subagent's final text as the task result, not the subagent's full message list.",
"alternatives": "Returning the full message list would expose more detail, but it would remove the boundary shown in this lesson.",
"zh": {
"title": "只有摘要返回父循环",
"description": "父循环收到的是压缩后的最终答案,而不是子代理的完整 transcript。这样委派的上下文成本可预测。"
"title": "只有最终文本返回父循环",
"description": "父循环收到的是作为 task 结果返回的最终文本,而不是子 Agent 的完整消息列表。"
},
"ja": {
"title": "親に戻るのは要約だけ",
"description": "親が受け取るのは子の完全な transcript ではなく、圧縮された最終回答です。委任のコンテキストコストを予測可能にします。"
"title": "親に戻るのは最終テキストだけ",
"description": "親が受け取るのは task result となる最終テキストであり、サブエージェントの完全なメッセージリストではない。"
}
},
{
"id": "no-recursive-task-tool",
"title": "Subagents Cannot Spawn Subagents",
"description": "The child tool set omits task, preventing recursive delegation from exploding. The lesson keeps isolation visible before adding richer team behavior later.",
"alternatives": "Allowing recursion is powerful, but much harder to bound and explain.",
"title": "The Subagent Has No Task Tool",
"description": "The subagent tool set omits task, so this lesson has one delegation level.",
"alternatives": "Recursive delegation is possible, but requires additional lifecycle and limit controls not introduced here.",
"zh": {
"title": "子代理不能再创建子代理",
"description": "子代理工具集中不包含 task避免递归委派失控。课程先把隔离讲清楚,再在后续章节加入更复杂团队行为。"
"title": "子 Agent 没有 task 工具",
"description": "子 Agent 的工具集中不包含 task因此本章只有一层委派。"
},
"ja": {
"title": "サブエージェントはさらにサブエージェントを作れない",
"description": "のツールセットから task を外し、再帰的委任の爆発を防ぎます。まず隔離を明確にし、後の章でより豊かなチーム動作を扱います。"
"title": "サブエージェントに task ツールはない",
"description": "サブエージェントのツールセット task はなく、本章の委任は 1 階層となる。"
}
}
]

View File

@@ -578,7 +578,7 @@ const CURRENT_FLOW_OVERRIDES: Record<string, FlowDefinition> = {
{ id: "llm", label: "LLM Call", type: "process", x: COL_CENTER, y: 120 },
{ id: "tool", label: "tool_use?", type: "decision", x: COL_CENTER, y: 210 },
{ id: "todo", label: "todo_write?", type: "decision", x: COL_LEFT, y: 310 },
{ id: "update", label: "Update\ncurrent_todos", type: "process", x: COL_LEFT, y: 410 },
{ id: "update", label: "TodoManager\n.update()", type: "process", x: COL_LEFT, y: 410 },
{ id: "other", label: "Run Tool", type: "subprocess", x: COL_CENTER, y: 410 },
{ id: "reminder", label: "3 rounds?\nInject Reminder", type: "process", x: COL_RIGHT, y: 500 },
{ id: "append", label: "Append Result", type: "process", x: COL_CENTER, y: 590 },
@@ -602,9 +602,9 @@ const CURRENT_FLOW_OVERRIDES: Record<string, FlowDefinition> = {
{ id: "start", label: "User Input", type: "start", x: COL_CENTER, y: 30 },
{ id: "parent", label: "Parent LLM", type: "process", x: COL_CENTER, y: 120 },
{ id: "task_check", label: "task tool?", type: "decision", x: COL_CENTER, y: 220 },
{ id: "spawn", label: "Spawn Subagent\nfresh messages[]", type: "subprocess", x: COL_LEFT, y: 330 },
{ id: "run", label: "Run Subagent\nfresh messages[]", type: "subprocess", x: COL_LEFT, y: 330 },
{ id: "subloop", label: "Subagent Loop\nmax 30 turns", type: "process", x: COL_LEFT, y: 430 },
{ id: "summary", label: "Return Summary\nOnly", type: "process", x: COL_LEFT, y: 530 },
{ id: "final_text", label: "Return Final\nText", type: "process", x: COL_LEFT, y: 530 },
{ id: "tool", label: "Run Parent Tool", type: "subprocess", x: COL_RIGHT, y: 330 },
{ id: "append", label: "Append Result", type: "process", x: COL_CENTER, y: 630 },
{ id: "end", label: "Output", type: "end", x: COL_RIGHT, y: 220 },
@@ -612,12 +612,12 @@ const CURRENT_FLOW_OVERRIDES: Record<string, FlowDefinition> = {
edges: [
{ from: "start", to: "parent" },
{ from: "parent", to: "task_check" },
{ from: "task_check", to: "spawn", label: "task" },
{ from: "task_check", to: "run", label: "task" },
{ from: "task_check", to: "tool", label: "other" },
{ from: "task_check", to: "end", label: "done" },
{ from: "spawn", to: "subloop" },
{ from: "subloop", to: "summary" },
{ from: "summary", to: "append" },
{ from: "run", to: "subloop" },
{ from: "subloop", to: "final_text" },
{ from: "final_text", to: "append" },
{ from: "tool", to: "append" },
{ from: "append", to: "parent" },
],

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -17,8 +17,8 @@
{
"type": "tool_result",
"toolName": "todo_write",
"content": "Todos updated.",
"annotation": "The current todo list is kept by the harness."
"content": "[>] Inspect parser\n[ ] Refactor parsing branch\n[ ] Add regression test\n\n(0/3 completed)",
"annotation": "The harness returns the current list to the model."
},
{
"type": "tool_call",
@@ -28,8 +28,8 @@
},
{
"type": "system_event",
"content": "<reminder>Update todo status after 3 rounds without todo_write.</reminder>",
"annotation": "The nag reminder keeps the plan fresh during long work."
"content": "<reminder>Update your todos.</reminder>",
"annotation": "After three rounds without todo_write, the harness appends a reminder."
},
{
"type": "assistant_text",

View File

@@ -1,7 +1,7 @@
{
"version": "s06",
"title": "Subagent",
"description": "The task tool spawns a fresh subagent context and returns only a final summary to the parent.",
"description": "The task tool runs a nested agent loop with fresh messages and returns its final text to the parent.",
"steps": [
{
"type": "user_message",
@@ -16,20 +16,20 @@
},
{
"type": "system_event",
"content": "spawn_subagent: messages=[{role:\"user\", content: prompt}], tools=bash/read/write/edit/glob",
"annotation": "The child receives a fresh message history and no recursive task tool."
"content": "run_subagent: messages=[{role:\"user\", content: prompt}], tools=bash/read/write/edit/glob",
"annotation": "The subagent receives fresh messages and no task tool."
},
{
"type": "tool_call",
"toolName": "read_file",
"content": "{\"path\":\"cli.py\"}",
"annotation": "Inside the child loop, intermediate tool calls stay private."
"annotation": "The tool call stays in the subagent's local message list."
},
{
"type": "tool_result",
"toolName": "task",
"content": "Summary: cli.py parses args, selects a command handler, then dispatches.",
"annotation": "Only the subagent's final summary returns to the parent."
"annotation": "The subagent's final text becomes the parent's task result."
},
{
"type": "assistant_text",

View File

@@ -51,8 +51,8 @@
{
"type": "tool_call",
"toolName": "spawn_teammate",
"content": "{\"name\":\"backend\",\"role\":\"backend engineer\",\"prompt\":\"Claim the authentication task and propose a plan.\"}",
"annotation": "A persistent teammate receives focused work through the team runtime."
"content": "{\"name\":\"backend\",\"role\":\"backend engineer\",\"prompt\":\"Claim the authentication task and propose a plan.\",\"require_plan\":true}",
"annotation": "The plan gate is active before the teammate thread starts, so claim and mutation cannot race ahead of approval."
},
{
"type": "tool_call",
@@ -62,13 +62,30 @@
},
{
"type": "system_event",
"content": "plan_request(req_plan_7) -> plan_response(req_plan_7, approved=true)",
"annotation": "Typed correlation and an approval gate protect mutating tools."
"content": "claim_next_task(backend) -> task_1712345678_0042; task_store_lock commits owner=backend",
"annotation": "The ownership check and persisted state transition share the cross-process task-store lock."
},
{
"type": "tool_call",
"toolName": "request_plan",
"content": "{\"teammate\":\"backend\",\"task\":\"Inspect the claimed authentication task and submit a plan before changing files.\"}",
"annotation": "The Lead delivers the plan request for the current assignment; the gate was already active before the teammate thread started."
},
{
"type": "system_event",
"content": "claim_next_task(backend) -> task_1712345678_0042; task_lock commits owner=backend",
"annotation": "The ownership check and state transition are atomic."
"content": "backend submit_plan -> plan_approval_request(request_id=req_000007, task_id=task_1712345678_0042)",
"annotation": "The request records the task and work version that the plan is meant to authorize."
},
{
"type": "tool_call",
"toolName": "review_plan",
"content": "{\"request_id\":\"req_000007\",\"approve\":true,\"feedback\":\"Proceed with the scoped refactor.\"}",
"annotation": "Approval is correlated by request ID and cannot carry into a different assignment."
},
{
"type": "system_event",
"content": "plan_approval_response(request_id=req_000007, approve=true) -> backend",
"annotation": "The teammate receives the typed response before mutating tools are released."
},
{
"type": "system_event",
@@ -84,7 +101,7 @@
{
"type": "system_event",
"content": "backend -> Lead: result(auth refactor complete) -> idle_notification",
"annotation": "Result and idle state are separate events; the teammate remains available."
"annotation": "The task directory stays selected through the completion turn, then IDLE releases the assignment."
},
{
"type": "system_event",

View File

@@ -62,9 +62,14 @@
{
"type": "tool_call",
"toolName": "bash",
"content": "{\"command\":\"npm run lint && npm run test\",\"run_in_background\":true}",
"content": "{\"command\":\"python -m unittest tests.test_agent_teams_runtime\",\"run_in_background\":true}",
"annotation": "Long-running validation goes through the background task path."
},
{
"type": "system_event",
"content": "permission: user approved the exact test command",
"annotation": "Team confirmation does not authorize shell execution; the foreground turn asks separately before dispatch."
},
{
"type": "tool_call",
"toolName": "connect_mcp",
@@ -85,7 +90,7 @@
},
{
"type": "system_event",
"content": "recover: background task done, teammate replied, deploy status result appended",
"content": "task_notification(status=completed): tests passed; teammate result and deploy status appended",
"annotation": "The integrated runtime folds asynchronous results back into the loop."
},
{

View File

@@ -11,12 +11,12 @@
{
"type": "tool_call",
"toolName": "Workflow",
"content": "{\"name\":\"review-changes\",\"description\":\"Review changed files across dimensions and verify each finding\",\"phases\":[\"Review\",\"Verify\"]}",
"annotation": "One tool call hands deterministic orchestration to the workflow runtime."
"content": "{\"name\":\"review-changes\",\"args\":{\"budget\":null}}",
"annotation": "The model selects a saved workflow and arguments; the host registry supplies its trusted metadata and script."
},
{
"type": "system_event",
"content": "async_launched(runId=wf_review-changes_6779) -> task_started",
"content": "async_launched(runId=wf_review-changes_0000000000001a7b) -> task_started",
"annotation": "The runtime emits launch lifecycle events before it executes the script; this is not a tool result."
},
{
@@ -36,19 +36,19 @@
},
{
"type": "system_event",
"content": "task_notification(status=completed, outputFile=.runtime/wf_review-changes_6779.output.json)",
"content": "task_notification(status=completed, outputFile=.runtime/wf_review-changes_0000000000001a7b.output.json)",
"annotation": "The task emits its final lifecycle event after output is written."
},
{
"type": "tool_result",
"toolName": "Workflow",
"content": "{\"launched\":{\"status\":\"async_launched\",\"runId\":\"wf_review-changes_6779\"},\"result\":{\"confirmed\":[]},\"task\":{\"status\":\"completed\"}}",
"annotation": "The completed call returns once, with launch metadata, the workflow result, and task state together."
"content": "{\"launched\":{\"status\":\"async_launched\",\"taskId\":\"local_workflow_wf_review-changes_0000000000001a7b\",\"taskType\":\"local_workflow\",\"runId\":\"wf_review-changes_0000000000001a7b\",\"workflowName\":\"review-changes\"},\"result\":{\"confirmed\":[{\"dimension\":\"security\",\"title\":\"audit:security #1\",\"severity\":\"high\"},{\"dimension\":\"style\",\"title\":\"audit:style #1\",\"severity\":\"high\"},{\"dimension\":\"security\",\"title\":\"audit:security #2\",\"severity\":\"medium\"},{\"dimension\":\"performance\",\"title\":\"audit:performance #2\",\"severity\":\"medium\"},{\"dimension\":\"correctness\",\"title\":\"audit:correctness #1\",\"severity\":\"low\"},{\"dimension\":\"performance\",\"title\":\"audit:performance #1\",\"severity\":\"low\"}]},\"task\":{\"taskId\":\"local_workflow_wf_review-changes_0000000000001a7b\",\"taskType\":\"local_workflow\",\"runId\":\"wf_review-changes_0000000000001a7b\",\"workflowName\":\"review-changes\",\"status\":\"completed\",\"usage\":{\"agents\":11,\"tokens\":352},\"progress\":[{\"type\":\"workflow_phase\",\"title\":\"Review\"},{\"type\":\"workflow_agent\",\"label\":\"audit:correctness\",\"phase\":\"Review\",\"status\":\"done\"},{\"type\":\"workflow_phase\",\"title\":\"Verify\"},{\"type\":\"workflow_agent\",\"label\":\"audit:security\",\"phase\":\"Review\",\"status\":\"done\"},{\"type\":\"workflow_agent\",\"label\":\"audit:performance\",\"phase\":\"Review\",\"status\":\"done\"},{\"type\":\"workflow_agent\",\"label\":\"audit:style\",\"phase\":\"Review\",\"status\":\"done\"},{\"type\":\"workflow_agent\",\"label\":\"verify:correctness:audit:correctness #1\",\"phase\":\"Verify\",\"status\":\"done\"},{\"type\":\"workflow_agent\",\"label\":\"verify:security:audit:security #1\",\"phase\":\"Verify\",\"status\":\"done\"},{\"type\":\"workflow_agent\",\"label\":\"verify:security:audit:security #2\",\"phase\":\"Verify\",\"status\":\"done\"},{\"type\":\"workflow_agent\",\"label\":\"verify:performance:audit:performance #1\",\"phase\":\"Verify\",\"status\":\"done\"},{\"type\":\"workflow_agent\",\"label\":\"verify:performance:audit:performance #2\",\"phase\":\"Verify\",\"status\":\"done\"},{\"type\":\"workflow_agent\",\"label\":\"verify:style:audit:style #1\",\"phase\":\"Verify\",\"status\":\"done\"},{\"type\":\"workflow_agent\",\"label\":\"verify:style:audit:style #2\",\"phase\":\"Verify\",\"status\":\"done\"},{\"type\":\"workflow_log\",\"message\":\"confirmed 6 real finding(s)\"}]}}",
"annotation": "The deterministic sample returns its six fixture findings and measured runner usage; these are not claims about the repository."
},
{
"type": "system_event",
"content": "append Workflow tool_result -> messages[]",
"annotation": "The main loop receives that single result and continues with the updated conversation."
"annotation": "A main-loop integration can append this JSON-safe result and continue with the updated conversation."
}
]
}