Browse Source

fix(app): notifications on child sessions

Adam 2 weeks ago
parent
commit
a52fe28246
1 changed files with 61 additions and 46 deletions
  1. 61 46
      packages/app/src/context/notification.tsx

+ 61 - 46
packages/app/src/context/notification.tsx

@@ -69,7 +69,7 @@ export const { use: useNotification, provider: NotificationProvider } = createSi
       }),
     )
 
-    const meta = { pruned: false }
+    const meta = { pruned: false, disposed: false }
 
     createEffect(() => {
       if (!ready()) return
@@ -84,6 +84,17 @@ export const { use: useNotification, provider: NotificationProvider } = createSi
 
     const index = createMemo(() => buildNotificationIndex(store.list))
 
+    const lookup = (directory: string, sessionID?: string) => {
+      if (!sessionID) return Promise.resolve(undefined)
+      const [syncStore] = globalSync.child(directory, { bootstrap: false })
+      const match = Binary.search(syncStore.session, sessionID, (s) => s.id)
+      if (match.found) return Promise.resolve(syncStore.session[match.index])
+      return globalSDK.client.session
+        .get({ directory, sessionID })
+        .then((x) => x.data)
+        .catch(() => undefined)
+    }
+
     const unsub = globalSDK.event.listen((e) => {
       const event = e.details
       if (event.type !== "session.idle" && event.type !== "session.error") return
@@ -102,61 +113,65 @@ export const { use: useNotification, provider: NotificationProvider } = createSi
       switch (event.type) {
         case "session.idle": {
           const sessionID = event.properties.sessionID
-          const [syncStore] = globalSync.child(directory, { bootstrap: false })
-          const match = Binary.search(syncStore.session, sessionID, (s) => s.id)
-          const session = match.found ? syncStore.session[match.index] : undefined
-          if (session?.parentID) break
-
-          playSound(soundSrc(settings.sounds.agent()))
-
-          append({
-            directory,
-            time,
-            viewed: viewed(sessionID),
-            type: "turn-complete",
-            session: sessionID,
+          void lookup(directory, sessionID).then((session) => {
+            if (meta.disposed) return
+            if (!session) return
+            if (session.parentID) return
+
+            playSound(soundSrc(settings.sounds.agent()))
+
+            append({
+              directory,
+              time,
+              viewed: viewed(sessionID),
+              type: "turn-complete",
+              session: sessionID,
+            })
+
+            const href = `/${base64Encode(directory)}/session/${sessionID}`
+            if (settings.notifications.agent()) {
+              void platform.notify(
+                language.t("notification.session.responseReady.title"),
+                session.title ?? sessionID,
+                href,
+              )
+            }
           })
-
-          const href = `/${base64Encode(directory)}/session/${sessionID}`
-          if (settings.notifications.agent()) {
-            void platform.notify(
-              language.t("notification.session.responseReady.title"),
-              session?.title ?? sessionID,
-              href,
-            )
-          }
           break
         }
         case "session.error": {
           const sessionID = event.properties.sessionID
-          const [syncStore] = globalSync.child(directory, { bootstrap: false })
-          const match = sessionID ? Binary.search(syncStore.session, sessionID, (s) => s.id) : undefined
-          const session = sessionID && match?.found ? syncStore.session[match.index] : undefined
-          if (session?.parentID) break
-
-          playSound(soundSrc(settings.sounds.errors()))
-
-          const error = "error" in event.properties ? event.properties.error : undefined
-          append({
-            directory,
-            time,
-            viewed: viewed(sessionID),
-            type: "error",
-            session: sessionID ?? "global",
-            error,
+          void lookup(directory, sessionID).then((session) => {
+            if (meta.disposed) return
+            if (session?.parentID) return
+
+            playSound(soundSrc(settings.sounds.errors()))
+
+            const error = "error" in event.properties ? event.properties.error : undefined
+            append({
+              directory,
+              time,
+              viewed: viewed(sessionID),
+              type: "error",
+              session: sessionID ?? "global",
+              error,
+            })
+            const description =
+              session?.title ??
+              (typeof error === "string" ? error : language.t("notification.session.error.fallbackDescription"))
+            const href = sessionID ? `/${base64Encode(directory)}/session/${sessionID}` : `/${base64Encode(directory)}`
+            if (settings.notifications.errors()) {
+              void platform.notify(language.t("notification.session.error.title"), description, href)
+            }
           })
-          const description =
-            session?.title ??
-            (typeof error === "string" ? error : language.t("notification.session.error.fallbackDescription"))
-          const href = sessionID ? `/${base64Encode(directory)}/session/${sessionID}` : `/${base64Encode(directory)}`
-          if (settings.notifications.errors()) {
-            void platform.notify(language.t("notification.session.error.title"), description, href)
-          }
           break
         }
       }
     })
-    onCleanup(unsub)
+    onCleanup(() => {
+      meta.disposed = true
+      unsub()
+    })
 
     return {
       ready,