fix(core): tell the parent when an interactive subagent parks

Parking is self-service only for the root, which the user is watching.
A parked child owes its parent a report it can no longer send, so the
parent would wait out its full timeout for nothing.
This commit is contained in:
Ahmed Allam
2026-08-02 02:15:51 +03:00
committed by Ahmed Allam
parent 49057f267f
commit 8f1bb64d16
2 changed files with 82 additions and 0 deletions
+34
View File
@@ -537,6 +537,10 @@ async def _exhausted_recovery(
agent_id,
)
await coordinator.set_status(agent_id, "waiting")
# The user talks to the root, so parking is only self-service there. A parked
# subagent owes its parent a report it can no longer send, and the parent would
# otherwise wait out its full timeout for a message that is never coming.
await _notify_parent_on_stall(coordinator, agent_id)
return result
@@ -839,6 +843,36 @@ _TERMINAL_NOTICE = {
}
_STALL_NOTICE = (
"[Agent stalled] {name} ({agent_id}) kept ending turns without a tool call and is "
"parked until it receives a message. It will not send a completion report on its "
"own: either message it with a concrete next step to unblock it, or stop waiting on "
"it and account for its unfinished subtask."
)
async def _notify_parent_on_stall(
coordinator: AgentCoordinator,
agent_id: str,
) -> None:
"""Tell the parent that a child parked mid-task, so it stops waiting blindly."""
async with coordinator._lock:
parent = coordinator.parent_of.get(agent_id)
name = coordinator.names.get(agent_id, agent_id)
if parent is None:
return
await coordinator.send(
parent,
{
"from": agent_id,
"type": "stalled",
"priority": "high",
"content": _STALL_NOTICE.format(name=name, agent_id=agent_id),
},
interrupt=False,
)
async def _notify_parent_on_terminal(
coordinator: AgentCoordinator,
agent_id: str,