Skip to content

fix: suppress stop notifications for subagent sessions#22

Merged
harryalbert merged 3 commits into
warpdotdev:mainfrom
aqeelat:fix/subagent-idle-status
Jun 5, 2026
Merged

fix: suppress stop notifications for subagent sessions#22
harryalbert merged 3 commits into
warpdotdev:mainfrom
aqeelat:fix/subagent-idle-status

Conversation

@aqeelat
Copy link
Copy Markdown
Contributor

@aqeelat aqeelat commented Jun 1, 2026

What

Subagent sessions (e.g. from the Task tool) fire session.idle when they complete, causing duplicate stop notifications in Warp.

How

On session.idle, fetch the session via client.session.get() and check parentID. If set, return early — no stop notification is sent for child sessions.

If the fetch fails, the notification is sent anyway to avoid silently dropping it.

Trade-off

This adds one API call (session.get) per session.idle event. Since idle fires once per session completion, the overhead is negligible.

Fetch the session on session.idle to check for parentID. If the session
is a child (subagent) session, return early without sending a stop
notification. Falls through on fetch failure so notifications are never
silently dropped.

Bump version to 0.1.7.
@aqeelat
Copy link
Copy Markdown
Contributor Author

aqeelat commented Jun 2, 2026

@harryalbert
Hi Harry
Can you please take a look?

Copy link
Copy Markdown
Contributor

harryalbert commented Jun 2, 2026

@harryalbert
Hi Harry
Can you please take a look?

​Can do! Feel free to tag me as a reviewer as well going forward (easier to track on my end)

@harryalbert harryalbert self-requested a review June 2, 2026 15:14
Comment thread src/index.ts Outdated
const session = await client.session.get({
path: { id: sessionId },
})
if (session.data?.parentID) return
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you only make this change for the session.idle event? Feels like we might want it for other events too (like prompt_submit, session_start, tool_complete, etc)

Copy link
Copy Markdown
Contributor Author

@aqeelat aqeelat Jun 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@harryalbert
Good point. I originally scoped this to session.idle because that was the noisy notification I observed, but the same subagent semantics should apply across all session-scoped notifications.

I've updated the PR to extract a shared isSubagentSession() helper and apply it to every notification handler: session.created, session.idle, permission.updated, permission.replied, permission.asked, chat.message, tool.execute.before, and tool.execute.after.

One thing I considered but left out: each handler independently calls client.session.get() to check parentID. Since parentID is immutable for a session's lifetime, a simple Map<string, boolean> cache would eliminate redundant lookups when multiple events fire for the same session in quick succession (e.g., tool.execute.beforetool.execute.aftersession.idle). I left it out for now since it's a minor optimization and the current approach is correct. Happy to add it if you'd prefer.

@aqeelat aqeelat force-pushed the fix/subagent-idle-status branch 2 times, most recently from f8cc4fb to 853cafe Compare June 2, 2026 17:14
Copy link
Copy Markdown
Contributor

@harryalbert harryalbert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for iterating! Just had a few more thoughts

Comment thread src/index.ts
async function isSubagentSession(sessionId?: string): Promise<boolean> {
if (!sessionId) return false
try {
const session = await client.session.get({
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mentioned this in your comment, but I think this is worth caching if it doesn't change. Would rather avoid an async call for every hook (especially frequently activated hooks like tool.execute.after) if we can

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aqeelat what do you think of this suggestion

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@harryalbert sorry i had already worked on it but forgot to push.

Comment thread src/index.ts Outdated
switch (event.type) {
case "session.created": {
const sessionId = event.properties.info.id
if (await isSubagentSession(sessionId)) return
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of adding this boundary at every hook (which feels brittle in case we add more hooks and forget to add the check for any of those new hooks), I'd rather this just be one unified gate that we check before surfacing a notification. We could define a wrapper around warpNotify (something like maybeWarpNotify, which would live inside index.ts) that checks the sub-agent predicate and, if it passes, internally calls warpNotify.

@aqeelat aqeelat force-pushed the fix/subagent-idle-status branch from 853cafe to 5107303 Compare June 3, 2026 06:48
@aqeelat aqeelat force-pushed the fix/subagent-idle-status branch from 5107303 to c935ffa Compare June 4, 2026 15:08
@aqeelat
Copy link
Copy Markdown
Contributor Author

aqeelat commented Jun 4, 2026

@harryalbert Both suggestions are addressed in the latest push

I added a Map<string, boolean> cache to isSubagentSession and introduced a maybeWarpNotify wrapper that centralizes the subagent check so all notification paths go through a single gate. Let me know if the implementation matches what you had in mind.

Copy link
Copy Markdown
Contributor

@harryalbert harryalbert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@harryalbert harryalbert merged commit 8469420 into warpdotdev:main Jun 5, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants