Count subagents, and keep a batch from looking free
Corrected from the previous commit, which had it backwards. When a batch is running the session is working, not waiting: the main agent will pick the results up and consolidate them itself, so sending you to that terminal wastes the trip. That is the common shape of the work here -- ask for a batch, let it run. Simply letting subagent tool calls set "busy" would mostly work and was tempting, but it leaves a hole. Stop fires before the batch finishes, so the session shows as free from the moment the turn ends until the first subagent tool call lands -- and longer whenever the subagents are thinking rather than calling tools. So subagents are counted instead: PreToolUse, matched to ^(Agent|Task)$ +1 SubagentStop -1 UserPromptSubmit reset to 0 While the count is above zero the session cannot read as waiting; Stop and an idle_prompt nudge both leave it working. The session is freed by the last subagent leaving, and only if the main agent has stopped by then. The matcher is anchored because it is a regex: a bare "Task" also matches TaskCreate and friends, which are not subagents. The hook re-checks the tool name itself in case a future matcher behaves differently, and the reset on UserPromptSubmit bounds a count that leaks because a subagent died without its SubagentStop. Measured, not assumed: a matched PreToolUse fires only on agent launches, SubagentStop arrives once per subagent carrying agent_id, and a real three-subagent run walks the count 0-1-2-3-2-0 before Stop frees it. The menu shows the number, as asked. The panel does not: a batch of eight is still one line saying "working 40 min", which is the right line.
This commit is contained in:
+18
-9
@@ -21,22 +21,31 @@ HOOK = os.path.join(os.path.dirname(os.path.abspath(__file__)), "claude-status-h
|
||||
# before it writes -- observed with `claude -p`, which left a session stuck at
|
||||
# "busy" forever. They fire at most once per turn, so ~20 ms is free; the
|
||||
# per-tool-call events stay async so they never sit in the agent's loop.
|
||||
# (async, matcher). PreToolUse is matched to the agent-spawning tools alone:
|
||||
# unmatched it would fire on every tool call in every session, and the only
|
||||
# thing it is here for is to count subagents as they start. The pattern is
|
||||
# anchored because it is a regex -- a bare "Task" also matches TaskCreate,
|
||||
# TaskUpdate and friends, which are not subagents. The hook re-checks the name
|
||||
# anyway, in case a future matcher works differently.
|
||||
EVENTS = {
|
||||
"SessionStart": True,
|
||||
"UserPromptSubmit": True,
|
||||
"Notification": True,
|
||||
"PostToolUse": True,
|
||||
"PreCompact": True,
|
||||
"Stop": False,
|
||||
"SessionEnd": False,
|
||||
"SessionStart": (True, ""),
|
||||
"UserPromptSubmit": (True, ""),
|
||||
"Notification": (True, ""),
|
||||
"PreToolUse": (True, "^(Agent|Task)$"),
|
||||
"PostToolUse": (True, ""),
|
||||
"PreCompact": (True, ""),
|
||||
"SubagentStop": (True, ""),
|
||||
"Stop": (False, ""),
|
||||
"SessionEnd": (False, ""),
|
||||
}
|
||||
|
||||
|
||||
def entry(async_):
|
||||
def entry(spec):
|
||||
async_, matcher = spec
|
||||
hook = {"type": "command", "command": HOOK, "timeout": 5}
|
||||
if async_:
|
||||
hook["async"] = True
|
||||
return {"matcher": "", "hooks": [hook]}
|
||||
return {"matcher": matcher, "hooks": [hook]}
|
||||
|
||||
|
||||
def is_ours(group):
|
||||
|
||||
Reference in New Issue
Block a user