Skip to content

fix(hooks): don't let a background subagent clear the main agent's 'notification' wait#238

Merged
hoangsonww merged 1 commit into
hoangsonww:masterfrom
Doccy008:fix/subagent-awaiting-guard
Jul 18, 2026
Merged

fix(hooks): don't let a background subagent clear the main agent's 'notification' wait#238
hoangsonww merged 1 commit into
hoangsonww:masterfrom
Doccy008:fix/subagent-awaiting-guard

Conversation

@Doccy008

Copy link
Copy Markdown
Contributor

Problem

PreToolUse and PostToolUse clear awaiting_input_since unconditionally, on the assumption that any tool event means the human resumed. That assumption breaks when the main agent is blocked on the user (an AskUserQuestion / permission prompt) while a background subagent keeps firing PreToolUse/PostToolUse (e.g. WebSearch/WebFetch): the subagent's tool event wipes the wait, even though no human has responded.

The flag then oscillates on/off in seconds, so consumers disagree about the same session — a fast poller catches an "on" moment and shows Waiting, a slower one catches "off" and shows active/working.

This is the same class of bug the code already fixed for SubagentStop (see the comment above the switch: "A subagent or background tool finishing tells us nothing about whether the human has actually responded, so those events must NOT clear the flag.") — PreToolUse/PostToolUse were simply not covered.

Fix

Reuse the existing subagent-actor heuristic (findDeepestWorkingAgent while the main agent is waiting), which the same two cases already use for event attribution:

  • Main agent is the actor → clear unconditionally, as before (keeps the documented permission-mid-tool path where PostToolUse clears an approved prompt).
  • A background subagent is the actor → clear only passive waits (stop / session_start / interrupted); a genuine notification wait is preserved.

Passive-clear-by-subagent is intentionally retained: it's what flips a merely-Stop-ed session back to active while a subagent still works.

Known residual (documented)

If the user answers mid-tool while a background subagent is running, the notification wait can linger until the next Stop/UserPromptSubmit. It's self-healing, and — since hook events carry no explicit agent id — indistinguishable from a subagent's own tool event without a heuristic. A lingering false "waiting" is cheaper than a missed one.

Tests

server/__tests__/awaiting-subagent-guard.test.js — route-level, proven to fail on the pre-fix code:

  • preserves a notification wait across a background subagent's PreToolUse and PostToolUse;
  • still clears a passive stop wait via subagent activity;
  • still clears a notification wait when the main agent itself resumes (no working subagent).

Full server suite green (670 tests).

@Doccy008
Doccy008 requested a review from hoangsonww as a code owner July 17, 2026 18:41
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@github-actions

github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown

✅ All contributors have signed the CLA. Thank you!
Posted by the CLA Assistant Lite bot.

@github-actions github-actions Bot added bug Something isn't working documentation Improvements or additions to documentation enhancement New feature or request good first issue Good for newcomers help wanted Extra attention is needed question Further information is requested labels Jul 17, 2026
…otification' wait

PreToolUse/PostToolUse cleared awaiting_input_since unconditionally, assuming a
tool event means the human resumed. That breaks when the MAIN agent is blocked
on the user (AskUserQuestion/permission) while a BACKGROUND subagent keeps
firing tool events: the subagent's event wiped the wait, so consumers
(AI-Deck 12s poll, deck-web 5s WS) lost the 'waiting for you' signal — it
oscillated on/off in seconds and the two UIs disagreed.

Reuse the existing subagent-actor heuristic (findDeepestWorkingAgent while main
is 'waiting'): when a subagent is the actor, clear only PASSIVE waits
(stop/session_start/interrupted); preserve a genuine 'notification' wait. When
MAIN is the actor, clear unconditionally as before — keeps the documented
permission-mid-tool clear (PostToolUse) intact. Passive-clear-by-subagent is
retained on purpose: it flips a merely-Stopped session back to active while a
subagent still works ('idle only while no agent works').

Known residual: if the user answers mid-tool while a background subagent runs,
the notification wait can linger until the next Stop/UserPromptSubmit —
self-healing, and cheaper than a missed question.

Regression test in server/__tests__/awaiting-subagent-guard.test.js (proven to
fail on the pre-fix code). Fork patch for the home-network AI-Deck/deck-web
consumers; a focused upstream PR follows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Doccy008
Doccy008 force-pushed the fix/subagent-awaiting-guard branch from d3d75d8 to 0dd7978 Compare July 17, 2026 18:49
@Doccy008

Copy link
Copy Markdown
Contributor Author

I have read the CLA Document and I hereby sign the CLA

@hoangsonww
hoangsonww merged commit 36d2cf4 into hoangsonww:master Jul 18, 2026
10 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 18, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

bug Something isn't working documentation Improvements or additions to documentation enhancement New feature or request good first issue Good for newcomers help wanted Extra attention is needed question Further information is requested

Projects

Development

Successfully merging this pull request may close these issues.

2 participants