From 823dd2d687a3f4bb09b3996cfe59f1c146a35b1f Mon Sep 17 00:00:00 2001 From: "codenomadbot[bot]" <261069733+codenomadbot[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 22:48:06 +0000 Subject: [PATCH] Suppress OS notifications for subagent (child) sessions (#236) This PR prevents OS notification spam from spawned subagent sessions by skipping OS-level notifications for any session that is a child thread (`parentId !== null`). What changed - `packages/ui/src/stores/session-events.ts` - Added `isChildSession(...)` + `shouldSendOsNotificationForSession(...)` - Applied the check to OS notifications emitted from: - `handleSessionIdle(...)` - `handlePermissionUpdated(...)` - `handleQuestionAsked(...)` - If a session is not yet hydrated in the client store, we conservatively *do not* emit an OS notification (avoids early subagent spam). Why - Subagent sessions are represented as child sessions in the UI thread model; OS notifications were previously emitted for all sessions indiscriminately. Testing - Not run here: `bun run typecheck` fails in this environment due to missing installed deps/types (e.g. `solid-js`). Closes #228 -- Yours, [CodeNomadBot](https://github.com/NeuralNomadsAI/CodeNomad) Co-authored-by: Shantur Rathore --- packages/ui/src/stores/session-events.ts | 35 ++++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/packages/ui/src/stores/session-events.ts b/packages/ui/src/stores/session-events.ts index 710c7dab..bb780d59 100644 --- a/packages/ui/src/stores/session-events.ts +++ b/packages/ui/src/stores/session-events.ts @@ -77,6 +77,29 @@ function shouldSendOsNotification(kind: "needsInput" | "idle"): boolean { return false } +function isChildSession(instanceId: string, sessionId: string): boolean | null { + const session = sessions().get(instanceId)?.get(sessionId) + if (!session) return null + return session.parentId !== null && session.parentId !== undefined +} + +function shouldSendOsNotificationForSession( + kind: "needsInput" | "idle", + instanceId: string, + sessionId: string | undefined | null, +): boolean { + if (!shouldSendOsNotification(kind)) return false + if (!sessionId) return true + + const child = isChildSession(instanceId, sessionId) + + // Avoid notification spam from spawned child/subagent sessions arriving before hydration. + if (child === null) return false + if (child) return false + + return true +} + function getInstanceDisplayName(instanceId: string): string { const instanceFolder = instances().get(instanceId)?.folder ?? instanceId return instanceFolder.split(/[\\/]/).filter(Boolean).pop() ?? instanceFolder @@ -492,7 +515,7 @@ function handleSessionIdle(instanceId: string, event: EventSessionIdle): void { const sessionId = event.properties?.sessionID if (!sessionId) return - if (shouldSendOsNotification("idle")) { + if (shouldSendOsNotificationForSession("idle", instanceId, sessionId)) { const title = getInstanceDisplayName(instanceId) const label = getSessionTitle(instanceId, sessionId) const body = label ? `Session "${label}" is idle` : "Session is idle" @@ -607,9 +630,10 @@ function handlePermissionUpdated(instanceId: string, event: { type: string; prop addPermissionToQueue(instanceId, permission) upsertPermissionV2(instanceId, permission) - if (shouldSendOsNotification("needsInput")) { + const sessionId = getPermissionSessionId(permission) + + if (shouldSendOsNotificationForSession("needsInput", instanceId, sessionId)) { const title = getInstanceDisplayName(instanceId) - const sessionId = getPermissionSessionId(permission) const label = getSessionTitle(instanceId, sessionId) const body = label ? `Session "${label}" needs permission` : "Session needs permission" fireOsNotification({ title, body }) @@ -634,9 +658,10 @@ function handleQuestionAsked(instanceId: string, event: { type: string; properti addQuestionToQueue(instanceId, request) upsertQuestionV2(instanceId, request) - if (shouldSendOsNotification("needsInput")) { + const sessionId = getQuestionSessionId(request) + + if (shouldSendOsNotificationForSession("needsInput", instanceId, sessionId)) { const title = getInstanceDisplayName(instanceId) - const sessionId = getQuestionSessionId(request) const label = getSessionTitle(instanceId, sessionId) const body = label ? `Session "${label}" needs input` : "Session needs input" fireOsNotification({ title, body })