diff --git a/apps/cli/composition.md b/apps/cli/composition.md
index e123e42195..96b711a333 100644
--- a/apps/cli/composition.md
+++ b/apps/cli/composition.md
@@ -140,8 +140,6 @@ flowchart LR
cfg --> plugin_dsh_base_command_compact
plugin_dsh_base_subagent["subagent
@deepseek-ai/dsh-subagent"]
cfg --> plugin_dsh_base_subagent
- plugin_dsh_base_subagent_names["subagent-names
@deepseek-ai/dsh-subagent-names"]
- cfg --> plugin_dsh_base_subagent_names
plugin_dsh_base_agent_team["agent-team
@deepseek-ai/dsh-agent-team"]
cfg --> plugin_dsh_base_agent_team
plugin_dsh_base_tool_agent_team["tool-agent-team
@deepseek-ai/dsh-tool-agent-team"]
@@ -278,7 +276,6 @@ flowchart LR
| `compaction-basic` | `@deepseek-ai/dsh-compaction-basic` |
| `command-compact` | `@deepseek-ai/dsh-command-compact` |
| `subagent` | `@deepseek-ai/dsh-subagent` |
-| `subagent-names` | `@deepseek-ai/dsh-subagent-names` |
| `agent-team` | `@deepseek-ai/dsh-agent-team` |
| `tool-agent-team` | `@deepseek-ai/dsh-tool-agent-team` |
| `subagent-spawn-in-process` | `@deepseek-ai/dsh-subagent-spawn-in-process` |
diff --git a/apps/cli/package.json b/apps/cli/package.json
index 8dd03dcd90..c194a246b9 100644
--- a/apps/cli/package.json
+++ b/apps/cli/package.json
@@ -57,7 +57,6 @@
"@deepseek-ai/dsh-sdk-minimal": "workspace:*",
"@deepseek-ai/dsh-session-projection": "workspace:*",
"@deepseek-ai/dsh-session-reference": "workspace:*",
- "@deepseek-ai/dsh-subagent-names": "workspace:*",
"@deepseek-ai/dsh-skill": "workspace:*",
"@deepseek-ai/dsh-skill-filesystem": "workspace:*",
"@deepseek-ai/dsh-skill-office": "workspace:*",
diff --git a/apps/cli/tests/profiles/headless/tests/expected/subagent-diagnostic/parent.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/subagent-diagnostic/parent.expected.jsonl
index 36af85437a..72a47cc8ed 100644
--- a/apps/cli/tests/profiles/headless/tests/expected/subagent-diagnostic/parent.expected.jsonl
+++ b/apps/cli/tests/profiles/headless/tests/expected/subagent-diagnostic/parent.expected.jsonl
@@ -22,7 +22,7 @@
{"type":"session/title","data":{"title":"Start a background job.","messageSeqs":[3],"source":{"kind":"fallback"}}}
{"type":"assistant/message","data":{"turn":2,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"list-once","name":"list_agents","arguments":"{}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":0,"index":0,"dt":[],"id":"list-once","name":"list_agents","args":["{}"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"list-once","name":"list_agents","arguments":"{}"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
{"type":"tool/call","data":{"turn":2,"step":1,"callId":"list-once","name":"list_agents","arguments":"{}"}}
-{"type":"tool/result","data":{"turn":2,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"list-once"},"toolCallId":"list-once","content":[{"type":"text","text":"{{sessionId}} [running] — lead: root agent\n{{sessionId}} [inactive] parent={{sessionId}} depth=1 — descriptorless child"}],"isError":false,"id":"{{sessionId}}"}},"sourceEventSeqs":[22],"surfaceOp":"append"}
+{"type":"tool/result","data":{"turn":2,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"list-once"},"toolCallId":"list-once","content":[{"type":"text","text":"{{sessionId}} [running] — root agent\n{{sessionId}} [inactive] parent={{sessionId}} depth=1 — descriptorless child"}],"isError":false,"id":"{{sessionId}}"}},"sourceEventSeqs":[22],"surfaceOp":"append"}
{"type":"step/end","data":{"turn":2,"step":1}}
{"type":"step/start","data":{"turn":2,"step":2}}
{"type":"assistant/message","data":{"turn":2,"step":2,"message":{"role":"assistant","content":[{"type":"text","text":"The catalogued subagent is ready. PARENT_DONE"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":0,"index":0,"dt":[],"texts":["The catalogued subagent is ready. PARENT_DONE"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"The catalogued subagent is ready. PARENT_DONE"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}
diff --git a/apps/cli/tests/profiles/headless/tests/expected/subagent-inheritance/child.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/subagent-inheritance/child.expected.jsonl
index 6bf221bc38..ea2320d83d 100644
--- a/apps/cli/tests/profiles/headless/tests/expected/subagent-inheritance/child.expected.jsonl
+++ b/apps/cli/tests/profiles/headless/tests/expected/subagent-inheritance/child.expected.jsonl
@@ -8,7 +8,7 @@
{"type":"step/start","data":{"turn":1,"step":1}}
{"type":"system/message","data":{"turn":1,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{sessionId}}"}},"surfaceOp":"append"}
{"type":"user/message","data":{"content":[{"type":"text","text":"Use the write tool exactly once with file_path set to exactly the relative path inherited.txt and content escaped. If the write is denied, reply with the single word CHILD_DENIED and the denial marker line; do not retry and do not request escalation. If it succeeds, reply CHILD_WROTE."},{"type":"text","text":"Your final answer is delivered automatically if your parent is still online. Include the result and relevant evidence in that answer; the parent does not receive your full transcript, tool output, or reasoning. If your last action is a message to your parent, the completion notice omits your final answer; include the result and relevant evidence in that message."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}
-{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: read-only. Any available operation enforced by the DSH file sandbox cannot modify files in the standing mode. Do not refuse a required modification from this policy alone: try an available tool normally and follow any denial and escalation guidance it returns.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYour parent agent id is \"{{sessionId}}\". Use send_message({ name: \"{{sessionId}}\", message: \"\" }) when a finding changes what the parent should do next; sending a message does not end your turn.\n\nDelegation depth for `subagent`: current 1, maximum 1, remaining levels 0. Do not call `subagent` at this depth; carry out the work directly.\n\nDelegation depth for `subagent_fork`: current 1, maximum 1, remaining levels 0. Do not call `subagent_fork` at this depth; carry out the work directly.\n\nYou are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: read-only. Any available operation enforced by the DSH file sandbox cannot modify files in the standing mode. Do not refuse a required modification from this policy alone: try an available tool normally and follow any denial and escalation guidance it returns."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:communication","text":"Your parent agent id is \"{{sessionId}}\". Use send_message({ name: \"{{sessionId}}\", message: \"\" }) when a finding changes what the parent should do next; sending a message does not end your turn."},{"name":"tool:subagent:depth","text":"Delegation depth for `subagent`: current 1, maximum 1, remaining levels 0. Do not call `subagent` at this depth; carry out the work directly."},{"name":"tool:subagent_fork:depth","text":"Delegation depth for `subagent_fork`: current 1, maximum 1, remaining levels 0. Do not call `subagent_fork` at this depth; carry out the work directly."},{"name":"subagent:delegation","text":"You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}
+{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: read-only. Any available operation enforced by the DSH file sandbox cannot modify files in the standing mode. Do not refuse a required modification from this policy alone: try an available tool normally and follow any denial and escalation guidance it returns.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYour parent agent id is \"{{sessionId}}\". Use send_message({ agent_id: \"{{sessionId}}\", message: \"\" }) when a finding changes what the parent should do next; sending a message does not end your turn.\n\nDelegation depth for `subagent`: current 1, maximum 1, remaining levels 0. Do not call `subagent` at this depth; carry out the work directly.\n\nDelegation depth for `subagent_fork`: current 1, maximum 1, remaining levels 0. Do not call `subagent_fork` at this depth; carry out the work directly.\n\nYou are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: read-only. Any available operation enforced by the DSH file sandbox cannot modify files in the standing mode. Do not refuse a required modification from this policy alone: try an available tool normally and follow any denial and escalation guidance it returns."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:communication","text":"Your parent agent id is \"{{sessionId}}\". Use send_message({ agent_id: \"{{sessionId}}\", message: \"\" }) when a finding changes what the parent should do next; sending a message does not end your turn."},{"name":"tool:subagent:depth","text":"Delegation depth for `subagent`: current 1, maximum 1, remaining levels 0. Do not call `subagent` at this depth; carry out the work directly."},{"name":"tool:subagent_fork:depth","text":"Delegation depth for `subagent_fork`: current 1, maximum 1, remaining levels 0. Do not call `subagent_fork` at this depth; carry out the work directly."},{"name":"subagent:delegation","text":"You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash","reasoningEffort":"low"},"tools":"{{tools}}"},"reason":"initial"}}
{"type":"request/context","data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}}
{"type":"session/title","data":{"title":"Use the write tool exactly","messageSeqs":[8],"source":{"kind":"fallback"}}}
diff --git a/apps/cli/tests/profiles/headless/tests/expected/subagent-inheritance/parent.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/subagent-inheritance/parent.expected.jsonl
index 830e693a8a..bfa0fd3ab0 100644
--- a/apps/cli/tests/profiles/headless/tests/expected/subagent-inheritance/parent.expected.jsonl
+++ b/apps/cli/tests/profiles/headless/tests/expected/subagent-inheritance/parent.expected.jsonl
@@ -24,13 +24,12 @@
{"type":"assistant/message","data":{"turn":2,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"delegate-write","name":"subagent","arguments":"{\"description\": \"Delegated write probe\", \"prompt\": \"Use the write tool exactly once with file_path set to exactly the relative path inherited.txt and content escaped. If the write is denied, reply with the single word CHILD_DENIED and the denial marker line; do not retry and do not request escalation. If it succeeds, reply CHILD_WROTE.\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":0,"index":0,"dt":[],"id":"delegate-write","name":"subagent","args":["{\"description\": \"Delegated write probe\", \"prompt\": \"Use the write tool exactly once with file_path set to exactly the relative path inherited.txt and content escaped. If the write is denied, reply with the single word CHILD_DENIED and the denial marker line; do not retry and do not request escalation. If it succeeds, reply CHILD_WROTE.\"}"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"delegate-write","name":"subagent","arguments":"{\"description\": \"Delegated write probe\", \"prompt\": \"Use the write tool exactly once with file_path set to exactly the relative path inherited.txt and content escaped. If the write is denied, reply with the single word CHILD_DENIED and the denial marker line; do not retry and do not request escalation. If it succeeds, reply CHILD_WROTE.\"}"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
{"type":"tool/call","data":{"turn":2,"step":1,"callId":"delegate-write","name":"subagent","arguments":"{\"description\": \"Delegated write probe\", \"prompt\": \"Use the write tool exactly once with file_path set to exactly the relative path inherited.txt and content escaped. If the write is denied, reply with the single word CHILD_DENIED and the denial marker line; do not retry and do not request escalation. If it succeeds, reply CHILD_WROTE.\"}"}}
{"type":"subagent/catalog","data":{"version":0,"childId":"{{sessionId}}","childCreatedAt":0,"mode":"continuable","label":"Delegated write probe"}}
-{"type":"subagent-name/bound","data":{"version":1,"childId":"{{sessionId}}","name":"lead/agent-1"}}
-{"type":"agent/inbox/spliced","data":{"target":"next-step","start":0,"inserted":[{"content":[{"type":"text","text":"Background subagent {{sessionId}} finished and will do no further work unless you send it more."},{"type":"text","text":"Its closing message:"},{"type":"text","text":"CHILD_DENIED [sandbox: file access denied under read-only mode]"}],"source":{"kind":"subagent-settled","form":"notice","summary":"Background subagent {{sessionId}} finished and will do no further work unless you send it more.","stopReason":"completed","senderSessionId":"{{sessionId}}"},"role":"user","id":"{{sessionId}}"}]}}
-{"type":"tool/result","data":{"turn":2,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"delegate-write"},"toolCallId":"delegate-write","content":[{"type":"text","text":"started subagent {{sessionId}}\nname: lead/agent-1"}],"isError":false,"id":"{{sessionId}}"},"meta":{"kind":"activation","name":"lead/agent-1"}},"sourceEventSeqs":[23],"surfaceOp":"append"}
+{"type":"agent/inbox/spliced","data":{"target":"next-step","start":0,"inserted":[{"content":[{"type":"text","text":"Background subagent {{sessionId}} finished and will do no further work unless you send it more."},{"type":"text","text":"Its closing message:"},{"type":"text","text":"CHILD_DENIED [sandbox: file access denied under read-only mode]"}],"source":{"kind":"subagent-settled","form":"notice","summary":"Background subagent {{sessionId}} finished and will do no further work unless you send it more.","senderSessionId":"{{sessionId}}"},"role":"user","id":"{{sessionId}}"}]}}
+{"type":"tool/result","data":{"turn":2,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"delegate-write"},"toolCallId":"delegate-write","content":[{"type":"text","text":"started subagent {{sessionId}}"}],"isError":false,"id":"{{sessionId}}"}},"sourceEventSeqs":[23],"surfaceOp":"append"}
{"type":"step/end","data":{"turn":2,"step":1}}
{"type":"agent/inbox/spliced","data":{"target":"next-step","start":0,"removedCount":1,"inserted":[]}}
{"type":"step/start","data":{"turn":2,"step":2}}
-{"type":"user/message","data":{"content":[{"type":"text","text":"Background subagent {{sessionId}} finished and will do no further work unless you send it more."},{"type":"text","text":"Its closing message:"},{"type":"text","text":"CHILD_DENIED [sandbox: file access denied under read-only mode]"}],"source":{"kind":"subagent-settled","form":"notice","summary":"Background subagent {{sessionId}} finished and will do no further work unless you send it more.","stopReason":"completed","senderSessionId":"{{sessionId}}"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}
+{"type":"user/message","data":{"content":[{"type":"text","text":"Background subagent {{sessionId}} finished and will do no further work unless you send it more."},{"type":"text","text":"Its closing message:"},{"type":"text","text":"CHILD_DENIED [sandbox: file access denied under read-only mode]"}],"source":{"kind":"subagent-settled","form":"notice","summary":"Background subagent {{sessionId}} finished and will do no further work unless you send it more.","senderSessionId":"{{sessionId}}"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}
{"type":"assistant/message","data":{"turn":2,"step":2,"message":{"role":"assistant","content":[{"type":"text","text":"The delegated child was denied by the sandbox. PARENT_DONE"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":0,"index":0,"dt":[],"texts":["The delegated child was denied by the sandbox. PARENT_DONE"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"The delegated child was denied by the sandbox. PARENT_DONE"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}
{"type":"step/end","data":{"turn":2,"step":2}}
{"type":"turn/end","data":{"turn":2,"reason":{"kind":"completed"}}}
diff --git a/apps/cli/tests/profiles/headless/tests/expected/subagent-settlement/child.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/subagent-settlement/child.expected.jsonl
index 196e82c256..7ac94689e3 100644
--- a/apps/cli/tests/profiles/headless/tests/expected/subagent-settlement/child.expected.jsonl
+++ b/apps/cli/tests/profiles/headless/tests/expected/subagent-settlement/child.expected.jsonl
@@ -8,7 +8,7 @@
{"type":"step/start","data":{"turn":1,"step":1}}
{"type":"system/message","data":{"turn":1,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{sessionId}}"}},"surfaceOp":"append"}
{"type":"user/message","data":{"content":[{"type":"text","text":"Reply with exactly CHILD_RESULT and nothing else. Do not call send_message."},{"type":"text","text":"Your final answer is delivered automatically if your parent is still online. Include the result and relevant evidence in that answer; the parent does not receive your full transcript, tool output, or reasoning. If your last action is a message to your parent, the completion notice omits your final answer; include the result and relevant evidence in that message."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}
-{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYour parent agent id is \"{{sessionId}}\". Use send_message({ name: \"{{sessionId}}\", message: \"\" }) when a finding changes what the parent should do next; sending a message does not end your turn.\n\nDelegation depth for `subagent`: current 1, maximum 1, remaining levels 0. Do not call `subagent` at this depth; carry out the work directly.\n\nDelegation depth for `subagent_fork`: current 1, maximum 1, remaining levels 0. Do not call `subagent_fork` at this depth; carry out the work directly.\n\nYou are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:communication","text":"Your parent agent id is \"{{sessionId}}\". Use send_message({ name: \"{{sessionId}}\", message: \"\" }) when a finding changes what the parent should do next; sending a message does not end your turn."},{"name":"tool:subagent:depth","text":"Delegation depth for `subagent`: current 1, maximum 1, remaining levels 0. Do not call `subagent` at this depth; carry out the work directly."},{"name":"tool:subagent_fork:depth","text":"Delegation depth for `subagent_fork`: current 1, maximum 1, remaining levels 0. Do not call `subagent_fork` at this depth; carry out the work directly."},{"name":"subagent:delegation","text":"You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}
+{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYour parent agent id is \"{{sessionId}}\". Use send_message({ agent_id: \"{{sessionId}}\", message: \"\" }) when a finding changes what the parent should do next; sending a message does not end your turn.\n\nDelegation depth for `subagent`: current 1, maximum 1, remaining levels 0. Do not call `subagent` at this depth; carry out the work directly.\n\nDelegation depth for `subagent_fork`: current 1, maximum 1, remaining levels 0. Do not call `subagent_fork` at this depth; carry out the work directly.\n\nYou are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:communication","text":"Your parent agent id is \"{{sessionId}}\". Use send_message({ agent_id: \"{{sessionId}}\", message: \"\" }) when a finding changes what the parent should do next; sending a message does not end your turn."},{"name":"tool:subagent:depth","text":"Delegation depth for `subagent`: current 1, maximum 1, remaining levels 0. Do not call `subagent` at this depth; carry out the work directly."},{"name":"tool:subagent_fork:depth","text":"Delegation depth for `subagent_fork`: current 1, maximum 1, remaining levels 0. Do not call `subagent_fork` at this depth; carry out the work directly."},{"name":"subagent:delegation","text":"You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"tools":"{{tools}}"},"reason":"initial"}}
{"type":"request/context","data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}}
{"type":"session/title","data":{"title":"Reply with exactly CHILD_RESULT and","messageSeqs":[8],"source":{"kind":"fallback"}}}
diff --git a/apps/cli/tests/profiles/headless/tests/expected/subagent-settlement/stream-json.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/subagent-settlement/stream-json.expected.jsonl
index 2b6536fb7d..441cab1aa2 100644
--- a/apps/cli/tests/profiles/headless/tests/expected/subagent-settlement/stream-json.expected.jsonl
+++ b/apps/cli/tests/profiles/headless/tests/expected/subagent-settlement/stream-json.expected.jsonl
@@ -13,17 +13,16 @@
{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":15,"time":0,"data":{"turn":1,"step":1,"callId":"start-child","name":"subagent","arguments":"{\"description\":\"Return child result\",\"prompt\":\"Reply with exactly CHILD_RESULT and nothing else. Do not call send_message.\"}"}}}
{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"session/title","seq":16,"time":0,"data":{"title":"Subagent settlement","messageSeqs":[8],"source":{"kind":"provider","provider":"session-title-first-prompt-llm","model":{"provider":"deepseek-official","model":"deepseek-v4-flash"}}}}}
{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"subagent/catalog","seq":17,"time":0,"data":{"version":0,"childId":"{{sessionId}}","childCreatedAt":0,"mode":"continuable","label":"Return child result"}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"subagent-name/bound","seq":18,"time":0,"data":{"version":1,"childId":"{{sessionId}}","name":"lead/agent-1"}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":19,"time":0,"data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"start-child"},"toolCallId":"start-child","content":[{"type":"text","text":"started subagent {{sessionId}}\nname: lead/agent-1"}],"isError":false,"id":"{{sessionId}}"},"meta":{"kind":"activation","name":"lead/agent-1"}},"sourceEventSeqs":[15],"surfaceOp":"append"}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":20,"time":0,"data":{"turn":1,"step":1}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"agent/inbox/spliced","seq":21,"time":0,"data":{"target":"next-step","start":0,"inserted":[{"content":[{"type":"text","text":"Background subagent {{sessionId}} finished and will do no further work unless you send it more."},{"type":"text","text":"Its closing message:"},{"type":"text","text":"CHILD_RESULT"}],"source":{"kind":"subagent-settled","form":"notice","summary":"Background subagent {{sessionId}} finished and will do no further work unless you send it more.","stopReason":"completed","senderSessionId":"{{sessionId}}"},"role":"user","id":"{{sessionId}}"}]}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":22,"time":0,"data":{"turn":1,"step":2}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":23,"time":0,"data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"text","text":"STARTED"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":0,"index":0,"dt":[],"texts":["STARTED"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"STARTED"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":24,"time":0,"data":{"turn":1,"step":2}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"agent/inbox/spliced","seq":25,"time":0,"data":{"target":"next-step","start":0,"removedCount":1,"inserted":[]}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":26,"time":0,"data":{"turn":1,"step":3}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":27,"time":0,"data":{"content":[{"type":"text","text":"Background subagent {{sessionId}} finished and will do no further work unless you send it more."},{"type":"text","text":"Its closing message:"},{"type":"text","text":"CHILD_RESULT"}],"source":{"kind":"subagent-settled","form":"notice","summary":"Background subagent {{sessionId}} finished and will do no further work unless you send it more.","stopReason":"completed","senderSessionId":"{{sessionId}}"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":28,"time":0,"data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"text","text":"PARENT_RECEIVED_SETTLEMENT_NOTICE"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":0,"index":0,"dt":[],"texts":["PARENT_RECEIVED_SETTLEMENT_NOTICE"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"PARENT_RECEIVED_SETTLEMENT_NOTICE"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":29,"time":0,"data":{"turn":1,"step":3}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"turn/end","seq":30,"time":0,"data":{"turn":1,"reason":{"kind":"completed"}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":18,"time":0,"data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"start-child"},"toolCallId":"start-child","content":[{"type":"text","text":"started subagent {{sessionId}}"}],"isError":false,"id":"{{sessionId}}"}},"sourceEventSeqs":[15],"surfaceOp":"append"}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":19,"time":0,"data":{"turn":1,"step":1}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"agent/inbox/spliced","seq":20,"time":0,"data":{"target":"next-step","start":0,"inserted":[{"content":[{"type":"text","text":"Background subagent {{sessionId}} finished and will do no further work unless you send it more."},{"type":"text","text":"Its closing message:"},{"type":"text","text":"CHILD_RESULT"}],"source":{"kind":"subagent-settled","form":"notice","summary":"Background subagent {{sessionId}} finished and will do no further work unless you send it more.","senderSessionId":"{{sessionId}}"},"role":"user","id":"{{sessionId}}"}]}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":21,"time":0,"data":{"turn":1,"step":2}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":22,"time":0,"data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"text","text":"STARTED"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":0,"index":0,"dt":[],"texts":["STARTED"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"STARTED"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":23,"time":0,"data":{"turn":1,"step":2}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"agent/inbox/spliced","seq":24,"time":0,"data":{"target":"next-step","start":0,"removedCount":1,"inserted":[]}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":25,"time":0,"data":{"turn":1,"step":3}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":26,"time":0,"data":{"content":[{"type":"text","text":"Background subagent {{sessionId}} finished and will do no further work unless you send it more."},{"type":"text","text":"Its closing message:"},{"type":"text","text":"CHILD_RESULT"}],"source":{"kind":"subagent-settled","form":"notice","summary":"Background subagent {{sessionId}} finished and will do no further work unless you send it more.","senderSessionId":"{{sessionId}}"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":27,"time":0,"data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"text","text":"PARENT_RECEIVED_SETTLEMENT_NOTICE"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":0,"index":0,"dt":[],"texts":["PARENT_RECEIVED_SETTLEMENT_NOTICE"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"PARENT_RECEIVED_SETTLEMENT_NOTICE"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":28,"time":0,"data":{"turn":1,"step":3}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"turn/end","seq":29,"time":0,"data":{"turn":1,"reason":{"kind":"completed"}}}}
{"type":"result","sessionId":"{{sessionId}}","output":"PARENT_RECEIVED_SETTLEMENT_NOTICE","usage":{"inputTokens":30,"outputTokens":15}}
diff --git a/apps/cli/tests/profiles/headless/tests/fixtures/team-llm.mjs b/apps/cli/tests/profiles/headless/tests/fixtures/team-llm.mjs
index bcbff9f11c..5fbceed744 100644
--- a/apps/cli/tests/profiles/headless/tests/fixtures/team-llm.mjs
+++ b/apps/cli/tests/profiles/headless/tests/fixtures/team-llm.mjs
@@ -72,7 +72,7 @@ function researcher(messages) {
if (!names.includes('list_agents')) return toolChunks([{ name: 'list_agents', args: {} }])
const sibling = messages.filter(message => message.role === 'tool')
.flatMap(message => message.content.filter(block => block.type === 'text').flatMap(block => block.text.split('\n')))
- .find(line => line.endsWith('Own deterministic implementation.'))?.split(' ')[0]
+ .find(line => line.endsWith('— Own deterministic implementation.'))?.split(' ')[0]
if (sibling === undefined) throw new Error('list_agents did not expose the implementation sibling')
if (!names.includes('team_task_create')) {
return toolChunks([{ name: 'team_task_create', args: {
@@ -87,13 +87,13 @@ function researcher(messages) {
if (!names.includes('send_message')) {
return toolChunks([
{ name: 'team_task_update', args: { task_id: 'task-1', expected_revision: 2, action: 'complete' } },
- { name: 'send_message', args: { name: sibling, message: 'Research complete: use the deterministic finding.' } },
+ { name: 'send_message', args: { agent_id: sibling, message: 'Research complete: use the deterministic finding.' } },
])
}
return textChunks('Research teammate complete.')
}
-function implementer(messages) {
+function implementer(messages, parentId) {
const names = calls(messages)
const last = latestAssistantCalls(messages)
const text = latestToolText(messages)
@@ -134,7 +134,7 @@ function implementer(messages) {
if (!names.includes('send_message')) {
return toolChunks([
{ name: 'team_task_update', args: { task_id: 'task-2', expected_revision: 2, action: 'complete' } },
- { name: 'send_message', args: { name: 'lead', message: 'Implementation complete and verified.' } },
+ { name: 'send_message', args: { agent_id: parentId, message: 'Implementation complete and verified.' } },
])
}
return textChunks('Implementation teammate complete.')
@@ -154,7 +154,6 @@ function lead(messages) {
return toolChunks([{
name: 'subagent',
args: {
- name: 'implementer',
description: 'Own deterministic implementation.',
prompt: 'IMPLEMENTER_MARK: wait for research, complete dependent task 2, report to lead.',
},
@@ -164,7 +163,6 @@ function lead(messages) {
return toolChunks([{
name: 'subagent',
args: {
- name: 'researcher',
description: 'Own deterministic research.',
prompt: 'RESEARCHER_MARK: complete research task 1, message implementer, then finish.',
},
@@ -179,7 +177,7 @@ function lead(messages) {
}
if (last.includes('list_agents')) {
const inactive = result.split('\n')
- .filter(row => row.includes('Own deterministic ') && row.includes('[inactive]')).length
+ .filter(row => row.includes('— Own deterministic ') && row.includes('[inactive]')).length
if (inactive >= 2) return textChunks('TEAM_WORKFLOW_OK: both teammates and dependent tasks completed.')
return toolChunks([{ name: hasNewCoordinationInput(messages) ? 'list_agents' : 'wait_agent',
args: hasNewCoordinationInput(messages) ? {} : { timeout_ms: 10000 } }])
@@ -196,6 +194,7 @@ class TeamFixtureAdapter extends LlmAdapter {
const context = options.messages.findLast(message => message.source?.kind === 'runtime-context')
const section = name => context?.source.sections?.find(candidate => candidate.name === name)?.text
const role = section('team:identity')
+ const parentId = role?.match(/Team led by agent "([^"]+)"/u)?.[1]
const task = initial?.content.filter(block => block.type === 'text').map(block => block.text).join('\n')
if (!workflowChild && (!tools.includes('subagent') || !tools.includes('workflow') || !tools.includes('team_task_create'))) {
throw new Error('Team profile is missing delegation, workflow, or task tools')
@@ -203,8 +202,8 @@ class TeamFixtureAdapter extends LlmAdapter {
let chunks
if (workflowChild) chunks = textChunks('Fresh workflow child complete.')
else if (task?.startsWith('RESEARCHER_MARK:')) chunks = researcher(options.messages)
- else if (task?.startsWith('IMPLEMENTER_MARK:')) chunks = implementer(options.messages)
- else if (role?.startsWith('Your name is "lead".')) chunks = lead(options.messages)
+ else if (task?.startsWith('IMPLEMENTER_MARK:')) chunks = implementer(options.messages, parentId)
+ else if (role?.includes('You are the Team Lead.')) chunks = lead(options.messages)
else throw new Error('Team runtime context is missing a recognized identity')
for (const chunk of chunks) {
options.signal?.throwIfAborted()
diff --git a/apps/cli/tests/profiles/headless/tests/headless.expected.e2e.ts b/apps/cli/tests/profiles/headless/tests/headless.expected.e2e.ts
index 578bbbd460..d57e6cde86 100644
--- a/apps/cli/tests/profiles/headless/tests/headless.expected.e2e.ts
+++ b/apps/cli/tests/profiles/headless/tests/headless.expected.e2e.ts
@@ -1254,12 +1254,8 @@ describe('headless stream-json snapshots', () => {
"checkedAgents": true,
"deliveredMessages": 0,
"identities": [
- "Your name is "lead/implementer". Your team lead is "lead".
- Use list_agents({}) to find your teammates and their full names.
- Use send_message({ name: "", message: "..." }) to message a teammate.",
- "Your name is "lead/researcher". Your team lead is "lead".
- Use list_agents({}) to find your teammates and their full names.
- Use send_message({ name: "", message: "..." }) to message a teammate.",
+ "You are a teammate in the Team led by agent "".",
+ "You are a teammate in the Team led by agent "".",
],
"queuedMessages": 0,
"sessions": 4,
diff --git a/apps/cli/tests/web-agent-presets.e2e.ts b/apps/cli/tests/web-agent-presets.e2e.ts
index 01aed139c7..ff5fd57cae 100644
--- a/apps/cli/tests/web-agent-presets.e2e.ts
+++ b/apps/cli/tests/web-agent-presets.e2e.ts
@@ -345,7 +345,7 @@ describe('the shipped Web composition', () => {
'model', 'provider', 'reasoning_effort',
]))
for (const agent of [disabled.agent, enabled.agent]) {
- expect(toolParameterNames(ctx, agent, 'subagent_fork')).toEqual(['cwd', 'description', 'name', 'prompt'])
+ expect(toolParameterNames(ctx, agent, 'subagent_fork')).toEqual(['cwd', 'description', 'prompt'])
}
} finally {
await policy.dispose()
@@ -802,7 +802,7 @@ describe.each(['web', 'desktop'] as const)('%s native subagent bundles', (surfac
})
try {
for (const product of installed) {
- expect(toolParameterNames(productCtx, handle.agent, toolName(product))).toEqual(['cwd', 'description', 'name', 'prompt'])
+ expect(toolParameterNames(productCtx, handle.agent, toolName(product))).toEqual(['cwd', 'description', 'prompt'])
}
} finally { await handle.dispose() }
expect(spawn).not.toHaveBeenCalled()
diff --git a/apps/web/tests/agent-team-panel.e2e.ts b/apps/web/tests/agent-team-panel.e2e.ts
index 70c90516a1..b66e96313f 100644
--- a/apps/web/tests/agent-team-panel.e2e.ts
+++ b/apps/web/tests/agent-team-panel.e2e.ts
@@ -273,7 +273,6 @@ describe('web e2e: agent teamwork panel', () => {
version: 2, childId: memberId, childCreatedAt: Date.now(), mode: 'external',
label: RESEARCHER_DESCRIPTION,
})
- scaffold.ctx.subagentNames.bind(agent.session, memberId, 'lead/researcher')
const countAction = page.locator('[data-subagent-action]')
await countAction.waitFor()
await page.mouse.move(2, 2)
@@ -362,7 +361,7 @@ describe('web e2e: agent teamwork panel', () => {
})))
expect(primaryStyles.map(style => style.fontSize)).toEqual(['13px', '13px'])
expect(primaryStyles[1]).toEqual(primaryStyles[0])
- expect(await member.getByText('researcher', { exact: true })
+ expect(await member.getByText('team-panel-researcher', { exact: true })
.evaluate(element => getComputedStyle(element).fontSize)).toBe('12px')
const memberHover = member.locator(':scope > div')
for (const target of [member, memberHover]) {
@@ -421,7 +420,7 @@ describe('web e2e: agent teamwork panel', () => {
taskId: task.id, expectedRevision: task.revision, action: 'claim',
})
await row.getByRole('img', { name: 'In progress', exact: true }).waitFor()
- await row.locator('[data-team-task-owner]').filter({ hasText: 'Lead' }).waitFor()
+ await row.locator('[data-team-task-owner]').filter({ hasText: agent.id }).waitFor()
await action.getByRole('heading', { name: 'Shared tasks 1 in progress', exact: true }).waitFor()
expect(await action.getByRole('button', { name: /^(New task|Edit|Complete|Reopen|Delete)$/u }).count()).toBe(0)
expect(await action.locator('input, select, textarea').count()).toBe(0)
@@ -553,7 +552,7 @@ describe('web e2e: agent teamwork panel', () => {
}
const row = panel.getByRole('treeitem', { name: /Researcher/u })
const primary = row.getByText(RESEARCHER_DESCRIPTION, { exact: true })
- const secondary = row.getByText('researcher', { exact: true })
+ const secondary = row.getByText('team-panel-researcher', { exact: true })
expect(await row.getByRole('button').count()).toBe(0)
expect(await primary.evaluate((element) => {
const style = getComputedStyle(element)
@@ -755,7 +754,7 @@ describe('web e2e: agent teamwork panel', () => {
expect(await row.getAttribute('data-expanded')).toBe('false')
expect(await row.locator('[data-team-task-details]').count()).toBe(0)
expect(await board.locator('[data-team-task-details]').count()).toBe(1)
- expect(await emptyRow.locator('[data-team-task-owner]').textContent()).toBe('Owner: Lead')
+ expect(await emptyRow.locator('[data-team-task-owner]').textContent()).toBe(`Owner: ${agent.id}`)
expect(await emptyRow.locator('[data-team-task-details] p:not([data-team-task-owner])').textContent()).toBe(completed.description)
expect(await emptyRow.locator('dl, dt, dd').count()).toBe(0)
expect(await emptyRow.locator('[data-team-task-details]').textContent()).not.toContain(completed.id)
diff --git a/apps/web/tests/official-subagent-bundle.e2e.ts b/apps/web/tests/official-subagent-bundle.e2e.ts
index 37371f7f11..ef6268cd42 100644
--- a/apps/web/tests/official-subagent-bundle.e2e.ts
+++ b/apps/web/tests/official-subagent-bundle.e2e.ts
@@ -161,9 +161,7 @@ describe.skipIf(MODE === 'record')('web snapshot: Official native subagent bundl
if (notice?.data.source.kind !== 'subagent-settled') throw new Error('Native completion was not delivered to the parent')
expect(notice.data.source.senderSessionId).toBe(catalog[0]?.childId)
expect(notice.data.content).toContainEqual({ type: 'text', text: RESPONSE })
- expect(dispatches[0]?.content).toEqual([{
- type: 'text', text: `started subagent ${notice.data.source.senderSessionId}\nname: lead/native-worker`,
- }])
+ expect(dispatches[0]?.content).toEqual([{ type: 'text', text: `started subagent ${notice.data.source.senderSessionId}` }])
expect(events.filter(event => event.type === 'turn/end')).toHaveLength(2)
expect(server.requests).toHaveLength(1)
expect(server.requests[0]?.body).toMatchObject({ model: 'fixture-model' })
diff --git a/apps/web/tests/shipped-composition.e2e.ts b/apps/web/tests/shipped-composition.e2e.ts
index 39cf63eafa..1e0ae9dfad 100644
--- a/apps/web/tests/shipped-composition.e2e.ts
+++ b/apps/web/tests/shipped-composition.e2e.ts
@@ -279,7 +279,6 @@ class ShippedChildAutoAdapter extends LlmAdapter {
this.parentPhase += 1
if (phase === 0 && prompt.includes(AUTO_PARENT_AUTHORIZED)) {
return toolChunks('parent-authorized', 'subagent', {
- name: 'authorized',
description: 'Auto authorized child',
prompt: [
AUTO_CHILD_AUTHORIZED,
@@ -292,7 +291,6 @@ class ShippedChildAutoAdapter extends LlmAdapter {
if (phase === 1) return textChunks('PARENT_AUTHORIZED_SETTLED')
if (phase === 2 && prompt.includes(AUTO_PARENT_CONTINUABLE)) {
return toolChunks('parent-continuable', 'subagent', {
- name: 'continuable',
description: 'Auto continuable child',
prompt: [
AUTO_CHILD_CONTINUABLE,
@@ -307,7 +305,7 @@ class ShippedChildAutoAdapter extends LlmAdapter {
throw new Error('continuable child id was not observed before parent adjustment')
}
return toolChunks('parent-adjust', 'send_message', {
- name: 'lead/continuable',
+ agent_id: this.continuableChildId,
message: [
AUTO_CHILD_ADJUSTED,
`Replace the earlier no-deletion restriction: permanently delete exactly ${this.continuableDeletePath}.`,
diff --git a/apps/web/tests/subagent-conversation.e2e.ts b/apps/web/tests/subagent-conversation.e2e.ts
index 7347949cab..c44066ca5d 100644
--- a/apps/web/tests/subagent-conversation.e2e.ts
+++ b/apps/web/tests/subagent-conversation.e2e.ts
@@ -157,7 +157,6 @@ describe('web e2e: persisted subagent conversation and human continuation', () =
prompt: [{ type: 'text', text: INITIAL_PROMPT }],
parent,
})
- scaffold.ctx.subagentNames.bind(parent.session, started.childId, 'lead/researcher')
childId = started.childId
await waitForAgentToSettle(scaffold, childId)
const liveInput = page.locator('[data-composer-input][contenteditable="true"]').first()
diff --git a/apps/web/tests/subagent-interrupt-ui.e2e.ts b/apps/web/tests/subagent-interrupt-ui.e2e.ts
index fb038ed766..8c5f8fb1ea 100644
--- a/apps/web/tests/subagent-interrupt-ui.e2e.ts
+++ b/apps/web/tests/subagent-interrupt-ui.e2e.ts
@@ -155,7 +155,6 @@ describe.skipIf(MODE === 'record')('web e2e: composer interrupt for a running co
signal: new AbortController().signal,
prompt: [{ type: 'text', text: INITIAL }], parent,
})
- scaffold.ctx.subagentNames.bind(parent.session, started.childId, 'lead/interrupt-worker')
childId = started.childId
await waitFor(() => existsSync(readyFile), 'the held child turn to open')
diff --git a/apps/web/tests/subagent-summary.e2e.ts b/apps/web/tests/subagent-summary.e2e.ts
index 2df6d36aed..5d3c564b09 100644
--- a/apps/web/tests/subagent-summary.e2e.ts
+++ b/apps/web/tests/subagent-summary.e2e.ts
@@ -152,7 +152,7 @@ describe.skipIf(MODE === 'record')('web e2e: subagent task summary', () => {
await expectSummary(card, DESCRIPTION)
await capture('Running')
- finishCall(agent, call, 'Delegation accepted.', false, { kind: 'activation', name: 'lead/foo' })
+ finishCall(agent, call, 'Delegation accepted.', false, { kind: 'activation', subagentId: 'child-foo' })
await scaffold.ctx.sessions.flush(agent.session)
await expect.poll(() => card.getAttribute('data-state')).toBe('ok')
await expectSummary(card, DESCRIPTION)
@@ -161,8 +161,8 @@ describe.skipIf(MODE === 'record')('web e2e: subagent task summary', () => {
await expectSummary(card, DESCRIPTION)
expect(await card.getByText('Agent response', { exact: true }).count()).toBe(0)
await card.getByText('Started', { exact: true }).waitFor()
- expect(await card.locator('dt').allTextContents()).toEqual(['Agent task description', 'Agent name'])
- expect(await card.locator('dd').allTextContents()).toEqual([`${DESCRIPTION}\nAdditional description context`, 'lead/foo'])
+ expect(await card.locator('dt').allTextContents()).toEqual(['Agent task description', 'ID'])
+ expect(await card.locator('dd').allTextContents()).toEqual([`${DESCRIPTION}\nAdditional description context`, 'child-foo'])
await capture('Creation receipt and complete task')
const beforeReload = tripwire.warnings.length
@@ -182,9 +182,9 @@ describe.skipIf(MODE === 'record')('web e2e: subagent task summary', () => {
it('falls back to the prompt, keeps synchronous replies in details, and preserves errors', async () => {
const cases = [
- { id: 'fallback', args: { prompt: 'Review the fallback summary.\nKeep the complete task in details.' }, summary: 'Review the fallback summary.', result: 'started subagent fallback-worker\nname: lead/fallback' },
+ { id: 'fallback', args: { prompt: 'Review the fallback summary.\nKeep the complete task in details.' }, summary: 'Review the fallback summary.', result: 'started subagent fallback-worker' },
{ id: 'reply', args: { description: 'Check synchronous agent reply', prompt: 'Review the synchronous report.\nKeep every instruction available.' }, summary: 'Check synchronous agent reply', result: 'The synchronous agent found two issues.\nBoth are documented in the report.' },
- { id: 'title-only', args: {}, summary: '', result: 'started subagent empty-worker\nname: lead/empty' },
+ { id: 'title-only', args: {}, summary: '', result: 'started subagent empty-worker' },
{ id: 'error', args: { description: 'Delegate a failing task', prompt: 'Attempt the requested delegation.' }, summary: 'Subagent capacity exceeded', result: 'Subagent capacity exceeded\nWait for an active agent to finish.', error: true },
]
const snapshots: string[] = []
@@ -244,13 +244,13 @@ describe.skipIf(MODE === 'record')('web e2e: subagent task summary', () => {
await expect.poll(() => card.getAttribute('data-state')).toBe('running')
await expectForkSummary()
await capture('Running')
- finishCall(agent, call, 'started subagent fork-worker\nname: lead/context-reviewer')
+ finishCall(agent, call, 'started subagent fork-worker')
await scaffold.ctx.sessions.flush(agent.session)
await expect.poll(() => card.getAttribute('data-state')).toBe('ok')
await expandTask(card, prompt)
await expectForkSummary()
- expect(await card.locator('dt').allTextContents()).toEqual(['Agent task description', 'Agent name'])
- expect(await card.locator('dd').allTextContents()).toEqual([description, 'lead/context-reviewer'])
+ expect(await card.locator('dt').allTextContents()).toEqual(['Agent task description', 'ID'])
+ expect(await card.locator('dd').allTextContents()).toEqual([description, 'fork-worker'])
expect(await card.getByText('Agent response', { exact: true }).count()).toBe(0)
await capture('Creation receipt and complete task')
const beforeReload = tripwire.warnings.length
diff --git a/docs/capability-seams.i18n.yaml b/docs/capability-seams.i18n.yaml
index a99543291b..1083094774 100644
--- a/docs/capability-seams.i18n.yaml
+++ b/docs/capability-seams.i18n.yaml
@@ -6,5 +6,5 @@
en: 41d772192075e133
zh: 5ef3da69b4de1d8a
/capability-seams-and-core-services:
- en: e1f7a4359af577e9
- zh: 642903ce98672936
+ en: 3c972fccec17a890
+ zh: 94c82847a3c8b83c
diff --git a/docs/capability-seams.md b/docs/capability-seams.md
index d4d9c8d098..2b5e9978b2 100644
--- a/docs/capability-seams.md
+++ b/docs/capability-seams.md
@@ -262,17 +262,14 @@ flowchart LR
pkg_subagent_spawn_in_process["subagent-spawn-in-process"]
pkg_subagent_fork_in_process["subagent-fork-in-process"]
pkg_subagent_dsh_sdk["subagent-dsh-sdk"]
- pkg_subagent_names["subagent-names"]
pkg_tool_subagent_control["tool-subagent-control"]
pkg_tool_ralph["tool-ralph"]
- svc_subagentNames["ctx.subagentNames
Optional subagent names"]
- pkg_tool_agent_team["tool-agent-team"]
- pkg_experimental_tool_subagent_oar["experimental-tool-subagent-oar"]
pkg_experimental_speech_to_text["experimental-speech-to-text"]
svc_speechToText["ctx.speechToText
Experimental speech recognition providers"]
pkg_experimental_speech_to_text_sensevoice["experimental-speech-to-text-sensevoice"]
pkg_agent_team["agent-team"]
svc_agentTeams["ctx.agentTeams
Agent Teams coordination domain"]
+ pkg_experimental_tool_agent_team["experimental-tool-agent-team"]
pkg_experimental_claude_code_mods["experimental-claude-code-mods"]
svc_claudeCodeMods["ctx.claudeCodeMods
Claude Code mods bridge"]
pkg_inspector["inspector"]
@@ -459,7 +456,6 @@ flowchart LR
pkg_subagent_codex --> svc_subagents
pkg_subagent_dsh_sdk --> svc_subagents
pkg_subagent_fork_in_process --> svc_subagents
- pkg_subagent_names --> svc_subagentNames
pkg_subagent_spawn_in_process --> svc_subagents
pkg_subprocess --> svc_subprocess
pkg_subprocess_local --> svc_subprocess
@@ -600,11 +596,6 @@ flowchart LR
svc_storage --> pkg_storage_domain
svc_storageDomain --> pkg_workspace
svc_subagentModelSelection --> pkg_tool_subagent
- svc_subagentNames --> pkg_experimental_tool_subagent_oar
- svc_subagentNames --> pkg_tool_agent_team
- svc_subagentNames --> pkg_tool_subagent
- svc_subagentNames --> pkg_tool_subagent_control
- svc_subagents --> pkg_subagent_names
svc_subagents --> pkg_tool_ralph
svc_subagents --> pkg_tool_subagent
svc_subagents --> pkg_tool_subagent_control
@@ -749,8 +740,7 @@ flowchart LR
| `ctx.ptcRuntime` | `seam` | [`ptc-runtime`](../packages/ptc-runtime/ptc-runtime) | [`ptc-runtime-node`](../packages/ptc-runtime/ptc-runtime-node), [`experimental-ptc-runtime-python`](../packages/experimental/ptc-runtime-python) | [`tool-executor-ptc`](../packages/core/tool-executor-ptc), [`workflow-ptc`](../packages/workflow/workflow-ptc) | - | Runs programs against host-provided async bindings; tool-executor-ptc owns PTC presentation and workflow-ptc owns workflow orchestration. |
| `ctx.fs` | `seam` | [`fs`](../packages/fs/fs) | [`fs-local`](../packages/fs/fs-local), [`fs-sandbox`](../packages/fs/fs-sandbox), [`fs-ssh`](../packages/ssh/fs-ssh) | [`tool-fs`](../packages/fs/tool-fs) | [`fs-observation-policy`](../packages/fs/fs-observation-policy) | tool-fs executes read/write/edit through ctx.fs; fs-sandbox fences mutations by the shared sandbox mode; fs-observation-policy contributes observed-state checks through the fs/* event gate. |
| `ctx.compaction` | `seam` | [`compaction`](../packages/compaction/compaction) | [`compaction-basic`](../packages/compaction/compaction-basic) | [`compaction-basic`](../packages/compaction/compaction-basic) | - | The basic backend consumes post-step pressure and request-error recovery events; there is no model-facing compact tool. |
-| `ctx.subagents` | `seam` | [`subagent`](../packages/subagent/subagent) | [`subagent-spawn-in-process`](../packages/subagent/subagent-spawn-in-process), [`subagent-fork-in-process`](../packages/subagent/subagent-fork-in-process), [`subagent-acp`](../packages/subagent/subagent-acp), [`subagent-codex`](../packages/subagent/subagent-codex), [`subagent-claude-code`](../packages/subagent/subagent-claude-code), [`subagent-dsh-sdk`](../packages/subagent/subagent-dsh-sdk) | [`subagent-names`](../packages/subagent/subagent-names), [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-subagent-control`](../packages/subagent/tool-subagent-control), [`tool-ralph`](../packages/experimental/tool-ralph) | - | Providers prepare local children or execute external tasks; one activation manager owns both lifecycles. The delegation tool selects a backend, control tools deliver local follow-ups, and workflows await activation results. |
-| `ctx.subagentNames` | `core` | [`subagent-names`](../packages/subagent/subagent-names) | - | [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-subagent-control`](../packages/subagent/tool-subagent-control), [`tool-agent-team`](../packages/team/tool-agent-team), [`experimental-tool-subagent-oar`](../packages/experimental/tool-subagent-oar) | - | Owns name reservations and durable name-to-id bindings in the root Session. Execution and authorization remain with the subagent service. |
+| `ctx.subagents` | `seam` | [`subagent`](../packages/subagent/subagent) | [`subagent-spawn-in-process`](../packages/subagent/subagent-spawn-in-process), [`subagent-fork-in-process`](../packages/subagent/subagent-fork-in-process), [`subagent-acp`](../packages/subagent/subagent-acp), [`subagent-codex`](../packages/subagent/subagent-codex), [`subagent-claude-code`](../packages/subagent/subagent-claude-code), [`subagent-dsh-sdk`](../packages/subagent/subagent-dsh-sdk) | [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-subagent-control`](../packages/subagent/tool-subagent-control), [`tool-ralph`](../packages/experimental/tool-ralph) | - | Providers prepare local children or execute external tasks; one activation manager owns both lifecycles. The delegation tool selects a backend, control tools deliver local follow-ups, and workflows await activation results. |
| `ctx.speechToText` | `seam` | [`experimental-speech-to-text`](../packages/experimental/speech-to-text) | [`experimental-speech-to-text-sensevoice`](../packages/experimental/speech-to-text-sensevoice) | [`experimental-api-speech-to-text`](../packages/experimental/api-speech-to-text) | - | Routes explicit recognizers; the browser uses the authenticated Remote and keeps transcripts in the draft until submission. |
| `ctx.agentTeams` | `core` | [`agent-team`](../packages/team/agent-team) | - | [`tool-agent-team`](../packages/team/tool-agent-team) | - | Owns the shared task DAG for a subagent tree; tool-agent-team contributes task controls. |
| `ctx.claudeCodeMods` | `core` | [`experimental-claude-code-mods`](../packages/experimental/claude-code-mods) | - | - | - | Loads mods that defineMod plugins add, raises their hook chains from harness extension points, and draws the band above the prompt over its Remote. |
diff --git a/docs/capability-seams.zh.md b/docs/capability-seams.zh.md
index 01eb46dd16..a92a944566 100644
--- a/docs/capability-seams.zh.md
+++ b/docs/capability-seams.zh.md
@@ -264,17 +264,14 @@ flowchart LR
pkg_subagent_spawn_in_process["subagent-spawn-in-process"]
pkg_subagent_fork_in_process["subagent-fork-in-process"]
pkg_subagent_dsh_sdk["subagent-dsh-sdk"]
- pkg_subagent_names["subagent-names"]
pkg_tool_subagent_control["tool-subagent-control"]
pkg_tool_ralph["tool-ralph"]
- svc_subagentNames["ctx.subagentNames
Optional subagent names"]
- pkg_tool_agent_team["tool-agent-team"]
- pkg_experimental_tool_subagent_oar["experimental-tool-subagent-oar"]
pkg_experimental_speech_to_text["experimental-speech-to-text"]
svc_speechToText["ctx.speechToText
Experimental speech recognition providers"]
pkg_experimental_speech_to_text_sensevoice["experimental-speech-to-text-sensevoice"]
pkg_agent_team["agent-team"]
svc_agentTeams["ctx.agentTeams
Agent Teams coordination domain"]
+ pkg_experimental_tool_agent_team["experimental-tool-agent-team"]
pkg_experimental_claude_code_mods["experimental-claude-code-mods"]
svc_claudeCodeMods["ctx.claudeCodeMods
Claude Code mods bridge"]
pkg_inspector["inspector"]
@@ -461,7 +458,6 @@ flowchart LR
pkg_subagent_codex --> svc_subagents
pkg_subagent_dsh_sdk --> svc_subagents
pkg_subagent_fork_in_process --> svc_subagents
- pkg_subagent_names --> svc_subagentNames
pkg_subagent_spawn_in_process --> svc_subagents
pkg_subprocess --> svc_subprocess
pkg_subprocess_local --> svc_subprocess
@@ -602,11 +598,6 @@ flowchart LR
svc_storage --> pkg_storage_domain
svc_storageDomain --> pkg_workspace
svc_subagentModelSelection --> pkg_tool_subagent
- svc_subagentNames --> pkg_experimental_tool_subagent_oar
- svc_subagentNames --> pkg_tool_agent_team
- svc_subagentNames --> pkg_tool_subagent
- svc_subagentNames --> pkg_tool_subagent_control
- svc_subagents --> pkg_subagent_names
svc_subagents --> pkg_tool_ralph
svc_subagents --> pkg_tool_subagent
svc_subagents --> pkg_tool_subagent_control
@@ -751,8 +742,7 @@ flowchart LR
| `ctx.ptcRuntime` | `seam` | [`ptc-runtime`](../packages/ptc-runtime/ptc-runtime) | [`ptc-runtime-node`](../packages/ptc-runtime/ptc-runtime-node), [`experimental-ptc-runtime-python`](../packages/experimental/ptc-runtime-python) | [`tool-executor-ptc`](../packages/core/tool-executor-ptc), [`workflow-ptc`](../packages/workflow/workflow-ptc) | - | 使用 Host 提供的异步绑定运行程序;tool-executor-ptc 负责 PTC 呈现,workflow-ptc 负责工作流编排。 |
| `ctx.fs` | `seam` | [`fs`](../packages/fs/fs) | [`fs-local`](../packages/fs/fs-local), [`fs-sandbox`](../packages/fs/fs-sandbox), [`fs-ssh`](../packages/ssh/fs-ssh) | [`tool-fs`](../packages/fs/tool-fs) | [`fs-observation-policy`](../packages/fs/fs-observation-policy) | tool-fs 通过 ctx.fs 执行读取/写入/编辑;fs-sandbox 按共享沙箱模式限制变更;fs-observation-policy 通过 fs/* 事件门禁贡献基于观测状态的检查。 |
| `ctx.compaction` | `seam` | [`compaction`](../packages/compaction/compaction) | [`compaction-basic`](../packages/compaction/compaction-basic) | [`compaction-basic`](../packages/compaction/compaction-basic) | - | 基础后端消费步骤后的压力事件和请求错误恢复事件;不存在面向模型的压缩工具。 |
-| `ctx.subagents` | `seam` | [`subagent`](../packages/subagent/subagent) | [`subagent-spawn-in-process`](../packages/subagent/subagent-spawn-in-process), [`subagent-fork-in-process`](../packages/subagent/subagent-fork-in-process), [`subagent-acp`](../packages/subagent/subagent-acp), [`subagent-codex`](../packages/subagent/subagent-codex), [`subagent-claude-code`](../packages/subagent/subagent-claude-code), [`subagent-dsh-sdk`](../packages/subagent/subagent-dsh-sdk) | [`subagent-names`](../packages/subagent/subagent-names), [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-subagent-control`](../packages/subagent/tool-subagent-control), [`tool-ralph`](../packages/experimental/tool-ralph) | - | 提供方准备本地子级或执行外部任务;一个 activation 管理器持有两类生命周期。委派工具选择后端,控制工具投递本地后续消息,工作流等待 activation 结果。 |
-| `ctx.subagentNames` | `core` | [`subagent-names`](../packages/subagent/subagent-names) | - | [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-subagent-control`](../packages/subagent/tool-subagent-control), [`tool-agent-team`](../packages/team/tool-agent-team), [`experimental-tool-subagent-oar`](../packages/experimental/tool-subagent-oar) | - | 持有名字预留及根 Session 中持久的名字到 ID 绑定。执行与授权仍由 subagent 服务负责。 |
+| `ctx.subagents` | `seam` | [`subagent`](../packages/subagent/subagent) | [`subagent-spawn-in-process`](../packages/subagent/subagent-spawn-in-process), [`subagent-fork-in-process`](../packages/subagent/subagent-fork-in-process), [`subagent-acp`](../packages/subagent/subagent-acp), [`subagent-codex`](../packages/subagent/subagent-codex), [`subagent-claude-code`](../packages/subagent/subagent-claude-code), [`subagent-dsh-sdk`](../packages/subagent/subagent-dsh-sdk) | [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-subagent-control`](../packages/subagent/tool-subagent-control), [`tool-ralph`](../packages/experimental/tool-ralph) | - | 提供方准备本地子级或执行外部任务;一个 activation 管理器持有两类生命周期。委派工具选择后端,控制工具投递本地后续消息,工作流等待 activation 结果。 |
| `ctx.speechToText` | `seam` | [`experimental-speech-to-text`](../packages/experimental/speech-to-text) | [`experimental-speech-to-text-sensevoice`](../packages/experimental/speech-to-text-sensevoice) | [`experimental-api-speech-to-text`](../packages/experimental/api-speech-to-text) | - | 路由显式选择的识别器;浏览器使用带认证的 Remote,并在提交前将转写保留在草稿中。 |
| `ctx.agentTeams` | `core` | [`agent-team`](../packages/team/agent-team) | - | [`tool-agent-team`](../packages/team/tool-agent-team) | - | 负责子代理树共享的任务 DAG;tool-agent-team 提供任务控制工具。 |
| `ctx.claudeCodeMods` | `core` | [`experimental-claude-code-mods`](../packages/experimental/claude-code-mods) | - | - | - | 加载 defineMod 插件添加的模组,从 harness 扩展点触发其钩子链,并通过其 Remote 绘制提示框上方的横幅。 |
diff --git a/docs/config-catalog.md b/docs/config-catalog.md
index 17e02d800a..09cfc53303 100644
--- a/docs/config-catalog.md
+++ b/docs/config-catalog.md
@@ -1424,13 +1424,27 @@ export interface Config {
```
+
+
+
+## `@deepseek-ai/dsh-experimental-tool-agent-team`
+
+- `inject`: `agents` · `agentTeams` · `subagents` · `tools` · `systemPrompt`
+- `source`: [`packages/experimental/tool-agent-team/src/index.ts:18`](../packages/experimental/tool-agent-team/src/index.ts)
+
+```ts config-catalog
+/** The Team tool plugin takes no configuration. */
+export type Config = Record
+```
+
+
## `@deepseek-ai/dsh-experimental-tool-subagent-oar`
-- `inject`: `tools` · `subagents` · `subagentNames`
-- `source`: [`packages/experimental/tool-subagent-oar/src/index.ts:14`](../packages/experimental/tool-subagent-oar/src/index.ts)
+- `inject`: `tools` · `subagents`
+- `source`: [`packages/experimental/tool-subagent-oar/src/index.ts:12`](../packages/experimental/tool-subagent-oar/src/index.ts)
```ts config-catalog
/** Deployment-owned runtime choices exposed by the external delegation tool. */
@@ -4290,9 +4304,9 @@ export interface Config {
## `@deepseek-ai/dsh-tool-subagent`
-- `inject`: `tools` · `subagents` · `subagentNames` · `systemPrompt` · `sessionProjections`
+- `inject`: `tools` · `subagents` · `systemPrompt` · `sessionProjections`
- `refs`: [`AgentOptions`](subsystems/core.md)
-- `source`: [`packages/subagent/tool-subagent/src/index.ts:47`](../packages/subagent/tool-subagent/src/index.ts)
+- `source`: [`packages/subagent/tool-subagent/src/index.ts:46`](../packages/subagent/tool-subagent/src/index.ts)
```ts config-catalog
/** Config: which registered provider this tool delegates to, plus child defaults. */
@@ -4348,8 +4362,8 @@ export interface PresetSelectionConfig {
## `@deepseek-ai/dsh-tool-subagent-control`
-- `inject`: `tools` · `subagents` · `subagentNames` · `agents` · `systemPrompt`
-- `source`: [`packages/subagent/tool-subagent-control/src/index.ts:25`](../packages/subagent/tool-subagent-control/src/index.ts)
+- `inject`: `tools` · `subagents` · `agents` · `systemPrompt`
+- `source`: [`packages/subagent/tool-subagent-control/src/index.ts:26`](../packages/subagent/tool-subagent-control/src/index.ts)
```ts config-catalog
/** Optional subagent control tools. */
@@ -4930,7 +4944,6 @@ These load from a `cordis.yml` entry with no `config:` block; they declare no co
| `@deepseek-ai/dsh-settings` | `configEditor` · `profileContext` | [`packages/settings/settings/src/index.ts`](../packages/settings/settings/src/index.ts) |
| `@deepseek-ai/dsh-skill-badge` | `skills` | [`packages/experimental/skill-badge/src/index.ts`](../packages/experimental/skill-badge/src/index.ts) |
| `@deepseek-ai/dsh-storage` | — | [`packages/storage/storage/src/index.ts`](../packages/storage/storage/src/index.ts) |
-| `@deepseek-ai/dsh-subagent-names` | `sessionProjections` | [`packages/subagent/subagent-names/src/index.ts`](../packages/subagent/subagent-names/src/index.ts) |
| `@deepseek-ai/dsh-subprocess-local` | — | [`packages/subprocess/subprocess-local/src/index.ts`](../packages/subprocess/subprocess-local/src/index.ts) |
| `@deepseek-ai/dsh-subprocess-ssh` | `ssh` | [`packages/ssh/subprocess-ssh/src/index.ts`](../packages/ssh/subprocess-ssh/src/index.ts) |
| `@deepseek-ai/dsh-terminal` | — | [`packages/terminal/terminal/src/index.ts`](../packages/terminal/terminal/src/index.ts) |
diff --git a/docs/config-catalog.zh.md b/docs/config-catalog.zh.md
index 99ec4ce6c9..4319bad0ba 100644
--- a/docs/config-catalog.zh.md
+++ b/docs/config-catalog.zh.md
@@ -1426,13 +1426,27 @@ export interface Config {
```
+
+
+
+## `@deepseek-ai/dsh-experimental-tool-agent-team`
+
+- `inject`: `agents` · `agentTeams` · `subagents` · `tools` · `systemPrompt`
+- `source`: [`packages/experimental/tool-agent-team/src/index.ts:18`](../packages/experimental/tool-agent-team/src/index.ts)
+
+```ts config-catalog
+/** The Team tool plugin takes no configuration. */
+export type Config = Record
+```
+
+
## `@deepseek-ai/dsh-experimental-tool-subagent-oar`
-- `inject`: `tools` · `subagents` · `subagentNames`
-- `source`: [`packages/experimental/tool-subagent-oar/src/index.ts:14`](../packages/experimental/tool-subagent-oar/src/index.ts)
+- `inject`: `tools` · `subagents`
+- `source`: [`packages/experimental/tool-subagent-oar/src/index.ts:12`](../packages/experimental/tool-subagent-oar/src/index.ts)
```ts config-catalog
/** Deployment-owned runtime choices exposed by the external delegation tool. */
@@ -4292,9 +4306,9 @@ export interface Config {
## `@deepseek-ai/dsh-tool-subagent`
-- `inject`: `tools` · `subagents` · `subagentNames` · `systemPrompt` · `sessionProjections`
+- `inject`: `tools` · `subagents` · `systemPrompt` · `sessionProjections`
- `refs`: [`AgentOptions`](subsystems/core.zh.md)
-- `source`: [`packages/subagent/tool-subagent/src/index.ts:47`](../packages/subagent/tool-subagent/src/index.ts)
+- `source`: [`packages/subagent/tool-subagent/src/index.ts:46`](../packages/subagent/tool-subagent/src/index.ts)
```ts config-catalog
/** Config: which registered provider this tool delegates to, plus child defaults. */
@@ -4350,8 +4364,8 @@ export interface PresetSelectionConfig {
## `@deepseek-ai/dsh-tool-subagent-control`
-- `inject`: `tools` · `subagents` · `subagentNames` · `agents` · `systemPrompt`
-- `source`: [`packages/subagent/tool-subagent-control/src/index.ts:25`](../packages/subagent/tool-subagent-control/src/index.ts)
+- `inject`: `tools` · `subagents` · `agents` · `systemPrompt`
+- `source`: [`packages/subagent/tool-subagent-control/src/index.ts:26`](../packages/subagent/tool-subagent-control/src/index.ts)
```ts config-catalog
/** Optional subagent control tools. */
@@ -4932,7 +4946,6 @@ export interface Config {
| `@deepseek-ai/dsh-settings` | `configEditor` · `profileContext` | [`packages/settings/settings/src/index.ts`](../packages/settings/settings/src/index.ts) |
| `@deepseek-ai/dsh-skill-badge` | `skills` | [`packages/experimental/skill-badge/src/index.ts`](../packages/experimental/skill-badge/src/index.ts) |
| `@deepseek-ai/dsh-storage` | — | [`packages/storage/storage/src/index.ts`](../packages/storage/storage/src/index.ts) |
-| `@deepseek-ai/dsh-subagent-names` | `sessionProjections` | [`packages/subagent/subagent-names/src/index.ts`](../packages/subagent/subagent-names/src/index.ts) |
| `@deepseek-ai/dsh-subprocess-local` | — | [`packages/subprocess/subprocess-local/src/index.ts`](../packages/subprocess/subprocess-local/src/index.ts) |
| `@deepseek-ai/dsh-subprocess-ssh` | `ssh` | [`packages/ssh/subprocess-ssh/src/index.ts`](../packages/ssh/subprocess-ssh/src/index.ts) |
| `@deepseek-ai/dsh-terminal` | — | [`packages/terminal/terminal/src/index.ts`](../packages/terminal/terminal/src/index.ts) |
diff --git a/docs/module-graph.md b/docs/module-graph.md
index 39a2c6156b..b8b97c101b 100644
--- a/docs/module-graph.md
+++ b/docs/module-graph.md
@@ -82,7 +82,6 @@ flowchart TD
pkg_subagent_codex["subagent-codex"]
pkg_subagent_dsh_sdk["subagent-dsh-sdk"]
pkg_subagent_fork_in_process["subagent-fork-in-process"]
- pkg_subagent_names["subagent-names"]
pkg_subagent_spawn_in_process["subagent-spawn-in-process"]
pkg_tool_subagent["tool-subagent"]
pkg_tool_subagent_control["tool-subagent-control"]
@@ -570,9 +569,6 @@ flowchart TD
pkg_fs --> pkg_brand
pkg_fs --> pkg_llm
pkg_fs --> pkg_sandbox
- pkg_subagent_names --> pkg_llm
- pkg_subagent_names --> pkg_session
- pkg_subagent_names --> pkg_session_projection
pkg_spill_local --> pkg_spill
pkg_session_log_export --> pkg_session
pkg_session_log_export --> pkg_session_persistence
@@ -1226,7 +1222,6 @@ flowchart TD
pkg_subagent --> pkg_session_persistence
pkg_subagent --> pkg_session_projection
pkg_subagent --> pkg_session_query
- pkg_subagent --> pkg_subagent_names
pkg_subagent --> pkg_system_prompt
pkg_subagent --> pkg_tools
pkg_subagent --> pkg_typert_protocol
@@ -1328,14 +1323,12 @@ flowchart TD
pkg_tool_subagent --> pkg_session
pkg_tool_subagent --> pkg_session_projection
pkg_tool_subagent --> pkg_subagent
- pkg_tool_subagent --> pkg_subagent_names
pkg_tool_subagent --> pkg_system_prompt
pkg_tool_subagent --> pkg_tools
pkg_tool_subagent_control --> pkg_agent
pkg_tool_subagent_control --> pkg_llm
pkg_tool_subagent_control --> pkg_session
pkg_tool_subagent_control --> pkg_subagent
- pkg_tool_subagent_control --> pkg_subagent_names
pkg_tool_subagent_control --> pkg_system_prompt
pkg_tool_subagent_control --> pkg_tools
pkg_api_session_controller --> pkg_agent
@@ -1407,9 +1400,7 @@ flowchart TD
pkg_experimental_subagent_oar --> pkg_session
pkg_experimental_subagent_oar --> pkg_subagent
pkg_experimental_subagent_oar --> pkg_subprocess
- pkg_experimental_tool_subagent_oar --> pkg_llm
pkg_experimental_tool_subagent_oar --> pkg_subagent
- pkg_experimental_tool_subagent_oar --> pkg_subagent_names
pkg_experimental_tool_subagent_oar --> pkg_tools
pkg_hooks_claude_code --> pkg_agent
pkg_hooks_claude_code --> pkg_hook_protocol
@@ -1446,6 +1437,12 @@ flowchart TD
pkg_workflow_ptc --> pkg_tools
pkg_workflow_ptc --> pkg_workflow
pkg_workflow_ptc --> pkg_working_directory
+ pkg_experimental_tool_agent_team --> pkg_agent
+ pkg_experimental_tool_agent_team --> pkg_experimental_agent_team
+ pkg_experimental_tool_agent_team --> pkg_session
+ pkg_experimental_tool_agent_team --> pkg_subagent
+ pkg_experimental_tool_agent_team --> pkg_system_prompt
+ pkg_experimental_tool_agent_team --> pkg_tools
pkg_schedule --> pkg_agent
pkg_schedule --> pkg_api_session_controller
pkg_schedule --> pkg_brand
@@ -1715,7 +1712,6 @@ flowchart TD
| [`otel`](../packages/telemetry/otel) | `telemetry` | [`session`](../packages/core/session) |
| [`session-snapshot`](../packages/test-support/session-snapshot) | `test-support` | [`http-proxy`](../packages/util/http-proxy), [`session`](../packages/core/session) |
| [`fs`](../packages/fs/fs) | `fs` | [`brand`](../packages/util/brand), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox) |
-| [`subagent-names`](../packages/subagent/subagent-names) | `subagent` | [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection) |
| [`spill-local`](../packages/spill/spill-local) | `spill` | [`spill`](../packages/spill/spill) |
| [`session-log-export`](../packages/session-query/session-log-export) | `session-query` | [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence) |
| [`config-editor`](../packages/boot/config-editor) | `boot` | [`app-boot`](../packages/boot/app-boot), [`hmr`](../packages/boot/hmr) |
@@ -1853,7 +1849,7 @@ flowchart TD
| [`sandbox-ssh`](../packages/ssh/sandbox-ssh) | `ssh` | [`sandbox`](../packages/sandbox/sandbox), [`ssh`](../packages/ssh/ssh) |
| [`subprocess-ssh`](../packages/ssh/subprocess-ssh) | `ssh` | [`ssh`](../packages/ssh/ssh), [`subprocess`](../packages/subprocess/subprocess), [`subprocess-local`](../packages/subprocess/subprocess-local) |
| [`agent-loop-testkit`](../packages/test-support/agent-loop-testkit) | `test-support` | [`agent`](../packages/core/agent), [`agent-loop`](../packages/core/agent-loop), [`fs-local`](../packages/fs/fs-local), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`working-directory`](../packages/session/working-directory) |
-| [`subagent`](../packages/subagent/subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-preset-registry`](../packages/preset/agent-preset-registry), [`attachment`](../packages/attachment/attachment), [`llm`](../packages/llm/llm), [`permission-presets`](../packages/interaction/permission-presets), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-query`](../packages/session-query/session-query), [`subagent-names`](../packages/subagent/subagent-names), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol), [`user-approval`](../packages/interaction/user-approval), [`util-time`](../packages/util/time), [`working-directory`](../packages/session/working-directory), [`workspace`](../packages/workspace/workspace) |
+| [`subagent`](../packages/subagent/subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-preset-registry`](../packages/preset/agent-preset-registry), [`attachment`](../packages/attachment/attachment), [`llm`](../packages/llm/llm), [`permission-presets`](../packages/interaction/permission-presets), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-query`](../packages/session-query/session-query), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol), [`user-approval`](../packages/interaction/user-approval), [`util-time`](../packages/util/time), [`working-directory`](../packages/session/working-directory), [`workspace`](../packages/workspace/workspace) |
| [`spill-policy`](../packages/spill/spill-policy) | `spill` | [`attachment`](../packages/attachment/attachment), [`fs`](../packages/fs/fs), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`spill`](../packages/spill/spill), [`token-meter`](../packages/llm/token-meter), [`tools`](../packages/core/tools) |
| [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | `session-query` | [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-query`](../packages/session-query/session-query) |
| [`acp`](../packages/acp/acp) | `acp` | [`agent`](../packages/core/agent), [`attachment`](../packages/attachment/attachment), [`llm`](../packages/llm/llm), [`mcp-client`](../packages/mcp/mcp-client), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`token-meter`](../packages/llm/token-meter), [`user-approval`](../packages/interaction/user-approval) |
@@ -1869,20 +1865,21 @@ flowchart TD
| [`subagent-codex`](../packages/subagent/subagent-codex) | `subagent` | [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
| [`subagent-fork-in-process`](../packages/subagent/subagent-fork-in-process) | `subagent` | [`agent`](../packages/core/agent), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) |
| [`subagent-spawn-in-process`](../packages/subagent/subagent-spawn-in-process) | `subagent` | [`subagent`](../packages/subagent/subagent) |
-| [`tool-subagent`](../packages/subagent/tool-subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-preset-registry`](../packages/preset/agent-preset-registry), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`subagent`](../packages/subagent/subagent), [`subagent-names`](../packages/subagent/subagent-names), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
-| [`tool-subagent-control`](../packages/subagent/tool-subagent-control) | `subagent` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subagent-names`](../packages/subagent/subagent-names), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
+| [`tool-subagent`](../packages/subagent/tool-subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-preset-registry`](../packages/preset/agent-preset-registry), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
+| [`tool-subagent-control`](../packages/subagent/tool-subagent-control) | `subagent` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
| [`api-session-controller`](../packages/api/session-controller) | `api` | [`agent`](../packages/core/agent), [`agent-default-model`](../packages/core/agent-default-model), [`agent-preset-registry`](../packages/preset/agent-preset-registry), [`api-gateway`](../packages/api/gateway), [`attachment`](../packages/attachment/attachment), [`client-connection`](../packages/client/connection), [`client-file-upload`](../packages/client/file-upload), [`commands`](../packages/interaction/commands), [`credentials`](../packages/credentials/credentials), [`file-reference`](../packages/context/file-reference), [`fs`](../packages/fs/fs), [`llm`](../packages/llm/llm), [`native-command`](../packages/util/native-command), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`session-title`](../packages/session/session-title), [`settings`](../packages/settings/settings), [`skill`](../packages/skill/skill), [`subagent`](../packages/subagent/subagent), [`typert-protocol`](../packages/typert/protocol), [`typert-registry`](../packages/typert/registry), [`util-time`](../packages/util/time), [`util-values`](../packages/util/values), [`util-workspace-path`](../packages/util/workspace-path), [`working-directory`](../packages/session/working-directory), [`workspace`](../packages/workspace/workspace) |
| [`plugin-market`](../packages/boot/plugin-market) | `boot` | [`plugin-manager`](../packages/boot/plugin-manager), [`settings`](../packages/settings/settings), [`subprocess`](../packages/subprocess/subprocess), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol) |
| [`headless`](../packages/bundle/headless) | `bundle` | [`agent`](../packages/core/agent), [`agent-default-model`](../packages/core/agent-default-model), [`fs`](../packages/fs/fs), [`llm`](../packages/llm/llm), [`permission-presets`](../packages/interaction/permission-presets), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session), [`session-query`](../packages/session-query/session-query), [`subagent`](../packages/subagent/subagent), [`user-approval`](../packages/interaction/user-approval) |
| [`compaction-basic`](../packages/compaction/compaction-basic) | `compaction` | [`agent`](../packages/core/agent), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`compaction-tool-result-pruner`](../packages/compaction/compaction-tool-result-pruner), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) |
| [`session-reference`](../packages/context/session-reference) | `context` | [`agent`](../packages/core/agent), [`compaction`](../packages/compaction/compaction), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`session-title`](../packages/session/session-title), [`spill`](../packages/spill/spill), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`typert-protocol`](../packages/typert/protocol) |
| [`experimental-subagent-oar`](../packages/experimental/subagent-oar) | `experimental` | [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess) |
-| [`experimental-tool-subagent-oar`](../packages/experimental/tool-subagent-oar) | `experimental` | [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`subagent-names`](../packages/subagent/subagent-names), [`tools`](../packages/core/tools) |
+| [`experimental-tool-subagent-oar`](../packages/experimental/tool-subagent-oar) | `experimental` | [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
| [`hooks-claude-code`](../packages/experimental/hooks-claude-code) | `experimental` | [`agent`](../packages/core/agent), [`hook-protocol`](../packages/experimental/hook-protocol), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools), [`working-directory`](../packages/session/working-directory) |
| [`tool-ralph`](../packages/experimental/tool-ralph) | `experimental` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
| [`sdk-protocol`](../packages/sdk/protocol) | `sdk` | [`commands`](../packages/interaction/commands), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`user-questions`](../packages/interaction/user-questions) |
| [`agent-team`](../packages/team/agent-team) | `team` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`subagent`](../packages/subagent/subagent), [`typert-protocol`](../packages/typert/protocol) |
| [`workflow-ptc`](../packages/workflow/workflow-ptc) | `workflow` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`ptc-runtime`](../packages/ptc-runtime/ptc-runtime), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow), [`working-directory`](../packages/session/working-directory) |
+| [`experimental-tool-agent-team`](../packages/experimental/tool-agent-team) | `experimental` | [`agent`](../packages/core/agent), [`experimental-agent-team`](../packages/experimental/agent-team), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
| [`schedule`](../packages/schedule/schedule) | `schedule` | [`agent`](../packages/core/agent), [`api-session-controller`](../packages/api/session-controller), [`brand`](../packages/util/brand), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`storage-domain`](../packages/storage/storage-domain), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol), [`util-time`](../packages/util/time), [`workspace`](../packages/workspace/workspace) |
| [`sdk-client`](../packages/sdk/client) | `sdk` | [`llm`](../packages/llm/llm), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session) |
| [`tool-agent-team`](../packages/team/tool-agent-team) | `team` | [`agent`](../packages/core/agent), [`agent-team`](../packages/team/agent-team), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subagent-names`](../packages/subagent/subagent-names), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
diff --git a/docs/module-graph.zh.md b/docs/module-graph.zh.md
index 9ba4d53201..f85b309e79 100644
--- a/docs/module-graph.zh.md
+++ b/docs/module-graph.zh.md
@@ -84,7 +84,6 @@ flowchart TD
pkg_subagent_codex["subagent-codex"]
pkg_subagent_dsh_sdk["subagent-dsh-sdk"]
pkg_subagent_fork_in_process["subagent-fork-in-process"]
- pkg_subagent_names["subagent-names"]
pkg_subagent_spawn_in_process["subagent-spawn-in-process"]
pkg_tool_subagent["tool-subagent"]
pkg_tool_subagent_control["tool-subagent-control"]
@@ -572,9 +571,6 @@ flowchart TD
pkg_fs --> pkg_brand
pkg_fs --> pkg_llm
pkg_fs --> pkg_sandbox
- pkg_subagent_names --> pkg_llm
- pkg_subagent_names --> pkg_session
- pkg_subagent_names --> pkg_session_projection
pkg_spill_local --> pkg_spill
pkg_session_log_export --> pkg_session
pkg_session_log_export --> pkg_session_persistence
@@ -1228,7 +1224,6 @@ flowchart TD
pkg_subagent --> pkg_session_persistence
pkg_subagent --> pkg_session_projection
pkg_subagent --> pkg_session_query
- pkg_subagent --> pkg_subagent_names
pkg_subagent --> pkg_system_prompt
pkg_subagent --> pkg_tools
pkg_subagent --> pkg_typert_protocol
@@ -1330,14 +1325,12 @@ flowchart TD
pkg_tool_subagent --> pkg_session
pkg_tool_subagent --> pkg_session_projection
pkg_tool_subagent --> pkg_subagent
- pkg_tool_subagent --> pkg_subagent_names
pkg_tool_subagent --> pkg_system_prompt
pkg_tool_subagent --> pkg_tools
pkg_tool_subagent_control --> pkg_agent
pkg_tool_subagent_control --> pkg_llm
pkg_tool_subagent_control --> pkg_session
pkg_tool_subagent_control --> pkg_subagent
- pkg_tool_subagent_control --> pkg_subagent_names
pkg_tool_subagent_control --> pkg_system_prompt
pkg_tool_subagent_control --> pkg_tools
pkg_api_session_controller --> pkg_agent
@@ -1409,9 +1402,7 @@ flowchart TD
pkg_experimental_subagent_oar --> pkg_session
pkg_experimental_subagent_oar --> pkg_subagent
pkg_experimental_subagent_oar --> pkg_subprocess
- pkg_experimental_tool_subagent_oar --> pkg_llm
pkg_experimental_tool_subagent_oar --> pkg_subagent
- pkg_experimental_tool_subagent_oar --> pkg_subagent_names
pkg_experimental_tool_subagent_oar --> pkg_tools
pkg_hooks_claude_code --> pkg_agent
pkg_hooks_claude_code --> pkg_hook_protocol
@@ -1448,6 +1439,12 @@ flowchart TD
pkg_workflow_ptc --> pkg_tools
pkg_workflow_ptc --> pkg_workflow
pkg_workflow_ptc --> pkg_working_directory
+ pkg_experimental_tool_agent_team --> pkg_agent
+ pkg_experimental_tool_agent_team --> pkg_experimental_agent_team
+ pkg_experimental_tool_agent_team --> pkg_session
+ pkg_experimental_tool_agent_team --> pkg_subagent
+ pkg_experimental_tool_agent_team --> pkg_system_prompt
+ pkg_experimental_tool_agent_team --> pkg_tools
pkg_schedule --> pkg_agent
pkg_schedule --> pkg_api_session_controller
pkg_schedule --> pkg_brand
@@ -1717,7 +1714,6 @@ flowchart TD
| [`otel`](../packages/telemetry/otel) | `telemetry` | [`session`](../packages/core/session) |
| [`session-snapshot`](../packages/test-support/session-snapshot) | `test-support` | [`http-proxy`](../packages/util/http-proxy), [`session`](../packages/core/session) |
| [`fs`](../packages/fs/fs) | `fs` | [`brand`](../packages/util/brand), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox) |
-| [`subagent-names`](../packages/subagent/subagent-names) | `subagent` | [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection) |
| [`spill-local`](../packages/spill/spill-local) | `spill` | [`spill`](../packages/spill/spill) |
| [`session-log-export`](../packages/session-query/session-log-export) | `session-query` | [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence) |
| [`config-editor`](../packages/boot/config-editor) | `boot` | [`app-boot`](../packages/boot/app-boot), [`hmr`](../packages/boot/hmr) |
@@ -1855,7 +1851,7 @@ flowchart TD
| [`sandbox-ssh`](../packages/ssh/sandbox-ssh) | `ssh` | [`sandbox`](../packages/sandbox/sandbox), [`ssh`](../packages/ssh/ssh) |
| [`subprocess-ssh`](../packages/ssh/subprocess-ssh) | `ssh` | [`ssh`](../packages/ssh/ssh), [`subprocess`](../packages/subprocess/subprocess), [`subprocess-local`](../packages/subprocess/subprocess-local) |
| [`agent-loop-testkit`](../packages/test-support/agent-loop-testkit) | `test-support` | [`agent`](../packages/core/agent), [`agent-loop`](../packages/core/agent-loop), [`fs-local`](../packages/fs/fs-local), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`working-directory`](../packages/session/working-directory) |
-| [`subagent`](../packages/subagent/subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-preset-registry`](../packages/preset/agent-preset-registry), [`attachment`](../packages/attachment/attachment), [`llm`](../packages/llm/llm), [`permission-presets`](../packages/interaction/permission-presets), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-query`](../packages/session-query/session-query), [`subagent-names`](../packages/subagent/subagent-names), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol), [`user-approval`](../packages/interaction/user-approval), [`util-time`](../packages/util/time), [`working-directory`](../packages/session/working-directory), [`workspace`](../packages/workspace/workspace) |
+| [`subagent`](../packages/subagent/subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-preset-registry`](../packages/preset/agent-preset-registry), [`attachment`](../packages/attachment/attachment), [`llm`](../packages/llm/llm), [`permission-presets`](../packages/interaction/permission-presets), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-query`](../packages/session-query/session-query), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol), [`user-approval`](../packages/interaction/user-approval), [`util-time`](../packages/util/time), [`working-directory`](../packages/session/working-directory), [`workspace`](../packages/workspace/workspace) |
| [`spill-policy`](../packages/spill/spill-policy) | `spill` | [`attachment`](../packages/attachment/attachment), [`fs`](../packages/fs/fs), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`spill`](../packages/spill/spill), [`token-meter`](../packages/llm/token-meter), [`tools`](../packages/core/tools) |
| [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | `session-query` | [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-query`](../packages/session-query/session-query) |
| [`acp`](../packages/acp/acp) | `acp` | [`agent`](../packages/core/agent), [`attachment`](../packages/attachment/attachment), [`llm`](../packages/llm/llm), [`mcp-client`](../packages/mcp/mcp-client), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`token-meter`](../packages/llm/token-meter), [`user-approval`](../packages/interaction/user-approval) |
@@ -1871,20 +1867,21 @@ flowchart TD
| [`subagent-codex`](../packages/subagent/subagent-codex) | `subagent` | [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
| [`subagent-fork-in-process`](../packages/subagent/subagent-fork-in-process) | `subagent` | [`agent`](../packages/core/agent), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) |
| [`subagent-spawn-in-process`](../packages/subagent/subagent-spawn-in-process) | `subagent` | [`subagent`](../packages/subagent/subagent) |
-| [`tool-subagent`](../packages/subagent/tool-subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-preset-registry`](../packages/preset/agent-preset-registry), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`subagent`](../packages/subagent/subagent), [`subagent-names`](../packages/subagent/subagent-names), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
-| [`tool-subagent-control`](../packages/subagent/tool-subagent-control) | `subagent` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subagent-names`](../packages/subagent/subagent-names), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
+| [`tool-subagent`](../packages/subagent/tool-subagent) | `subagent` | [`agent`](../packages/core/agent), [`agent-preset-registry`](../packages/preset/agent-preset-registry), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
+| [`tool-subagent-control`](../packages/subagent/tool-subagent-control) | `subagent` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
| [`api-session-controller`](../packages/api/session-controller) | `api` | [`agent`](../packages/core/agent), [`agent-default-model`](../packages/core/agent-default-model), [`agent-preset-registry`](../packages/preset/agent-preset-registry), [`api-gateway`](../packages/api/gateway), [`attachment`](../packages/attachment/attachment), [`client-connection`](../packages/client/connection), [`client-file-upload`](../packages/client/file-upload), [`commands`](../packages/interaction/commands), [`credentials`](../packages/credentials/credentials), [`file-reference`](../packages/context/file-reference), [`fs`](../packages/fs/fs), [`llm`](../packages/llm/llm), [`native-command`](../packages/util/native-command), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`session-title`](../packages/session/session-title), [`settings`](../packages/settings/settings), [`skill`](../packages/skill/skill), [`subagent`](../packages/subagent/subagent), [`typert-protocol`](../packages/typert/protocol), [`typert-registry`](../packages/typert/registry), [`util-time`](../packages/util/time), [`util-values`](../packages/util/values), [`util-workspace-path`](../packages/util/workspace-path), [`working-directory`](../packages/session/working-directory), [`workspace`](../packages/workspace/workspace) |
| [`plugin-market`](../packages/boot/plugin-market) | `boot` | [`plugin-manager`](../packages/boot/plugin-manager), [`settings`](../packages/settings/settings), [`subprocess`](../packages/subprocess/subprocess), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol) |
| [`headless`](../packages/bundle/headless) | `bundle` | [`agent`](../packages/core/agent), [`agent-default-model`](../packages/core/agent-default-model), [`fs`](../packages/fs/fs), [`llm`](../packages/llm/llm), [`permission-presets`](../packages/interaction/permission-presets), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session), [`session-query`](../packages/session-query/session-query), [`subagent`](../packages/subagent/subagent), [`user-approval`](../packages/interaction/user-approval) |
| [`compaction-basic`](../packages/compaction/compaction-basic) | `compaction` | [`agent`](../packages/core/agent), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`compaction-tool-result-pruner`](../packages/compaction/compaction-tool-result-pruner), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) |
| [`session-reference`](../packages/context/session-reference) | `context` | [`agent`](../packages/core/agent), [`compaction`](../packages/compaction/compaction), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-query`](../packages/session-query/session-query), [`session-title`](../packages/session/session-title), [`spill`](../packages/spill/spill), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`typert-protocol`](../packages/typert/protocol) |
| [`experimental-subagent-oar`](../packages/experimental/subagent-oar) | `experimental` | [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess) |
-| [`experimental-tool-subagent-oar`](../packages/experimental/tool-subagent-oar) | `experimental` | [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`subagent-names`](../packages/subagent/subagent-names), [`tools`](../packages/core/tools) |
+| [`experimental-tool-subagent-oar`](../packages/experimental/tool-subagent-oar) | `experimental` | [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
| [`hooks-claude-code`](../packages/experimental/hooks-claude-code) | `experimental` | [`agent`](../packages/core/agent), [`hook-protocol`](../packages/experimental/hook-protocol), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools), [`working-directory`](../packages/session/working-directory) |
| [`tool-ralph`](../packages/experimental/tool-ralph) | `experimental` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
| [`sdk-protocol`](../packages/sdk/protocol) | `sdk` | [`commands`](../packages/interaction/commands), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`user-questions`](../packages/interaction/user-questions) |
| [`agent-team`](../packages/team/agent-team) | `team` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`subagent`](../packages/subagent/subagent), [`typert-protocol`](../packages/typert/protocol) |
| [`workflow-ptc`](../packages/workflow/workflow-ptc) | `workflow` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`ptc-runtime`](../packages/ptc-runtime/ptc-runtime), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow), [`working-directory`](../packages/session/working-directory) |
+| [`experimental-tool-agent-team`](../packages/experimental/tool-agent-team) | `experimental` | [`agent`](../packages/core/agent), [`experimental-agent-team`](../packages/experimental/agent-team), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
| [`schedule`](../packages/schedule/schedule) | `schedule` | [`agent`](../packages/core/agent), [`api-session-controller`](../packages/api/session-controller), [`brand`](../packages/util/brand), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-projection`](../packages/session/session-projection), [`storage-domain`](../packages/storage/storage-domain), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol), [`util-time`](../packages/util/time), [`workspace`](../packages/workspace/workspace) |
| [`sdk-client`](../packages/sdk/client) | `sdk` | [`llm`](../packages/llm/llm), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session) |
| [`tool-agent-team`](../packages/team/tool-agent-team) | `team` | [`agent`](../packages/core/agent), [`agent-team`](../packages/team/agent-team), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subagent-names`](../packages/subagent/subagent-names), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
diff --git a/docs/persistence-catalog.md b/docs/persistence-catalog.md
index 84ce0dffdd..16c1cb90f8 100644
--- a/docs/persistence-catalog.md
+++ b/docs/persistence-catalog.md
@@ -61,7 +61,6 @@ The [format references](persistence-changes/historical-formats/README.md) cover
| `event:session/title-llm-request` | event | `d95c624eddecdacf1ee74356196c09d2f3fcd625714be5e852a6b643fa12a7ca` | [`{ type: "session/title-llm-request" }`](#persistence-type-sha256-d95c624eddecdacf1ee74356196c09d2f3fcd625714be5e852a6b643fa12a7ca) |
| `event:step/end` | event | `e0a787e6ec76c7c94fecbc501b489164ab0293db05bc947914077ad01e674f05` | [`{ type: "step/end" }`](#persistence-type-sha256-e0a787e6ec76c7c94fecbc501b489164ab0293db05bc947914077ad01e674f05) |
| `event:step/start` | event | `4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986` | [`{ type: "step/start" }`](#persistence-type-sha256-4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986) |
-| `event:subagent-name/bound` | event | `2073e98f0c214cc431b1a9a027efe75d22190a8ed8fed2791b47c2b52dd32a57` | [`{ type: "subagent-name/bound" }`](#persistence-type-sha256-2073e98f0c214cc431b1a9a027efe75d22190a8ed8fed2791b47c2b52dd32a57) |
| `event:subagent/catalog` | event | `53750b9abf61efb7992b0aadc3e247ec927449c63266df28230fd1139f5590ac` | [`{ type: "subagent/catalog" }`](#persistence-type-sha256-53750b9abf61efb7992b0aadc3e247ec927449c63266df28230fd1139f5590ac) |
| `event:subagent/descriptor` | event | `b79ada42962cad0190a9d465805260567621fa3a4abd757eb31e6016b52d5ab5` | [`{ type: "subagent/descriptor" }`](#persistence-type-sha256-b79ada42962cad0190a9d465805260567621fa3a4abd757eb31e6016b52d5ab5) |
| `event:subagent/model-selection-policy` | event | `a6567ccb2e530606b775371eb4fa31468d72084339968e8b0440a516a23b39dc` | [`{ type: "subagent/model-selection-policy" }`](#persistence-type-sha256-a6567ccb2e530606b775371eb4fa31468d72084339968e8b0440a516a23b39dc) |
@@ -977,22 +976,6 @@ Source: [`packages/subagent/subagent/src/descriptor.ts:38`](../packages/subagent
Source: [`packages/subagent/tool-subagent/src/model-selection-state.ts:17`](../packages/subagent/tool-subagent/src/model-selection-state.ts)
-### `subagent-name/*`
-
-
-
-#### `subagent-name/bound` — log-only
-
-```ts persistence-catalog
-/**
- * A root-owned alias for an accepted subagent identity.
- * @param data - versioned child identity and complete name.
- */
-'subagent-name/bound': SubagentNameBinding & { readonly version: 1 }
-```
-
-Source: [`packages/subagent/subagent-names/src/projection.ts:20`](../packages/subagent/subagent-names/src/projection.ts)
-
### `system/*`
@@ -2639,14 +2622,6 @@ SHA-256: `aacda84a69739238aa782eea902d3073017d9d74b9808de2bf5a83c9738cbdc6`
`"subagent"`
-
-
-### `"subagent-name/bound"`
-
-SHA-256: `5cc512378245b2dfad1cf88a732c05d86e41c91408421f2fff2b3b0a06557974`
-
-`"subagent-name/bound"`
-
### `"subagent-settled"`
@@ -6079,18 +6054,6 @@ SHA-256: `cbbe8377ee744964537dbafd83607219e58ba79a13f6db0d0645c7ad3d5e8a09`
| `mode` | required | `"external"` |
| `version` | required | `2` |
-
-
-### `{ childId, name, version }`
-
-SHA-256: `671fc8cbd3a924961ccfeada2462f460120381a806c7dc97a2c01ba6a74ac960`
-
-| Property | Presence | Type |
-|---|---|---|
-| `childId` | required | `string` |
-| `name` | required | `string` |
-| `version` | required | `1` |
-
### `{ code, name, reason? }`
@@ -8894,22 +8857,6 @@ SHA-256: `4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986`
| `time` | required | `number` |
| `type` | required | `"step/start"` |
-
-
-
-
-### `{ type: "subagent-name/bound" }`
-
-SHA-256: `2073e98f0c214cc431b1a9a027efe75d22190a8ed8fed2791b47c2b52dd32a57`
-
-| Property | Presence | Type |
-|---|---|---|
-| `data` | required | [`{ childId, name, version }`](#persistence-type-sha256-671fc8cbd3a924961ccfeada2462f460120381a806c7dc97a2c01ba6a74ac960) |
-| `ignorable` | optional | `true` |
-| `seq` | required | `number` |
-| `time` | required | `number` |
-| `type` | required | `"subagent-name/bound"` |
-
diff --git a/docs/persistence-catalog.zh.md b/docs/persistence-catalog.zh.md
index 18f41dc67a..5e045309fd 100644
--- a/docs/persistence-catalog.zh.md
+++ b/docs/persistence-catalog.zh.md
@@ -63,7 +63,6 @@
| `event:session/title-llm-request` | event | `d95c624eddecdacf1ee74356196c09d2f3fcd625714be5e852a6b643fa12a7ca` | [`{ type: "session/title-llm-request" }`](#persistence-type-sha256-d95c624eddecdacf1ee74356196c09d2f3fcd625714be5e852a6b643fa12a7ca) |
| `event:step/end` | event | `e0a787e6ec76c7c94fecbc501b489164ab0293db05bc947914077ad01e674f05` | [`{ type: "step/end" }`](#persistence-type-sha256-e0a787e6ec76c7c94fecbc501b489164ab0293db05bc947914077ad01e674f05) |
| `event:step/start` | event | `4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986` | [`{ type: "step/start" }`](#persistence-type-sha256-4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986) |
-| `event:subagent-name/bound` | event | `2073e98f0c214cc431b1a9a027efe75d22190a8ed8fed2791b47c2b52dd32a57` | [`{ type: "subagent-name/bound" }`](#persistence-type-sha256-2073e98f0c214cc431b1a9a027efe75d22190a8ed8fed2791b47c2b52dd32a57) |
| `event:subagent/catalog` | event | `53750b9abf61efb7992b0aadc3e247ec927449c63266df28230fd1139f5590ac` | [`{ type: "subagent/catalog" }`](#persistence-type-sha256-53750b9abf61efb7992b0aadc3e247ec927449c63266df28230fd1139f5590ac) |
| `event:subagent/descriptor` | event | `b79ada42962cad0190a9d465805260567621fa3a4abd757eb31e6016b52d5ab5` | [`{ type: "subagent/descriptor" }`](#persistence-type-sha256-b79ada42962cad0190a9d465805260567621fa3a4abd757eb31e6016b52d5ab5) |
| `event:subagent/model-selection-policy` | event | `a6567ccb2e530606b775371eb4fa31468d72084339968e8b0440a516a23b39dc` | [`{ type: "subagent/model-selection-policy" }`](#persistence-type-sha256-a6567ccb2e530606b775371eb4fa31468d72084339968e8b0440a516a23b39dc) |
@@ -979,22 +978,6 @@ export type SessionEvent = {
来源:[`packages/subagent/tool-subagent/src/model-selection-state.ts:17`](../packages/subagent/tool-subagent/src/model-selection-state.ts)
-### `subagent-name/*`
-
-
-
-#### `subagent-name/bound` — log-only
-
-```ts persistence-catalog
-/**
- * A root-owned alias for an accepted subagent identity.
- * @param data - versioned child identity and complete name.
- */
-'subagent-name/bound': SubagentNameBinding & { readonly version: 1 }
-```
-
-来源:[`packages/subagent/subagent-names/src/projection.ts:20`](../packages/subagent/subagent-names/src/projection.ts)
-
### `system/*`
@@ -2641,14 +2624,6 @@ SHA-256: `aacda84a69739238aa782eea902d3073017d9d74b9808de2bf5a83c9738cbdc6`
`"subagent"`
-
-
-### `"subagent-name/bound"`
-
-SHA-256: `5cc512378245b2dfad1cf88a732c05d86e41c91408421f2fff2b3b0a06557974`
-
-`"subagent-name/bound"`
-
### `"subagent-settled"`
@@ -6081,18 +6056,6 @@ SHA-256: `cbbe8377ee744964537dbafd83607219e58ba79a13f6db0d0645c7ad3d5e8a09`
| `mode` | 必需 | `"external"` |
| `version` | 必需 | `2` |
-
-
-### `{ childId, name, version }`
-
-SHA-256: `671fc8cbd3a924961ccfeada2462f460120381a806c7dc97a2c01ba6a74ac960`
-
-| 属性 | 存在性 | 类型 |
-|---|---|---|
-| `childId` | 必需 | `string` |
-| `name` | 必需 | `string` |
-| `version` | 必需 | `1` |
-
### `{ code, name, reason? }`
@@ -8896,22 +8859,6 @@ SHA-256: `4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986`
| `time` | 必需 | `number` |
| `type` | 必需 | `"step/start"` |
-
-
-
-
-### `{ type: "subagent-name/bound" }`
-
-SHA-256: `2073e98f0c214cc431b1a9a027efe75d22190a8ed8fed2791b47c2b52dd32a57`
-
-| 属性 | 存在性 | 类型 |
-|---|---|---|
-| `data` | 必需 | [`{ childId, name, version }`](#persistence-type-sha256-671fc8cbd3a924961ccfeada2462f460120381a806c7dc97a2c01ba6a74ac960) |
-| `ignorable` | 可选 | `true` |
-| `seq` | 必需 | `number` |
-| `time` | 必需 | `number` |
-| `type` | 必需 | `"subagent-name/bound"` |
-
diff --git a/docs/persistence-changes/2026-10-25-subagent-tool-names.i18n.yaml b/docs/persistence-changes/2026-10-25-subagent-tool-names.i18n.yaml
deleted file mode 100644
index f0c9dcea5e..0000000000
--- a/docs/persistence-changes/2026-10-25-subagent-tool-names.i18n.yaml
+++ /dev/null
@@ -1,28 +0,0 @@
-# Bilingual-pair consistency record for 2026-10-25-subagent-tool-names.md (docs/i18n/README.md): per heading
-# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
-# After editing either side, bring the other along and re-record with:
-# pnpm run verify-translation-pairing --write docs/persistence-changes/2026-10-25-subagent-tool-names.md
-/:
- en: 3d5a424ae7d7e46b
- zh: c22a8e4a62d8cc1a
-/2026-10-25-subagent-tool-names:
- en: 74dd331220011a1b
- zh: 008acdd3c41a03f4
-/2026-10-25-subagent-tool-names/summary:
- en: bb91739791e437e2
- zh: a75903b7a3d1c437
-/2026-10-25-subagent-tool-names/table-of-contents:
- en: 6cf314a069ceb451
- zh: 9adff678e9ecab3b
-/2026-10-25-subagent-tool-names/declaration:
- en: 6907136f28e48c90
- zh: 02f8298485f3d8e7
-/2026-10-25-subagent-tool-names/compatibility:
- en: e50cc33503dc233f
- zh: 3e08289200786f8b
-/2026-10-25-subagent-tool-names/verification:
- en: 5e801f6794f1bdee
- zh: c3313150883bf75e
-/2026-10-25-subagent-tool-names/dev-note:
- en: b75c8458928b72b9
- zh: 003ba4e17b4b5269
diff --git a/docs/persistence-changes/2026-10-25-subagent-tool-names.md b/docs/persistence-changes/2026-10-25-subagent-tool-names.md
deleted file mode 100644
index 5535477b9b..0000000000
--- a/docs/persistence-changes/2026-10-25-subagent-tool-names.md
+++ /dev/null
@@ -1,48 +0,0 @@
----
-description: "Records a persistence type transition and its compatibility acknowledgement."
-kind: persistence-change
----
-
-# 2026-10-25-subagent-tool-names
-
-English | [中文](2026-10-25-subagent-tool-names.zh.md)
-
-## Summary
-
-Adds the root-Session-owned subagent-name/bound event for persistent name-to-id bindings.
-
-## Table of Contents
-
-- [Declaration](#declaration)
-- [Compatibility](#compatibility)
-- [Verification](#verification)
-- [Dev Note](#dev-note)
-
-
-## Declaration
-
-```yaml persistence-change
-schemaVersion: 1
-id: 2026-10-25-subagent-tool-names
-baseline: false
-changes:
- - root: "event:subagent-name/bound"
- previous: null
- after: "2073e98f0c214cc431b1a9a027efe75d22190a8ed8fed2791b47c2b52dd32a57"
- decision: same-version
-```
-
-
-## Compatibility
-
-Existing V4 Sessions remain readable and unnamed catalog children retain their Session ids. The new event has a distinct discriminator and does not change subagent/catalog. Older readers without this required event in their vocabulary refuse a Session containing it before adoption; they do not silently discard names or misinterpret another event. The writer format remains V4.
-
-
-## Verification
-
-The subagent-names package tests cover binding replay, inherited-fork exclusion, checkpoint recovery, and conflicting binding rejection. The storage-contract.spec.ts and V4 codec.spec.ts tests cover refusal of unknown required events before adoption.
-
-
-## Dev Note
-
-None.
diff --git a/docs/persistence-changes/2026-10-25-subagent-tool-names.schema.json b/docs/persistence-changes/2026-10-25-subagent-tool-names.schema.json
deleted file mode 100644
index a7016772f7..0000000000
--- a/docs/persistence-changes/2026-10-25-subagent-tool-names.schema.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "formatVersion": 2,
- "roots": [
- {"key":"event:subagent-name/bound","kind":"event","event":"subagent-name/bound","surface":false,"digest":"2073e98f0c214cc431b1a9a027efe75d22190a8ed8fed2791b47c2b52dd32a57"}
- ],
- "types": [],
- "nodes": {
- "0657d3ca5ac4e7bf": {"kind":"primitive","type":"number"},
- "2073e98f0c214cc4": {"kind":"object","properties":[{"name":"data","type":"671fc8cbd3a92496","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"5cc512378245b2df","optional":false}],"indices":[]},
- "4cd48f3e5108bd6e": {"kind":"primitive","type":"string"},
- "5cc512378245b2df": {"kind":"literal","value":"subagent-name/bound"},
- "671fc8cbd3a92496": {"kind":"object","properties":[{"name":"childId","type":"4cd48f3e5108bd6e","optional":false},{"name":"name","type":"4cd48f3e5108bd6e","optional":false},{"name":"version","type":"f88f1b7b6bb733f6","optional":false}],"indices":[]},
- "dacf3d5f3e4ff619": {"kind":"literal","value":true},
- "f88f1b7b6bb733f6": {"kind":"literal","value":1}
- }
-}
diff --git a/docs/persistence-changes/2026-10-25-subagent-tool-names.zh.md b/docs/persistence-changes/2026-10-25-subagent-tool-names.zh.md
deleted file mode 100644
index 70766711ec..0000000000
--- a/docs/persistence-changes/2026-10-25-subagent-tool-names.zh.md
+++ /dev/null
@@ -1,48 +0,0 @@
----
-description: "记录持久化类型更改及其兼容性确认。"
-kind: persistence-change
----
-
-# 2026-10-25-subagent-tool-names
-
-[English](2026-10-25-subagent-tool-names.md) | 中文
-
-## 概述
-
-增加由根 Session 持有的 subagent-name/bound 事件,持久保存名字到 ID 的绑定。
-
-## 目录
-
-- [声明](#declaration)
-- [兼容性](#compatibility)
-- [验证](#verification)
-- [开发备注](#dev-note)
-
-
-## 声明
-
-```yaml persistence-change
-schemaVersion: 1
-id: 2026-10-25-subagent-tool-names
-baseline: false
-changes:
- - root: "event:subagent-name/bound"
- previous: null
- after: "2073e98f0c214cc431b1a9a027efe75d22190a8ed8fed2791b47c2b52dd32a57"
- decision: same-version
-```
-
-
-## 兼容性
-
-已有 V4 Session 仍可读取,未命名的 catalog 子节点保留其 Session id。新事件使用独立判别符,不改变 subagent/catalog。事件词汇表中没有这一必读事件的旧读取器会在接管前拒绝包含它的 Session,不会静默丢弃名字或将其误解为其他事件。写入格式仍为 V4。
-
-
-## 验证
-
-subagent-names 包测试覆盖绑定回放、排除 fork 继承事件、checkpoint 恢复及拒绝冲突绑定。storage-contract.spec.ts 与 V4 codec.spec.ts 测试覆盖在接管前拒绝未知必读事件。
-
-
-## 开发备注
-
-无。
diff --git a/docs/persistence-schema.json b/docs/persistence-schema.json
index 16ec7e64f6..3a30b6f025 100644
--- a/docs/persistence-schema.json
+++ b/docs/persistence-schema.json
@@ -43,7 +43,6 @@
{"key":"event:session/title-llm-request","kind":"event","event":"session/title-llm-request","surface":false,"digest":"d95c624eddecdacf1ee74356196c09d2f3fcd625714be5e852a6b643fa12a7ca"},
{"key":"event:step/end","kind":"event","event":"step/end","surface":false,"digest":"e0a787e6ec76c7c94fecbc501b489164ab0293db05bc947914077ad01e674f05"},
{"key":"event:step/start","kind":"event","event":"step/start","surface":false,"digest":"4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986"},
- {"key":"event:subagent-name/bound","kind":"event","event":"subagent-name/bound","surface":false,"digest":"2073e98f0c214cc431b1a9a027efe75d22190a8ed8fed2791b47c2b52dd32a57"},
{"key":"event:subagent/catalog","kind":"event","event":"subagent/catalog","surface":false,"digest":"53750b9abf61efb7992b0aadc3e247ec927449c63266df28230fd1139f5590ac"},
{"key":"event:subagent/descriptor","kind":"event","event":"subagent/descriptor","surface":false,"digest":"b79ada42962cad0190a9d465805260567621fa3a4abd757eb31e6016b52d5ab5"},
{"key":"event:subagent/model-selection-policy","kind":"event","event":"subagent/model-selection-policy","surface":false,"digest":"a6567ccb2e530606b775371eb4fa31468d72084339968e8b0440a516a23b39dc"},
@@ -154,7 +153,6 @@
{"digest":"1f1385dbc3e875c021e387c7096d671d606f22daec51b25c80348735b6bbfa10","names":[],"sources":[]},
{"digest":"1f8c126cfab3df812cd115cfc23e3256f0fa2383400f4ce91ecad313577e59b0","names":["packages/core/session/src/types.ts#TurnEndCancelCause"],"sources":["packages/core/session/src/types.ts:201"]},
{"digest":"1fdad624334d354820dfb3a26e28d0bc9fc1b62a33f87bab63f715b3f4391bfd","names":[],"sources":[]},
- {"digest":"2073e98f0c214cc431b1a9a027efe75d22190a8ed8fed2791b47c2b52dd32a57","names":[],"sources":[]},
{"digest":"20a57544bbf204dacd1ae6beb2ab29444365c3c869f2afdf489dcdcbc3d9c8c5","names":[],"sources":["packages/plan/plan-mode/src/index.ts:53"]},
{"digest":"2142e391b9ccb60d487afcf373ce74db98d952f69e8289eddb352a7e16e996c5","names":[],"sources":[]},
{"digest":"2152caf1a71e588e4df2358a806dea24936c1c47131134f01a12939d12cdc0c0","names":["packages/team/agent-team/src/types.ts#TeamMessageSource"],"sources":["packages/team/agent-team/src/types.ts:117"]},
@@ -296,7 +294,6 @@
{"digest":"5bd310104cfe448e530beb11422d2f791e2e32e8e95fdc528a15f9ca693dae75","names":[],"sources":[]},
{"digest":"5c45bf4c544a7211dcd8ba6ba7e5f1bc39b49e7a9df9d5cbdc8e87c22771b37b","names":[],"sources":[]},
{"digest":"5cb63db9fe57dc09c3a1c2b84c3edf73ff5b62960155d8436a2377a5c43ce32c","names":[],"sources":[]},
- {"digest":"5cc512378245b2dfad1cf88a732c05d86e41c91408421f2fff2b3b0a06557974","names":[],"sources":[]},
{"digest":"5cdbf342b7748d152bc987b68f58e565e5bba4b227e076e2d2120d87662e45cd","names":[],"sources":[]},
{"digest":"5d03ba38734809bcbd2a55221bd938b3b3fc34b49bb686c6113e9e4931e3aa78","names":[],"sources":[]},
{"digest":"5d17f27a1ef9f7026c0232714adf7573961536d75f3303ca97973975f5af170e","names":[],"sources":[]},
@@ -323,7 +320,6 @@
{"digest":"65a8400e451e667e5b6e34df72ceb81fca8c12330330fa72083ad40279b189ad","names":["packages/llm/llm/src/message.ts#SystemPromptMessageSource"],"sources":["packages/llm/llm/src/message.ts:35"]},
{"digest":"65d583e66518c5236015e0846470fb32efcf92375ed306aef14e50a9d2cd2099","names":["packages/skill/tool-skill/src/index.ts#SkillCatalogSource"],"sources":["packages/skill/tool-skill/src/index.ts:35"]},
{"digest":"66ba70f6f068da443f969a0b947a013c3addd776b9b60a0a393759c19825e9a2","names":["packages/llm/llm/src/types.ts#ToolSchema"],"sources":["packages/llm/llm/src/types.ts:517"]},
- {"digest":"671fc8cbd3a924961ccfeada2462f460120381a806c7dc97a2c01ba6a74ac960","names":[],"sources":[]},
{"digest":"672c4aa2a9b736e3d6e5da6346d2e2ed5e3573f2d0baafa18e7407c9f3fee3db","names":["packages/skill/skill/src/index.ts#SkillInvocationSource"],"sources":["packages/skill/skill/src/index.ts:146"]},
{"digest":"67d5f73ceae82f5265258142ad6cf172de2c1fef93ba551b7f0454e0a93bffe0","names":["packages/llm/llm/src/call-config.ts#LlmCallConfig"],"sources":["packages/llm/llm/src/call-config.ts:31"]},
{"digest":"68141cbe3994a5ffcd064c07c75996538437fd9dbf77ce8a2927e89ec577fabe","names":[],"sources":[]},
@@ -790,7 +786,6 @@
"1f1385dbc3e875c0": {"kind":"literal","value":"repeat-tool-reminder"},
"1f8c126cfab3df81": {"kind":"union","types":["4bb451330ff699f3","6c03546143cdf6ae","6c5a37d42ebdb12d","ada310bf0bdb8fed","eaa71be0fbf0f702"]},
"1fdad624334d3548": {"kind":"object","properties":[{"name":"form","type":"16d0507cb94b4cfc","optional":false},{"name":"kind","type":"bb94f3217aa56c88","optional":false}],"indices":[]},
- "2073e98f0c214cc4": {"kind":"object","properties":[{"name":"data","type":"671fc8cbd3a92496","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"5cc512378245b2df","optional":false}],"indices":[]},
"20a57544bbf204da": {"kind":"object","properties":[{"name":"active","type":"aa93010d0e521ad7","optional":false}],"indices":[]},
"2142e391b9ccb60d": {"kind":"literal","value":"cancelled"},
"2152caf1a71e588e": {"kind":"object","properties":[{"name":"kind","type":"2e4debca12f2c449","optional":false},{"name":"messageId","type":"4cd48f3e5108bd6e","optional":false},{"name":"senderId","type":"4cd48f3e5108bd6e","optional":false},{"name":"senderName","type":"4cd48f3e5108bd6e","optional":false},{"name":"teamId","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]},
@@ -932,7 +927,6 @@
"5bd310104cfe448e": {"kind":"literal","value":"resource-cost"},
"5c45bf4c544a7211": {"kind":"object","properties":[{"name":"data","type":"8a9c990773f798ea","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"ae63d9d1080ed894","optional":false}],"indices":[]},
"5cb63db9fe57dc09": {"kind":"literal","value":"teardown"},
- "5cc512378245b2df": {"kind":"literal","value":"subagent-name/bound"},
"5cdbf342b7748d15": {"kind":"object","properties":[{"name":"form","type":"16d0507cb94b4cfc","optional":false},{"name":"kind","type":"f68c335306535a00","optional":false}],"indices":[]},
"5d03ba38734809bc": {"kind":"array","element":"0657d3ca5ac4e7bf"},
"5d17f27a1ef9f702": {"kind":"literal","value":"tool-workflow/agent-end"},
@@ -959,7 +953,6 @@
"65a8400e451e667e": {"kind":"object","properties":[{"name":"kind","type":"09655b34d7f3cf1e","optional":false}],"indices":[]},
"65d583e66518c523": {"kind":"object","properties":[{"name":"entries","type":"aba175fb20ffc711","optional":false},{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"incomplete","type":"dacf3d5f3e4ff619","optional":true},{"name":"kind","type":"6ebcc2dbec9f2dab","optional":false},{"name":"update","type":"dacf3d5f3e4ff619","optional":true}],"indices":[]},
"66ba70f6f068da44": {"kind":"object","properties":[{"name":"deferLoading","type":"dacf3d5f3e4ff619","optional":true},{"name":"description","type":"4cd48f3e5108bd6e","optional":false},{"name":"name","type":"4cd48f3e5108bd6e","optional":false},{"name":"parameters","type":"0aa62ab51b36c0e6","optional":false}],"indices":[]},
- "671fc8cbd3a92496": {"kind":"object","properties":[{"name":"childId","type":"4cd48f3e5108bd6e","optional":false},{"name":"name","type":"4cd48f3e5108bd6e","optional":false},{"name":"version","type":"f88f1b7b6bb733f6","optional":false}],"indices":[]},
"672c4aa2a9b736e3": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"1922cd79a70806c1","optional":false},{"name":"name","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]},
"67d5f73ceae82f52": {"kind":"object","properties":[{"name":"maxTokens","type":"0657d3ca5ac4e7bf","optional":true},{"name":"model","type":"4cd48f3e5108bd6e","optional":false},{"name":"provider","type":"4cd48f3e5108bd6e","optional":false},{"name":"reasoningEffort","type":"4cd48f3e5108bd6e","optional":true},{"name":"stop","type":"93c33d9687613293","optional":true},{"name":"temperature","type":"0657d3ca5ac4e7bf","optional":true}],"indices":[]},
"68141cbe3994a5ff": {"kind":"literal","value":"max-tokens"},
diff --git a/docs/subsystems/subagent.i18n.yaml b/docs/subsystems/subagent.i18n.yaml
index e138f10cda..33a716829f 100644
--- a/docs/subsystems/subagent.i18n.yaml
+++ b/docs/subsystems/subagent.i18n.yaml
@@ -17,9 +17,6 @@
/subagents/durable-enumeration:
en: e02e1703b183594c
zh: 130d475a4304f453
-/subagents/tool-names:
- en: cd71a4c5bc8edfbb
- zh: bcb4dfca408fa803
/subagents/results-and-backend-handles:
en: 69ea5bed7d9fb64a
zh: b187a822b813e80a
diff --git a/docs/subsystems/subagent.md b/docs/subsystems/subagent.md
index c281f57680..e95ff79273 100644
--- a/docs/subsystems/subagent.md
+++ b/docs/subsystems/subagent.md
@@ -227,10 +227,6 @@ type SubagentInterruptAuthority =
The parent-owned `subagentCatalog` projection lists all local children and parent-delivery external children. Caller-delivery external executions leave membership and result collection to their caller; local workflow children remain discoverable after completion. External entries carry `mode: 'external'` and cannot open a child Session or accept follow-ups. Catalog entries record membership at creation without execution status. `list_agents` exposes the root and reachable continuable descendants with `running` or `inactive` activity; see the [control tool](../../packages/subagent/tool-subagent-control/README.md#list_agents).
-## Tool names
-
-Model-facing subagent tools require the [naming plugin](../../packages/subagent/subagent-names/README.md), which owns name allocation and path lookup. It stores name-to-id bindings in the root Session; execution, authorization, provider requests and runtime notifications continue to use Session ids. Direct service callers do not acquire names automatically.
-
## Results and backend handles
SubagentResult is available to program consumers. The activation registry retains the external backend handle until disposal completes. A cleanup failure does not replace a captured execution result: the activation result and parent notice retain it, while dispose rejects and the live subagent/end event reports error. Backend-owned diagnostics must satisfy the safe-detail requirements below.
@@ -411,52 +407,6 @@ Host settings owner that records Session authorization before the first model re
Source: [`packages/subagent/tool-subagent/src/model-selection-settings.ts`](../../packages/subagent/tool-subagent/src/model-selection-settings.ts)
-
-
-### `ctx.subagentNames` — `SubagentNames`
-
-Root-Session aliases shared by named creation, discovery, and control tools.
-
-```ts cordis-catalog
-/**
- * Reserve a complete name without starting an agent or writing a Session event.
- * @param rootSession - root Session selected by the caller through the subagent service.
- * @param parentId - parent identity whose name prefixes the child name.
- * @param requested - optional sibling segment; omission selects the first free agent-N.
- * @returns a reservation the caller must dispose after startup and binding.
- */
-reserve(rootSession: Session, parentId: SessionId, requested?: string): SubagentNameReservation
-
-/**
- * Record an accepted child's full name in the caller's root Session.
- * Binding failure does not cancel or dispose the child; callers report its id.
- * @param rootSession - root Session selected by the caller through the subagent service.
- * @param childId - identity returned by the subagent service.
- * @param name - complete name returned by reserve.
- */
-bind(rootSession: Session, childId: SessionId, name: string): void
-
-/**
- * Read a bound name from the root projection without loading ancestors.
- * @param rootSession - root Session selected by the caller through the subagent service.
- * @param targetId - identity whose name is requested.
- * @returns lead for the root, a bound full name, or the unchanged id.
- */
-nameOf(rootSession: Session, targetId: SessionId): string
-
-/**
- * Resolve an alias or pass through an id for the subagent service to authorize.
- * @param rootSession - root Session selected by the caller through the subagent service.
- * @param name - lead, a bound full name, or a raw Session id.
- * @returns the target identity; an unknown lead/... name throws.
- */
-resolveName(rootSession: Session, name: string): SessionId
-```
-
-Types: [Session](session.md) · [SessionId](core.md)
-
-Source: [`packages/subagent/subagent-names/src/index.ts`](../../packages/subagent/subagent-names/src/index.ts)
-
### `ctx.subagents` — `SubagentRuntime`
@@ -507,8 +457,6 @@ async waitForTreeWork(root: Agent): Promise
* A cold target resumes under its runtime subagent tree root without restoring
* its creation ancestors. Sender identity is rechecked before inbox acceptance; cancellation
* stops only pre-acceptance work and never retracts an accepted message.
- * Display attribution uses the sender's bound name when the naming service is mounted,
- * otherwise its Session id. Name lookup failures reject before inbox acceptance.
* @param sender - exact live root or resident continuable Agent originating the message.
* @param targetId - another root or continuable member's durable Session id.
* @param content - model-authored content to deliver.
diff --git a/docs/subsystems/subagent.zh.md b/docs/subsystems/subagent.zh.md
index 197c1f8e21..b3098ac979 100644
--- a/docs/subsystems/subagent.zh.md
+++ b/docs/subsystems/subagent.zh.md
@@ -227,10 +227,6 @@ type SubagentInterruptAuthority =
父级拥有的 `subagentCatalog` 投影列出所有本地子级及 parent 投递的外部子级。caller 投递的外部执行由调用方负责成员关系与结果收集;本地工作流子级在完成后仍可被发现。外部条目携带 `mode: 'external'`,不能打开子 Session 或接受后续消息。目录在创建时记录成员关系,不携带执行状态。`list_agents` 展示根和可达的可继续后代,其活跃状态为 `running` 或 `inactive`;参见[控制工具](../../packages/subagent/tool-subagent-control/README.zh.md#list_agents)。
-## 工具名字
-
-面向模型的子代理工具需要[命名插件](../../packages/subagent/subagent-names/README.zh.md),由它负责名字分配和路径查询。它在根 Session 中保存名字到 ID 的绑定;执行、授权、provider 请求和运行时通知继续使用 Session id。直接调用服务不会自动分配名字。
-
## 结果与后端句柄
SubagentResult 供程序消费方读取。activation 注册表保留外部后端句柄,直到释放完成。清理失败不会覆盖已捕获的执行结果:activation 结果与父级通知保留该结果,dispose 拒绝,而在线 subagent/end 事件报告 error。后端提供的诊断必须满足下述安全信息要求。
@@ -413,52 +409,6 @@ Host settings owner that records Session authorization before the first model re
Source: [`packages/subagent/tool-subagent/src/model-selection-settings.ts`](../../packages/subagent/tool-subagent/src/model-selection-settings.ts)
-
-
-### `ctx.subagentNames` — `SubagentNames`
-
-Root-Session aliases shared by named creation, discovery, and control tools.
-
-```ts cordis-catalog
-/**
- * Reserve a complete name without starting an agent or writing a Session event.
- * @param rootSession - root Session selected by the caller through the subagent service.
- * @param parentId - parent identity whose name prefixes the child name.
- * @param requested - optional sibling segment; omission selects the first free agent-N.
- * @returns a reservation the caller must dispose after startup and binding.
- */
-reserve(rootSession: Session, parentId: SessionId, requested?: string): SubagentNameReservation
-
-/**
- * Record an accepted child's full name in the caller's root Session.
- * Binding failure does not cancel or dispose the child; callers report its id.
- * @param rootSession - root Session selected by the caller through the subagent service.
- * @param childId - identity returned by the subagent service.
- * @param name - complete name returned by reserve.
- */
-bind(rootSession: Session, childId: SessionId, name: string): void
-
-/**
- * Read a bound name from the root projection without loading ancestors.
- * @param rootSession - root Session selected by the caller through the subagent service.
- * @param targetId - identity whose name is requested.
- * @returns lead for the root, a bound full name, or the unchanged id.
- */
-nameOf(rootSession: Session, targetId: SessionId): string
-
-/**
- * Resolve an alias or pass through an id for the subagent service to authorize.
- * @param rootSession - root Session selected by the caller through the subagent service.
- * @param name - lead, a bound full name, or a raw Session id.
- * @returns the target identity; an unknown lead/... name throws.
- */
-resolveName(rootSession: Session, name: string): SessionId
-```
-
-Types: [Session](session.zh.md) · [SessionId](core.zh.md)
-
-Source: [`packages/subagent/subagent-names/src/index.ts`](../../packages/subagent/subagent-names/src/index.ts)
-
### `ctx.subagents` — `SubagentRuntime`
@@ -509,8 +459,6 @@ async waitForTreeWork(root: Agent): Promise
* A cold target resumes under its runtime subagent tree root without restoring
* its creation ancestors. Sender identity is rechecked before inbox acceptance; cancellation
* stops only pre-acceptance work and never retracts an accepted message.
- * Display attribution uses the sender's bound name when the naming service is mounted,
- * otherwise its Session id. Name lookup failures reject before inbox acceptance.
* @param sender - exact live root or resident continuable Agent originating the message.
* @param targetId - another root or continuable member's durable Session id.
* @param content - model-authored content to deliver.
diff --git a/docs/tool-catalog.i18n.yaml b/docs/tool-catalog.i18n.yaml
index c9ff662788..247a5563fe 100644
--- a/docs/tool-catalog.i18n.yaml
+++ b/docs/tool-catalog.i18n.yaml
@@ -9,8 +9,8 @@
en: 6cc2cd9ced70bb09
zh: 1c0e6cb4ba2ed637
/tool-schema-catalog/tool-package-map:
- en: a1b2a95aa66ea6b6
- zh: 3511895e766987d5
+ en: db58fe23a6ae897f
+ zh: 49ad708d251d5e92
/tool-schema-catalog/deepseek-ai-dsh-plugin-manager:
en: e0143916bb634762
zh: e0143916bb634762
@@ -237,8 +237,8 @@
en: 8daafae6faf7898e
zh: 8daafae6faf7898e
/tool-schema-catalog/deepseek-ai-dsh-experimental-tool-subagent-oar/subagent-oar:
- en: c39b672aa8258fba
- zh: 111aa3637f661b2f
+ en: 6283c3023d6ea436
+ zh: 9c018b8c12a3f1e7
/tool-schema-catalog/deepseek-ai-dsh-tool-subagent:
en: 841abe0dd5913ea7
zh: 841abe0dd5913ea7
@@ -246,8 +246,8 @@
en: 207228068bc61885
zh: 36e9344ee1af8869
/tool-schema-catalog/deepseek-ai-dsh-tool-subagent/subagent:
- en: dc28d2a126a09339
- zh: 2aabc96fca1dc3ff
+ en: 430672da3c1a6ca6
+ zh: bd3a9ab4089f9dbb
/tool-schema-catalog/deepseek-ai-dsh-tool-subagent-control:
en: ab82e130c3413f04
zh: ab82e130c3413f04
@@ -255,14 +255,14 @@
en: a622b15cc2598d51
zh: 48e1b05956d63e26
/tool-schema-catalog/deepseek-ai-dsh-tool-subagent-control/list-agents:
- en: 7e5f44383f14d021
- zh: 8037d7b62ddb33b2
+ en: 6ff6254e604397d2
+ zh: 32b2f1ba4052b19e
/tool-schema-catalog/deepseek-ai-dsh-tool-subagent-control/send-message:
en: aaccc4f194398018
zh: d918c1346a87a4b1
/tool-schema-catalog/deepseek-ai-dsh-tool-subagent-control/wait-agent:
- en: 7426beca6d7f766d
- zh: 94803f041b819a66
+ en: f3cf5a0c56ddc07a
+ zh: 7f6754d71e1b4ae4
/tool-schema-catalog/deepseek-ai-dsh-tool-jobs:
en: 9be673b1604d0114
zh: 9be673b1604d0114
diff --git a/docs/tool-catalog.md b/docs/tool-catalog.md
index 834dbf0845..d87112db37 100644
--- a/docs/tool-catalog.md
+++ b/docs/tool-catalog.md
@@ -39,11 +39,11 @@ This table connects model-visible tool names to the plugin package and service s
| `@deepseek-ai/dsh-tool-ralph` | `ralph` | `ctx.tools`, `ctx.workflowEngine`, `ctx.subagents`, `ctx.systemPrompt`, `a calling Agent (exec.agent parents every fresh round)` | `tool/call`, `tool/result`, `workflow and child session events during execution` | - | A fixed foreground workflow starts one fresh structured child per round; the model selects only the immutable objective and an optional round cap. |
| `@deepseek-ai/dsh-tool-skill` | `skill` | `ctx.workingDirectory`, `ctx.tools`, `ctx.agents`, `ctx.skills` | `tool/call`, `tool/result`, `user/message replacement catalogs via agent.inject()` | - | - |
| `@deepseek-ai/dsh-tool-session-query` | `session_event_read`, `session_event_search`, `session_event_trace`, `session_search`, `session_trace` | `ctx.tools`, `ctx.systemPrompt`, `ctx.sessionQuery`, `ctx.agents`, `a calling Agent for workspace authority` | `tool/call`, `tool/result` | - | The five read-only tools hide provider cursors and authorize every result from the immutable calling agent session. The package is opt-in; compositions that need enforced deadlines or bounded inline output also mount the generic timeout or spill policies. |
-| `@deepseek-ai/dsh-experimental-tool-subagent-oar` | `subagent_oar` | `ctx.tools`, `ctx.subagents`, `ctx.subagentNames` | `tool/call`, `tool/result`, `parent subagent catalog and completion notices` | - | The subagent_oar tool selects among configured aliases for external providers. This catalog shows Codex and Claude Code aliases; each deployment chooses its providers. Native model and permission settings belong to the selected provider configuration. |
-| `@deepseek-ai/dsh-tool-subagent` | `list_subagent_models`, `subagent` | `ctx.tools`, `ctx.subagents`, `ctx.systemPrompt`, `ctx.sessionProjections`, `ctx.subagentNames`, `ctx.llm for model discovery and selected-route validation` | `tool/call`, `tool/result`, `child session events through the chosen provider` | `subagent`, `subagent_fork` | The load-time `toolName` selects the delegation name (default `subagent`); `modelSelection` adds optional route fields. `modelDiscovery` defaults off and registers shared discovery on one instance per scope. Web and Desktop presets enable spawn discovery and route fields and leave `subagent_fork` route fields disabled. The Host settings service records authorization for each new top-level Session; child Sessions inherit it. Without a recorded policy, discovery and explicit selection permit only the current parent route. The required naming plugin lets delegation accept a sibling name and return its full path alongside the child Session id. Local children accept follow-ups, while external backends report their single execution automatically. |
-| `@deepseek-ai/dsh-tool-subagent-control` | `interrupt_agent`, `list_agents`, `send_message`, `wait_agent` | `ctx.tools`, `ctx.subagents`, `ctx.agents`, `ctx.systemPrompt`, `ctx.subagentNames` | `tool/call`, `tool/result`, `child session events through ctx.subagents` | - | The shared control tools discover and contact agents in the subagent tree, interrupt owned descendants, and wait for input in the caller’s inbox. Provider-bound `tool-subagent` instances supply delegation tools. Controls require the naming plugin and accept a name path or Session id through `name`; discovery adds available names while retaining Session ids. |
+| `@deepseek-ai/dsh-experimental-tool-subagent-oar` | `subagent_oar` | `ctx.tools`, `ctx.subagents` | `tool/call`, `tool/result`, `parent subagent catalog and completion notices` | - | The subagent_oar tool selects among configured aliases for external providers. This catalog shows Codex and Claude Code aliases; each deployment chooses its providers. Native model and permission settings belong to the selected provider configuration. |
+| `@deepseek-ai/dsh-tool-subagent` | `list_subagent_models`, `subagent` | `ctx.tools`, `ctx.subagents`, `ctx.systemPrompt`, `ctx.sessionProjections`, `ctx.llm for model discovery and selected-route validation` | `tool/call`, `tool/result`, `child session events through the chosen provider` | `subagent`, `subagent_fork` | The load-time `toolName` selects the delegation name (default `subagent`); `modelSelection` adds optional route fields. `modelDiscovery` defaults off and registers shared discovery on one instance per scope. Web and Desktop presets enable spawn discovery and route fields and leave `subagent_fork` route fields disabled. The Host settings service records authorization for each new top-level Session; child Sessions inherit it. Without a recorded policy, discovery and explicit selection permit only the current parent route. Every delegation returns a child id promptly; local children accept follow-ups, while external backends report their single execution automatically. |
+| `@deepseek-ai/dsh-tool-subagent-control` | `interrupt_agent`, `list_agents`, `send_message`, `wait_agent` | `ctx.tools`, `ctx.subagents`, `ctx.agents` | `tool/call`, `tool/result`, `child session events through ctx.subagents` | - | The shared control tools discover and contact agents in the subagent tree, interrupt owned descendants, and wait for input in the caller’s inbox. Provider-bound `tool-subagent` instances supply delegation tools. |
| `@deepseek-ai/dsh-tool-jobs` | `job_kill`, `job_list`, `job_output` | `ctx.tools`, `ctx.jobs`, `ctx.systemPrompt` | `tool/call`, `tool/result`, `user/message via agent.inject() for background completion notices` | - | The kind-agnostic background-job controller: background bash commands and PTY sends are read, listed, and killed through the same three tools. Loading the plugin attaches the controller that arms producers' `ctx.jobs.start()`. |
-| `@deepseek-ai/dsh-tool-agent-team` | `team_task_create`, `team_task_get`, `team_task_list`, `team_task_update` | `ctx.tools`, `ctx.systemPrompt`, `ctx.agentTeams`, `ctx.subagents`, `ctx.subagentNames`, `an exact live Team member Agent` | `tool/call`, `team/task`, `tool/result` | - | Four task-board tools share the subagent tree’s root Session. Enabling Team mode on the root Session adds task-board guidance and required Team identity alongside standard subagent delegation and control tools. |
+| `@deepseek-ai/dsh-experimental-tool-agent-team` | `team_task_create`, `team_task_get`, `team_task_list`, `team_task_update` | `ctx.tools`, `ctx.systemPrompt`, `ctx.agentTeams`, `ctx.subagents`, `an exact live Team member Agent` | `tool/call`, `team/task`, `tool/result` | - | Four task-board tools share the subagent tree’s root Session. The optional Agent Teams profile adds task-board guidance and required Team identity derived from the subagent root, alongside standard subagent delegation and control tools. |
| `@deepseek-ai/dsh-tool-todo` | `todo_write` | `ctx.tools`, `owning Agent session` | `tool/call`, `todo/write`, `tool/result` | - | todo_write is session-owned state; UIs render the latest todo/write event as a checklist. `allowParallelInProgress` is required with no default, so the catalog states its choice: `true`, whose description invites several `in_progress` items. A deployment choosing `false` receives the same tool with a description asking for exactly one active task. |
| `@deepseek-ai/dsh-tool-working-directory` | `working_directory` | `ctx.tools`, `ctx.workingDirectory` | `tool/call`, `working-directory/change`, `user context for directory changes`, `tool/result` | - | Reads or changes the calling Session directory. Existing shells and processes retain their own directories; origin metadata and permission roots stay fixed. |
| `@deepseek-ai/dsh-experimental-tool-worktree` | `create_worktree` | `ctx.tools`, `ctx.worktrees`, `a calling Agent` | `tool/call`, `Git branch and checkout`, `working-directory/change`, `tool/result` | - | Explicit experimental composition only. Creates a new branch and checkout from a pinned local commit under existing write permissions, then changes the Session directory. Leaving retains the branch and checkout. |
@@ -1973,16 +1973,12 @@ The five read-only tools hide provider cursors and authorize every result from t
### `subagent_oar`
-Delegate a self-contained task to a configured external agent. Choose its runtime for each call. The child works in its own context and does not see this conversation. This tool returns the child id and full agent path; a later completion notice includes its final answer. The child does not accept follow-up messages. Start independent tasks together and continue useful work while they run. When only waiting for their results remains, end your turn instead of polling.
+Delegate a self-contained task to a configured external agent. Choose its runtime for each call. The child works in its own context and does not see this conversation. This tool returns a child id; a later completion notice includes its final answer. The child does not accept follow-up messages. Start independent tasks together and continue useful work while they run. When only waiting for their results remains, end your turn instead of polling.
```json
{
"type": "object",
"properties": {
- "name": {
- "type": "string",
- "description": "Optional sibling-unique name; omission selects the first unused agent-N, starting at agent-1. Explicit names: start with a lower-case letter and use lower-case letters, digits, underscores, or hyphens."
- },
"runtime": {
"type": "string",
"description": "Configured external runtime for this task.",
@@ -2050,10 +2046,6 @@ Delegate a self-contained task to a subagent (a separate agent that works in its
{
"type": "object",
"properties": {
- "name": {
- "type": "string",
- "description": "Optional name unique among your direct children. Use a short role name, such as reviewer or researcher. Put the task in description. Add a specialty or numeric suffix when needed for uniqueness. Defaults to the first unused agent-N. Returns the full path, e.g. lead/reviewer."
- },
"cwd": {
"type": "string",
"description": "Initial child working directory. Relative paths use your current directory; omitted inherits it. Later directory changes in either agent are independent."
@@ -2076,7 +2068,7 @@ Delegate a self-contained task to a subagent (a separate agent that works in its
Source: [`packages/subagent/tool-subagent/src/index.ts`](../packages/subagent/tool-subagent/src/index.ts)
-The load-time `toolName` selects the delegation name (default `subagent`); `modelSelection` adds optional route fields. `modelDiscovery` defaults off and registers shared discovery on one instance per scope. Web and Desktop presets enable spawn discovery and route fields and leave `subagent_fork` route fields disabled. The Host settings service records authorization for each new top-level Session; child Sessions inherit it. Without a recorded policy, discovery and explicit selection permit only the current parent route. The required naming plugin lets delegation accept a sibling name and return its full path alongside the child Session id. Local children accept follow-ups, while external backends report their single execution automatically.
+The load-time `toolName` selects the delegation name (default `subagent`); `modelSelection` adds optional route fields. `modelDiscovery` defaults off and registers shared discovery on one instance per scope. Web and Desktop presets enable spawn discovery and route fields and leave `subagent_fork` route fields disabled. The Host settings service records authorization for each new top-level Session; child Sessions inherit it. Without a recorded policy, discovery and explicit selection permit only the current parent route. Every delegation returns a child id promptly; local children accept follow-ups, while external backends report their single execution automatically.
@@ -2090,13 +2082,13 @@ Ask a subagent to stop its current work. This call returns without waiting for i
{
"type": "object",
"properties": {
- "name": {
+ "agent_id": {
"type": "string",
- "description": "The full agent path or Session id of an agent created under you: your direct child or a deeper descendant."
+ "description": "The id of an agent created under you: your direct child or a deeper descendant."
}
},
"required": [
- "name"
+ "agent_id"
]
}
```
@@ -2105,7 +2097,7 @@ Source: [`packages/subagent/tool-subagent-control/src/index.ts`](../packages/sub
### `list_agents`
-List your entire subagent tree: the root agent and all reachable continuable descendants, including yourself. Rows carry ids, descriptions, and status; descendant rows carry parent ids and depth from the root. Rows also include available names alongside Session ids. You can message any other agent in the subagent tree listed as running or inactive. running means it is working; inactive means it is not currently working. While you remain active, you will be notified when a direct child finishes; there is no need to keep checking its status. Use send_message to continue the conversation.
+List your entire subagent tree: the root agent and all reachable continuable descendants, including yourself. Rows carry ids, descriptions, and status; descendant rows carry parent ids and depth from the root. You can message any other agent in the subagent tree listed as running or inactive. running means it is working; inactive means it is not currently working. While you remain active, you will be notified when a direct child finishes; there is no need to keep checking its status. Use send_message to continue the conversation.
```json
{
@@ -2124,9 +2116,9 @@ Send a message to an agent. A working agent receives it at its next step; an idl
{
"type": "object",
"properties": {
- "name": {
+ "agent_id": {
"type": "string",
- "description": "The full agent path (such as lead/reviewer) or Session id of another member of your subagent tree."
+ "description": "The agent id of another member of your subagent tree, as shown by list_agents."
},
"message": {
"type": "string",
@@ -2134,7 +2126,7 @@ Send a message to an agent. A working agent receives it at its next step; an idl
}
},
"required": [
- "name",
+ "agent_id",
"message"
]
}
@@ -2160,7 +2152,7 @@ Wait for input at your next step, including agent messages, completion notificat
Source: [`packages/subagent/tool-subagent-control/src/wait-agent.ts`](../packages/subagent/tool-subagent-control/src/wait-agent.ts)
-The shared control tools discover and contact agents in the subagent tree, interrupt owned descendants, and wait for input in the caller’s inbox. Provider-bound `tool-subagent` instances supply delegation tools. Controls require the naming plugin and accept a name path or Session id through `name`; discovery adds available names while retaining Session ids.
+The shared control tools discover and contact agents in the subagent tree, interrupt owned descendants, and wait for input in the caller’s inbox. Provider-bound `tool-subagent` instances supply delegation tools.
@@ -2319,7 +2311,7 @@ List shared tasks, including readiness, owner, revision, blockers, and write-sco
},
"owner": {
"type": "string",
- "description": "Optional exact ownerName filter; use unowned for tasks without an owner."
+ "description": "Optional exact ownerId filter; use unowned for tasks without an owner."
},
"ready": {
"type": "boolean",
@@ -2393,7 +2385,7 @@ Compare-and-set a shared task action using the latest revision from team_task_ge
},
"owner": {
"type": "string",
- "description": "Agent name or Session id of the root or any continuable descendant for root-only reassign; omit to unassign."
+ "description": "Agent id of the root or any continuable descendant for root-only reassign; omit to unassign."
}
},
"required": [
diff --git a/docs/tool-catalog.zh.md b/docs/tool-catalog.zh.md
index 7fad6589d8..413190a3e7 100644
--- a/docs/tool-catalog.zh.md
+++ b/docs/tool-catalog.zh.md
@@ -43,11 +43,11 @@
| `@deepseek-ai/dsh-tool-ralph` | `ralph` | `ctx.tools`、`ctx.workflowEngine`、`ctx.subagents`、`ctx.systemPrompt`、`a calling Agent (exec.agent parents every fresh round)` | `tool/call`、`tool/result`、`workflow and child session events during execution` | - | 固定的前台工作流会在每个 Round 启动一个全新的结构化子级;模型只能选择不可变目标和可选的 Round 上限。 |
| `@deepseek-ai/dsh-tool-skill` | `skill` | `ctx.workingDirectory`、`ctx.tools`、`ctx.agents`、`ctx.skills` | `tool/call`、`tool/result`、`user/message replacement catalogs via agent.inject()` | - | - |
| `@deepseek-ai/dsh-tool-session-query` | `session_event_read`、`session_event_search`、`session_event_trace`、`session_search`、`session_trace` | `ctx.tools`、`ctx.systemPrompt`、`ctx.sessionQuery`、`a calling Agent for workspace authority` | `tool/call`、`tool/result` | - | 这 5 个只读工具会隐藏提供方游标,并根据不可变的调用 agent 会话为每个结果授权。该包需要选择启用;需要强制截止时间或限制行内输出的组合还会挂载通用超时或 spill 策略。 |
-| `@deepseek-ai/dsh-experimental-tool-subagent-oar` | `subagent_oar` | `ctx.tools`, `ctx.subagents`, `ctx.subagentNames` | `tool/call`, `tool/result`, `parent subagent catalog and completion notices` | - | subagent_oar 工具在为外部提供方配置的别名之间选择。本目录展示 Codex 和 Claude Code 别名;每个部署自行选择提供方。原生模型和权限设置由所选提供方的配置决定。 |
-| `@deepseek-ai/dsh-tool-subagent` | `list_subagent_models`、`subagent` | `ctx.tools`、`ctx.subagents`、`ctx.systemPrompt`、`ctx.sessionProjections`、`ctx.subagentNames`、`用于模型发现和所选路由校验的 ctx.llm` | `tool/call`、`tool/result`、`child session events through the chosen provider` | `subagent`、`subagent_fork` | 加载时的 `toolName` 选择委派名称(默认为 `subagent`);`modelSelection` 增加可选路由字段。`modelDiscovery` 默认关闭,每个作用域由一个实例注册共享发现工具。Web 与 Desktop preset 启用 spawn 发现和路由字段,并为 `subagent_fork` 保持路由字段关闭。Host 设置服务为每个新顶层 Session 记录授权;子 Session 继承该授权。没有已记录策略时,发现和显式选择只允许当前父级路由。必需的命名插件让委派接受同级名称,并在子级 Session id 之外返回完整路径。本地子代理接受后续消息,外部后端自动汇报单次执行结果。 |
-| `@deepseek-ai/dsh-tool-subagent-control` | `interrupt_agent`、`list_agents`、`send_message`、`wait_agent` | `ctx.tools`、`ctx.subagents`、`ctx.agents`、`ctx.systemPrompt`、`ctx.subagentNames` | `tool/call`、`tool/result`、`child session events through ctx.subagents` | - | 共享控制工具发现并联系 subagent 树中的 Agent,中断有权控制的后代,并等待调用者收件箱中的输入。绑定提供方的 `tool-subagent` 实例提供委派工具。控制工具需要命名插件,通过 `name` 接受名称路径或 Session id;发现结果保留 Session id,并附加可用的名称。 |
+| `@deepseek-ai/dsh-experimental-tool-subagent-oar` | `subagent_oar` | `ctx.tools`, `ctx.subagents` | `tool/call`, `tool/result`, `parent subagent catalog and completion notices` | - | subagent_oar 工具在为外部提供方配置的别名之间选择。本目录展示 Codex 和 Claude Code 别名;每个部署自行选择提供方。原生模型和权限设置由所选提供方的配置决定。 |
+| `@deepseek-ai/dsh-tool-subagent` | `list_subagent_models`、`subagent` | `ctx.tools`、`ctx.subagents`、`ctx.systemPrompt`、`ctx.sessionProjections`、`用于模型发现和所选路由校验的 ctx.llm` | `tool/call`、`tool/result`、`child session events through the chosen provider` | `subagent`、`subagent_fork` | 加载时的 `toolName` 选择委派名称(默认为 `subagent`);`modelSelection` 增加可选路由字段。`modelDiscovery` 默认关闭,每个作用域由一个实例注册共享发现工具。Web 与 Desktop preset 启用 spawn 发现和路由字段,并为 `subagent_fork` 保持路由字段关闭。Host 设置服务为每个新顶层 Session 记录授权;子 Session 继承该授权。没有已记录策略时,发现和显式选择只允许当前父级路由。每次委派都会立即返回子代理 id;本地子代理接受后续消息,外部后端自动汇报单次执行结果。 |
+| `@deepseek-ai/dsh-tool-subagent-control` | `interrupt_agent`、`list_agents`、`send_message`、`wait_agent` | `ctx.tools`、`ctx.subagents`、`ctx.agents` | `tool/call`、`tool/result`、`child session events through ctx.subagents` | - | 共享控制工具发现并联系 subagent 树中的 Agent,中断有权控制的后代,并等待调用者收件箱中的输入。绑定提供方的 `tool-subagent` 实例提供委派工具。 |
| `@deepseek-ai/dsh-tool-jobs` | `job_kill`、`job_list`、`job_output` | `ctx.tools`、`ctx.jobs`、`ctx.systemPrompt` | `tool/call`、`tool/result`、`user/message via agent.inject() for background completion notices` | - | 与任务种类无关的后台任务控制器:后台 bash 命令与 PTY 发送 都通过相同的 3 个工具读取、列出和终止。加载该插件会挂接控制器,从而启用生产方的 `ctx.jobs.start()`。 |
-| `@deepseek-ai/dsh-tool-agent-team` | `team_task_create`, `team_task_get`, `team_task_list`, `team_task_update` | `ctx.tools`, `ctx.systemPrompt`, `ctx.agentTeams`, `ctx.subagents`, `ctx.subagentNames`, `an exact live Team member Agent` | `tool/call`, `team/task`, `tool/result` | - | 四个任务板工具共享 subagent 树的根 Session。在根 Session 开启 Team 模式后,会在标准子代理委派和控制工具之外增加任务板指导与必需的 Team 身份。 |
+| `@deepseek-ai/dsh-experimental-tool-agent-team` | `team_task_create`, `team_task_get`, `team_task_list`, `team_task_update` | `ctx.tools`, `ctx.systemPrompt`, `ctx.agentTeams`, `ctx.subagents`, `an exact live Team member Agent` | `tool/call`, `team/task`, `tool/result` | - | 四个任务板工具共享 subagent 树的根 Session。可选 Agent Teams profile 在标准子代理委派和控制工具之外增加任务板指导,以及从 subagent 根派生的必需 Team 身份。 |
| `@deepseek-ai/dsh-tool-todo` | `todo_write` | `ctx.tools`、`owning Agent session` | `tool/call`、`todo/write`、`tool/result` | - | todo_write 是会话所有的状态;UI 将最新的 todo/write 事件渲染为检查清单。`allowParallelInProgress` 是没有默认值的必填项,因此本目录明确选择 `true`,对应描述允许同时存在多个 `in_progress` 项。选择 `false` 的部署会获得同一工具,但描述会要求只能有 1 个活动任务。 |
| `@deepseek-ai/dsh-tool-working-directory` | `working_directory` | `ctx.tools`, `ctx.workingDirectory` | `tool/call`, `working-directory/change`, `user context for directory changes`, `tool/result` | - | 读取或改变调用方 Session 的目录。已有 shell 和进程保留自己的目录;原始元数据和权限根目录保持不变。 |
| `@deepseek-ai/dsh-experimental-tool-worktree` | `create_worktree` | `ctx.tools`, `ctx.worktrees`, `a calling Agent` | `tool/call`, `Git branch and checkout`, `working-directory/change`, `tool/result` | - | 仅通过显式实验组合加载。在现有写权限下从固定的本地提交创建新分支与检出目录,再改变 Session 工作目录。离开时保留分支与检出目录。 |
@@ -1979,16 +1979,12 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后,
### `subagent_oar`
-将上下文完整的任务委派给已配置的外部 agent。每次调用选择一个运行时。subagent 在独立上下文中工作,无法看到当前对话。工具返回子级 id 和完整 Agent 路径,后续完成通知包含其最终回答。subagent 不接受后续消息。并发启动相互独立的任务,并在其运行期间继续其他有用工作。只剩等待结果时结束当前轮次,不要轮询。
+将上下文完整的任务委派给已配置的外部 agent。每次调用选择一个运行时。subagent 在独立上下文中工作,无法看到当前对话。工具返回子级 id,后续完成通知包含其最终回答。subagent 不接受后续消息。并发启动相互独立的任务,并在其运行期间继续其他有用工作。只剩等待结果时结束当前轮次,不要轮询。
```json
{
"type": "object",
"properties": {
- "name": {
- "type": "string",
- "description": "Optional sibling-unique name; omission selects the first unused agent-N, starting at agent-1. Explicit names: start with a lower-case letter and use lower-case letters, digits, underscores, or hyphens."
- },
"runtime": {
"type": "string",
"description": "Configured external runtime for this task.",
@@ -2056,10 +2052,6 @@ subagent_oar 工具在为外部提供方配置的别名之间选择。本目录
{
"type": "object",
"properties": {
- "name": {
- "type": "string",
- "description": "Optional name unique among your direct children. Use a short role name, such as reviewer or researcher. Put the task in description. Add a specialty or numeric suffix when needed for uniqueness. Defaults to the first unused agent-N. Returns the full path, e.g. lead/reviewer."
- },
"cwd": {
"type": "string",
"description": "Initial child working directory. Relative paths use your current directory; omitted inherits it. Later directory changes in either agent are independent."
@@ -2082,7 +2074,7 @@ subagent_oar 工具在为外部提供方配置的别名之间选择。本目录
来源:[`packages/subagent/tool-subagent/src/index.ts`](../packages/subagent/tool-subagent/src/index.ts)
-加载时的 `toolName` 选择委派名称(默认为 `subagent`);`modelSelection` 增加可选路由字段。`modelDiscovery` 默认关闭,每个作用域由一个实例注册共享发现工具。Web 与 Desktop preset 启用 spawn 发现和路由字段,并为 `subagent_fork` 保持路由字段关闭。Host 设置服务为每个新顶层 Session 记录授权;子 Session 继承该授权。没有已记录策略时,发现和显式选择只允许当前父级路由。必需的命名插件让委派接受同级名称,并在子级 Session id 之外返回完整路径。本地子代理接受后续消息,外部后端自动汇报单次执行结果。
+加载时的 `toolName` 选择委派名称(默认为 `subagent`);`modelSelection` 增加可选路由字段。`modelDiscovery` 默认关闭,每个作用域由一个实例注册共享发现工具。Web 与 Desktop preset 启用 spawn 发现和路由字段,并为 `subagent_fork` 保持路由字段关闭。Host 设置服务为每个新顶层 Session 记录授权;子 Session 继承该授权。没有已记录策略时,发现和显式选择只允许当前父级路由。每次委派都会立即返回子代理 id;本地子代理接受后续消息,外部后端自动汇报单次执行结果。
@@ -2096,13 +2088,13 @@ subagent_oar 工具在为外部提供方配置的别名之间选择。本目录
{
"type": "object",
"properties": {
- "name": {
+ "agent_id": {
"type": "string",
- "description": "The full agent path or Session id of an agent created under you: your direct child or a deeper descendant."
+ "description": "The id of an agent created under you: your direct child or a deeper descendant."
}
},
"required": [
- "name"
+ "agent_id"
]
}
```
@@ -2111,7 +2103,7 @@ subagent_oar 工具在为外部提供方配置的别名之间选择。本目录
### `list_agents`
-列出整棵 subagent 树:根代理和所有可达的可继续后代,包括调用方自身。行包含 id、描述和状态;后代行包含父级 id 和相对根的深度。行也会在 Session id 之外提供可用名称。可以向树中列为 running 或 inactive 的任意其他代理发送消息。running 表示正在工作;inactive 表示当前没有工作。自身仍在线时,直属子代理结束会收到通知,无需反复查询其状态。使用 send_message 继续对话。
+列出整棵 subagent 树:根代理和所有可达的可继续后代,包括调用方自身。行包含 id、描述和状态;后代行包含父级 id 和相对根的深度。可以向树中列为 running 或 inactive 的任意其他代理发送消息。running 表示正在工作;inactive 表示当前没有工作。自身仍在线时,直属子代理结束会收到通知,无需反复查询其状态。使用 send_message 继续对话。
```json
{
@@ -2130,9 +2122,9 @@ subagent_oar 工具在为外部提供方配置的别名之间选择。本目录
{
"type": "object",
"properties": {
- "name": {
+ "agent_id": {
"type": "string",
- "description": "The full agent path (such as lead/reviewer) or Session id of another member of your subagent tree."
+ "description": "The agent id of another member of your subagent tree, as shown by list_agents."
},
"message": {
"type": "string",
@@ -2140,7 +2132,7 @@ subagent_oar 工具在为外部提供方配置的别名之间选择。本目录
}
},
"required": [
- "name",
+ "agent_id",
"message"
]
}
@@ -2166,7 +2158,7 @@ subagent_oar 工具在为外部提供方配置的别名之间选择。本目录
来源:[`packages/subagent/tool-subagent-control/src/wait-agent.ts`](../packages/subagent/tool-subagent-control/src/wait-agent.ts)
-共享控制工具发现并联系 subagent 树中的 Agent,中断有权控制的后代,并等待调用者收件箱中的输入。绑定提供方的 `tool-subagent` 实例提供委派工具。控制工具需要命名插件,通过 `name` 接受名称路径或 Session id;发现结果保留 Session id,并附加可用的名称。
+共享控制工具发现并联系 subagent 树中的 Agent,中断有权控制的后代,并等待调用者收件箱中的输入。绑定提供方的 `tool-subagent` 实例提供委派工具。
@@ -2325,7 +2317,7 @@ subagent_oar 工具在为外部提供方配置的别名之间选择。本目录
},
"owner": {
"type": "string",
- "description": "Optional exact ownerName filter; use unowned for tasks without an owner."
+ "description": "Optional exact ownerId filter; use unowned for tasks without an owner."
},
"ready": {
"type": "boolean",
@@ -2399,7 +2391,7 @@ subagent_oar 工具在为外部提供方配置的别名之间选择。本目录
},
"owner": {
"type": "string",
- "description": "Agent name or Session id of the root or any continuable descendant for root-only reassign; omit to unassign."
+ "description": "Agent id of the root or any continuable descendant for root-only reassign; omit to unassign."
}
},
"required": [
diff --git a/docs/upgrade-guide/v0.2.1-rc.3/subagent-tool-names/guide.i18n.yaml b/docs/upgrade-guide/v0.2.1-rc.3/subagent-tool-names/guide.i18n.yaml
deleted file mode 100644
index 587dada927..0000000000
--- a/docs/upgrade-guide/v0.2.1-rc.3/subagent-tool-names/guide.i18n.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-# Bilingual-pair consistency record for guide.md (docs/i18n/README.md): per heading
-# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
-# After editing either side, bring the other along and re-record with:
-# pnpm run verify-translation-pairing --write docs/upgrade-guide/v0.2.1-rc.3/subagent-tool-names/guide.md
-/:
- en: 17fbe065c454bfce
- zh: 1f9fe6287993abdb
-/subagent-tools-require-the-naming-plugin:
- en: 183491734336053d
- zh: fddd829da66becae
-/subagent-tools-require-the-naming-plugin/change:
- en: 0333588e4e2807c9
- zh: 6bdabbae22657790
-/subagent-tools-require-the-naming-plugin/migration:
- en: 0db31f99da6de4b5
- zh: 40a439e97edfc86c
diff --git a/docs/upgrade-guide/v0.2.1-rc.3/subagent-tool-names/guide.md b/docs/upgrade-guide/v0.2.1-rc.3/subagent-tool-names/guide.md
deleted file mode 100644
index 84be3b05fc..0000000000
--- a/docs/upgrade-guide/v0.2.1-rc.3/subagent-tool-names/guide.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-kind: upgrade-guide
-description: "Base-backed profiles address subagents by names in model-facing tools while host APIs retain Session ids."
----
-
-# Subagent tools require the naming plugin
-
-English | [中文](guide.zh.md)
-
-## Change
-
-Subagent tools require `@deepseek-ai/dsh-subagent-names`, which base-backed profiles mount by default. `subagent` and `subagent_fork` accept an optional sibling `name` and return `subagentId` plus a full `name` such as `lead/reviewer`. Omission allocates the first unused `agent-N`. `send_message` and `interrupt_agent` use the `name` argument, which accepts a discovered path or an existing member's Session id. `list_agents` adds names and parent paths to its ID fields. Experimental Team tools expose `ownerName`; the OAR tool also returns a name.
-
-The subagent service, provider requests, Session catalog and SDK handles retain their existing ID interfaces. The message service resolves display names from the actual sender: `lead` for the root, a bound path for a named child, or the Session id when no name is available. Durable message sources and completion notices retain Session ids. The naming plugin records name-to-id bindings in the root Session after startup succeeds. A child can begin its first step before its name is bound. Delegation, control, experimental Team and OAR tools all require the naming service; unloading it removes their definitions.
-
-## Migration
-
-1. Update scripted model tool calls from `send_message({ agent_id: id, ... })` to `send_message({ name: id, ... })`, and from `interrupt_agent({ agent_id: id })` to `interrupt_agent({ name: id })`. Use the returned `name` for subsequent calls when available.
-2. Read `name` alongside the existing ID from creation results and available names from discovery results, and `ownerName` from experimental Team task results. Keep existing host `startActivation`, `sendMessage`, `interrupt`, and `ownerId` calls unchanged.
-3. In custom compositions using subagent tools, mount `@deepseek-ai/dsh-subagent-names` alongside the subagent service and Session projection service. The shipped base bundle supplies this plugin.
-4. Create a child with `name: "reviewer"`, confirm the result is `lead/reviewer`, and confirm `list_agents` and a follow-up message resolve that path. Names remain reserved for the lifetime of the root Session.
diff --git a/docs/upgrade-guide/v0.2.1-rc.3/subagent-tool-names/guide.zh.md b/docs/upgrade-guide/v0.2.1-rc.3/subagent-tool-names/guide.zh.md
deleted file mode 100644
index 15320a03ed..0000000000
--- a/docs/upgrade-guide/v0.2.1-rc.3/subagent-tool-names/guide.zh.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-kind: upgrade-guide
-description: "基于 base 的配置通过模型工具中的名字寻址子代理,Host API 继续使用 Session id。"
----
-
-# 子代理工具需要命名插件
-
-[English](guide.md) | 中文
-
-## 变更
-
-子代理工具需要 `@deepseek-ai/dsh-subagent-names`,基于 base 的配置默认挂载该插件。`subagent` 和 `subagent_fork` 接受可选的同级 `name`,返回 `subagentId`,以及 `lead/reviewer` 这样的完整 `name`。省略时分配首个未使用的 `agent-N`。`send_message` 和 `interrupt_agent` 使用 `name` 参数,接受发现到的路径或现有成员的 Session id。`list_agents` 在 ID 字段之外附加名字和父路径。实验性 Team 工具提供 `ownerName`;OAR 工具也返回名字。
-
-subagent 服务、provider 请求、Session catalog 和 SDK 句柄保留现有 ID 接口。消息服务根据实际发送者解析显示名称:根代理使用 `lead`,已命名子代理使用绑定路径,没有可用名称时使用 Session id。持久化消息来源和完成通知保留 Session id。命名插件在启动成功后将名字到 ID 的绑定记录在根 Session 中。子代理可能在名字绑定前开始第一步。委派、控制以及实验性 Team 和 OAR 工具都需要命名服务;卸载该服务会移除这些工具定义。
-
-## 迁移
-
-1. 将脚本中的模型工具调用从 `send_message({ agent_id: id, ... })` 改为 `send_message({ name: id, ... })`,从 `interrupt_agent({ agent_id: id })` 改为 `interrupt_agent({ name: id })`。有返回的 `name` 时,后续调用使用该名字。
-2. 从创建结果中读取原有 ID 及 `name`,从发现结果中读取可用的名字,从实验性 Team 任务结果读取 `ownerName`。现有 Host `startActivation`、`sendMessage`、`interrupt` 和 `ownerId` 调用保持不变。
-3. 在使用子代理工具的自定义装配中,与 subagent 服务及 Session 投影服务一起挂载 `@deepseek-ai/dsh-subagent-names`。随附的 base bundle 已提供该插件。
-4. 使用 `name: "reviewer"` 创建子代理,确认结果为 `lead/reviewer`,并确认 `list_agents` 和后续消息可以解析该路径。名字在根 Session 的整个生命周期内保留。
diff --git a/packages/bundle/base/README.i18n.yaml b/packages/bundle/base/README.i18n.yaml
index 33b9849cc6..8c6ebd500c 100644
--- a/packages/bundle/base/README.i18n.yaml
+++ b/packages/bundle/base/README.i18n.yaml
@@ -21,8 +21,8 @@
en: 0f971f7ac7c09139
zh: ceb866da681c709c
/deepseek-ai-dsh-base/use-this-package/what-you-get:
- en: f89afd9f3b2a875e
- zh: d184abde8d3d31a0
+ en: 94430c891006526d
+ zh: 94ba771960ec6f71
/deepseek-ai-dsh-base/use-this-package/shell-tools-per-platform:
en: 2dce12f82d6ee955
zh: d4599eb899a3cd88
diff --git a/packages/bundle/base/README.md b/packages/bundle/base/README.md
index f508879259..db77c345ec 100644
--- a/packages/bundle/base/README.md
+++ b/packages/bundle/base/README.md
@@ -49,7 +49,7 @@ Run `dsh --profile my-profile "your task"` and you get a working agent with mode
Out of the box, every profile built on this core provides: a DeepSeek model connection (the provider and model are configurable, and you can enable extra providers from your settings), the full tool set — file editing, shell commands, web search, HTTP(S) fetch, subagents, task and goal tracking — durable sessions that survive restarts, and the default permission policy that confines file writes to your workspace and asks before risky actions. Web fetch runs without per-call approval and can reach loopback and private-network hosts. Feedback stays in the Session log. [OTel session upload](../../session/session-telemetry-otel/README.md) defaults to `FEEDBACK_ONLY` for all users, including `deepseek-official`: new text feedback, message ratings, edits, and withdrawals release the complete canonical prefix through that event, including context. Later records wait for the next explicit feedback; sending an authorized batch needs no further interaction or model call. `DISABLED` prevents OTel capture. The default-on [DeepSeek session-log contributor](../../session/session-log-deepseek/README.md) remains a separate request path.
-Both `subagent` and `subagent_fork` create managed children and return a child id with its full agent path immediately. The bundle mounts [Subagent names](../../subagent/subagent-names/README.md) for optional child names and name-based control tools. Use `send_message` to steer active children or continue their conversations after completion. [Delegation-tool behavior](../../subagent/tool-subagent/README.md) describes result delivery and backend capabilities.
+Both `subagent` and `subagent_fork` create managed children and return a child id immediately. Use `send_message` to steer active children or continue their conversations after completion. [Delegation-tool behavior](../../subagent/tool-subagent/README.md) describes result delivery and backend capabilities.
The bundle also mounts [Agent Teams](../../team/agent-team/README.md) and its task tools. Team mode defaults off per root Session; the root conversation’s **Use Agent Teams** menu switch enables collaboration for that tree without changing the profile.
diff --git a/packages/bundle/base/README.zh.md b/packages/bundle/base/README.zh.md
index f2587a0f66..53c04f4b52 100644
--- a/packages/bundle/base/README.zh.md
+++ b/packages/bundle/base/README.zh.md
@@ -49,7 +49,7 @@ kind: "package-bundle"
开箱即用,基于本核心构建的每个 profile 都提供:DeepSeek 模型连接(提供方与模型可配置,你还可以在设置中启用额外提供方)、完整工具集——文件编辑、shell 命令、web 搜索、HTTP(S) 抓取、subagent、任务与目标跟踪——可跨重启存活的持久会话,以及默认权限策略:把文件写入限制在工作区内,危险操作前征询许可。Web 抓取无需逐次审批,并且可以访问 loopback 与内网主机。反馈保存在会话日志中。[OTel 会话上传](../../session/session-telemetry-otel/README.zh.md)对所有用户默认使用 `FEEDBACK_ONLY`,包括 `deepseek-official`:新的文本反馈、消息评分、编辑与撤回会释放截至该事件的完整规范会话日志前缀,包含上下文。后续记录等待下一次显式反馈;发送已授权批次无需进一步交互或模型调用。`DISABLED` 阻止 OTel 捕获。默认开启的 [DeepSeek 会话日志贡献器](../../session/session-log-deepseek/README.zh.md)仍是独立的请求路径。
-`subagent` 与 `subagent_fork` 都创建受管理的子任务,并立即返回子任务 ID 及其完整的 Agent 路径。bundle 挂载 [Subagent names](../../subagent/subagent-names/README.zh.md),提供可选的子任务名称和按名称寻址的控制工具。使用 `send_message` 可引导活跃子任务,或在完成后继续其对话。[委派工具行为](../../subagent/tool-subagent/README.zh.md)说明了结果交付和后端能力。
+`subagent` 与 `subagent_fork` 都创建受管理的子任务,并立即返回 child id。使用 `send_message` 可引导活跃子任务,或在完成后继续其对话。[委派工具行为](../../subagent/tool-subagent/README.zh.md)说明了结果交付和后端能力。
此 bundle 还挂载 [Agent Teams](../../team/agent-team/README.zh.md) 及其任务工具。每个根 Session 的 Team 模式默认关闭;根会话菜单中的**使用智能体团队**开关为当前树开启协作,无需修改 profile。
diff --git a/packages/bundle/base/cordis.patch.yml b/packages/bundle/base/cordis.patch.yml
index 8b378fc37c..07cd0d03ce 100644
--- a/packages/bundle/base/cordis.patch.yml
+++ b/packages/bundle/base/cordis.patch.yml
@@ -359,8 +359,6 @@
- id: subagent
name: '@deepseek-ai/dsh-subagent'
- - id: subagent-names
- name: '@deepseek-ai/dsh-subagent-names'
- id: agent-team
name: '@deepseek-ai/dsh-agent-team'
config:
diff --git a/packages/bundle/base/package.json b/packages/bundle/base/package.json
index c4a3c2498e..68a395af92 100644
--- a/packages/bundle/base/package.json
+++ b/packages/bundle/base/package.json
@@ -100,7 +100,6 @@
"@deepseek-ai/dsh-storage-json": "workspace:*",
"@deepseek-ai/dsh-subagent": "workspace:*",
"@deepseek-ai/dsh-subagent-fork-in-process": "workspace:*",
- "@deepseek-ai/dsh-subagent-names": "workspace:*",
"@deepseek-ai/dsh-subagent-spawn-in-process": "workspace:*",
"@deepseek-ai/dsh-subprocess-local": "workspace:*",
"@deepseek-ai/dsh-system-prompt": "workspace:*",
diff --git a/packages/client/ui-tool/README.i18n.yaml b/packages/client/ui-tool/README.i18n.yaml
index bf6f885c44..4cfaeae5cb 100644
--- a/packages/client/ui-tool/README.i18n.yaml
+++ b/packages/client/ui-tool/README.i18n.yaml
@@ -15,8 +15,8 @@
en: d152484eb41ac6b4
zh: 09388d293f9be9cb
/deepseek-ai-dsh-client-ui-tool/use-this-package:
- en: fd961d923feca636
- zh: 5925ea0fbdfc207d
+ en: 2419beff9bcd8139
+ zh: 5aafe9b168e571a5
/deepseek-ai-dsh-client-ui-tool/use-this-package/registering-a-business-tool-view:
en: e458aff61e634190
zh: 650e417f450b3edf
@@ -30,8 +30,8 @@
en: 672e63b2f92e689b
zh: ba950ecb480325a6
/deepseek-ai-dsh-client-ui-tool/understand-the-implementation/cards:
- en: f14a14ec529126b1
- zh: 414cad04d6af8e5e
+ en: d2ac2f855da27aff
+ zh: 61d257d60971f259
/deepseek-ai-dsh-client-ui-tool/understand-the-implementation/declared-optional-capabilities:
en: c1926deb4e5f3734
zh: c5845f465b94a459
diff --git a/packages/client/ui-tool/README.md b/packages/client/ui-tool/README.md
index 6fbcbd915d..843fd750a3 100644
--- a/packages/client/ui-tool/README.md
+++ b/packages/client/ui-tool/README.md
@@ -25,7 +25,7 @@ English | [中文](README.zh.md)
## Use this package
-Tool calls appear in the conversation as cards: a root call tree with its nested subcalls, each atomic call rendered by its owning view. Every lifecycle state retains the tool's ordinary business glyph; failure and interruption remain explicit through the frozen call/result state, accessible status text, and failure summary. Users can open files or inspect calls through the Host callbacks. A collapsed `web_fetch` row links its http(s) URL, which opens in a new browser tab. Control receipts display agent `name` arguments; historical `agent_id` recordings remain readable. `send_message` receipts omit the leading `lead/` from target labels while preserving nested paths and the original arguments for inspection. Text agent lists show the name or path above a single-line description, with compact spacing and recorded status. Click the description to expand or collapse its full text; its accessible name follows the selected locale.
+Tool calls appear in the conversation as cards: a root call tree with its nested subcalls, each atomic call rendered by its owning view. Every lifecycle state retains the tool's ordinary business glyph; failure and interruption remain explicit through the frozen call/result state, accessible status text, and failure summary. Users can open files or inspect calls through the Host callbacks. A collapsed `web_fetch` row links its http(s) URL, which opens in a new browser tab. Control receipts display the agent ID supplied by the recorded call. Text agent lists show the ID above a single-line description, with compact spacing and recorded status. Click the description to expand or collapse its full text; its accessible name follows the selected locale.
Settled foreground commands with a nonzero exit code, a terminating signal, or an explicit missing exit code keep their description in the ordinary gray text and show a neutral capsule with a red dot immediately after it. The capsule displays only the recorded code, signal, or localized missing-code status and stays on the same line; the description truncates with an ellipsis to reserve its space. Running, successful, and background calls omit it. Generic execution errors and stopped summaries retain their error and warning colors, including on hover.
@@ -93,7 +93,7 @@ Chat diff cards keep nine rows before folding, enough for a file header, one rem
An Auto denial takes precedence over keyed specialized views. Its generic row preserves the call identity, omits raw arguments, and normalizes the stored reason only for display: trim surrounding whitespace and collapse line separators to spaces, with localized fallback for an empty result. Session and SDK error details keep the original reason.
-Recorded tool details cover goal and schedule tools, Cordis inspection, workflow and Ralph reports, Session event/search/trace queries, agent and teammate controls, background jobs, persistent terminals, and LSP navigation. These expanded bodies read successful logged results, preserve generic input/output for failures or unsupported data, and keep Inspect available. Dates include the viewer's time zone, and statuses reflect the call result rather than current session state. Agent control receipts display the recorded target name or historical identifier. `wait_agent` shows a single waiting, ended, or timed-out header without a repeated summary; historical `noProgress` results keep their recorded explanation. Session traces preserve descendant indentation. LSP results open filesystem paths through the Host callback and display other URIs as text. The browser adapter consumes recorded producer text and JSON; Host service objects and presenter callbacks do not cross into the Client.
+Recorded tool details cover goal and schedule tools, Cordis inspection, workflow and Ralph reports, Session event/search/trace queries, agent and teammate controls, background jobs, persistent terminals, and LSP navigation. These expanded bodies read successful logged results, preserve generic input/output for failures or unsupported data, and keep Inspect available. Dates include the viewer's time zone, and statuses reflect the call result rather than current session state. Agent control receipts display the recorded target Session id. `wait_agent` shows a single waiting, ended, or timed-out header without a repeated summary; historical `noProgress` results keep their recorded explanation. Session traces preserve descendant indentation. LSP results open filesystem paths through the Host callback and display other URIs as text. The browser adapter consumes recorded producer text and JSON; Host service objects and presenter callbacks do not cross into the Client.
Expanded status dots and labels use static semantic colors. Receipt and job-output headers keep neutral text and omit the status while expanded. An interruption receipt confirms only that interruption was requested.
diff --git a/packages/client/ui-tool/README.zh.md b/packages/client/ui-tool/README.zh.md
index 4de4f92010..641200a4d2 100644
--- a/packages/client/ui-tool/README.zh.md
+++ b/packages/client/ui-tool/README.zh.md
@@ -25,7 +25,7 @@ kind: "package-reference"
## 使用本包
-工具调用在对话中显示为卡片:一个根调用树带其嵌套子调用,每个原子调用由所属视图渲染。所有生命周期状态都保留工具的普通业务图标;失败与中断仍通过冻结调用/结果状态、无障碍状态文本和失败摘要明确表达。用户可通过宿主回调打开文件或检查调用。折叠的 `web_fetch` 行把其 http(s) URL 显示为链接,在新浏览器标签页中打开。控制工具回执显示 agent 的 `name` 参数;历史 `agent_id` 记录仍可读取。`send_message` 回执的目标标签省略开头的 `lead/`,保留嵌套路径,检查视图仍显示原始参数。文本形式的智能体列表以紧凑间距展示名称或路径、下方的单行描述及记录中的状态。点击描述可展开或收起全文;其无障碍名称使用当前语言。
+工具调用在对话中显示为卡片:一个根调用树带其嵌套子调用,每个原子调用由所属视图渲染。所有生命周期状态都保留工具的普通业务图标;失败与中断仍通过冻结调用/结果状态、无障碍状态文本和失败摘要明确表达。用户可通过宿主回调打开文件或检查调用。折叠的 `web_fetch` 行把其 http(s) URL 显示为链接,在新浏览器标签页中打开。控制工具回执显示记录的调用所提供的智能体 ID。文本形式的智能体列表以紧凑间距展示 ID、下方的单行描述及记录中的状态。点击描述可展开或收起全文;其无障碍名称使用当前语言。
已结束的前台命令若返回非零退出码、终止信号,或明确记录为无退出码,描述保持普通灰色,后面紧接带红点的中性胶囊。胶囊仅显示记录的退出码、信号或本地化的“未正常退出”状态,并保持在同一行;描述超出可用宽度时显示省略号,为胶囊预留空间。运行中、成功和后台调用不显示胶囊。通用执行错误与停止摘要仍保留错误色和警告色,悬停时也不改变。
@@ -93,7 +93,7 @@ Chat diff 卡片在折叠前保留九行,足以容纳文件标题、一对删
Auto 拒绝优先于按工具名选择的专门视图。其通用行保留调用身份、省略原始参数,并且只在显示时归一化存储的理由:去除首尾空白,把行分隔符折叠为空格,结果为空时使用本地化通用理由。Session 与 SDK 错误详情保留原始理由。
-记录结果的工具详情覆盖目标和定时任务工具、Cordis 检查、workflow 与 Ralph 报告、Session 事件/搜索/轨迹查询、Agent 与 teammate 控制、后台作业、持久终端以及 LSP 导航。展开内容读取成功的记录结果,为失败或不支持的数据保留通用输入/输出,并保留 Inspect。日期包含查看者的时区,状态反映调用结果而非当前会话状态。Agent 控制回执显示记录的目标名称或历史标识符。`wait_agent` 的行标题仅显示等待中、已结束或已超时,不重复追加摘要;历史 `noProgress` 结果保留记录中的说明。Session 轨迹保留后代的缩进。LSP 结果通过 Host 回调打开文件系统路径,其他 URI 则显示为文本。浏览器适配器消费已记录的 producer 文本与 JSON;Host service 对象和 presenter 回调不会进入 Client。
+记录结果的工具详情覆盖目标和定时任务工具、Cordis 检查、workflow 与 Ralph 报告、Session 事件/搜索/轨迹查询、Agent 与 teammate 控制、后台作业、持久终端以及 LSP 导航。展开内容读取成功的记录结果,为失败或不支持的数据保留通用输入/输出,并保留 Inspect。日期包含查看者的时区,状态反映调用结果而非当前会话状态。Agent 控制回执显示记录的目标 Session id。`wait_agent` 的行标题仅显示等待中、已结束或已超时,不重复追加摘要;历史 `noProgress` 结果保留记录中的说明。Session 轨迹保留后代的缩进。LSP 结果通过 Host 回调打开文件系统路径,其他 URI 则显示为文本。浏览器适配器消费已记录的 producer 文本与 JSON;Host service 对象和 presenter 回调不会进入 Client。
展开后的状态圆点和文字使用静态语义色。操作回执和任务输出的标题保持中性色,展开时省略标题中的状态。中断回执仅确认已发出中断请求。
diff --git a/packages/client/ui-tool/src/client/tool/models/control-details-model.ts b/packages/client/ui-tool/src/client/tool/models/control-details-model.ts
index 59b4aa3bfb..2de87b4318 100644
--- a/packages/client/ui-tool/src/client/tool/models/control-details-model.ts
+++ b/packages/client/ui-tool/src/client/tool/models/control-details-model.ts
@@ -114,12 +114,12 @@ export function subagentDetails(
} else {
if (text === undefined) return null
// Historical results lack the structured receipt stored by current tools.
- const started = /^started (background subagent job|subagent) (\S+)(?:\nname: (\S+))?$/u.exec(text)
+ const started = /^started (background subagent job|subagent) (\S+)$/u.exec(text)
if (started === null) {
return detailList([{ title: t('detail.agent.reply'), markdown: text, fields: [], groups: [{ label: t('detail.field.task'), items: [{ description: arg(args, 'prompt'), fields: [] }] }] }], t('detail.agent.reply'), t)
}
if (started[1] === 'background subagent job') fields.push({ label: t('detail.field.job'), value: started[2] ?? '' })
- if (started[3] !== undefined) fields.push({ label: t('detail.field.agentName'), value: started[3] })
+ else fields.push({ label: t('detail.field.id'), value: started[2] ?? '' })
}
return detailList([{
title: t('detail.receipt.started'), fields,
@@ -139,7 +139,7 @@ export function subagentDetails(
export function controlDetails(
name: string, args: Record, text: string, json: unknown, t: DetailTranslate,
): ToolDetailsModel | null {
- const target = arg(args, 'name') || arg(args, 'target') || arg(args, 'agent_id') || arg(args, 'sessionId') || arg(args, 'job_id')
+ const target = arg(args, 'target') || arg(args, 'agent_id') || arg(args, 'sessionId') || arg(args, 'job_id')
switch (name) {
case 'list_agents': return agentList(text, json, t)
case 'job_list': return jobList(text, t)
@@ -161,12 +161,11 @@ export function controlDetails(
...(json.nextCursor === undefined ? {} : { caption: t('detail.tasks.nextPage', { cursor: String(json.nextCursor) }) }),
}
case 'send_message': {
- const title = target.replace(/^lead\//u, '')
const status = detailRecord(json) ? json.status : undefined
- if (status === 'accepted' || status === 'queued') return receipt(title, {
+ if (status === 'accepted' || status === 'queued') return receipt(target, {
label: t(status === 'queued' ? 'detail.status.queued' : 'detail.receipt.delivered'), tone: status === 'queued' ? 'warning' : 'success',
}, t, [], arg(args, 'message'))
- return text === `message delivered to agent ${target}` ? receipt(title, { label: t('detail.receipt.delivered'), tone: 'success' }, t, [], arg(args, 'message')) : null
+ return text === `message delivered to agent ${target}` ? receipt(target, { label: t('detail.receipt.delivered'), tone: 'success' }, t, [], arg(args, 'message')) : null
}
case 'interrupt_agent':
if (detailRecord(json) && typeof json.previousStatus === 'string') return receipt(target, { label: t('detail.receipt.interrupt'), tone: 'warning' }, t, [{ label: t('detail.field.previousStatus'), value: detailBadge(json.previousStatus, t).label }])
diff --git a/packages/client/ui-tool/src/client/tool/models/detail-model-shared.ts b/packages/client/ui-tool/src/client/tool/models/detail-model-shared.ts
index 46c6b6b886..7bba7fb2de 100644
--- a/packages/client/ui-tool/src/client/tool/models/detail-model-shared.ts
+++ b/packages/client/ui-tool/src/client/tool/models/detail-model-shared.ts
@@ -66,7 +66,7 @@ export function detailBadge(status: string, t: DetailTranslate): NonNullable {
expect(details('lsp', 'hover text', { file_path: 'src/main.ts', line: 2, character: 3, operation: 'hover' })?.items[0]?.markdown).toBe('hover text')
})
- it('shows named agent targets in recorded messaging and interruption receipts', () => {
- expect(details('send_message', 'message delivered to agent lead/reviewer', {
- name: 'lead/reviewer', message: 'Review the change.',
- })).toMatchObject({
- summary: 'reviewer · Message delivered', expandedSummary: 'reviewer',
- items: [{ title: 'reviewer', description: 'Review the change.' }],
- })
- expect(details('interrupt_agent', '{"previousStatus":"running"}', {
- name: 'lead/reviewer',
- })?.items[0]).toMatchObject({
- title: 'lead/reviewer', fields: [{ label: 'Previous status', value: 'Running' }],
- })
- })
-
- it.each(['subagent', 'subagent_fork'])('%s recognizes named creation receipts and retains the complete task', (name) => {
+ it.each(['subagent', 'subagent_fork'])('%s recognizes ID creation receipts and retains the complete task', (name) => {
const prompt = 'Research CLI agent products.\nCompare business models and write a report.'
- const model = details(name, 'started subagent child-1\nname: lead/researcher', { description: 'Research CLI agent products', prompt })
+ const model = details(name, 'started subagent child-1', { description: 'Research CLI agent products', prompt })
expect(model?.summary).toBe('Research CLI agent products')
expect(model?.items[0]).toEqual({
title: 'Started',
- fields: [{ label: 'Agent task description', value: 'Research CLI agent products' }, { label: 'Agent name', value: 'lead/researcher' }],
+ fields: [{ label: 'Agent task description', value: 'Research CLI agent products' }, { label: 'ID', value: 'child-1' }],
groups: [{ label: 'Task', items: [{ description: prompt, fields: [] }] }],
})
expect(details(name, 'started subagent child-1', { prompt })?.items[0]?.title).toBe('Started')
- expect(details(name, 'started subagent child-1\nname: lead/researcher\nAdditional reply', { prompt })?.items[0]?.title).toBe('Agent response')
+ expect(details(name, 'started subagent child-1\nAdditional reply', { prompt })?.items[0]?.title).toBe('Agent response')
})
it.each(['subagent', 'subagent_fork'])('%s renders persisted creation metadata independently of result wording', (name) => {
- const args = { description: 'Review the changes', prompt: 'Read the diff and report defects.', name: 'requested-name' }
+ const args = { description: 'Review the changes', prompt: 'Read the diff and report defects.' }
const block = { ...output(name, 'Delegation accepted.', args), meta: { kind: 'activation', subagentId: 'child-1' } }
const model = detailsCardModel(block, t, 'en')
expect(model?.items[0]).toEqual({
@@ -132,7 +118,7 @@ describe('control detail adapters', () => {
it.each([null, [], {}, { kind: 'other', subagentId: 'child-1' }, { kind: 'activation' }, { kind: 'activation', subagentId: 1 }, { kind: 'activation', subagentId: ' ' }])(
'keeps malformed metadata on the generic result path (%j)', (meta) => {
- const block = { ...output('subagent', 'started subagent child-1\nname: lead/reviewer'), meta }
+ const block = { ...output('subagent', 'started subagent child-1'), meta }
expect(detailsCardModel(block, t, 'en')).toBeNull()
},
)
@@ -142,7 +128,7 @@ describe('control detail adapters', () => {
expect(details('team_task_create', '{"id":"task-1","subject":"Review","status":"pending"}')?.summary).toBe('Review')
expect(details('team_task_list', '{"tasks":[{"id":"task-1","subject":"Review"}],"nextCursor":3}')?.caption).toBe('More tasks available; next cursor is 3')
expect(details('send_message', '{"status":"queued"}', { agent_id: 'a1', message: 'hello' })?.items[0]?.badge?.label).toBe('Queued')
- expect(details('send_message', 'message delivered to agent reviewer', { name: 'reviewer', message: 'hello' })?.summary).toBe('reviewer · Message delivered')
+ expect(details('send_message', 'message delivered to agent reviewer', { agent_id: 'reviewer', message: 'hello' })?.summary).toBe('reviewer · Message delivered')
expect(details('interrupt_agent', '{"previousStatus":"running"}', { agent_id: 'a1' })?.items[0]?.fields).toContainEqual({ label: 'Previous status', value: 'Running' })
expect(details('wait_agent', '{"timedOut":true}')?.summary).toBe('Wait timed out')
expect(details('wait_agent', '{"timedOut":false,"noProgress":{"message":"No peer"}}')?.items[0]?.description).toBe('No peer')
@@ -163,7 +149,7 @@ describe('control detail adapters', () => {
expect(details('unknown', 'x')).toBeNull()
expect(details('team_task_list', '{"tasks":[],"nextCursor":"bad"}')).toBeNull()
expect(details('terminal_read', 'bad', { sessionId: 'pty-1' })).toBeNull()
- expect(details('interrupt_agent', 'interrupt requested for agent reviewer', { name: 'reviewer' })?.summary).toContain('Interrupt')
+ expect(details('interrupt_agent', 'interrupt requested for agent reviewer', { agent_id: 'reviewer' })?.summary).toContain('Interrupt')
expect(details('interrupt_agent', 'unexpected', { agent_id: 'a1' })).toBeNull()
expect(details('job_kill', 'unexpected', { job_id: 'j1' })).toBeNull()
expect(details('terminal_close', 'unexpected', { sessionId: 'pty-1' })).toBeNull()
diff --git a/packages/client/ui-tool/tests/preparing-rows.client.spec.tsx b/packages/client/ui-tool/tests/preparing-rows.client.spec.tsx
index 38a5827061..5421e99eda 100644
--- a/packages/client/ui-tool/tests/preparing-rows.client.spec.tsx
+++ b/packages/client/ui-tool/tests/preparing-rows.client.spec.tsx
@@ -96,15 +96,15 @@ describe('tool preparation', () => {
const settled: ToolResultNode = {
kind: 'tool-result', seq: 3, time: 3, callId: 'call', callTime: 2, name,
args: started.args, call: { name, argsRaw }, isError: false, subCalls: [],
- content: [{ type: 'text', text: 'started subagent child-1\nname: lead/researcher' }],
+ content: [{ type: 'text', text: 'started subagent child-1' }],
}
view.rerender()
expect(view.getByText('Research CLI products')).toBeTruthy()
expect(view.queryByText('Agent response')).toBeNull()
fireEvent.click(view.getByRole('button', { expanded: false }))
- expect(view.getByText('Research CLI products')).toBeTruthy()
+ expect(view.getAllByText('Research CLI products')).toHaveLength(2)
expect(view.getByText('Research products in detail.')).toBeTruthy()
- expect(view.getByText('lead/researcher')).toBeTruthy()
+ expect(view.getByText('child-1')).toBeTruthy()
})
it('retains the file row through streamed arguments, dispatch, and result', () => {
diff --git a/packages/core/agent-loop/package.json b/packages/core/agent-loop/package.json
index 8975a352db..be922d4fde 100644
--- a/packages/core/agent-loop/package.json
+++ b/packages/core/agent-loop/package.json
@@ -59,7 +59,6 @@
"@deepseek-ai/dsh-tool-executor-native": "workspace:*",
"@deepseek-ai/dsh-tool-executor-ptc": "workspace:*",
"@deepseek-ai/dsh-tool-testkit": "workspace:*",
- "@deepseek-ai/dsh-tools": "workspace:*",
- "@deepseek-ai/dsh-subagent-names": "workspace:*"
+ "@deepseek-ai/dsh-tools": "workspace:*"
}
}
diff --git a/packages/core/agent-loop/tests/resource-lifecycle.spec.ts b/packages/core/agent-loop/tests/resource-lifecycle.spec.ts
index 42a089f026..991746f567 100644
--- a/packages/core/agent-loop/tests/resource-lifecycle.spec.ts
+++ b/packages/core/agent-loop/tests/resource-lifecycle.spec.ts
@@ -1,4 +1,3 @@
-import SubagentNames from '@deepseek-ai/dsh-subagent-names'
import { executeToolFixture } from '@deepseek-ai/dsh-tool-testkit'
import { setImmediate } from 'node:timers/promises'
import { mkdtempSync, rmSync } from 'node:fs'
@@ -91,7 +90,6 @@ it.each(['loop', 'root'] as const)('unloads %s while a background child is stopp
await ctx.plugin(JsonlSessionPersistence, { root })
const loop = await ctx.plugin(AgentLoop, { agents: [] })
await ctx.plugin(SubagentRuntime)
- await ctx.plugin(SubagentNames)
await ctx.plugin(LocalJobRegistry)
await ctx.plugin(SubagentSpawn)
await ctx.plugin(ToolSubagent, { provider: 'spawn' })
diff --git a/packages/core/session/src/known-event-types.ts b/packages/core/session/src/known-event-types.ts
index 6c4257a181..466e76bb80 100644
--- a/packages/core/session/src/known-event-types.ts
+++ b/packages/core/session/src/known-event-types.ts
@@ -59,7 +59,6 @@ export const KNOWN_SESSION_EVENT_TYPES: ReadonlySet = new Set([
'session/title-llm-request',
'step/end',
'step/start',
- 'subagent-name/bound',
'subagent/catalog',
'subagent/descriptor',
'subagent/model-selection-policy',
diff --git a/packages/experimental/auto-review/package.json b/packages/experimental/auto-review/package.json
index 875b50172b..e388365620 100644
--- a/packages/experimental/auto-review/package.json
+++ b/packages/experimental/auto-review/package.json
@@ -76,8 +76,7 @@
"@deepseek-ai/dsh-tools": "workspace:*",
"@deepseek-ai/dsh-user-approval": "workspace:*",
"@deepseek-ai/cordis": "workspace:~",
- "@deepseek-ai/dsh-working-directory": "workspace:*",
- "@deepseek-ai/dsh-subagent-names": "workspace:*"
+ "@deepseek-ai/dsh-working-directory": "workspace:*"
},
"publishConfig": {
"access": "public"
diff --git a/packages/experimental/auto-review/tests/auto-review.spec.ts b/packages/experimental/auto-review/tests/auto-review.spec.ts
index ac50cd066e..45e0b8dcb5 100644
--- a/packages/experimental/auto-review/tests/auto-review.spec.ts
+++ b/packages/experimental/auto-review/tests/auto-review.spec.ts
@@ -1,4 +1,3 @@
-import SubagentNames from '@deepseek-ai/dsh-subagent-names'
import { executeToolFixture, executeModelToolFixture } from '@deepseek-ai/dsh-tool-testkit'
import * as NativeToolExecutor from '@deepseek-ai/dsh-tool-executor-native'
import { externalTestParent } from '../../../subagent/subagent/tests/external-activation-helpers.ts'
@@ -1372,7 +1371,6 @@ describe('out-of-process delegation boundary', () => {
scriptedDecision('allow', 'allow'),
])
await ctx.plugin(SubagentRuntime)
- await ctx.plugin(SubagentNames)
let providerRequest: SubagentStartRequest | undefined
ctx.subagents.registerProvider({
name: 'remote-boundary',
diff --git a/packages/experimental/tool-subagent-oar/README.i18n.yaml b/packages/experimental/tool-subagent-oar/README.i18n.yaml
index b5c8367aa9..a652d96c43 100644
--- a/packages/experimental/tool-subagent-oar/README.i18n.yaml
+++ b/packages/experimental/tool-subagent-oar/README.i18n.yaml
@@ -9,26 +9,26 @@
en: 520d9dc51e2b0142
zh: 8f332776243107a9
/deepseek-ai-dsh-experimental-tool-subagent-oar/summary:
- en: 2d63ab94ccdafa8f
- zh: 6372823aea399513
+ en: 8adbaf2511d2c47f
+ zh: 1495f6bdb84a30ea
/deepseek-ai-dsh-experimental-tool-subagent-oar/table-of-contents:
en: d152484eb41ac6b4
zh: 8d1e20b826450ffe
/deepseek-ai-dsh-experimental-tool-subagent-oar/use-this-package:
- en: f95f1df04a1d3231
- zh: 46647a030250eefe
+ en: 045000a545e143bb
+ zh: db19a60804c8d561
/deepseek-ai-dsh-experimental-tool-subagent-oar/use-this-package/when-to-choose-it:
en: 368805e5bcffeb0a
zh: 9340ff5074ada9e1
/deepseek-ai-dsh-experimental-tool-subagent-oar/use-this-package/minimal-configuration:
- en: 7777b50b62aa53c0
- zh: ff2a53de5dcbf518
+ en: 5b2b33c1d0fae20a
+ zh: 26bff1e013e2bfcd
/deepseek-ai-dsh-experimental-tool-subagent-oar/understand-the-implementation:
- en: e168a1ffb8497b1a
- zh: e9085b004a2d2c55
+ en: 3e8a9fffa9c5afd0
+ zh: 932b6d0b682208ba
/deepseek-ai-dsh-experimental-tool-subagent-oar/further-exploration:
- en: 8aeb6cf566b48838
- zh: cc0f5bb71ee7a9fe
+ en: a796236202b695f5
+ zh: 8e76361f31517714
/deepseek-ai-dsh-experimental-tool-subagent-oar/model-experience:
en: 215e7ba838619b7b
zh: a311da3843709f90
@@ -36,8 +36,8 @@
en: 8febbb031aa0452d
zh: da3f9011631652da
/deepseek-ai-dsh-experimental-tool-subagent-oar/model-experience/external-delegation-tool/what-the-model-sees:
- en: 4b2fc7303598e643
- zh: efaa45f0c42befd2
+ en: 2e0f5274092f794b
+ zh: 83a14e5f7018717f
/deepseek-ai-dsh-experimental-tool-subagent-oar/model-experience/external-delegation-tool/token-effect:
en: 60d7ffec7f4dc858
zh: 09f286978df6b4ec
@@ -45,8 +45,8 @@
en: 7c1ac0b007b2f0ce
zh: 2332a07c6f8bcbdc
/deepseek-ai-dsh-experimental-tool-subagent-oar/known-limitations-and-deferred-work:
- en: e0ed82ba366c0f17
- zh: c7fd3d1b48bb3c11
+ en: 5157ca8c4aa1a865
+ zh: 47ad253d87a02838
/deepseek-ai-dsh-experimental-tool-subagent-oar/known-limitations-and-deferred-work/dev-note:
en: e67f633dc6fe7773
zh: 8ec3e73528ddb1a6
diff --git a/packages/experimental/tool-subagent-oar/README.md b/packages/experimental/tool-subagent-oar/README.md
index fded6c3bfe..991dfc0c3e 100644
--- a/packages/experimental/tool-subagent-oar/README.md
+++ b/packages/experimental/tool-subagent-oar/README.md
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
## Summary
-Use one `subagent_oar` tool to choose a configured external agent for each standalone text task. Configuration fixes the available runtime aliases and their providers; the model selects an alias without changing native arguments or permissions. Each task uses independent context and returns its child id and full name, with a later completion notice delivered to the parent.
+Use one `subagent_oar` tool to choose a configured external agent for each standalone text task. Configuration fixes the available runtime aliases and their providers; the model selects an alias without changing native arguments or permissions. Each task uses independent context and returns a child id, with a later completion notice delivered to the parent.
## Table of Contents
@@ -25,7 +25,7 @@ Use one `subagent_oar` tool to choose a configured external agent for each stand
## Use this package
-Mount this tool with `@deepseek-ai/dsh-subagent-names` beside configured external providers, such as [OAR provider instances](../subagent-oar/README.md). Declare the naming, tool, and provider packages as dependencies of your composition.
+Mount this tool beside configured external providers, such as [OAR provider instances](../subagent-oar/README.md). Declare the tool and provider packages as dependencies of your composition.
### When to choose it
@@ -33,10 +33,9 @@ Choose this tool when one model-facing entry should select among independent, on
### Minimal configuration
-With the shared subagent services available and `oar-codex` and `oar-claude` already registered, mount the naming service once alongside this tool:
+With `oar-codex` and `oar-claude` already registered, mount this row in the composition:
```yaml
-- name: '@deepseek-ai/dsh-subagent-names'
- name: '@deepseek-ai/dsh-experimental-tool-subagent-oar'
config:
providers:
@@ -49,7 +48,7 @@ With the shared subagent services available and `oar-codex` and `oar-claude` alr
| `providers` | required | Nonempty map from model-visible runtime aliases to registered provider names |
| `toolName` | `subagent_oar` | Tool name; every mounted instance needs a distinct name |
-The [configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-experimental-tool-subagent-oar) owns accepted fields and validation. A call requires `runtime`, `description`, and `prompt`; optional `name` selects a sibling segment under the [naming service rules](../../subagent/subagent-names/README.md); optional `cwd` selects the child directory, with relative paths resolved from the parent's current directory. The prompt must contain the context the child needs. Native installation, authentication, model settings, and permissions belong to the selected provider.
+The [configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-experimental-tool-subagent-oar) owns accepted fields and validation. A call requires `runtime`, `description`, and `prompt`; optional `cwd` selects the child directory, with relative paths resolved from the parent's current directory. The prompt must contain the context the child needs. Native installation, authentication, model settings, and permissions belong to the selected provider.
-----
@@ -59,7 +58,7 @@ The [configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-exper
Implementation internals — click to expand
-[`src/index.ts`](src/index.ts) registers the configured runtime choices and calls `ctx.subagents.startActivation()` directly. The naming service reserves a sibling name and maps the accepted child id to its full name; the child's prompt is the submitted task. The subagent service owns capacity, parent lifetime, cancellation, terminal recording, and completion delivery. The tool's call card uses the task description and submitted arguments. Disposing the plugin removes its tool registration; the activation manager retains ownership of accepted children.
+[`src/index.ts`](src/index.ts) builds the runtime enum from the configured aliases and registers one tool. Each call resolves its provider and starts an activation through the shared subagent service, which owns capacity, parent lifetime, cancellation, terminal recording, and completion delivery. The tool's call card uses the task description and submitted arguments. Disposing the plugin removes its tool registration; the activation manager retains ownership of accepted children.
@@ -69,7 +68,6 @@ The [configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-exper
## Further Exploration
- [Subagent service](../../subagent/subagent/README.md) — provider registration and activation ownership.
-- [Subagent names](../../subagent/subagent-names/README.md) — sibling names and full-name lookup.
- [OAR provider](../subagent-oar/README.md) — native runtime setup and permission configuration.
- [Subagent subsystem](../../../docs/subsystems/subagent.md) — parent completion notices and retained results.
@@ -82,7 +80,7 @@ The [configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-exper
#### What the model sees
-The [tool catalog](../../../docs/tool-catalog.md#deepseek-aidsh-experimental-tool-subagent-oar) owns the description and argument schema. The `runtime` enum contains the configured aliases. After acceptance, the result contains `kind: "activation"`, `subagentId`, and `name`. The model sees `started subagent ` followed by `name: ` on the next line. The shared subagent service later supplies the child's answer or failure notice, identifying the external execution by the same child id.
+The [tool catalog](../../../docs/tool-catalog.md#deepseek-aidsh-experimental-tool-subagent-oar) owns the description and argument schema. The `runtime` enum contains the configured aliases. After acceptance, the tool returns `started subagent `, where `` identifies the child. The shared subagent service later supplies the child's answer or failure notice.
#### Token effect
@@ -100,7 +98,6 @@ The tool's choices and execution capabilities are fixed by its configured provid
- **One-shot providers only:** child context is independent, and the tool exposes no follow-up, resume, structured output, or per-call native permission override.
- **Provider availability:** a selected provider that is absent or unloaded fails at call time; its configured alias remains in the schema until this tool's configuration changes.
-- **Name binding failure:** if the accepted child's name cannot be recorded, the error reports its id and leaves execution managed by the subagent service. Check that child's outcome before retrying; the reserved name is released.
- **Provider-owned work:** runtime setup, startup cancellation, process cleanup, and answer selection follow the selected provider's documented behavior. Removing this tool does not revoke accepted activations.
diff --git a/packages/experimental/tool-subagent-oar/README.zh.md b/packages/experimental/tool-subagent-oar/README.zh.md
index 0542a1ab40..3213e82786 100644
--- a/packages/experimental/tool-subagent-oar/README.zh.md
+++ b/packages/experimental/tool-subagent-oar/README.zh.md
@@ -9,7 +9,7 @@ kind: "package-reference"
## 概述
-使用一个 `subagent_oar` 工具,为每个独立文本任务选择已配置的外部智能体。配置固定可用的运行时别名及其提供方;模型选择别名,不能更改原生参数或权限。每个任务使用独立上下文并返回子任务 id 和完整名称,完成通知稍后送达父智能体。
+使用一个 `subagent_oar` 工具,为每个独立文本任务选择已配置的外部智能体。配置固定可用的运行时别名及其提供方;模型选择别名,不能更改原生参数或权限。每个任务使用独立上下文并返回子任务 id,完成通知稍后送达父智能体。
## 目录
@@ -25,7 +25,7 @@ kind: "package-reference"
## 使用本包
-将此工具与 `@deepseek-ai/dsh-subagent-names` 一起挂载在已配置的外部提供方旁,例如 [OAR 提供方实例](../subagent-oar/README.zh.md)。在组合中将命名、工具和提供方包声明为依赖。
+在已配置的外部提供方旁挂载此工具,例如 [OAR 提供方实例](../subagent-oar/README.zh.md)。在组合中将工具包和提供方包声明为依赖。
### 适用场景
@@ -33,10 +33,9 @@ kind: "package-reference"
### 最小配置
-在共享 subagent 服务可用,且 `oar-codex` 和 `oar-claude` 已注册后,在此工具旁挂载一次命名服务:
+在 `oar-codex` 和 `oar-claude` 已注册的情况下,在组合中挂载此行:
```yaml
-- name: '@deepseek-ai/dsh-subagent-names'
- name: '@deepseek-ai/dsh-experimental-tool-subagent-oar'
config:
providers:
@@ -49,7 +48,7 @@ kind: "package-reference"
| `providers` | 必填 | 从模型可见运行时别名映射到已注册提供方名称的非空映射 |
| `toolName` | `subagent_oar` | 工具名称;每个挂载实例需要不同名称 |
-[配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-experimental-tool-subagent-oar)定义接受的字段和校验规则。调用要求提供 `runtime`、`description` 和 `prompt`;可选的 `name` 按[命名服务规则](../../subagent/subagent-names/README.zh.md)选择同级路径段;可选的 `cwd` 选择子任务目录,相对路径从父智能体的当前目录解析。提示必须包含子任务需要的上下文。原生安装、认证、模型设置和权限由所选提供方负责。
+[配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-experimental-tool-subagent-oar)定义接受的字段和校验规则。调用要求提供 `runtime`、`description` 和 `prompt`;可选的 `cwd` 选择子任务目录,相对路径从父智能体的当前目录解析。提示必须包含子任务需要的上下文。原生安装、认证、模型设置和权限由所选提供方负责。
-----
@@ -59,7 +58,7 @@ kind: "package-reference"
实现内部细节 — 点击展开
-[`src/index.ts`](src/index.ts)注册配置的运行时选项,并直接调用 `ctx.subagents.startActivation()`。命名服务预留同级名称,并将已接受的子任务 id 映射到完整名称;子任务的提示就是提交的任务。subagent 服务负责容量、父智能体生命周期、取消、最终记录和完成通知交付。工具调用卡片使用任务描述和提交的参数。释放插件会移除其工具注册;激活管理器继续负责已接受的子任务。
+[`src/index.ts`](src/index.ts)根据配置的别名构建运行时枚举,并注册一个工具。每次调用解析其提供方,并通过共享子智能体服务启动激活;该服务负责容量、父智能体生命周期、取消、最终记录和完成通知交付。工具调用卡片使用任务描述和提交的参数。释放插件会移除其工具注册;激活管理器继续负责已接受的子任务。
@@ -69,7 +68,6 @@ kind: "package-reference"
## 延伸阅读
- [子智能体服务](../../subagent/subagent/README.zh.md) — 提供方注册和激活所有权。
-- [Subagent 命名](../../subagent/subagent-names/README.zh.md) — 同级名称和完整名称查询。
- [OAR 提供方](../subagent-oar/README.zh.md) — 原生运行时配置和权限配置。
- [子智能体子系统](../../../docs/subsystems/subagent.zh.md) — 父智能体完成通知和保留结果。
@@ -82,7 +80,7 @@ kind: "package-reference"
#### 模型看到什么
-[工具目录](../../../docs/tool-catalog.zh.md#deepseek-aidsh-experimental-tool-subagent-oar)定义描述和参数 schema。`runtime` 枚举包含配置的别名。接受任务后,结果包含 `kind: "activation"`、`subagentId` 和 `name`。模型看到 `started subagent `,下一行是 `name: `。共享子智能体服务稍后提供子任务的答复或失败通知,以相同的子任务 id 标识外部执行。
+[工具目录](../../../docs/tool-catalog.zh.md#deepseek-aidsh-experimental-tool-subagent-oar)定义描述和参数 schema。`runtime` 枚举包含配置的别名。接受任务后,工具返回 `started subagent `,其中 `` 标识子任务。共享子智能体服务稍后提供子任务的答复或失败通知。
#### Token 影响
@@ -100,7 +98,6 @@ kind: "package-reference"
- **仅支持单次提供方:** 子任务上下文独立,工具不提供后续输入、恢复、结构化输出或按调用覆盖原生权限的功能。
- **提供方可用性:** 选择的提供方不存在或已卸载时,调用会失败;其配置的别名会保留在 schema 中,直到此工具的配置改变。
-- **名称绑定失败:** 如果已接受的子任务名称无法记录,错误会报告其 id,执行仍由 subagent 服务管理。重试前应检查该子任务的结果;预留的名称会被释放。
- **提供方负责的工作:** 运行时配置、启动取消、进程清理和答复选择遵循所选提供方的文档行为。移除此工具不会撤销已接受的激活。
diff --git a/packages/experimental/tool-subagent-oar/package.json b/packages/experimental/tool-subagent-oar/package.json
index b54bfd0493..de6d30efda 100644
--- a/packages/experimental/tool-subagent-oar/package.json
+++ b/packages/experimental/tool-subagent-oar/package.json
@@ -30,9 +30,7 @@
"license": "MIT",
"peerDependencies": {
"@deepseek-ai/cordis": "workspace:~",
- "@deepseek-ai/dsh-llm": "workspace:*",
"@deepseek-ai/dsh-subagent": "workspace:*",
- "@deepseek-ai/dsh-subagent-names": "workspace:*",
"@deepseek-ai/dsh-tools": "workspace:*"
},
"dependencies": {
@@ -45,7 +43,6 @@
"@deepseek-ai/dsh-llm": "workspace:*",
"@deepseek-ai/dsh-session": "workspace:*",
"@deepseek-ai/dsh-subagent": "workspace:*",
- "@deepseek-ai/dsh-subagent-names": "workspace:*",
"@deepseek-ai/dsh-tools": "workspace:*",
"@deepseek-ai/dsh-tool-testkit": "workspace:*"
}
diff --git a/packages/experimental/tool-subagent-oar/src/index.ts b/packages/experimental/tool-subagent-oar/src/index.ts
index 65cd48d209..c73af97901 100644
--- a/packages/experimental/tool-subagent-oar/src/index.ts
+++ b/packages/experimental/tool-subagent-oar/src/index.ts
@@ -2,13 +2,11 @@
import type { Context } from '@deepseek-ai/cordis'
import z from '@deepseek-ai/schemastery'
-import { HarnessError } from '@deepseek-ai/dsh-llm'
import { defineTool } from '@deepseek-ai/dsh-tools'
import type {} from '@deepseek-ai/dsh-subagent'
-import type {} from '@deepseek-ai/dsh-subagent-names'
export const name = 'experimental-tool-subagent-oar'
-export const inject = ['tools', 'subagents', 'subagentNames']
+export const inject = ['tools', 'subagents']
/** Deployment-owned runtime choices exposed by the external delegation tool. */
export interface Config {
@@ -25,7 +23,7 @@ export const Config: z = z.object({
/**
* Register a tool that selects one configured external provider per task.
- * @param ctx - shared tool registry, managed subagents, and hierarchical naming service.
+ * @param ctx - shared tool registry and managed subagent service.
* @param config - runtime choices and the model-facing tool name.
*/
export function apply(ctx: Context, config: Config): void {
@@ -38,14 +36,10 @@ export function apply(ctx: Context, config: Config): void {
name: toolName,
description: 'Delegate a self-contained task to a configured external agent. Choose its runtime for each call. '
+ 'The child works in its own context and does not see this conversation. '
- + 'This tool returns the child id and full agent path; a later completion notice includes its final answer. '
+ + 'This tool returns a child id; a later completion notice includes its final answer. '
+ 'The child does not accept follow-up messages. Start independent tasks together and continue useful work while they run. '
+ 'When only waiting for their results remains, end your turn instead of polling.',
parameters: {
- name: {
- type: 'string',
- description: 'Optional sibling-unique name; omission selects the first unused agent-N, starting at agent-1. Explicit names: start with a lower-case letter and use lower-case letters, digits, underscores, or hyphens.',
- },
runtime: {
type: 'string',
required: true,
@@ -76,10 +70,9 @@ export function apply(ctx: Context, config: Config): void {
properties: {
kind: { type: 'string', required: true, const: 'activation' },
subagentId: { type: 'string', required: true },
- name: { type: 'string', required: true },
},
},
- render: (_args, value) => [{ type: 'text', text: `started subagent ${value.subagentId}\nname: ${value.name}` }],
+ render: (_args, value) => [{ type: 'text', text: `started subagent ${value.subagentId}` }],
},
/* jscpd:ignore-end */
isConcurrencySafe: () => true,
@@ -92,32 +85,16 @@ export function apply(ctx: Context, config: Config): void {
if (provider !== undefined && (provider.prepareContinuable !== undefined || provider.inheritsParentContext)) {
throw new Error('subagent_oar requires a one-shot provider with independent conversation context')
}
- const names = ctx.subagentNames
- const rootSession = ctx.subagents.rootOf(parent).session
- const reservation = names.reserve(rootSession, parent.id, args.name)
- try {
- const activation = await ctx.subagents.startActivation({
- provider: providerName,
- label: args.description,
- parent,
- prompt: [{ type: 'text', text: args.prompt }],
- ...args.cwd === undefined ? {} : { cwd: args.cwd },
- signal: exec.signal,
- delivery: 'parent',
- })
- try {
- names.bind(rootSession, activation.childId, reservation.name)
- } catch (cause: unknown) {
- throw new HarnessError(
- `Subagent ${activation.childId} started, but its name ${reservation.name} could not be recorded. `
- + 'Its execution is still managed by the subagent service. Check this child before retrying.',
- 'SUBAGENT_NAME_BIND_FAILED', { cause },
- )
- }
- return { kind: 'activation' as const, subagentId: activation.childId, name: reservation.name }
- } finally {
- reservation.dispose()
- }
+ const activation = await ctx.subagents.startActivation({
+ provider: providerName,
+ label: args.description,
+ parent,
+ prompt: [{ type: 'text', text: args.prompt }],
+ ...args.cwd === undefined ? {} : { cwd: args.cwd },
+ signal: exec.signal,
+ delivery: 'parent',
+ })
+ return { kind: 'activation' as const, subagentId: activation.childId }
},
presentCall: args => ({ card: 'generic', title: args.description, rawInput: args }),
}))
diff --git a/packages/experimental/tool-subagent-oar/tests/tool-subagent-oar.spec.ts b/packages/experimental/tool-subagent-oar/tests/tool-subagent-oar.spec.ts
index 7053d28ff0..62bc37dee4 100644
--- a/packages/experimental/tool-subagent-oar/tests/tool-subagent-oar.spec.ts
+++ b/packages/experimental/tool-subagent-oar/tests/tool-subagent-oar.spec.ts
@@ -7,9 +7,8 @@ import { mountAgentLoopTestDependencies, mountAgentLoopTestHarness } from '@deep
import { ToolCallId } from '@deepseek-ai/dsh-llm'
import { SessionId } from '@deepseek-ai/dsh-session'
import SubagentRuntime, { NO_START_CAPABILITIES } from '@deepseek-ai/dsh-subagent'
-import SubagentNames from '@deepseek-ai/dsh-subagent-names'
-import type { ResolvedSubagentStartRequest, SubagentResult, SubagentRun } from '@deepseek-ai/dsh-subagent'
-import { expect, it, vi } from 'vitest'
+import type { ResolvedSubagentStartRequest } from '@deepseek-ai/dsh-subagent'
+import { expect, it } from 'vitest'
import { mountWorkingDirectoryFixture } from '../../../subagent/subagent/tests/working-directory-fixture.ts'
import * as externalTool from '../src/index.ts'
@@ -19,16 +18,14 @@ async function setup() {
const harness = await mountAgentLoopTestHarness(ctx)
await mountWorkingDirectoryFixture(ctx)
await ctx.plugin(SubagentRuntime)
- await ctx.plugin(SubagentNames)
- const calls: { id: SessionId; provider: string; request: ResolvedSubagentStartRequest }[] = []
+ const calls: { provider: string; request: ResolvedSubagentStartRequest }[] = []
for (const name of ['codex-provider', 'claude-provider', 'future-provider']) {
ctx.subagents.registerProvider({
name, capabilities: NO_START_CAPABILITIES, inheritsParentContext: false,
start: async (request) => {
- const id = SessionId(randomUUID())
- calls.push({ id, provider: name, request })
+ calls.push({ provider: name, request })
return {
- id,
+ id: SessionId(randomUUID()),
result: Promise.resolve({ output: [{ type: 'text' as const, text: 'child result' }], stopReason: 'completed' as const }),
dispose: () => Promise.resolve(),
}
@@ -47,22 +44,22 @@ it('selects one configured provider per call and exposes only task inputs', asyn
})
const schema = ctx.tools.schemas().find(tool => tool.name === 'subagent_oar')
expect(schema?.parameters.required).toEqual(['runtime', 'description', 'prompt'])
- expect(Object.keys(schema?.parameters.properties as Record).sort()).toEqual(['cwd', 'description', 'name', 'prompt', 'runtime'])
+ expect(Object.keys(schema?.parameters.properties as Record).sort()).toEqual(['cwd', 'description', 'prompt', 'runtime'])
expect(schema?.parameters.properties).toMatchObject({ runtime: { enum: ['codex', 'claude', 'future'] } })
- for (const [index, runtime] of ['codex', 'claude', 'future'].entries()) {
+ for (const runtime of ['codex', 'claude', 'future']) {
const result = await executeToolFixture(ctx, {
agent: parent, name: 'subagent_oar', signal: test.signal,
callId: ToolCallId(randomUUID()),
arguments: { runtime, description: `Use ${runtime}`, prompt: 'independent task' },
})
expect(result.isError, JSON.stringify(result.content)).toBe(false)
- expect(result.value).toEqual({ kind: 'activation', subagentId: calls[index]?.id, name: `lead/agent-${index + 1}` })
- expect(result.content).toEqual([{ type: 'text', text: `started subagent ${calls[index]?.id}\nname: lead/agent-${index + 1}` }])
+ expect(result.content).toHaveLength(1)
+ const content = result.content[0]
+ expect(content?.type).toBe('text')
+ if (content?.type === 'text') expect(content.text).toMatch(/^started subagent /u)
}
expect(calls.map(call => call.provider)).toEqual(['codex-provider', 'claude-provider', 'future-provider'])
- expect(calls[0]?.request.prompt).toEqual([
- { type: 'text', text: 'independent task' },
- ])
+ expect(calls[0]?.request.prompt).toEqual([{ type: 'text', text: 'independent task' }])
expect(calls[0]?.request.parent).toBe(parent)
expect(calls[0]?.request.cwd).toBe(process.cwd())
expect(ctx.tools.get('subagent_oar')?.isConcurrencySafe?.({
@@ -116,7 +113,7 @@ it('requires a caller and independently scoped one-shot providers', async (test)
start: async () => { throw new Error('must not run') },
})
await ctx.plugin(externalTool, { providers: { inherited: 'inherited' } })
- const args = { name: 'inspector', runtime: 'inherited', description: 'task', prompt: 'task' }
+ const args = { runtime: 'inherited', description: 'task', prompt: 'task' }
const noParent = await executeToolFixture(ctx, {
name: 'subagent_oar', arguments: args, callId: ToolCallId(randomUUID()), signal: test.signal,
})
@@ -132,7 +129,7 @@ it('passes an explicit child directory and presents the task description', async
const { ctx, parent, calls } = await setup()
test.onTestFinished(() => ctx.fiber.dispose())
await ctx.plugin(externalTool, { providers: { codex: 'codex-provider' } })
- const args = { name: 'inspector', runtime: 'codex', description: 'Inspect child', prompt: 'task', cwd: 'packages' }
+ const args = { runtime: 'codex', description: 'Inspect child', prompt: 'task', cwd: 'packages' }
expect(ctx.tools.get('subagent_oar')?.presentCall?.(args)).toEqual({
card: 'generic', title: 'Inspect child', rawInput: args,
})
@@ -140,8 +137,6 @@ it('passes an explicit child directory and presents the task description', async
agent: parent, name: 'subagent_oar', arguments: args, callId: ToolCallId(randomUUID()), signal: test.signal,
})
expect(result.isError).toBe(false)
- expect(result.content).toEqual([{ type: 'text', text: `started subagent ${calls[0]?.id}\nname: lead/inspector` }])
- expect(result.value).toEqual({ kind: 'activation', subagentId: calls[0]?.id, name: 'lead/inspector' })
expect(calls[0]?.request.cwd).toBe(join(process.cwd(), 'packages'))
})
@@ -151,69 +146,3 @@ it('supports direct composition with the declared optional defaults', async (tes
externalTool.apply(ctx, { providers: { codex: 'codex-provider' } })
expect(ctx.tools.schemas().some(tool => tool.name === 'subagent_oar')).toBe(true)
})
-
-it('releases the requested name when provider startup fails', async (test) => {
- const { ctx, parent } = await setup()
- test.onTestFinished(() => ctx.fiber.dispose())
- const childId = SessionId(randomUUID())
- const start = vi.fn<() => Promise>()
- .mockRejectedValueOnce(new Error('provider startup failed'))
- .mockResolvedValueOnce({
- id: childId,
- result: Promise.resolve({ output: [], stopReason: 'completed' }),
- dispose: async () => {},
- })
- ctx.subagents.registerProvider({
- name: 'retry-provider', capabilities: NO_START_CAPABILITIES, inheritsParentContext: false, start,
- })
- await ctx.plugin(externalTool, { providers: { retry: 'retry-provider' } })
- const args = { name: 'inspector', runtime: 'retry', description: 'task', prompt: 'task' }
- const failed = await executeToolFixture(ctx, {
- agent: parent, name: 'subagent_oar', arguments: args, callId: ToolCallId(randomUUID()), signal: test.signal,
- })
- expect(failed.isError).toBe(true)
- expect(failed.error?.message).toContain('provider startup failed')
- const retried = await executeToolFixture(ctx, {
- agent: parent, name: 'subagent_oar', arguments: args, callId: ToolCallId(randomUUID()), signal: test.signal,
- })
- expect(retried.isError, JSON.stringify(retried.content)).toBe(false)
- expect(retried.value).toEqual({ kind: 'activation', subagentId: childId, name: 'lead/inspector' })
- expect(start).toHaveBeenCalledTimes(2)
-})
-
-it('reports the accepted child id without stopping it when name binding fails', async (test) => {
- const { ctx, parent } = await setup()
- const childId = SessionId(randomUUID())
- const childResult = Promise.withResolvers()
- let childRequest: ResolvedSubagentStartRequest | undefined
- const dispose = vi.fn(async () => { childResult.resolve({ output: [], stopReason: 'aborted' }) })
- const bind = vi.spyOn(ctx.subagentNames, 'bind').mockImplementationOnce(() => { throw new Error('session append failed') })
- test.onTestFinished(async () => {
- bind.mockRestore()
- childResult.resolve({ output: [], stopReason: 'completed' })
- await ctx.fiber.dispose()
- })
- ctx.subagents.registerProvider({
- name: 'pending-provider', capabilities: NO_START_CAPABILITIES, inheritsParentContext: false,
- start: async (request) => {
- childRequest = request
- return { id: childId, result: childResult.promise, dispose }
- },
- })
- await ctx.plugin(externalTool, { providers: { pending: 'pending-provider' } })
- const result = await executeToolFixture(ctx, {
- agent: parent, name: 'subagent_oar', callId: ToolCallId(randomUUID()), signal: test.signal,
- arguments: { name: 'inspector', runtime: 'pending', description: 'task', prompt: 'task' },
- })
- expect(result.isError).toBe(true)
- expect(result.error?.info?.code).toBe('SUBAGENT_NAME_BIND_FAILED')
- expect(result.error?.message).toContain(`Subagent ${childId} started, but its name lead/inspector could not be recorded.`)
- expect(result.error?.message).toContain('Check this child before retrying.')
- expect(dispose).not.toHaveBeenCalled()
- expect(childRequest?.signal.aborted).toBe(false)
- const reservation = ctx.subagentNames.reserve(parent.session, parent.id, 'inspector')
- expect(reservation.name).toBe('lead/inspector')
- reservation.dispose()
- childResult.resolve({ output: [{ type: 'text', text: 'child finished' }], stopReason: 'completed' })
- await expect.poll(() => dispose.mock.calls.length).toBe(1)
-})
diff --git a/packages/experimental/tool-subagent-oar/tsconfig.json b/packages/experimental/tool-subagent-oar/tsconfig.json
index 2aec884c01..e7e2ee8f91 100644
--- a/packages/experimental/tool-subagent-oar/tsconfig.json
+++ b/packages/experimental/tool-subagent-oar/tsconfig.json
@@ -17,14 +17,8 @@
{
"path": "../../core/tools"
},
- {
- "path": "../../llm/llm"
- },
{
"path": "../../subagent/subagent"
- },
- {
- "path": "../../subagent/subagent-names"
}
]
}
diff --git a/packages/extensions/tool-cordis/src/api-catalog.ts b/packages/extensions/tool-cordis/src/api-catalog.ts
index 3b6991921a..2be3b830a9 100644
--- a/packages/extensions/tool-cordis/src/api-catalog.ts
+++ b/packages/extensions/tool-cordis/src/api-catalog.ts
@@ -3595,36 +3595,6 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
description: 'Host settings owner that records Session authorization before the first model request.',
methods: [],
},
- {
- key: 'subagentNames',
- summary: 'Root-Session aliases shared by named creation, discovery, and control tools.',
- description: 'Root-Session aliases shared by named creation, discovery, and control tools.',
- methods: [
- {
- signature: 'reserve(rootSession: Session, parentId: SessionId, requested?: string): SubagentNameReservation',
- description: 'Reserve a complete name without starting an agent or writing a Session event.',
- parameters: [{ name: 'rootSession', description: 'root Session selected by the caller through the subagent service.' }, { name: 'parentId', description: 'parent identity whose name prefixes the child name.' }, { name: 'requested', description: 'optional sibling segment; omission selects the first free agent-N.' }],
- returns: 'a reservation the caller must dispose after startup and binding.',
- },
- {
- signature: 'bind(rootSession: Session, childId: SessionId, name: string): void',
- description: 'Record an accepted child\'s full name in the caller\'s root Session. Binding failure does not cancel or dispose the child; callers report its id.',
- parameters: [{ name: 'rootSession', description: 'root Session selected by the caller through the subagent service.' }, { name: 'childId', description: 'identity returned by the subagent service.' }, { name: 'name', description: 'complete name returned by reserve.' }],
- },
- {
- signature: 'nameOf(rootSession: Session, targetId: SessionId): string',
- description: 'Read a bound name from the root projection without loading ancestors.',
- parameters: [{ name: 'rootSession', description: 'root Session selected by the caller through the subagent service.' }, { name: 'targetId', description: 'identity whose name is requested.' }],
- returns: 'lead for the root, a bound full name, or the unchanged id.',
- },
- {
- signature: 'resolveName(rootSession: Session, name: string): SessionId',
- description: 'Resolve an alias or pass through an id for the subagent service to authorize.',
- parameters: [{ name: 'rootSession', description: 'root Session selected by the caller through the subagent service.' }, { name: 'name', description: 'lead, a bound full name, or a raw Session id.' }],
- returns: 'the target identity; an unknown lead/... name throws.',
- },
- ],
- },
{
key: 'subagents',
summary: 'Named provider registry with managed activations, durable discovery, and local child messaging.',
@@ -3663,7 +3633,7 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
},
{
signature: 'async sendMessage( sender: Agent, targetId: SessionId, content: ContentBlock[], options: SubagentSendMessageOptions, ): Promise',
- description: 'Steer one model-authored message to another member of the same subagent tree. A running target receives it at its next step; an idle target starts a turn. A cold target resumes under its runtime subagent tree root without restoring its creation ancestors. Sender identity is rechecked before inbox acceptance; cancellation stops only pre-acceptance work and never retracts an accepted message. Display attribution uses the sender\'s bound name when the naming service is mounted, otherwise its Session id. Name lookup failures reject before inbox acceptance.',
+ description: 'Steer one model-authored message to another member of the same subagent tree. A running target receives it at its next step; an idle target starts a turn. A cold target resumes under its runtime subagent tree root without restoring its creation ancestors. Sender identity is rechecked before inbox acceptance; cancellation stops only pre-acceptance work and never retracts an accepted message.',
parameters: [{ name: 'sender', description: 'exact live root or resident continuable Agent originating the message.' }, { name: 'targetId', description: 'another root or continuable member\'s durable Session id.' }, { name: 'content', description: 'model-authored content to deliver.' }, { name: 'options', description: 'caller cancellation before inbox acceptance.' }],
returns: 'the accepted message\'s inbox id.',
throws: ['when the target is outside the tree, cannot resume, or rejects input.'],
@@ -9095,10 +9065,6 @@ export const TYPE_API: readonly TypeApiEntry[] = [
name: 'SubagentListEntry',
declaration: 'export type SubagentListEntry = SubagentCatalogRow & {\n readonly kind: \'child\';\n readonly hasChildren: boolean;\n} | {\n readonly kind: \'diagnostic\';\n readonly id: SessionId;\n readonly reason: \'corrupt\' | \'unsupported\' | \'unavailable\';\n};',
},
- {
- name: 'SubagentNameReservation',
- declaration: 'export interface SubagentNameReservation {\n readonly name: string;\n dispose(): void;\n}',
- },
{
name: 'SubagentPromptReceipt',
declaration: 'export interface SubagentPromptReceipt {\n readonly messageId: MessageId;\n}',
diff --git a/packages/preset/agent-preset/skills/cordis-composition-reference/references/packages.md b/packages/preset/agent-preset/skills/cordis-composition-reference/references/packages.md
index 2dcec77bdc..f3abca5fc4 100644
--- a/packages/preset/agent-preset/skills/cordis-composition-reference/references/packages.md
+++ b/packages/preset/agent-preset/skills/cordis-composition-reference/references/packages.md
@@ -466,7 +466,6 @@ Every package below exports a Cordis plugin that a bundle patch can name in a Lo
| `@deepseek-ai/dsh-subagent-codex` | yes | One-shot Codex subagent provider over the official app-server protocol |
| `@deepseek-ai/dsh-subagent-dsh-sdk` | yes | Out-of-process SDK subagent backend: drives a child DeepSeek Harness runtime subprocess over stdio JSON-RPC through the TypeScript SDK client |
| `@deepseek-ai/dsh-subagent-fork-in-process` | yes | In-process fork subagent backend: runs a child agent seeded with a prefix of the parent's log |
-| `@deepseek-ai/dsh-subagent-names` | no | Durable name mappings for subagent tools |
| `@deepseek-ai/dsh-subagent-spawn-in-process` | yes | In-process spawn subagent backend: runs a fresh child agent on ctx.agents |
| `@deepseek-ai/dsh-tool-subagent` | yes | Model-facing subagent delegation tool over the ctx.subagents seam |
| `@deepseek-ai/dsh-tool-subagent-control` | yes | Shared messaging, interruption, and child discovery tools for subagents |
diff --git a/packages/sdk/server/README.i18n.yaml b/packages/sdk/server/README.i18n.yaml
index e08184697e..fcc20f3d98 100644
--- a/packages/sdk/server/README.i18n.yaml
+++ b/packages/sdk/server/README.i18n.yaml
@@ -15,8 +15,8 @@
en: d152484eb41ac6b4
zh: 09388d293f9be9cb
/deepseek-ai-dsh-sdk-jsonrpc-server/use-this-package:
- en: 364c47155e5687be
- zh: 7322c098fc8f23c5
+ en: 1a8598a9ca7ec995
+ zh: dbbd0dd3aecb7d24
/deepseek-ai-dsh-sdk-jsonrpc-server/use-this-package/wiring:
en: 47a33e9397e36e15
zh: e6d173820f9ea6e5
diff --git a/packages/sdk/server/README.md b/packages/sdk/server/README.md
index 7ecc0232a4..b2fe1e211a 100644
--- a/packages/sdk/server/README.md
+++ b/packages/sdk/server/README.md
@@ -27,7 +27,7 @@ English | [中文](README.zh.md)
Mount this plugin when a runtime must serve SDK clients: add it to a `cordis.yml` that composes the agent service, boot the runtime, and clients connect over stdio. The common path is explicit — the plugin needs the `agents` service; every other capability comes from the surrounding tree.
-Set `initialize.approvalRequests` to `true` to send internal approvals as server-to-client `approval/request` calls. The bridge handles SDK-owned Agents and their live in-process descendants, resolving descendants through `subagents.rootOf()` and matching the exact SDK-owned root instance. Persisted `parentSession` lineage does not establish approval ownership. Unrelated Agents and clients that omit the flag continue through the composed answerer chain. The approval service still applies `never` policy before dispatch and records the ask/decision audit pair. The bridge accepts only `allowed-once`, `rejected`, or `cancelled`; an invalid response, client error, or transport loss yields the service's fail-closed `unavailable` outcome. Request cancellation abandons the pending wire waiter; shutdown abandons all such waiters before draining Agents. Late replies cannot grant an abandoned operation. See the [protocol](../protocol/README.md) for the payload and the [Python example](../../../python/sdk/README.md#client-approvals) for client handling.
+Set `initialize.approvalRequests` to `true` to send internal approvals as server-to-client `approval/request` calls. The bridge handles SDK-owned Agents and their live in-process descendants, resolving descendants through `subagents.rootOf()` and matching the exact SDK-owned root instance. Persisted `parentSession` lineage does not establish approval ownership. A root lookup error with `name: SubagentError` and `code: UNAUTHORIZED` delegates to the next answerer regardless of its constructor; other lookup failures yield `unavailable` without delegation. Unrelated Agents and clients that omit the flag continue through the composed answerer chain. The approval service still applies `never` policy before dispatch and records the ask/decision audit pair. The bridge accepts only `allowed-once`, `rejected`, or `cancelled`; an invalid response, client error, or transport loss yields the service's fail-closed `unavailable` outcome. Request cancellation abandons the pending wire waiter; shutdown abandons all such waiters before draining Agents. Late replies cannot grant an abandoned operation. See the [protocol](../protocol/README.md) for the payload and the [Python example](../../../python/sdk/README.md#client-approvals) for client handling.
`session/resume` accepts a persisted `{ sessionId }` after initialization and returns `{}` once its Agent is ready. It loads history through `agents.resume()`, repairs an interrupted final turn, and preserves the stored origin and effective directory while recording the initialized model route as the Session selection. An omitted effort preserves an explicit saved effort only for that same route. It sends no new input. Subagent sessions reject before loading or repairing history; resume their root session instead. Missing, unreadable, incompatible, or occupied sessions reject without creating a replacement. Prompts for an identity currently being restored wait for that restoration; shutdown drains pending restoration and releases its Agent. Historical events are retained in the log rather than streamed again as new notifications. A model selection recorded during resume emits a new `session.event` notification before the resume response.
diff --git a/packages/sdk/server/README.zh.md b/packages/sdk/server/README.zh.md
index b27805dae8..ac9bc98399 100644
--- a/packages/sdk/server/README.zh.md
+++ b/packages/sdk/server/README.zh.md
@@ -27,7 +27,7 @@ kind: "package-reference"
当运行时必须服务 SDK 客户端时挂载本插件:把它加入组合了 agent 服务的 `cordis.yml`,启动运行时,客户端即可通过 stdio 连接。常用路径是显式的——插件需要 `agents` 服务;其余每个能力都来自外围插件树。
-将 `initialize.approvalRequests` 设为 `true`,即可把内部审批作为服务端到客户端的 `approval/request` 请求发送。桥接处理 SDK 拥有的 Agent 及其仍在运行的进程内后代,通过 `subagents.rootOf()` 解析后代的根,并与 SDK 拥有的确切根实例匹配,持久化的 `parentSession` 历史关系不决定审批归属;其他 Agent,以及未提供该标志的客户端,继续使用已组合的应答链。审批服务仍在分发前执行 `never` 策略,并记录询问与决定的审计事件。桥接仅接受 `allowed-once`、`rejected` 或 `cancelled`;无效响应、客户端错误或传输断开会产生审批服务的拒绝放行结果 `unavailable`。请求取消时释放待处理的协议等待项;shutdown 在等待 Agent 结束前释放所有此类等待项。迟到响应不能授权已放弃的操作。载荷见[协议](../protocol/README.zh.md),客户端处理见 [Python 示例](../../../python/sdk/README.zh.md#client-approvals)。
+将 `initialize.approvalRequests` 设为 `true`,即可把内部审批作为服务端到客户端的 `approval/request` 请求发送。桥接处理 SDK 拥有的 Agent 及其仍在运行的进程内后代,通过 `subagents.rootOf()` 解析后代的根,并与 SDK 拥有的确切根实例匹配,持久化的 `parentSession` 历史关系不决定审批归属。根查找错误的 `name: SubagentError` 与 `code: UNAUTHORIZED` 同时匹配时,无论其构造器是什么,均委派给下一个应答方;其他查找失败返回 `unavailable`,不继续委派。其他 Agent,以及未提供该标志的客户端,继续使用已组合的应答链。审批服务仍在分发前执行 `never` 策略,并记录询问与决定的审计事件。桥接仅接受 `allowed-once`、`rejected` 或 `cancelled`;无效响应、客户端错误或传输断开会产生审批服务的拒绝放行结果 `unavailable`。请求取消时释放待处理的协议等待项;shutdown 在等待 Agent 结束前释放所有此类等待项。迟到响应不能授权已放弃的操作。载荷见[协议](../protocol/README.zh.md),客户端处理见 [Python 示例](../../../python/sdk/README.zh.md#client-approvals)。
`session/resume` 在初始化后接受持久化的 `{ sessionId }`,待其 Agent 就绪后返回 `{}`。它通过 `agents.resume()` 加载历史、修复最后一个被中断的轮次,并保留存储的起始目录和当前有效目录,同时将初始化时选定的模型路由记录为 Session 选择。省略推理强度时,仅在路由相同的情况下保留已保存的显式强度。它不发送新输入。子代理会话在加载或修复历史前被拒绝;应恢复其根会话。会话缺失、不可读、不兼容或被占用时,请求失败且不创建替代会话。对正在恢复的标识发送提示词时,会等待恢复完成;shutdown 会等待进行中的恢复并释放其 Agent。历史事件保留在日志中,不会作为新通知重新发送。恢复期间记录的模型选择会在恢复响应前发出新的 `session.event` 通知。
diff --git a/packages/sdk/server/src/server.ts b/packages/sdk/server/src/server.ts
index 06c28d220c..bccfa6634e 100644
--- a/packages/sdk/server/src/server.ts
+++ b/packages/sdk/server/src/server.ts
@@ -21,7 +21,7 @@ import type {} from '@deepseek-ai/dsh-working-directory'
import type {} from '@deepseek-ai/dsh-user-approval'
import type {} from '@deepseek-ai/dsh-schedule'
-import { SubagentError, type SubagentRunEndInfo } from '@deepseek-ai/dsh-subagent'
+import type { SubagentRunEndInfo } from '@deepseek-ai/dsh-subagent'
import * as LlmDeepSeek from '@deepseek-ai/dsh-llm-deepseek-api-key'
import type {
ApprovalRequestParams,
@@ -382,6 +382,11 @@ export class HarnessSdkJsonRpcServer {
}
}
+ /**
+ * Resolves live SDK ownership; root lookup failures other than SubagentError/UNAUTHORIZED propagate.
+ * @param agent - Agent whose requests need routing.
+ * @returns Whether this server owns the Agent or its live subagent tree root.
+ */
private ownsAgent(agent: Agent): boolean {
const agents = this.ctx.agents
if (agents.get(agent.id) !== agent) return false
@@ -392,7 +397,9 @@ export class HarnessSdkJsonRpcServer {
try {
root = subagents.rootOf(agent)
} catch (error: unknown) {
- if (error instanceof SubagentError && error.code === 'UNAUTHORIZED') return false
+ if (typeof error === 'object' && error !== null
+ && 'name' in error && error.name === 'SubagentError'
+ && 'code' in error && error.code === 'UNAUTHORIZED') return false
throw error
}
return this.sessions.get(root.session.id)?.handle.agent === root
diff --git a/packages/sdk/server/tests/approval.spec.ts b/packages/sdk/server/tests/approval.spec.ts
index 9272bc4265..e3436587c5 100644
--- a/packages/sdk/server/tests/approval.spec.ts
+++ b/packages/sdk/server/tests/approval.spec.ts
@@ -237,8 +237,30 @@ describe('SDK approval bridge', () => {
expect(clientDecision).not.toHaveBeenCalled()
})
+ it.each([
+ { name: 'SubagentError', code: 'UNAUTHORIZED' },
+ Object.assign(new Error('not a managed subagent'), { name: 'SubagentError', code: 'UNAUTHORIZED' }),
+ ])('delegates approval for an unauthorized ownership lookup by error fields: %s', async (error) => {
+ const h = await setup(true, true)
+ const foreign = await h.ctx.agents.create({ sessionId: SessionId('foreign') })
+ onTestFinished(() => foreign.dispose())
+ foreign.agent.session.append('turn/start', { turn: 1 })
+ vi.spyOn(h.ctx.subagents, 'rootOf').mockImplementationOnce(() => { throw error })
+ const clientDecision = vi.fn(async () => ({ outcome: 'allowed-once' }))
+ h.client.onRequest(clientDecision)
+ const fallback = vi.fn(() => Promise.resolve('rejected' as const))
+ h.ctx.on('approval/request', fallback)
+ await expect(h.ctx.approval.request({ agent: foreign.agent, toolName: 'bash' })).resolves.toBe('rejected')
+ expect(fallback).toHaveBeenCalledOnce()
+ expect(clientDecision).not.toHaveBeenCalled()
+ })
+
it.each([
new Error('root lookup failed'), new SubagentError('root lookup failed', 'NOT_RESUMABLE'),
+ null, undefined, 'root lookup failed', {},
+ { name: 'SubagentError' }, { code: 'UNAUTHORIZED' },
+ { name: 'OtherError', code: 'UNAUTHORIZED' },
+ { name: 'SubagentError', code: 'NOT_RESUMABLE' },
])('does not pass a failed ownership lookup to another approval answerer: %s', async (error) => {
const h = await setup(true, true)
const foreign = await h.ctx.agents.create({ sessionId: SessionId('foreign') })
diff --git a/packages/subagent/README.i18n.yaml b/packages/subagent/README.i18n.yaml
index 6f9754b820..c69de6ed65 100644
--- a/packages/subagent/README.i18n.yaml
+++ b/packages/subagent/README.i18n.yaml
@@ -15,8 +15,8 @@
en: 1eb35b015a6c423f
zh: a8a3dceee2c9e943
/subagent-subagent-capability-family/packages:
- en: 65ac5ca8f6108b9a
- zh: 35a61d1049a5b5d5
+ en: 6e34528cfd8a3b2c
+ zh: 88655c4fbe96c861
/subagent-subagent-capability-family/related-documentation:
en: e525958323eebabe
zh: d32725ee5393ad33
diff --git a/packages/subagent/README.md b/packages/subagent/README.md
index 7c5cb6f68b..e030cf9a78 100644
--- a/packages/subagent/README.md
+++ b/packages/subagent/README.md
@@ -25,7 +25,6 @@ The subagent package family lets an agent delegate a task to a child, continue t
| Package | Role | ctx key |
|---|---|---|
| [`subagent/`](subagent/README.md) | Defines the delegation service: provider registry, one-shot runs, continuable children, and discovery | `ctx.subagents` |
-| [`subagent-names/`](subagent-names/README.md) | Adds optional names to delegation and control tools without changing the execution service | `ctx.subagentNames` |
| [`subagent-spawn-in-process/`](subagent-spawn-in-process/README.md) | Runs a fresh in-process child | registers on `ctx.subagents` |
| [`subagent-fork-in-process/`](subagent-fork-in-process/README.md) | Runs an in-process child seeded from the parent's completed history | registers on `ctx.subagents` |
| [`subagent-acp/`](subagent-acp/README.md) | Runs an out-of-process child over the Agent Client Protocol | registers on `ctx.subagents` |
diff --git a/packages/subagent/README.zh.md b/packages/subagent/README.zh.md
index d449af3e43..4f501d2ee9 100644
--- a/packages/subagent/README.zh.md
+++ b/packages/subagent/README.zh.md
@@ -25,7 +25,6 @@ subagent 包家族让 agent(智能体)将任务委派给子 agent、继续
| 包 | 职责 | ctx 键 |
|---|---|---|
| [`subagent/`](subagent/README.zh.md) | 定义委派服务:提供方注册表、一次性运行、可继续子级与发现 | `ctx.subagents` |
-| [`subagent-names/`](subagent-names/README.zh.md) | 为委派和控制工具添加可选名字,保持执行服务不变 | `ctx.subagentNames` |
| [`subagent-spawn-in-process/`](subagent-spawn-in-process/README.zh.md) | 运行全新的进程内子 agent | 注册到 `ctx.subagents` |
| [`subagent-fork-in-process/`](subagent-fork-in-process/README.zh.md) | 运行从父级已完成历史派生的进程内子 agent | 注册到 `ctx.subagents` |
| [`subagent-acp/`](subagent-acp/README.zh.md) | 经 Agent Client Protocol 运行进程外子 agent | 注册到 `ctx.subagents` |
diff --git a/packages/subagent/subagent-acp/tests/fixtures/loader/mock-delegating-llm.ts b/packages/subagent/subagent-acp/tests/fixtures/loader/mock-delegating-llm.ts
index f07a34b9c3..d1e51f5ee5 100644
--- a/packages/subagent/subagent-acp/tests/fixtures/loader/mock-delegating-llm.ts
+++ b/packages/subagent/subagent-acp/tests/fixtures/loader/mock-delegating-llm.ts
@@ -14,7 +14,7 @@ class MockDelegatingAdapter extends LlmAdapter {
: ''
if (!options.messages.some(message => message.role === 'tool')) {
- const args = JSON.stringify({ name: 'cwd-probe', description: 'cwd probe', prompt: 'report your workspace' })
+ const args = JSON.stringify({ description: 'cwd probe', prompt: 'report your workspace' })
yield { type: 'block-start', index: 0, blockType: 'tool-call' }
yield { type: 'tool-call-delta', index: 0, id: ToolCallId('call-delegate'), name: 'subagent', argumentsDelta: args }
yield { type: 'block-end', index: 0, block: { type: 'tool-call', id: ToolCallId('call-delegate'), name: 'subagent', arguments: args } }
diff --git a/packages/subagent/subagent-acp/tests/loader-composition.e2e.ts b/packages/subagent/subagent-acp/tests/loader-composition.e2e.ts
index cf63acbbbe..7d32f04fee 100644
--- a/packages/subagent/subagent-acp/tests/loader-composition.e2e.ts
+++ b/packages/subagent/subagent-acp/tests/loader-composition.e2e.ts
@@ -43,7 +43,7 @@ function settlementText(events: SessionEvent[]): string[] {
const notice = notices[0]!
if (notice.type !== 'user/message' || notice.data.source.kind !== 'subagent-settled') throw new Error('missing completion notice')
expect(results[0]!.data.message.content).toEqual([
- { type: 'text', text: `started subagent ${notice.data.source.senderSessionId}\nname: lead/cwd-probe` },
+ { type: 'text', text: `started subagent ${notice.data.source.senderSessionId}` },
])
return notice.data.content.slice(1).filter(block => block.type === 'text').map(block => block.text)
}
diff --git a/packages/subagent/subagent-claude-code/tests/loader-composition.e2e.ts b/packages/subagent/subagent-claude-code/tests/loader-composition.e2e.ts
index 6c3234b2f8..26543fb219 100644
--- a/packages/subagent/subagent-claude-code/tests/loader-composition.e2e.ts
+++ b/packages/subagent/subagent-claude-code/tests/loader-composition.e2e.ts
@@ -79,22 +79,22 @@ describe('product-provider public Loader composition', () => {
tools: [
{
name: 'subagent_codex',
- parameterNames: ['cwd', 'description', 'name', 'prompt'],
+ parameterNames: ['cwd', 'description', 'prompt'],
required: ['description', 'prompt'],
},
{
name: 'subagent_claude_code',
- parameterNames: ['cwd', 'description', 'name', 'prompt'],
+ parameterNames: ['cwd', 'description', 'prompt'],
required: ['description', 'prompt'],
},
{
name: 'subagent_claude_primary',
- parameterNames: ['cwd', 'description', 'name', 'prompt'],
+ parameterNames: ['cwd', 'description', 'prompt'],
required: ['description', 'prompt'],
},
{
name: 'subagent_claude_secondary',
- parameterNames: ['cwd', 'description', 'name', 'prompt'],
+ parameterNames: ['cwd', 'description', 'prompt'],
required: ['description', 'prompt'],
},
],
diff --git a/packages/subagent/subagent-codex/tests/loader-composition.e2e.ts b/packages/subagent/subagent-codex/tests/loader-composition.e2e.ts
index e77ad6cd73..a9972381ae 100644
--- a/packages/subagent/subagent-codex/tests/loader-composition.e2e.ts
+++ b/packages/subagent/subagent-codex/tests/loader-composition.e2e.ts
@@ -69,17 +69,17 @@ describe('Codex provider public Loader composition', () => {
tools: [
{
name: 'subagent_codex',
- parameterNames: ['cwd', 'description', 'name', 'prompt'],
+ parameterNames: ['cwd', 'description', 'prompt'],
required: ['description', 'prompt'],
},
{
name: 'subagent_codex_primary',
- parameterNames: ['cwd', 'description', 'name', 'prompt'],
+ parameterNames: ['cwd', 'description', 'prompt'],
required: ['description', 'prompt'],
},
{
name: 'subagent_codex_secondary',
- parameterNames: ['cwd', 'description', 'name', 'prompt'],
+ parameterNames: ['cwd', 'description', 'prompt'],
required: ['description', 'prompt'],
},
],
diff --git a/packages/subagent/subagent-dsh-sdk/tests/fixtures/loader/mock-delegating-llm.ts b/packages/subagent/subagent-dsh-sdk/tests/fixtures/loader/mock-delegating-llm.ts
index d15aa1a5a4..dee4ac0f45 100644
--- a/packages/subagent/subagent-dsh-sdk/tests/fixtures/loader/mock-delegating-llm.ts
+++ b/packages/subagent/subagent-dsh-sdk/tests/fixtures/loader/mock-delegating-llm.ts
@@ -33,7 +33,6 @@ class MockDelegatingAdapter extends LlmAdapter {
? { reasoning_effort: 'max' }
: { provider: 'mock', model: 'mock-routed', reasoning_effort: 'max' }
const args = JSON.stringify({
- name: 'route-probe',
description: 'route probe',
prompt: 'report your route and workspace',
...selectedRoute,
diff --git a/packages/subagent/subagent-dsh-sdk/tests/fixtures/loader/nested-mock-llm.ts b/packages/subagent/subagent-dsh-sdk/tests/fixtures/loader/nested-mock-llm.ts
index d17f64b048..25748da58a 100644
--- a/packages/subagent/subagent-dsh-sdk/tests/fixtures/loader/nested-mock-llm.ts
+++ b/packages/subagent/subagent-dsh-sdk/tests/fixtures/loader/nested-mock-llm.ts
@@ -20,7 +20,7 @@ class NestedAdapter extends LlmAdapter {
}
answer = 'nested child result'
} else if (!options.messages.some(message => message.role === 'tool')) {
- const args = JSON.stringify({ name: 'nested-fork', description: 'nested fork', prompt: 'nested-child-task' })
+ const args = JSON.stringify({ description: 'nested fork', prompt: 'nested-child-task' })
const id = ToolCallId('nested-fork')
yield { type: 'block-start', index: 0, blockType: 'tool-call' }
yield { type: 'tool-call-delta', index: 0, id, name: 'subagent_fork', argumentsDelta: args }
diff --git a/packages/subagent/subagent-dsh-sdk/tests/loader-composition.e2e.ts b/packages/subagent/subagent-dsh-sdk/tests/loader-composition.e2e.ts
index 9a10d66ed2..3e8b4c2b4d 100644
--- a/packages/subagent/subagent-dsh-sdk/tests/loader-composition.e2e.ts
+++ b/packages/subagent/subagent-dsh-sdk/tests/loader-composition.e2e.ts
@@ -47,7 +47,7 @@ function settlementText(events: SessionEvent[]): string[] {
const notice = notices[0]!
if (notice.type !== 'user/message' || notice.data.source.kind !== 'subagent-settled') throw new Error('missing completion notice')
expect(results[0]!.data.message.content).toEqual([
- { type: 'text', text: `started subagent ${notice.data.source.senderSessionId}\nname: lead/route-probe` },
+ { type: 'text', text: `started subagent ${notice.data.source.senderSessionId}` },
])
return notice.data.content.slice(1).filter(block => block.type === 'text').map(block => block.text)
}
diff --git a/packages/subagent/subagent-names/README.i18n.yaml b/packages/subagent/subagent-names/README.i18n.yaml
deleted file mode 100644
index e0381804e5..0000000000
--- a/packages/subagent/subagent-names/README.i18n.yaml
+++ /dev/null
@@ -1,46 +0,0 @@
-# Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
-# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
-# After editing either side, bring the other along and re-record with:
-# pnpm run verify-translation-pairing --write packages/subagent/subagent-names/README.md
-/:
- en: 26564f09306cf08f
- zh: b8933154b4911a0c
-/deepseek-ai-dsh-subagent-names:
- en: 622989d6dcd8611a
- zh: 6f0a3beb8e665332
-/deepseek-ai-dsh-subagent-names/summary:
- en: 1af1d0f9ab2e446e
- zh: 4846168336979ca6
-/deepseek-ai-dsh-subagent-names/table-of-contents:
- en: d152484eb41ac6b4
- zh: c614dc45fe9577a5
-/deepseek-ai-dsh-subagent-names/use-this-package:
- en: 15e2ab025baa3f2e
- zh: eab7ed264c78a4e4
-/deepseek-ai-dsh-subagent-names/use-this-package/minimal-configuration:
- en: 434c0ecf540e5fd6
- zh: e3db4a17ad90b531
-/deepseek-ai-dsh-subagent-names/use-this-package/choosing-and-finding-names:
- en: d7f5ce2da602deb1
- zh: 9862710f0cd113b9
-/deepseek-ai-dsh-subagent-names/use-this-package/binding-after-startup:
- en: f262bc2818040a38
- zh: edd0a989f1b50dc5
-/deepseek-ai-dsh-subagent-names/understand-the-implementation:
- en: 5f15aa5294842556
- zh: 790309123df2b152
-/deepseek-ai-dsh-subagent-names/further-exploration:
- en: ed0fb57dc13736e6
- zh: acd0cd0756510e65
-/deepseek-ai-dsh-subagent-names/model-experience:
- en: 40f9481ebd3e077d
- zh: 118c16ec3fed9652
-/deepseek-ai-dsh-subagent-names/model-experience/kv-cache-effect:
- en: cf0b791cc8ab26f4
- zh: 73f733b039240070
-/deepseek-ai-dsh-subagent-names/known-limitations-and-deferred-work:
- en: 81988fdd0823cffa
- zh: 96bacb5621c1e874
-/deepseek-ai-dsh-subagent-names/known-limitations-and-deferred-work/dev-note:
- en: e67f633dc6fe7773
- zh: 8ec3e73528ddb1a6
diff --git a/packages/subagent/subagent-names/README.md b/packages/subagent/subagent-names/README.md
deleted file mode 100644
index a5202fd912..0000000000
--- a/packages/subagent/subagent-names/README.md
+++ /dev/null
@@ -1,113 +0,0 @@
----
-description: "Bind readable subagent names to Session ids and recover the mappings from the root Session."
-kind: "package-reference"
----
-
-# @deepseek-ai/dsh-subagent-names
-
-English | [中文](README.zh.md)
-
-## Summary
-
-Address delegated agents by readable names such as `lead/research` and `lead/research/checker`. Bound names survive root Session reloads and keep the same spelling after agents finish. Choose this package when delegation tools need names while preserving Session ids for execution and authorization. Agents without a bound name remain addressable by id.
-
-## Table of Contents
-
-- [Use this package](#use-this-package)
-- [Understand the implementation](#understand-the-implementation)
-- [Further Exploration](#further-exploration)
-- [Model Experience](#model-experience)
-- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
-- [Dev Note](#dev-note)
-
------
-
-
-## Use this package
-
-Mount this plugin with the naming-aware [delegation tool](../tool-subagent/README.md) and [control tools](../tool-subagent-control/README.md).
-
-### Minimal configuration
-
-Add this row to a composition providing `sessionProjections`:
-
-```yaml
-- name: '@deepseek-ai/dsh-subagent-names'
-```
-
-This plugin has no configuration fields. It exposes `ctx.subagentNames`; the subagent service owns execution, messages, discovery, and authorization.
-
-### Choosing and finding names
-
-A requested name segment starts with a lower-case letter and contains only lower-case letters, digits, underscores, and hyphens. Omission selects the first available `agent-N` under the parent's name, starting at `agent-1`. Reservations prevent concurrent starts from choosing the same full name. A bound name remains occupied after execution settles.
-
-The root is `lead`. `nameOf` returns a bound full name, or the original Session id when no binding exists. `resolveName` accepts `lead` and bound full names; it rejects an unknown `lead/...` name and passes other ids through. The subsequent subagent operation still authorizes the caller.
-
-### Binding after startup
-
-Resolve `rootSession = ctx.subagents.rootOf(parent).session`, then call `reserve(rootSession, parent.id, requested?)`, start the child through `ctx.subagents.startActivation`, then call `bind(rootSession, childId, reservation.name)` with the successful receipt. Release the reservation with `dispose()` in `finally`, whether startup and binding succeed or fail.
-
-Binding records the full name in the root Session. If binding fails after startup succeeds, the caller must report the already-started child id; the child remains managed by the subagent service. A crash before binding can likewise leave an unnamed child that remains addressable by id.
-
------
-
-
-## Understand the implementation
-
-
-Implementation internals — click to expand
-
-Each root Session stores its own name-to-id bindings. All naming operations receive that root Session explicitly; the naming service does not resolve live Agent membership. A projection recovers those bindings and excludes inherited fork records. Lookups read this root mapping without observing ancestor Sessions or joining child catalogs. Callers own transient reservations and release them after their operation.
-
-The mapping retains one binding per named child: storage is O(n), a lookup or binding is O(n), and replaying n distinct bindings is O(n²) in the worst case because each event searches the binding array.
-
-| File | Role |
-|---|---|
-| [`src/index.ts`](src/index.ts) | Name reservations, binding, and lookup |
-| [`src/projection.ts`](src/projection.ts) | Durable bindings and replay validation |
-
-
-
------
-
-
-## Further Exploration
-
-These pages own execution and the model-facing tools that use names.
-
-- [Subagent service](../subagent/README.md) — activation ownership, catalogs, and authorization.
-- [Delegation tool](../tool-subagent/README.md) — named creation and start acknowledgements.
-- [Control tools](../tool-subagent-control/README.md) — discovery, messaging, and interruption.
-- [Session projections](../../session/session-projection/README.md) — incremental recovery.
-
------
-
-
-## Model Experience
-
-Indirectly, through the [delegation tool](../tool-subagent/README.md) and [control tools](../tool-subagent-control/README.md), which render names alongside Session ids and accept names as addresses.
-
-#### KV Cache effect
-
-The subagent message service reads sender names from this service automatically. This plugin adds no prompt text or tool schema. Its consumers own any model-visible name text and its cache effect.
-
-## Known Limitations and Deferred Work
-
-
-
-Name bindings have these limits:
-
-- **Names are available after binding** — the child's first request may precede its binding; this plugin adds no initial identity message.
-- **Names are immutable** — bound names and ids cannot be reassigned or reused after an activation ends.
-- **Paths capture the parent's name at reservation time** — an unnamed parent uses `lead/legacy:` as its prefix; a later parent binding does not rewrite the child's stored path.
-- **Naming is explicit** — callers that do not bind a name continue to use Session ids.
-
-
-### Dev Note
-
-
-Working context for maintainers — click to expand
-
-None.
-
-
diff --git a/packages/subagent/subagent-names/README.zh.md b/packages/subagent/subagent-names/README.zh.md
deleted file mode 100644
index c463b7190c..0000000000
--- a/packages/subagent/subagent-names/README.zh.md
+++ /dev/null
@@ -1,113 +0,0 @@
----
-description: "将可读的 subagent 名称绑定到 Session id,并从根 Session 恢复映射。"
-kind: "package-reference"
----
-
-# @deepseek-ai/dsh-subagent-names
-
-[English](README.md) | 中文
-
-## 概述
-
-通过 `lead/research` 和 `lead/research/checker` 这样的可读名称寻址委派的 agent(智能体)。绑定名称在根 Session 重新加载后仍然保留,agent 执行结束后也保持原名称。委派工具需要名称,同时仍以 Session id 执行操作和检查授权时,可选择此包。未绑定名称的 agent 仍可通过 id 寻址。
-
-## 目录
-
-- [使用此包](#use-this-package)
-- [了解实现](#understand-the-implementation)
-- [进一步探索](#further-exploration)
-- [模型体验](#model-experience)
-- [已知限制与待办工作](#known-limitations-and-deferred-work)
-- [开发备注](#dev-note)
-
------
-
-
-## 使用此包
-
-将此插件与支持命名的[委派工具](../tool-subagent/README.zh.md)和[控制工具](../tool-subagent-control/README.zh.md)一起挂载。
-
-### 最小配置
-
-在提供 `sessionProjections` 的组合中添加此配置项:
-
-```yaml
-- name: '@deepseek-ai/dsh-subagent-names'
-```
-
-此插件没有配置字段。它提供 `ctx.subagentNames`;subagent 服务负责执行、消息、发现和授权。
-
-### 选择和查找名称
-
-请求的名称段以小写字母开头,只能包含小写字母、数字、下划线和连字符。省略时,从 `agent-1` 开始选择父名称下第一个可用的 `agent-N`。预留可防止并发启动选择相同的完整名称。执行结算后,绑定名称仍被占用。
-
-根名称为 `lead`。`nameOf` 返回已绑定的完整名称;没有绑定时,返回原 Session id。`resolveName` 接受 `lead` 和已绑定的完整名称;它拒绝未知的 `lead/...` 名称,并透传其他 id。后续 subagent 操作仍会对调用方进行授权检查。
-
-### 启动后绑定
-
-先解析 `rootSession = ctx.subagents.rootOf(parent).session`,再调用 `reserve(rootSession, parent.id, requested?)`,通过 `ctx.subagents.startActivation` 启动子 agent,再根据成功回执调用 `bind(rootSession, childId, reservation.name)`。无论启动和绑定成功还是失败,都要在 `finally` 中调用 `dispose()` 释放预留。
-
-绑定将完整名称记录到根 Session。若启动成功后绑定失败,调用方必须报告已启动的子 agent id;该子 agent 仍由 subagent 服务管理。绑定前崩溃也可能留下未命名的子 agent,它仍可通过 id 寻址。
-
------
-
-
-## 了解实现
-
-
-实现内部细节 — 点击展开
-
-每个根 Session 保存自己的名称到 id 绑定。所有命名操作都显式接收该根 Session;命名服务不解析在线 Agent 的树成员关系。投影恢复这些绑定,并排除 fork 继承的记录。查询读取根映射,无需观察祖先 Session 或关联子 agent 目录。调用方拥有临时预留,并在操作后释放它们。
-
-映射为每个具名子 agent 保留一条绑定:空间为 O(n),单次查询或绑定为 O(n);由于每个事件都会搜索绑定数组,回放 n 条不同绑定的最坏时间复杂度为 O(n²)。
-
-| 文件 | 职责 |
-|---|---|
-| [`src/index.ts`](src/index.ts) | 名称预留、绑定与查询 |
-| [`src/projection.ts`](src/projection.ts) | 持久绑定与回放校验 |
-
-
-
------
-
-
-## 进一步探索
-
-以下页面负责执行行为以及使用名称的模型侧工具。
-
-- [Subagent 服务](../subagent/README.zh.md) — 激活所有权、目录与授权。
-- [委派工具](../tool-subagent/README.zh.md) — 命名创建与启动确认。
-- [控制工具](../tool-subagent-control/README.zh.md) — 发现、消息与中断。
-- [Session 投影](../../session/session-projection/README.zh.md) — 增量恢复。
-
------
-
-
-## 模型体验
-
-通过[委派工具](../tool-subagent/README.zh.md)和[控制工具](../tool-subagent-control/README.zh.md)间接影响模型;这些工具在 Session id 旁展示名称,并接受名称作为地址。
-
-#### KV Cache 影响
-
-subagent 消息服务自动从此服务读取发送者名称。此插件不添加提示词文本或工具 schema。消费方负责模型可见的名称文本及其缓存影响。
-
-## 已知限制与待办工作
-
-
-
-名称绑定存在以下限制:
-
-- **绑定后才可查询名称** — 子 agent 的首个请求可能早于绑定;此插件不添加初始身份消息。
-- **名称不可变** — 激活结束后,绑定的名称和 id 也不能重新分配或复用。
-- **路径采用预留时的父名称** — 未命名的父 agent 使用 `lead/legacy:` 作为前缀;后续父级绑定不会改写子 agent 已存储的路径。
-- **命名需要显式绑定** — 不绑定名称的调用方继续使用 Session id。
-
-
-### 开发备注
-
-
-维护者工作上下文 — 点击展开
-
-无。
-
-
diff --git a/packages/subagent/subagent-names/locale/de.json b/packages/subagent/subagent-names/locale/de.json
deleted file mode 100644
index f916efbaba..0000000000
--- a/packages/subagent/subagent-names/locale/de.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "meta": {
- "title": "Namen der Unteragenten"
- }
-}
diff --git a/packages/subagent/subagent-names/locale/en.json b/packages/subagent/subagent-names/locale/en.json
deleted file mode 100644
index aac18fd6a7..0000000000
--- a/packages/subagent/subagent-names/locale/en.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "meta": {
- "title": "Subagent names"
- }
-}
diff --git a/packages/subagent/subagent-names/locale/es.json b/packages/subagent/subagent-names/locale/es.json
deleted file mode 100644
index e4d0825c41..0000000000
--- a/packages/subagent/subagent-names/locale/es.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "meta": {
- "title": "Nombres de subagentes"
- }
-}
diff --git a/packages/subagent/subagent-names/locale/fr.json b/packages/subagent/subagent-names/locale/fr.json
deleted file mode 100644
index d067cb7cff..0000000000
--- a/packages/subagent/subagent-names/locale/fr.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "meta": {
- "title": "Noms des sous-agents"
- }
-}
diff --git a/packages/subagent/subagent-names/locale/ja.json b/packages/subagent/subagent-names/locale/ja.json
deleted file mode 100644
index 61aa889191..0000000000
--- a/packages/subagent/subagent-names/locale/ja.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "meta": {
- "title": "サブエージェント名"
- }
-}
diff --git a/packages/subagent/subagent-names/locale/pt.json b/packages/subagent/subagent-names/locale/pt.json
deleted file mode 100644
index de2c360643..0000000000
--- a/packages/subagent/subagent-names/locale/pt.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "meta": {
- "title": "Nomes de subagentes"
- }
-}
diff --git a/packages/subagent/subagent-names/locale/ru.json b/packages/subagent/subagent-names/locale/ru.json
deleted file mode 100644
index 6ec06806f1..0000000000
--- a/packages/subagent/subagent-names/locale/ru.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "meta": {
- "title": "Имена субагентов"
- }
-}
diff --git a/packages/subagent/subagent-names/locale/zh.json b/packages/subagent/subagent-names/locale/zh.json
deleted file mode 100644
index 5ba715505c..0000000000
--- a/packages/subagent/subagent-names/locale/zh.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "meta": {
- "title": "子智能体名称"
- }
-}
diff --git a/packages/subagent/subagent-names/package.json b/packages/subagent/subagent-names/package.json
deleted file mode 100644
index 0f3f854f2e..0000000000
--- a/packages/subagent/subagent-names/package.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
- "name": "@deepseek-ai/dsh-subagent-names",
- "description": "Durable name mappings for subagent tools",
- "version": "0.2.2-alpha.2",
- "publishConfig": {
- "access": "public"
- },
- "repository": {
- "type": "git",
- "url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
- "directory": "packages/subagent/subagent-names"
- },
- "type": "module",
- "main": "lib/index.js",
- "types": "lib/types/index.d.ts",
- "exports": {
- ".": {
- "types": "./lib/types/index.d.ts",
- "default": "./lib/index.js"
- },
- "./src/*": "./src/*",
- "./package.json": "./package.json",
- "./locale/*.json": "./locale/*.json"
- },
- "files": [
- "locale/*.json",
- "lib/index.js",
- "lib/types/**/*.d.ts"
- ],
- "license": "MIT",
- "dependencies": {
- "zod": "4.4.3"
- },
- "peerDependencies": {
- "@deepseek-ai/cordis": "workspace:~",
- "@deepseek-ai/dsh-llm": "workspace:*",
- "@deepseek-ai/dsh-session": "workspace:*",
- "@deepseek-ai/dsh-session-projection": "workspace:*"
- },
- "devDependencies": {
- "@deepseek-ai/cordis": "workspace:~",
- "@deepseek-ai/dsh-agent": "workspace:*",
- "@deepseek-ai/dsh-agent-loop": "workspace:*",
- "@deepseek-ai/dsh-agent-loop-testkit": "workspace:*",
- "@deepseek-ai/dsh-llm": "workspace:*",
- "@deepseek-ai/dsh-session": "workspace:*",
- "@deepseek-ai/dsh-session-persistence": "workspace:*",
- "@deepseek-ai/dsh-session-persistence-jsonl": "workspace:*",
- "@deepseek-ai/dsh-session-projection": "workspace:*",
- "@deepseek-ai/dsh-subagent": "workspace:*",
- "@deepseek-ai/dsh-subagent-spawn-in-process": "workspace:*",
- "@deepseek-ai/dsh-working-directory": "workspace:*"
- }
-}
diff --git a/packages/subagent/subagent-names/src/index.ts b/packages/subagent/subagent-names/src/index.ts
deleted file mode 100644
index de7ed6d5e0..0000000000
--- a/packages/subagent/subagent-names/src/index.ts
+++ /dev/null
@@ -1,130 +0,0 @@
-/** Durable aliases for subagent tools; execution remains owned by subagents. @module */
-
-import { Context, Service } from '@deepseek-ai/cordis'
-import type { Session } from '@deepseek-ai/dsh-session'
-import { HarnessError } from '@deepseek-ai/dsh-llm'
-import { SessionId } from '@deepseek-ai/dsh-session'
-import type { ProjectionHandle } from '@deepseek-ai/dsh-session-projection'
-import { fullNameSchema, nameSchema, subagentNamesProjection } from './projection.ts'
-import type { SubagentNamesState } from './projection.ts'
-
-export type { SubagentNameBinding } from './projection.ts'
-
-declare module '@deepseek-ai/cordis' {
- interface Context {
- subagentNames: SubagentNames
- }
-}
-
-/** Stable categories for alias validation and lookup failures. */
-export type SubagentNameErrorCode = 'INVALID_AGENT_NAME' | 'DUPLICATE_AGENT_NAME' | 'AGENT_NAME_NOT_FOUND'
-
-/** An alias could not be reserved, bound, or resolved. */
-export class SubagentNameError extends HarnessError {
- constructor(message: string, code: SubagentNameErrorCode) {
- super(message, code)
- this.name = 'SubagentNameError'
- }
-}
-
-/** A caller-owned name reservation; release it after startup and binding settle. */
-export interface SubagentNameReservation {
- readonly name: string
- /** Release the reservation; repeated disposal is harmless. */
- dispose(): void
-}
-
-/** Root-Session aliases shared by named creation, discovery, and control tools. */
-export class SubagentNames extends Service {
- static inject = ['sessionProjections']
-
- private projection!: ProjectionHandle
- private readonly pending = new WeakMap>()
-
- constructor(ctx: Context) {
- super(ctx, 'subagentNames')
- }
-
- protected async [Service.init](): Promise {
- this.projection = await this.ctx.sessionProjections.register(subagentNamesProjection)
- }
-
- /**
- * Reserve a complete name without starting an agent or writing a Session event.
- * @param rootSession - root Session selected by the caller through the subagent service.
- * @param parentId - parent identity whose name prefixes the child name.
- * @param requested - optional sibling segment; omission selects the first free agent-N.
- * @returns a reservation the caller must dispose after startup and binding.
- */
- reserve(rootSession: Session, parentId: SessionId, requested?: string): SubagentNameReservation {
- if (requested !== undefined && !nameSchema.safeParse(requested).success) {
- throw new SubagentNameError('agent name must start with a lower-case letter and contain only lower-case letters, digits, underscores, or hyphens', 'INVALID_AGENT_NAME')
- }
- const bindings = this.projection.stateOf(rootSession).bindings
- const prefix = parentId === rootSession.id ? 'lead'
- : bindings.find(binding => binding.childId === parentId)?.name ?? `lead/legacy:${parentId}`
- const pending = this.pending.get(rootSession) ?? new Set()
- this.pending.set(rootSession, pending)
- const occupied = new Set([...bindings.map(binding => binding.name), ...pending])
- let segment = requested
- if (segment === undefined) {
- let ordinal = 1
- while (occupied.has(`${prefix}/agent-${ordinal}`)) ordinal++
- segment = `agent-${ordinal}`
- }
- const name = `${prefix}/${segment}`
- if (occupied.has(name)) throw new SubagentNameError(`agent name "${name}" is already in use; choose another name`, 'DUPLICATE_AGENT_NAME')
- pending.add(name)
- let active = true
- return { name, dispose: () => {
- if (!active) return
- active = false
- pending.delete(name)
- } }
- }
-
- /**
- * Record an accepted child's full name in the caller's root Session.
- * Binding failure does not cancel or dispose the child; callers report its id.
- * @param rootSession - root Session selected by the caller through the subagent service.
- * @param childId - identity returned by the subagent service.
- * @param name - complete name returned by reserve.
- */
- bind(rootSession: Session, childId: SessionId, name: string): void {
- if (!fullNameSchema.safeParse(name).success) throw new SubagentNameError('a bound agent name must be a complete lead/... path', 'INVALID_AGENT_NAME')
- const bindings = this.projection.stateOf(rootSession).bindings
- const existing = bindings.find(binding => binding.childId === childId || binding.name === name)
- if (existing !== undefined) {
- if (existing.childId === childId && existing.name === name) return
- throw new SubagentNameError(`agent name "${name}" or identity ${childId} is already bound`, 'DUPLICATE_AGENT_NAME')
- }
- rootSession.append('subagent-name/bound', { version: 1, childId, name })
- }
-
- /**
- * Read a bound name from the root projection without loading ancestors.
- * @param rootSession - root Session selected by the caller through the subagent service.
- * @param targetId - identity whose name is requested.
- * @returns lead for the root, a bound full name, or the unchanged id.
- */
- nameOf(rootSession: Session, targetId: SessionId): string {
- if (targetId === rootSession.id) return 'lead'
- return this.projection.stateOf(rootSession).bindings.find(binding => binding.childId === targetId)?.name ?? targetId
- }
-
- /**
- * Resolve an alias or pass through an id for the subagent service to authorize.
- * @param rootSession - root Session selected by the caller through the subagent service.
- * @param name - lead, a bound full name, or a raw Session id.
- * @returns the target identity; an unknown lead/... name throws.
- */
- resolveName(rootSession: Session, name: string): SessionId {
- if (name === 'lead') return rootSession.id
- const binding = this.projection.stateOf(rootSession).bindings.find(binding => binding.name === name)
- if (binding !== undefined) return binding.childId
- if (name.startsWith('lead/')) throw new SubagentNameError(`agent "${name}" was not found; use list_agents to discover names or ids`, 'AGENT_NAME_NOT_FOUND')
- return SessionId(name)
- }
-}
-
-export default SubagentNames
diff --git a/packages/subagent/subagent-names/src/projection.ts b/packages/subagent/subagent-names/src/projection.ts
deleted file mode 100644
index e082aecd57..0000000000
--- a/packages/subagent/subagent-names/src/projection.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-/** Root-Session aliases restored independently of subagent execution. @module */
-
-import { z } from 'zod'
-import { SessionId, SessionLogOffset } from '@deepseek-ai/dsh-session'
-import type { SessionEvent, SessionHeader } from '@deepseek-ai/dsh-session'
-import type { ProjectionDefinition } from '@deepseek-ai/dsh-session-projection'
-
-/** One immutable full name bound to an accepted child identity. */
-export interface SubagentNameBinding {
- readonly childId: SessionId
- readonly name: string
-}
-
-declare module '@deepseek-ai/dsh-session/types' {
- interface SessionEventMap {
- /**
- * A root-owned alias for an accepted subagent identity.
- * @param data - versioned child identity and complete name.
- */
- 'subagent-name/bound': SubagentNameBinding & { readonly version: 1 }
- }
-}
-
-declare module '@deepseek-ai/dsh-session-projection/types' {
- interface SessionProjectionMap {
- subagentNames: SubagentNameBinding[]
- }
-}
-
-/** Requested sibling names use one lower-case path segment. */
-export const nameSchema = z.string().regex(/^[a-z][a-z0-9_-]*$/)
-
-/** Bound paths include the root prefix and may include an unnamed parent's id. */
-export const fullNameSchema = z.string().startsWith('lead/').min(6)
-
-const bindingSchema = z.object({ childId: z.string().transform(SessionId), name: fullNameSchema }).strict()
-const boundSchema = bindingSchema.extend({ version: z.literal(1) })
-const bindingsSchema = z.array(bindingSchema).refine(
- bindings => new Set(bindings.map(binding => binding.childId)).size === bindings.length
- && new Set(bindings.map(binding => binding.name)).size === bindings.length,
- 'child identities and names must each be unique',
-)
-const stateSchema = z.object({
- inheritedEventCount: z.number().int().nonnegative().transform(SessionLogOffset),
- bindings: bindingsSchema,
-}).strict()
-
-/** Recoverable root aliases, excluding inherited fork records. */
-export type SubagentNamesState = z.infer
-
-/** Alias recovery does not start agents or read other Sessions. */
-export const subagentNamesProjection = {
- key: 'subagentNames',
- stateVersion: 1,
- stateSchema,
- init: (_header: SessionHeader, inheritedEventCount: SessionLogOffset): SubagentNamesState => ({
- inheritedEventCount, bindings: [],
- }),
- apply(state: SubagentNamesState, event: SessionEvent): SubagentNamesState {
- if (event.seq < state.inheritedEventCount) return state
- if (event.type === 'subagent-name/bound') {
- const { version: _version, ...binding } = boundSchema.parse(event.data)
- const previous = state.bindings.find(entry => entry.childId === binding.childId || entry.name === binding.name)
- if (previous !== undefined) {
- if (previous.name !== binding.name || previous.childId !== binding.childId) throw new Error('subagent names and identities must have one immutable binding')
- return state
- }
- return { ...state, bindings: [...state.bindings, binding] }
- }
- return state
- },
- wire: { viewSchema: z.array(bindingSchema), view: (state: SubagentNamesState) => state.bindings },
-} satisfies ProjectionDefinition<'subagentNames', SubagentNamesState>
diff --git a/packages/subagent/subagent-names/tests/names.spec.ts b/packages/subagent/subagent-names/tests/names.spec.ts
deleted file mode 100644
index 25d0a987b2..0000000000
--- a/packages/subagent/subagent-names/tests/names.spec.ts
+++ /dev/null
@@ -1,224 +0,0 @@
-import { randomUUID } from 'node:crypto'
-import { describe, expect, it, onTestFinished, vi } from 'vitest'
-import { Context } from '@deepseek-ai/cordis'
-import AgentLoop from '@deepseek-ai/dsh-agent-loop'
-import type { Agent } from '@deepseek-ai/dsh-agent'
-import { mountAgentLoopTestDependencies } from '@deepseek-ai/dsh-agent-loop-testkit'
-import SessionStore, { SessionId } from '@deepseek-ai/dsh-session'
-import SessionProjectionRegistry from '@deepseek-ai/dsh-session-projection'
-import SubagentRuntime from '@deepseek-ai/dsh-subagent'
-import * as SubagentSpawn from '@deepseek-ai/dsh-subagent-spawn-in-process'
-import { MockAdapter, textResponse } from '../../../core/agent-loop/tests/mock-adapter.ts'
-import { mountLocalActivations } from '../../subagent/tests/local-activation.ts'
-import { loadStoredSession } from '../../subagent/tests/persistence-helpers.ts'
-import SubagentNames from '../src/index.ts'
-
-async function setup(script: ConstructorParameters[0] = []) {
- const ctx = new Context()
- onTestFinished(() => ctx.fiber.dispose())
- await mountAgentLoopTestDependencies(ctx)
- await mountLocalActivations(ctx)
- await ctx.plugin(AgentLoop, { agents: [] })
- await ctx.plugin(SubagentRuntime)
- await ctx.plugin(SubagentSpawn, { providerName: 'spawn' })
- const namesFiber = await ctx.plugin(SubagentNames)
- ctx.llm.registerAdapter(['mock'], new MockAdapter(script))
- const parentHandle = await ctx.agents.create({
- sessionId: SessionId(randomUUID()), agentOptions: { provider: 'mock', model: 'mock' },
- })
- const parent = parentHandle.agent
- ctx.on('agent/pre-step', async ({ agent }, next) => agent.id === parent.id ? { kind: 'reject' } : next())
- const start = (creator: Agent = parent) => ctx.subagents.startActivation({
- provider: 'spawn', label: 'Review', parent: creator, delivery: 'parent',
- prompt: [{ type: 'text', text: 'Review the change' }], signal: new AbortController().signal,
- })
- return { ctx, parent, parentHandle, namesFiber, start }
-}
-
-describe('root Session name mappings', () => {
- it('isolates root mappings and reservations without a subagent runtime', async () => {
- const ctx = new Context()
- onTestFinished(() => ctx.fiber.dispose())
- await ctx.plugin(SessionStore)
- await ctx.plugin(SessionProjectionRegistry)
- await ctx.plugin(SubagentNames)
- const first = ctx.sessions.create(SessionId('first-root'))
- const second = ctx.sessions.create(SessionId('second-root'))
- const names = ctx.subagentNames
- const firstName = names.reserve(first, first.id, 'reviewer')
- const secondName = names.reserve(second, second.id, 'reviewer')
- onTestFinished(() => { firstName.dispose(); secondName.dispose() })
- names.bind(first, SessionId('first-child'), firstName.name)
- names.bind(second, SessionId('second-child'), secondName.name)
-
- expect(ctx.get('subagents')).toBeUndefined()
- expect(names.resolveName(first, 'lead/reviewer')).toBe('first-child')
- expect(names.resolveName(second, 'lead/reviewer')).toBe('second-child')
- expect(names.nameOf(first, SessionId('second-child'))).toBe('second-child')
- expect(names.nameOf(second, second.id)).toBe('lead')
- })
-
- it('binds an accepted child without changing its id, prompt, or execution', async () => {
- const { ctx, parent, start } = await setup([textResponse('done')])
- const reservation = ctx.subagentNames.reserve(parent.session, parent.id, 'reviewer')
- const activation = await start()
- expect(ctx.subagentNames.nameOf(parent.session, activation.childId)).toBe(activation.childId)
- ctx.subagentNames.bind(parent.session, activation.childId, reservation.name)
- reservation.dispose()
- await activation.result
-
- expect(ctx.subagentNames.nameOf(parent.session, parent.id)).toBe('lead')
- expect(ctx.subagentNames.nameOf(parent.session, activation.childId)).toBe('lead/reviewer')
- expect(ctx.subagentNames.resolveName(parent.session, 'lead')).toBe(parent.id)
- expect(ctx.subagentNames.resolveName(parent.session, 'lead/reviewer')).toBe(activation.childId)
- expect(ctx.subagentNames.resolveName(parent.session, activation.childId)).toBe(activation.childId)
- expect(ctx.subagentNames.resolveName(parent.session, 'unmapped-id')).toBe('unmapped-id')
- expect(() => ctx.subagentNames.resolveName(parent.session, 'lead/misspelled')).toThrow('was not found')
- const stored = await loadStoredSession(ctx.sessionPersistence, activation.childId)
- const message = stored.events.find(event => event.type === 'user/message')
- expect(message?.data.content[0]).toEqual({ type: 'text', text: 'Review the change' })
- expect(JSON.stringify(message)).not.toContain('Your name is')
- expect(stored.events.some(event => event.type === 'subagent-name/bound')).toBe(false)
- })
-
- it('reserves distinct defaults, rejects overlap, and reuses released unbound names', async () => {
- const { ctx, parent } = await setup()
- const first = ctx.subagentNames.reserve(parent.session, parent.id)
- const second = ctx.subagentNames.reserve(parent.session, parent.id)
- expect([first.name, second.name]).toEqual(['lead/agent-1', 'lead/agent-2'])
- expect(() => ctx.subagentNames.reserve(parent.session, parent.id, 'agent-1')).toThrow('already in use')
- first.dispose()
- first.dispose()
- const retry = ctx.subagentNames.reserve(parent.session, parent.id)
- expect(retry.name).toBe('lead/agent-1')
- first.dispose()
- expect(() => ctx.subagentNames.reserve(parent.session, parent.id, 'agent-1')).toThrow('already in use')
- ctx.subagentNames.bind(parent.session, SessionId('accepted-child'), retry.name)
- retry.dispose()
- expect(() => ctx.subagentNames.reserve(parent.session, parent.id, 'agent-1')).toThrow('already in use')
- second.dispose()
- const available = ctx.subagentNames.reserve(parent.session, parent.id)
- expect(available.name).toBe('lead/agent-2')
- available.dispose()
- })
-
- it.each(['', 'Reviewer', 'lead/reviewer', 'two words', '1reviewer', 'legacy:child'])(
- 'rejects invalid requested segment %j before reserving it', async (name) => {
- const { ctx, parent } = await setup()
- expect(() => ctx.subagentNames.reserve(parent.session, parent.id, name)).toThrow('agent name must')
- expect(ctx.sessionProjections.snapshot(parent.session).values.subagentNames).toEqual([])
- },
- )
-
- it('keeps exact bindings idempotent while rejecting name and identity conflicts', async () => {
- const { ctx, parent } = await setup()
- const id = SessionId('accepted-child')
- expect(() => { ctx.subagentNames.bind(parent.session, id, 'reviewer') }).toThrow('complete lead/... path')
- ctx.subagentNames.bind(parent.session, id, 'lead/reviewer')
- const seq = parent.session.seq
- ctx.subagentNames.bind(parent.session, id, 'lead/reviewer')
- expect(parent.session.seq).toBe(seq)
- expect(() => { ctx.subagentNames.bind(parent.session, id, 'lead/renamed') }).toThrow('already bound')
- expect(() => { ctx.subagentNames.bind(parent.session, SessionId('another-child'), 'lead/reviewer') }).toThrow('already bound')
- })
-
- it('records nested aliases only on the root and restores them without ancestor reads', async () => {
- const { ctx, parent, parentHandle, start } = await setup(['hang', 'hang'])
- const creator = await start()
- ctx.subagentNames.bind(parent.session, creator.childId, 'lead/reviewer')
- const creatorAgent = ctx.agents.get(creator.childId)!
- const reservation = ctx.subagentNames.reserve(parent.session, creatorAgent.id, 'facts')
- const leaf = await start(creatorAgent)
- ctx.subagentNames.bind(parent.session, leaf.childId, reservation.name)
- reservation.dispose()
- expect(ctx.subagentNames.nameOf(parent.session, creatorAgent.id)).toBe('lead/reviewer')
- expect(ctx.sessionProjections.snapshot(creatorAgent.session).values.subagentNames).toEqual([])
- expect(ctx.sessionProjections.snapshot(parent.session).values.subagentNames).toEqual([
- { childId: creator.childId, name: 'lead/reviewer' },
- { childId: leaf.childId, name: 'lead/reviewer/facts' },
- ])
- await creator.dispose()
- expect(ctx.agents.get(creator.childId)).toBeUndefined()
- expect(ctx.subagentNames.nameOf(parent.session, leaf.childId)).toBe('lead/reviewer/facts')
- await parentHandle.dispose()
- const restored = await ctx.agents.resume({ resumeSessionId: parent.id })
- expect(ctx.subagentNames.resolveName(restored.agent.session, 'lead/reviewer/facts')).toBe(leaf.childId)
- expect(ctx.get('sessionQuery')).toBeUndefined()
- })
-
- it('uses a stable id prefix for children whose parent has no name', async () => {
- const { ctx, parent, start } = await setup(['hang'])
- const creator = await start()
- const creatorAgent = ctx.agents.get(creator.childId)!
- expect(ctx.subagentNames.nameOf(parent.session, creatorAgent.id)).toBe(creator.childId)
- const reservation = ctx.subagentNames.reserve(parent.session, creatorAgent.id, 'facts')
- expect(reservation.name).toBe(`lead/legacy:${creator.childId}/facts`)
- const childId = SessionId('accepted-leaf')
- ctx.subagentNames.bind(parent.session, childId, reservation.name)
- reservation.dispose()
- ctx.subagentNames.bind(parent.session, creator.childId, 'lead/reviewer')
- expect(ctx.subagentNames.nameOf(parent.session, childId)).toBe(`lead/legacy:${creator.childId}/facts`)
- })
-
- it('does not stop an accepted child when the alias append fails', async () => {
- const { ctx, parent, start } = await setup(['hang'])
- const reservation = ctx.subagentNames.reserve(parent.session, parent.id, 'reviewer')
- const child = await start()
- const failure = new Error('binding append failed')
- const append = vi.spyOn(parent.session, 'append').mockImplementationOnce(() => { throw failure })
- expect(() => { ctx.subagentNames.bind(parent.session, child.childId, reservation.name) }).toThrow(failure)
- append.mockRestore()
- reservation.dispose()
- expect(ctx.agents.get(child.childId)).toBeDefined()
- expect(ctx.subagentNames.nameOf(parent.session, child.childId)).toBe(child.childId)
- const retry = ctx.subagentNames.reserve(parent.session, parent.id, 'reviewer')
- retry.dispose()
- await child.dispose()
- })
-
- it('resolves message attribution automatically across naming service unload and reload', async () => {
- const { ctx, parent, namesFiber, start } = await setup(['hang'])
- const child = await start()
- const sender = ctx.agents.get(child.childId)!
- ctx.subagentNames.bind(parent.session, child.childId, 'lead/reviewer')
- const steer = vi.spyOn(parent, 'steer')
- const send = () => ctx.subagents.sendMessage(sender, parent.id, [{ type: 'text', text: 'finding' }], {
- signal: new AbortController().signal,
- })
-
- await send()
- expect(steer.mock.lastCall?.[0]).toMatchObject({
- content: [{ type: 'text', text: 'Agent lead/reviewer sent a message: ' }, { type: 'text', text: 'finding' }],
- source: { kind: 'agent-message', senderSessionId: child.childId },
- })
- const lookupFailure = new Error('name lookup failed')
- const lookup = vi.spyOn(ctx.subagentNames, 'nameOf').mockImplementationOnce(() => { throw lookupFailure })
- await expect(send()).rejects.toBe(lookupFailure)
- expect(steer).toHaveBeenCalledTimes(1)
- lookup.mockRestore()
- await namesFiber.dispose()
- await send()
- expect(steer.mock.lastCall?.[0].content[0]).toEqual({ type: 'text', text: `Agent ${child.childId} sent a message: ` })
- await ctx.plugin(SubagentNames)
- await send()
- expect(steer.mock.lastCall?.[0].content[0]).toEqual({ type: 'text', text: 'Agent lead/reviewer sent a message: ' })
- await child.dispose()
- })
-
- it('unregisters its projection and leaves accepted execution with its owner', async () => {
- const { ctx, parent, namesFiber, start } = await setup(['hang'])
- const names = ctx.subagentNames
- const reservation = names.reserve(parent.session, parent.id, 'reviewer')
- const child = await start()
- await namesFiber.dispose()
- expect(ctx.get('subagentNames')).toBeUndefined()
- expect(ctx.sessionProjections.snapshot(parent.session).values.subagentNames).toBeUndefined()
- expect(ctx.agents.get(child.childId)).toBeDefined()
- // Accepted callers retain their projection handle while completing a binding.
- names.bind(parent.session, child.childId, reservation.name)
- reservation.dispose()
- await ctx.plugin(SubagentNames)
- expect(ctx.subagentNames.nameOf(parent.session, child.childId)).toBe('lead/reviewer')
- await child.dispose()
- })
-})
diff --git a/packages/subagent/subagent-names/tests/projection.spec.ts b/packages/subagent/subagent-names/tests/projection.spec.ts
deleted file mode 100644
index d5095a30d7..0000000000
--- a/packages/subagent/subagent-names/tests/projection.spec.ts
+++ /dev/null
@@ -1,177 +0,0 @@
-import { describe, expect, it, onTestFinished } from 'vitest'
-import { Context } from '@deepseek-ai/cordis'
-import SessionStore, { SESSION_FORMAT_VERSION, SessionId, SessionLogOffset, SessionSeq } from '@deepseek-ai/dsh-session'
-import type { SessionEvent, SessionHeader } from '@deepseek-ai/dsh-session'
-import SessionProjectionRegistry from '@deepseek-ai/dsh-session-projection'
-import { subagentNamesProjection } from '../src/projection.ts'
-
-const header: SessionHeader = {
- version: SESSION_FORMAT_VERSION,
- id: SessionId('parent'),
- createdAt: 0,
- isSeeded: false,
-}
-
-function bound(seq: number, childId = 'child', name = 'lead/worker'): SessionEvent<'subagent-name/bound'> {
- return {
- type: 'subagent-name/bound', seq: SessionSeq(seq), time: seq,
- data: { version: 1, childId: SessionId(childId), name },
- }
-}
-
-async function registry() {
- const ctx = new Context()
- onTestFinished(async () => { await ctx.fiber.dispose() })
- await ctx.plugin(SessionStore)
- await ctx.plugin(SessionProjectionRegistry)
- await ctx.sessionProjections.register(subagentNamesProjection)
- return ctx.sessionProjections
-}
-
-describe('subagent names projection', () => {
- it('keeps each child binding immutable without mutating earlier states', () => {
- const initial = subagentNamesProjection.init(header, SessionLogOffset(0))
- const first = subagentNamesProjection.apply(initial, bound(0))
- const second = subagentNamesProjection.apply(first, bound(1, 'other-child', 'lead/reviewer'))
-
- expect(initial.bindings).toEqual([])
- expect(first.bindings).toEqual([{ childId: 'child', name: 'lead/worker' }])
- expect(second.bindings).toEqual([
- { childId: 'child', name: 'lead/worker' },
- { childId: 'other-child', name: 'lead/reviewer' },
- ])
- expect(() => subagentNamesProjection.apply(second, bound(2, 'child', 'lead/renamed')))
- .toThrow('one immutable binding')
- expect(() => subagentNamesProjection.apply(second, bound(2, 'different-child', 'lead/worker')))
- .toThrow('one immutable binding')
- expect(second.bindings).toEqual([
- { childId: 'child', name: 'lead/worker' },
- { childId: 'other-child', name: 'lead/reviewer' },
- ])
- })
-
- it('preserves state and view references for repeated bindings and unrelated events', () => {
- const state = subagentNamesProjection.apply(
- subagentNamesProjection.init(header, SessionLogOffset(0)), bound(0),
- )
- const duplicate = subagentNamesProjection.apply(state, bound(1))
- const unrelated = subagentNamesProjection.apply(state, {
- type: 'turn/start', seq: SessionSeq(2), time: 2, data: { turn: 1 },
- })
-
- expect(duplicate).toBe(state)
- expect(unrelated).toBe(state)
- expect(subagentNamesProjection.wire.view(duplicate)).toBe(state.bindings)
- expect(subagentNamesProjection.wire.view(unrelated)).toBe(state.bindings)
- })
-
- it('excludes inherited bindings and admits the event at the exact inherited cut', () => {
- const initial = subagentNamesProjection.init(header, SessionLogOffset(2))
- expect(subagentNamesProjection.apply(initial, bound(0, 'child', 'lead/inherited'))).toBe(initial)
- expect(subagentNamesProjection.apply(initial, bound(1, 'other-child', 'lead/inherited-too'))).toBe(initial)
- const own = subagentNamesProjection.apply(initial, bound(2))
-
- expect(own.bindings).toEqual([{ childId: 'child', name: 'lead/worker' }])
- expect(own.inheritedEventCount).toBe(2)
- })
-
- it.each([
- { version: 2, childId: 'child', name: 'lead/worker' },
- { childId: 'child', name: 'lead/worker' },
- { version: 1, childId: 1, name: 'lead/worker' },
- { version: 1, name: 'lead/worker' },
- { version: 1, childId: 'child' },
- { version: 1, childId: 'child', name: 1 },
- { version: 1, childId: 'child', name: 'lead/worker', extra: true },
- ...['', 'Worker', '1worker', 'parent/worker', 'legacy:child', 'worker name'].map(name => ({
- version: 1, childId: 'child', name,
- })),
- ])('rejects malformed persisted binding data %j', (data) => {
- const initial = subagentNamesProjection.init(header, SessionLogOffset(0))
- // Persisted events can violate the declared event fields before replay validation.
- const event = { ...bound(0), data } as SessionEvent<'subagent-name/bound'>
- expect(() => subagentNamesProjection.apply(initial, event)).toThrow()
- expect(initial.bindings).toEqual([])
- })
-
- it.each([
- {},
- { inheritedEventCount: -1, bindings: [] },
- { inheritedEventCount: 0.5, bindings: [] },
- { inheritedEventCount: '0', bindings: [] },
- { inheritedEventCount: 0, bindings: {} },
- { inheritedEventCount: 0, bindings: [{ childId: 'child' }] },
- { inheritedEventCount: 0, bindings: [{ childId: 1, name: 'lead/worker' }] },
- { inheritedEventCount: 0, bindings: [{ childId: 'child', name: 'parent/worker' }] },
- { inheritedEventCount: 0, bindings: [{ childId: 'child', name: 'lead/worker', version: 1 }] },
- { inheritedEventCount: 0, bindings: [{ childId: 'child', name: 'lead/worker' }, { childId: 'child', name: 'lead/reviewer' }] },
- { inheritedEventCount: 0, bindings: [{ childId: 'child', name: 'lead/worker' }, { childId: 'other', name: 'lead/worker' }] },
- { inheritedEventCount: 0, bindings: [], extra: true },
- ])('rejects malformed checkpoint state %j', (state) => {
- expect(subagentNamesProjection.stateSchema.safeParse(state).success).toBe(false)
- })
-
- it('restores a versioned checkpoint and suffix to the same state as complete replay', async () => {
- const projections = await registry()
- const inheritedEventCount = SessionLogOffset(1)
- const events: SessionEvent[] = [
- bound(0, 'ancestor-child', 'lead/inherited'),
- bound(1),
- bound(2),
- bound(3, 'other-child', 'lead/reviewer'),
- { type: 'turn/start', seq: SessionSeq(4), time: 4, data: { turn: 1 } },
- ]
- const prefix = projections.restore({}, events.slice(0, 2), SessionLogOffset(0), header, inheritedEventCount)
- expect(prefix.checkpoint.subagentNames).toEqual({
- ver: 1, seq: 1,
- val: { inheritedEventCount: 1, bindings: [{ childId: 'child', name: 'lead/worker' }] },
- })
- const resumed = projections.restore(
- prefix.checkpoint, events.slice(2), SessionLogOffset(2), header, inheritedEventCount,
- )
- const replayed = projections.restore({}, events, SessionLogOffset(0), header, inheritedEventCount)
-
- expect(resumed).toEqual(replayed)
- expect(resumed.snapshot).toEqual({
- asOfSeq: 4,
- values: { subagentNames: [
- { childId: 'child', name: 'lead/worker' },
- { childId: 'other-child', name: 'lead/reviewer' },
- ] },
- })
- expect(projections.viewCheckpoint(resumed.checkpoint)).toEqual(resumed.snapshot.values)
- expect(projections.restore(
- resumed.checkpoint, [], SessionLogOffset(5), header, inheritedEventCount,
- )).toEqual(resumed)
- })
-
- it('replays from the log when the checkpoint version is incompatible', async () => {
- const projections = await registry()
- const incompatible = {
- subagentNames: { ver: 2, seq: SessionSeq(0), val: { unsupported: true } },
- }
-
- expect(projections.viewCheckpoint(incompatible)).toEqual({})
- expect(() => projections.restore(
- incompatible, [bound(1, 'other-child', 'lead/reviewer')], SessionLogOffset(1), header, SessionLogOffset(0),
- )).toThrow(/re-read from seq 0/)
- expect(projections.restore(
- incompatible, [bound(0)], SessionLogOffset(0), header, SessionLogOffset(0),
- ).snapshot.values.subagentNames).toEqual([{ childId: 'child', name: 'lead/worker' }])
- })
-
- it('rejects a version-matching checkpoint with invalid binding fields', async () => {
- const projections = await registry()
- const invalid = {
- subagentNames: {
- ver: 1, seq: SessionSeq(0),
- val: { inheritedEventCount: 0, bindings: [{ childId: 'child', name: 'Invalid' }] },
- },
- }
-
- expect(projections.viewCheckpoint(invalid)).toEqual({})
- expect(() => projections.restore(
- invalid, [], SessionLogOffset(1), header, SessionLogOffset(0),
- )).toThrow()
- })
-})
diff --git a/packages/subagent/subagent-names/tsconfig.json b/packages/subagent/subagent-names/tsconfig.json
deleted file mode 100644
index 943cc3e212..0000000000
--- a/packages/subagent/subagent-names/tsconfig.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "extends": "../../../tsconfig.base.json",
- "compilerOptions": {
- "rootDir": "src",
- "outDir": "lib/types"
- },
- "include": [
- "src"
- ],
- "references": [
- {
- "path": "../../../vendor/cosmokit"
- },
- {
- "path": "../../../vendor/cordis"
- },
- {
- "path": "../../llm/llm"
- },
- {
- "path": "../../core/session"
- },
- {
- "path": "../../session/session-projection"
- }
- ]
-}
diff --git a/packages/subagent/subagent-spawn-in-process/package.json b/packages/subagent/subagent-spawn-in-process/package.json
index d410e182fe..5eb7538c7e 100644
--- a/packages/subagent/subagent-spawn-in-process/package.json
+++ b/packages/subagent/subagent-spawn-in-process/package.json
@@ -47,7 +47,6 @@
"@deepseek-ai/dsh-llm-deepseek-api-key": "workspace:*",
"@deepseek-ai/dsh-session": "workspace:*",
"@deepseek-ai/dsh-subagent": "workspace:*",
- "@deepseek-ai/dsh-subagent-names": "workspace:*",
"@deepseek-ai/dsh-tool-bash": "workspace:*",
"@deepseek-ai/dsh-tool-subagent": "workspace:*",
"@deepseek-ai/cordis": "workspace:~",
diff --git a/packages/subagent/subagent-spawn-in-process/tests/harness.ts b/packages/subagent/subagent-spawn-in-process/tests/harness.ts
index 2493d2b878..6bc59cb6b4 100644
--- a/packages/subagent/subagent-spawn-in-process/tests/harness.ts
+++ b/packages/subagent/subagent-spawn-in-process/tests/harness.ts
@@ -11,7 +11,6 @@ import LocalSubprocessRuntime from '@deepseek-ai/dsh-subprocess-local'
import * as ToolBash from '@deepseek-ai/dsh-tool-bash'
import * as LlmDeepSeek from '@deepseek-ai/dsh-llm-deepseek-api-key'
import SubagentRuntime from '@deepseek-ai/dsh-subagent'
-import SubagentNames from '@deepseek-ai/dsh-subagent-names'
import * as Spawn from '../src/index.ts'
import * as ToolSubagent from '@deepseek-ai/dsh-tool-subagent'
@@ -41,7 +40,6 @@ export async function spawnHarness(workdir: string): Promise {
await ctx.plugin(JsonlSessionPersistence, { root: join(workdir, '.sessions') })
await mountWorkingDirectoryFixture(ctx)
await ctx.plugin(SubagentRuntime)
- await ctx.plugin(SubagentNames)
await ctx.plugin(Spawn, { providerName: 'spawn' })
// The model-facing subagent tool, bound to the spawn backend.
await ctx.plugin(ToolSubagent, { provider: 'spawn' })
diff --git a/packages/subagent/subagent/README.i18n.yaml b/packages/subagent/subagent/README.i18n.yaml
index f2d958e978..106360686c 100644
--- a/packages/subagent/subagent/README.i18n.yaml
+++ b/packages/subagent/subagent/README.i18n.yaml
@@ -33,8 +33,8 @@
en: a740e5e9bdd661d9
zh: 712a5458fc8b3615
/deepseek-ai-dsh-subagent/use-this-package/messaging-interrupting-and-discovering:
- en: c6b551c4dc6dde80
- zh: a03e93ca3ca3e67d
+ en: bf3175c2218a16dd
+ zh: 4be9271efe71ddb7
/deepseek-ai-dsh-subagent/use-this-package/failure-and-recovery:
en: 0dc416ded19e304e
zh: 4726e5fe5f188709
diff --git a/packages/subagent/subagent/README.md b/packages/subagent/subagent/README.md
index dcd702422f..4803cff356 100644
--- a/packages/subagent/subagent/README.md
+++ b/packages/subagent/subagent/README.md
@@ -68,7 +68,7 @@ In-process spawn accepts an independent `agentPreset`; fork and external backend
### Messaging, interrupting, and discovering
-`sendMessage()` lets the live root and resident continuable subagents contact any other root or continuable member in the same tree by Session id. The target receives Steer input at its next step or starts an idle turn. Only the cold target resumes, under the subagent tree root; its creation ancestors stay offline and the message retains its actual sender. The message service resolves visible attribution from the actual sender through the naming service and the tree root Session; without a provider, the Session id is used. Durable attribution always keeps `senderSessionId`. `rootOf()` resolves the caller’s live root. Agent interruption requires ancestor authority. Browser prompts and user interrupts address only the child Session; the Gateway checks the corresponding action on that Session before any side effect. Parent or global grants do not imply child access. Prompts require a live subagent tree root; the creator may be offline. User interrupts perform no restoration and accept absent targets as no-ops. They select Queue or Steer and admit image batches through the attachment store; incompatible target models reject images. `listDescendants()` discovers members recursively through parent-owned `subagentCatalog` projections. It preserves catalog order, reads each reachable Session once, skips external leaves, and reports unreadable branches without activating Agents.
+`sendMessage()` lets the live root and resident continuable subagents contact any other root or continuable member in the same tree by Session id. The target receives Steer input at its next step or starts an idle turn. Only the cold target resumes, under the subagent tree root; its creation ancestors stay offline and the message retains its actual sender. `rootOf()` resolves the caller’s live root. Agent interruption requires ancestor authority. Browser prompts and user interrupts address only the child Session; the Gateway checks the corresponding action on that Session before any side effect. Parent or global grants do not imply child access. Prompts require a live subagent tree root; the creator may be offline. User interrupts perform no restoration and accept absent targets as no-ops. They select Queue or Steer and admit image batches through the attachment store; incompatible target models reject images. `listDescendants()` discovers members recursively through parent-owned `subagentCatalog` projections. It preserves catalog order, reads each reachable Session once, skips external leaves, and reports unreadable branches without activating Agents.
### Failure and recovery
diff --git a/packages/subagent/subagent/README.zh.md b/packages/subagent/subagent/README.zh.md
index 2da7571227..c73f19f5ba 100644
--- a/packages/subagent/subagent/README.zh.md
+++ b/packages/subagent/subagent/README.zh.md
@@ -68,7 +68,7 @@ kind: "package-reference"
### 消息、中断与发现
-`sendMessage()` 允许在线根和驻留的可继续子代理,按 Session id 联系同一棵树中的任意其他根或可继续成员。目标在下一步接收 Steer 输入,或在空闲时开始轮次。仅在 subagent 树根下恢复冷目标,其创建祖先保持离线;消息保留实际发送者。`rootOf()` 解析调用方的在线根。Agent 中断要求祖先权限。浏览器提示词和用户中断仅按子 Session 寻址;Gateway 在任何副作用之前检查该 Session 上对应操作的权限。父级或 global 授权不意味着子级访问权。提示词要求 subagent 树根在线;创建者可以离线。用户中断不恢复目标,目标缺席时接受为无操作。提示词选择 Queue 或 Steer,经附件存储接受图片批次;不兼容的目标模型拒绝图片。`listDescendants()` 通过父级拥有的 `subagentCatalog` 投影递归发现成员。它保留目录顺序,每个可达 Session 读取一次,跳过外部叶子,并报告不可读分支而不激活 Agent。 消息服务通过命名服务和树根 Session,从实际发送者自动解析消息中显示的名称;没有提供方时使用 Session id。持久归属始终保留 `senderSessionId`。
+`sendMessage()` 允许在线根和驻留的可继续子代理,按 Session id 联系同一棵树中的任意其他根或可继续成员。目标在下一步接收 Steer 输入,或在空闲时开始轮次。仅在 subagent 树根下恢复冷目标,其创建祖先保持离线;消息保留实际发送者。`rootOf()` 解析调用方的在线根。Agent 中断要求祖先权限。浏览器提示词和用户中断仅按子 Session 寻址;Gateway 在任何副作用之前检查该 Session 上对应操作的权限。父级或 global 授权不意味着子级访问权。提示词要求 subagent 树根在线;创建者可以离线。用户中断不恢复目标,目标缺席时接受为无操作。提示词选择 Queue 或 Steer,经附件存储接受图片批次;不兼容的目标模型拒绝图片。`listDescendants()` 通过父级拥有的 `subagentCatalog` 投影递归发现成员。它保留目录顺序,每个可达 Session 读取一次,跳过外部叶子,并报告不可读分支而不激活 Agent。
### 失败与恢复
diff --git a/packages/subagent/subagent/package.json b/packages/subagent/subagent/package.json
index 445ffebd57..07d7ec7f55 100644
--- a/packages/subagent/subagent/package.json
+++ b/packages/subagent/subagent/package.json
@@ -72,8 +72,7 @@
"@deepseek-ai/dsh-util-time": "workspace:*",
"@deepseek-ai/dsh-permission-presets": "workspace:*",
"@deepseek-ai/dsh-workspace": "workspace:*",
- "@deepseek-ai/dsh-working-directory": "workspace:*",
- "@deepseek-ai/dsh-subagent-names": "workspace:*"
+ "@deepseek-ai/dsh-working-directory": "workspace:*"
},
"peerDependenciesMeta": {
"@deepseek-ai/dsh-agent-preset-registry": {
@@ -99,9 +98,6 @@
},
"@deepseek-ai/dsh-user-approval": {
"optional": true
- },
- "@deepseek-ai/dsh-subagent-names": {
- "optional": true
}
},
"devDependencies": {
@@ -132,7 +128,6 @@
"@deepseek-ai/dsh-fs-sandbox": "workspace:*",
"@deepseek-ai/dsh-tool-fs": "workspace:*",
"@deepseek-ai/dsh-session-persistence-jsonl": "workspace:*",
- "@deepseek-ai/dsh-working-directory": "workspace:*",
- "@deepseek-ai/dsh-subagent-names": "workspace:*"
+ "@deepseek-ai/dsh-working-directory": "workspace:*"
}
}
diff --git a/packages/subagent/subagent/src/continuation-messages.ts b/packages/subagent/subagent/src/continuation-messages.ts
index 3d76d6fce6..8b97212a59 100644
--- a/packages/subagent/subagent/src/continuation-messages.ts
+++ b/packages/subagent/subagent/src/continuation-messages.ts
@@ -58,17 +58,15 @@ function agentMessageSource(sender: Agent): AgentMessageSource {
* Build the model-visible and durable representation of one Agent message.
* @param sender - exact live Agent that authored the message.
* @param content - model-visible message blocks supplied by the sender.
- * @param senderName - resolved sender name or Session id for the visible attribution.
* @returns the durable user-message representation delivered to the recipient.
*/
export function createAgentMessage(
sender: Agent,
content: ContentBlock[],
- senderName: string,
): ReturnType {
return createUserMessage({
content: [
- { type: 'text' as const, text: `Agent ${senderName} sent a message: ` },
+ { type: 'text' as const, text: `Agent ${sender.id} sent a message: ` },
...content,
],
source: agentMessageSource(sender),
diff --git a/packages/subagent/subagent/src/index.ts b/packages/subagent/subagent/src/index.ts
index 6cd6099683..d79e12bb1d 100644
--- a/packages/subagent/subagent/src/index.ts
+++ b/packages/subagent/subagent/src/index.ts
@@ -311,8 +311,6 @@ export class SubagentRuntime extends TypertRemoteService {
* A cold target resumes under its runtime subagent tree root without restoring
* its creation ancestors. Sender identity is rechecked before inbox acceptance; cancellation
* stops only pre-acceptance work and never retracts an accepted message.
- * Display attribution uses the sender's bound name when the naming service is mounted,
- * otherwise its Session id. Name lookup failures reject before inbox acceptance.
* @param sender - exact live root or resident continuable Agent originating the message.
* @param targetId - another root or continuable member's durable Session id.
* @param content - model-authored content to deliver.
diff --git a/packages/subagent/subagent/src/manager.ts b/packages/subagent/subagent/src/manager.ts
index bd741a6e67..dbd9d3a382 100644
--- a/packages/subagent/subagent/src/manager.ts
+++ b/packages/subagent/subagent/src/manager.ts
@@ -9,7 +9,6 @@
import { randomUUID } from 'node:crypto'
import { isAbsolute, resolve } from 'node:path'
import type {} from '@deepseek-ai/dsh-working-directory'
-import type {} from '@deepseek-ai/dsh-subagent-names'
import type { Context } from '@deepseek-ai/cordis'
import type { Agent, AgentOptions, CreateAgentOptions } from '@deepseek-ai/dsh-agent'
import { brandString } from '@deepseek-ai/dsh-brand'
@@ -486,9 +485,7 @@ export class SubagentManager {
const root = this.rootOf(sender)
if (sender.id === targetId) throw new SubagentError('send_message requires another agent in the subagent tree', 'UNAUTHORIZED')
this.assertAdmitting(sender)
- const names = this.ctx.get('subagentNames')
- const senderName = names === undefined ? sender.id : names.nameOf(root.session, sender.id)
- const message = createAgentMessage(sender, content, senderName)
+ const message = createAgentMessage(sender, content)
const activation = this.resident.get(sender.id)
return this.deliverToMember(root, targetId, [...message.content], {
signal: options.signal, delivery: 'steer', source: message.source,
diff --git a/packages/subagent/subagent/tests/continuation.spec.ts b/packages/subagent/subagent/tests/continuation.spec.ts
index 71c7f98430..73c18d70b2 100644
--- a/packages/subagent/subagent/tests/continuation.spec.ts
+++ b/packages/subagent/subagent/tests/continuation.spec.ts
@@ -12,7 +12,6 @@ import { agentEvents } from '@deepseek-ai/dsh-agent'
import AgentLoop from '@deepseek-ai/dsh-agent-loop'
import { mountAgentLoopTestDependencies } from '@deepseek-ai/dsh-agent-loop-testkit'
import { SessionId } from '@deepseek-ai/dsh-session'
-import SubagentNames from '@deepseek-ai/dsh-subagent-names'
import type { SessionEvent, SessionEventMap } from '@deepseek-ai/dsh-session'
import * as JsonlSessionPersistence from '@deepseek-ai/dsh-session-persistence-jsonl'
import * as SubagentSpawn from '@deepseek-ai/dsh-subagent-spawn-in-process'
@@ -2965,7 +2964,6 @@ describe('continuable settlement delivery', () => {
it('includes the child answer when messaging is available', async () => {
const { ctx, parent } = await setup([textResponse('the answer'), textResponse('parent ack')])
- await ctx.plugin(SubagentNames)
await ctx.plugin(SubagentControl)
const started = await ctx.subagents.startActivation({ ...startSpec(parent), delivery: 'parent' })
await waitNoActivation(ctx, started.childId)
@@ -3086,7 +3084,7 @@ describe('continuable settlement delivery', () => {
const parentId = /Your parent agent id is \\"([^\\]+)\\"/.exec(history)![1]!
const calls = order.map(name => name === 'noop'
? { id: ToolCallId('n1'), name, arguments: '{}' }
- : { id: ToolCallId('s1'), name, arguments: JSON.stringify({ name: parentId, message: 'interim' }) })
+ : { id: ToolCallId('s1'), name, arguments: JSON.stringify({ agent_id: parentId, message: 'interim' }) })
return [
...calls.flatMap((call, index): StreamChunk[] => [
{ type: 'block-start', index, blockType: 'tool-call' },
@@ -3098,7 +3096,6 @@ describe('continuable settlement delivery', () => {
]
}
const { ctx, parent } = await setup(Array.from({ length: 6 }, () => respond))
- await ctx.plugin(SubagentNames)
await ctx.plugin(SubagentControl)
ctx.tools.register(defineTool({
name: 'noop',
diff --git a/packages/subagent/subagent/tests/parent-result.spec.ts b/packages/subagent/subagent/tests/parent-result.spec.ts
index 319986750f..1d16f38cc2 100644
--- a/packages/subagent/subagent/tests/parent-result.spec.ts
+++ b/packages/subagent/subagent/tests/parent-result.spec.ts
@@ -6,7 +6,6 @@ import { Context } from '@deepseek-ai/cordis'
import AgentLoop from '@deepseek-ai/dsh-agent-loop'
import { mountAgentLoopTestDependencies } from '@deepseek-ai/dsh-agent-loop-testkit'
import { SessionId } from '@deepseek-ai/dsh-session'
-import SubagentNames from '@deepseek-ai/dsh-subagent-names'
import * as Spawn from '@deepseek-ai/dsh-subagent-spawn-in-process'
import * as Control from '@deepseek-ai/dsh-tool-subagent-control'
import { MockAdapter, textResponse, toolCallResponse } from '../../../core/agent-loop/tests/mock-adapter.ts'
@@ -20,7 +19,6 @@ it.each(['absent', 'unused'] as const)('returns the closing answer when send_mes
await ctx.plugin(AgentLoop, { agents: [] })
await mountWorkingDirectoryFixture(ctx)
await ctx.plugin(SubagentRuntime)
- await ctx.plugin(SubagentNames)
await ctx.plugin(Spawn, { providerName: 'spawn' })
if (availability !== 'absent') await ctx.plugin(Control)
const adapter = new MockAdapter([textResponse('CHILD_RESULT_42'), textResponse('Parent received the answer.')])
@@ -50,7 +48,6 @@ it('delivers structured output to the parent when the child has send_message', a
await ctx.plugin(AgentLoop, { agents: [] })
await mountWorkingDirectoryFixture(ctx)
await ctx.plugin(SubagentRuntime)
- await ctx.plugin(SubagentNames)
await ctx.plugin(Spawn, { providerName: 'spawn' })
await ctx.plugin(Control)
const adapter = new MockAdapter([
diff --git a/packages/subagent/subagent/tsconfig.json b/packages/subagent/subagent/tsconfig.json
index 50f0c80a1b..8783b69afc 100644
--- a/packages/subagent/subagent/tsconfig.json
+++ b/packages/subagent/subagent/tsconfig.json
@@ -73,9 +73,6 @@
},
{
"path": "../../session/working-directory"
- },
- {
- "path": "../subagent-names"
}
]
}
diff --git a/packages/subagent/tool-subagent-control/README.i18n.yaml b/packages/subagent/tool-subagent-control/README.i18n.yaml
index baa896f85f..83515c71aa 100644
--- a/packages/subagent/tool-subagent-control/README.i18n.yaml
+++ b/packages/subagent/tool-subagent-control/README.i18n.yaml
@@ -9,38 +9,38 @@
en: 465d36925c792167
zh: 269cac314f638827
/deepseek-ai-dsh-tool-subagent-control/summary:
- en: 02f6c3d0e96dfc56
- zh: 79eb0cf759d9a849
+ en: 7e68f9a2d58e1ab6
+ zh: 24edd923e898cc3b
/deepseek-ai-dsh-tool-subagent-control/table-of-contents:
en: d152484eb41ac6b4
zh: 09388d293f9be9cb
/deepseek-ai-dsh-tool-subagent-control/use-this-package:
- en: a64710fadb2b8913
- zh: 7eb30752c24604b2
+ en: f486d856fd8e392c
+ zh: 6ddbc59dd08d3c49
/deepseek-ai-dsh-tool-subagent-control/use-this-package/minimal-configuration:
en: d224de77b41ed4e4
zh: f1e94f9cc9e04384
/deepseek-ai-dsh-tool-subagent-control/use-this-package/send-message:
- en: b4475ddaeb2dd461
- zh: e907663d014a0639
+ en: 849b9b3e576aed01
+ zh: d52239ca40d3a168
/deepseek-ai-dsh-tool-subagent-control/use-this-package/interrupt-agent:
- en: a01fe963745c654c
- zh: 71466b72505cf80c
+ en: de45d5a4b98d3c91
+ zh: 666aa187170b9c0d
/deepseek-ai-dsh-tool-subagent-control/use-this-package/wait-agent:
en: 29a3466bcc8e8e9d
zh: ea38770df450a43e
/deepseek-ai-dsh-tool-subagent-control/use-this-package/list-agents:
- en: d8cbaa3189c9ecc5
- zh: 7409b14df342fb53
+ en: 912206fb3da120b5
+ zh: 3b247046a52d5f2a
/deepseek-ai-dsh-tool-subagent-control/understand-the-implementation:
en: c5cdf01a78c990f2
zh: 53c180d726ce4502
/deepseek-ai-dsh-tool-subagent-control/understand-the-implementation/design-concept:
- en: 23d67aa784753b65
- zh: b4064f922b104992
+ en: 3b6f1956d232964d
+ zh: 9949b906020c9a79
/deepseek-ai-dsh-tool-subagent-control/understand-the-implementation/delivery-and-signal-ownership:
- en: 186b5c0fad1a176b
- zh: 6c3a104e7f4ba0fe
+ en: 65137f5fe14ebb7f
+ zh: ce00e4f32709246a
/deepseek-ai-dsh-tool-subagent-control/understand-the-implementation/listing-projection:
en: ee3136b09f0c9ef2
zh: 5cbe189bb857fdc7
@@ -57,32 +57,32 @@
en: e4c7376d4f29dbd5
zh: 6b7a9eaf69c9ea53
/deepseek-ai-dsh-tool-subagent-control/model-experience/tool-schema/what-the-model-sees:
- en: 22389e32a54dc053
- zh: 37ad7b7a9c2f67d0
+ en: db2e45684a4d0117
+ zh: 5cd3b646c010b530
/deepseek-ai-dsh-tool-subagent-control/model-experience/tool-schema/token-effect:
en: 5eb1d46a94b7ec1b
zh: 5670760ca695d4ad
/deepseek-ai-dsh-tool-subagent-control/model-experience/tool-schema/kv-cache-effect:
- en: 53a81243f3acd543
- zh: 472cf727e5180501
+ en: 89619e31f3ea7585
+ zh: 5681bc8096cd8e32
/deepseek-ai-dsh-tool-subagent-control/model-experience/communication-context:
en: 95d76d1aba983086
zh: b645a3837ec17ef4
/deepseek-ai-dsh-tool-subagent-control/model-experience/communication-context/what-the-model-sees:
- en: adb5b38af8f1cfb1
- zh: 2a7f2779ed5e8a9f
+ en: 037ef2cc0d09692c
+ zh: 57691926fb5b4e41
/deepseek-ai-dsh-tool-subagent-control/model-experience/communication-context/token-effect:
en: 24d9c15986cb4d3d
zh: 6fb66cf84f8bc812
/deepseek-ai-dsh-tool-subagent-control/model-experience/communication-context/kv-cache-effect:
- en: be04fa8fa539cad0
- zh: 797fd37af7d32f90
+ en: d5c696fb6be74875
+ zh: 433881338cffd55e
/deepseek-ai-dsh-tool-subagent-control/model-experience/interrupt-result:
en: d64e936e83e89a2b
zh: b9905c33af6cca45
/deepseek-ai-dsh-tool-subagent-control/model-experience/interrupt-result/what-the-model-sees:
- en: 00d6ca03eab6e7fa
- zh: 202e242f06ea8818
+ en: 89305619897680ba
+ zh: e610a844fc09c53f
/deepseek-ai-dsh-tool-subagent-control/model-experience/interrupt-result/token-effect:
en: 5d1bcef28b5f18da
zh: 027d67d93d660e76
@@ -93,11 +93,11 @@
en: ab964e307bd37dca
zh: 03f975252f838a42
/deepseek-ai-dsh-tool-subagent-control/model-experience/delivery-result/what-the-model-sees:
- en: b8d03632a5550f87
- zh: 084e74cf10944b23
+ en: 8746cb9fa6557bfe
+ zh: 49828e113e901160
/deepseek-ai-dsh-tool-subagent-control/model-experience/delivery-result/token-effect:
- en: 721928e32768b3ad
- zh: a314801790bd58a9
+ en: f7e47f835a1e0628
+ zh: d2818b98c773ad35
/deepseek-ai-dsh-tool-subagent-control/model-experience/delivery-result/kv-cache-effect:
en: f5d5f97a153f7c70
zh: 3d6bc05b9eadfbc2
@@ -105,8 +105,8 @@
en: 094e55d258f2ec2e
zh: f364bc9046530bff
/deepseek-ai-dsh-tool-subagent-control/model-experience/listing-result/what-the-model-sees:
- en: aeef4da057b78b1f
- zh: f500ca4ceab1f87a
+ en: b56b4d01b6516e13
+ zh: f9089c18c732539c
/deepseek-ai-dsh-tool-subagent-control/model-experience/listing-result/token-effect:
en: 027aaeb808238388
zh: 5b974abc429d9e23
diff --git a/packages/subagent/tool-subagent-control/README.md b/packages/subagent/tool-subagent-control/README.md
index a090bd8168..88675a1062 100644
--- a/packages/subagent/tool-subagent-control/README.md
+++ b/packages/subagent/tool-subagent-control/README.md
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
## Summary
-`dsh-tool-subagent-control` lets agents discover and message their subagent tree by path or Session id, interrupt descendants, and wait for their own next-step inbox. By default, one plugin instance registers all four tools; members inherit the same definitions and ordering.
+`dsh-tool-subagent-control` lets agents discover and message their subagent tree by Session id, interrupt descendants, and wait for their own next-step inbox. By default, one plugin instance registers all four tools; members inherit the same definitions and ordering.
## Table of Contents
@@ -25,7 +25,7 @@ English | [中文](README.zh.md)
## Use this package
-Mount this package once per tool scope. It requires `tools`, `subagents`, `subagentNames`, `agents`, and `systemPrompt`. The [subagent-names](../subagent-names/README.md) plugin resolves names and Session ids through the fixed `name` argument. Cordis removes these tools when the naming service unloads and restores them when it returns.
+Mount this package once per tool scope. It requires `tools`, `subagents`, `agents`, and `systemPrompt`.
### Minimal configuration
@@ -33,7 +33,6 @@ With the required services available, load the subagent service, a backend, the
```yaml
- name: '@deepseek-ai/dsh-subagent'
-- name: '@deepseek-ai/dsh-subagent-names'
- name: '@deepseek-ai/dsh-subagent-spawn-in-process'
- name: '@deepseek-ai/dsh-tool-subagent'
config:
@@ -45,11 +44,11 @@ Set `config.interrupt: false` to omit `interrupt_agent`. The default is `true`.
### send_message
-`name` selects a full path or Session id of another agent in the same subagent tree. The caller must be the live root or a resident continuable subagent. A working target receives Steer input at its next step; an inactive target starts or resumes a turn. Only the target resumes; its creation ancestors stay offline. Success returns inbox acceptance (`messageId`), never a reply. Self, unrelated trees, unsupported targets, unknown ids, unavailable history, and rejected admission return errors.
+Sends a message to another agent in the same subagent tree by `agent_id`. The caller must be the live root or a resident continuable subagent. A working target receives Steer input at its next step; an inactive target starts or resumes a turn. Only the target resumes; its creation ancestors stay offline. Success returns inbox acceptance (`messageId`), never a reply. Self, unrelated trees, unsupported targets, unknown ids, unavailable history, and rejected admission return errors.
### interrupt_agent
-`name` identifies a descendant by full path or Session id. External executions stop permanently and cannot receive follow-ups. Local targets stop only their current turn: queued messages stay parked until a later `send_message`, descendants keep running, and the child stays available for follow-ups. The call returns when the stop request is accepted, not when the target is quiet; interrupting an already-finished agent is an accepted no-op, and self, sibling, stale, and non-ancestor callers get errored results.
+`agent_id` identifies a descendant by Session id. External executions stop permanently and cannot receive follow-ups. Local targets stop only their current turn: queued messages stay parked until a later `send_message`, descendants keep running, and the child stays available for follow-ups. The call returns when the stop request is accepted, not when the target is quiet; interrupting an already-finished agent is an accepted no-op, and self, sibling, stale, and non-ancestor callers get errored results.
### wait_agent
@@ -58,7 +57,7 @@ Waits for the exact caller’s next-step inbox. Pending input returns immediatel
### list_agents
-Lists the root and all reachable continuable descendants, including the caller, in stable pre-order. Rows retain Session ids, parent ids, and depth from the root. The naming plugin adds `name` and `parentName` when a mapping is available; the root is named `lead`. Unnamed children retain their ids. Each child’s label comes from the `description` supplied at creation. Live status is `running` or `inactive`. External entries are omitted without reading child Sessions; readable one-shot children remain traversal nodes. Unknown modes and unreadable catalogs produce diagnostics. Ordinary Session forks lead separate subagent trees.
+Lists the root and all reachable continuable descendants, including the caller, in stable pre-order. Descendant rows carry their direct parent id and depth from the root. Live status is `running` or `inactive`. External entries are omitted without reading child Sessions; readable one-shot children remain traversal nodes. Unknown modes and unreadable catalogs produce diagnostics. Ordinary Session forks lead separate subagent trees.
-----
@@ -72,11 +71,11 @@ This section explains what the tools delegate to the subagent service; the obser
### Design concept
-`ctx.subagentNames` resolves names synchronously; messaging, interruption, and catalog traversal delegate to `ctx.subagents`; residency, cold resume, and authorization belong to that service. The wait tool subscribes to the exact caller’s inbox before starting the timer and checking pending next-step input, and removes its listeners and timer on every settlement.
+Messaging, interruption, and discovery delegate to `ctx.subagents`; residency, cold resume, and authorization belong to that service. The wait tool subscribes to the exact caller’s inbox events before starting the timer and checking pending next-step input, and removes its listeners and timer on every settlement.
### Delivery and signal ownership
-The execution signal owns work only until inbox acceptance. Accepted messages cannot be cancelled through this tool. Every message is framed as `Agent sent a message:` and recorded with `{ kind: 'agent-message', form: 'relay', senderSessionId: sender.id }`. Tree membership authorizes communication; the subagent tree root owns runtime instances and capacity.
+The execution signal owns work only until inbox acceptance. Accepted messages cannot be cancelled through this tool. Every message is framed as `Agent sent a message:` and recorded with `{ kind: 'agent-message', form: 'relay', senderSessionId: sender.id }`. Tree membership authorizes communication; the subagent tree root owns runtime instances and capacity.
### Listing projection
@@ -112,7 +111,7 @@ Read these pages when the package-level contract is not enough; they move from t
#### What the model sees
-The generated [schemas](../../../docs/tool-catalog.md#deepseek-aidsh-tool-subagent-control) define path- or id-addressed messaging and interruption, whole-tree discovery, and inbox waiting with `timeout_ms`. `wait_agent` returns `{ "timedOut": false }` for available input, and `{ "timedOut": true }` on timeout. It returns no message body or peer-activity diagnosis.
+The generated [schemas](../../../docs/tool-catalog.md#deepseek-aidsh-tool-subagent-control) define id-addressed messaging and interruption, whole-tree discovery, and inbox waiting with `timeout_ms`. `wait_agent` returns `{ "timedOut": false }` for available input, and `{ "timedOut": true }` on timeout. It returns no message body or peer-activity diagnosis.
#### Token effect
@@ -120,13 +119,13 @@ Fixed schema cost per request, independent of the number or descriptions of chil
#### KV Cache effect
-The schema prefix stays stable while these tools are available. A parent and its continuable children, including fork children, inherit the same definitions.
+Prefix-stable; the schemas do not change at runtime, and a parent and its continuable children, including fork children, receive identical definitions.
### Communication context
#### What the model sees
-The logged `subagent:communication` runtime context tells delegated children their direct creator’s JSON-encoded Session id and how to send findings that change the parent’s next action. Named controls also accept this id. Sending a message does not end the turn. Root Agents and ordinary Session forks receive no communication context; delegated children receive it only when the standard messaging definition is admitted in the current scope and step. Automatic result delivery remains owned by the subagent service.
+The logged `subagent:communication` runtime context tells delegated children their direct creator’s JSON-encoded id and how to send findings that change the parent’s next action. Sending a message does not end the turn. Root Agents and ordinary Session forks receive no communication context; delegated children receive it only when the standard messaging definition is admitted in the current scope and step. Automatic result delivery remains owned by the subagent service.
#### Token effect
@@ -134,13 +133,13 @@ One short context entry per delegated child, independent of tree size.
#### KV Cache effect
-Communication guidance is retained as runtime context after inherited history, leaving the shared system prompt and tool definitions unchanged between parent and child. The parent id comes from the child Session header; prompt assembly does not wait for a name binding or read the name map.
+Communication guidance is retained as runtime context after inherited history, leaving the shared system prompt and tool definitions unchanged between parent and child. Cold resume derives the parent id again from the target Session.
### Interrupt result
#### What the model sees
-`interrupt requested for agent ` on acceptance. An unauthorized caller — self, sibling, stale, or non-ancestor — is an errored result naming the rejection; a known settled target still renders the acceptance line. Unknown name paths are rejected; an absent raw Session id retains an accepted no-op.
+`interrupt requested for agent ` on acceptance. An unauthorized caller — self, sibling, stale, or non-ancestor — is an errored result naming the rejection; an absent or settled target still renders the acceptance line.
#### Token effect
@@ -154,11 +153,11 @@ Append-only; each result follows the reusable request prefix.
#### What the model sees
-`message delivered to agent ` on acceptance; canonical output carries the accepted `messageId`. A target outside the caller’s subagent tree or rejected admission produces an errored result.
+`message delivered to agent ` on acceptance; canonical output carries the accepted `messageId`. A target outside the caller’s subagent tree or rejected admission produces an errored result.
#### Token effect
-One short acknowledgement per call; replies arrive as separately addressed messages. Use addresses from `list_agents` for follow-ups across the subagent tree.
+One short acknowledgement per call; replies arrive as separately addressed messages. Use ids from `list_agents` for follow-ups across the subagent tree.
#### KV Cache effect
@@ -168,7 +167,7 @@ Append-only; newly visible content follows the reusable request prefix and does
#### What the model sees
-The first row is ` [] — lead: root agent`. Each continuable descendant follows as ` [] parent= depth= —