Repository navigation
Subagent tool description says "returns its result" but the call returns immediately (non-blocking) — and spawn_teammate never says it does not block #10854
warm-flame-core
started this conversation in
General
Replies: 1 comment
|
Currently, a significant portion of my work involves extensive file modifications. After the main agent has completed its planning, it will attempt to utilize either the intelligent agent team or the sub-agent function. However, due to the interdependencies among multiple files, file modifications heavily emphasize both asynchronous and synchronous processes. Often, the lead fails to recognize the need to wait for teammates' changes before proceeding, resulting in premature modifications that disrupt teammates' judgment and lead to repeated rework. A temporary solution involves clearly defining the synchronous and asynchronous methods in file specifications, but I believe this falls under the scope of system prompt design |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Subagent tool description contradicts runtime: it says "returns its result" but returns immediately with
started subagent <id>Summary
The model-facing tool description for
subagent(andsubagent_fork) tells the model it will receive the subagent's result:But the runtime does not wait.
render()returnsstarted subagent ${value.subagentId}, and perpackages/subagent/subagent/README.zh.mdthe tool "立即返回子会话 ID,后台 activation 结算后父级收到完成通知". The result arrives later, as a separate completion notification.A model that trusts the description believes the delegation is synchronous. It then continues immediately, treating the just-launched child as if it had already reported — or it "helpfully" fills the wait with other work. There is no instruction anywhere in the model-visible text telling it that (a) the call returns at once, (b) a completion notification will arrive later and will re-enter the conversation, or (c) what it must do in between.
The
agent-teamplugin has the mirror-image gap:teamPolicy()does say "The Lead must wait for required teammates before giving the final answer" and explainswait_agentsemantics in detail, butspawn_teammate's own description says nothing about the fact that spawning is also non-blocking — it only says "Create one named, durable teammate." A model reading only that tool description has no signal that it mustwait_agent(or at leastlist_agents) before assuming the work is done.Why this matters in practice
In real sessions this produces two recurring failure modes, both observed repeatedly:
Lead continues after spawning. The Lead spawns a subagent or teammate, then immediately performs work that depends on the child's output — using stale conclusions, or producing deliverables that the child's result will invalidate.
Concurrent unsynchronized writes. The Lead spawns a teammate, does not wait, and starts editing files itself. The teammate later edits the same file. Nothing in the model-facing text explains the shared-filesystem + no-lock model strongly enough at the point of the
spawn_teammatecall; the guidance lives only in the injectedteamPolicyblock, far from the tool call itself.The second mode is the expensive one: the teammate discovers the Lead's edit mid-task, its work is invalidated, and it returns to redo it — a full round-trip that a one-line "this call does not block; call
wait_agentbefore depending on the result" would have prevented.Where the gap is
subagent/subagent_forktooldescriptionsubagenttool result (render)started subagent <childId>spawn_teammatetooldescriptionwait_agent/list_agentsteamPolicy()wait_agentsemantics, "The Lead must wait…"spawn_teammatebeing non-blocking; not co-located with the callsubagent(no team plugin)The asymmetry is the core issue: the team plugin injects a policy block that describes waiting, while the plain subagent path injects nothing — yet both are non-blocking. A model that has never been told the subagent path is asynchronous has no way to infer it, and the description actively suggests the opposite.
Suggested fix (small, model-facing text only)
No runtime change needed — the behaviour is fine; the description is what misleads.
providerWording()inpackages/subagent/tool-subagent/src/index.ts— replace "returns its result" with something like:spawn_teammatedescription inpackages/experimental/tool-agent-team/src/index.ts— add one clause:Consider an injected policy block for the plain subagent path, mirroring
teamPolicy(), or at minimum a sentence in the tool resultrender()such asstarted subagent <id> (running in background; result arrives as a notification).Environment
F:\Code\deepseek-harness, HEAD22ddee3792subagentpath and theagent-teamplugin path, across multiple long writing sessions where delegation was used heavily.Happy to open a PR with the wording changes if that is useful — though I understand from CONTRIBUTING that external PRs are not being accepted right now.
All reactions