|
@@ -4,13 +4,12 @@ import { createSimpleContext } from "@opencode-ai/ui/context"
|
|
|
import { useGlobalSDK } from "./global-sdk"
|
|
import { useGlobalSDK } from "./global-sdk"
|
|
|
import { useGlobalSync } from "./global-sync"
|
|
import { useGlobalSync } from "./global-sync"
|
|
|
import { usePlatform } from "@/context/platform"
|
|
import { usePlatform } from "@/context/platform"
|
|
|
|
|
+import { useSettings } from "@/context/settings"
|
|
|
import { Binary } from "@opencode-ai/util/binary"
|
|
import { Binary } from "@opencode-ai/util/binary"
|
|
|
import { base64Encode } from "@opencode-ai/util/encode"
|
|
import { base64Encode } from "@opencode-ai/util/encode"
|
|
|
import { EventSessionError } from "@opencode-ai/sdk/v2"
|
|
import { EventSessionError } from "@opencode-ai/sdk/v2"
|
|
|
-import { makeAudioPlayer } from "@solid-primitives/audio"
|
|
|
|
|
-import idleSound from "@opencode-ai/ui/audio/staplebops-01.aac"
|
|
|
|
|
-import errorSound from "@opencode-ai/ui/audio/nope-03.aac"
|
|
|
|
|
import { Persist, persisted } from "@/utils/persist"
|
|
import { Persist, persisted } from "@/utils/persist"
|
|
|
|
|
+import { playSound, soundSrc } from "@/utils/sound"
|
|
|
|
|
|
|
|
type NotificationBase = {
|
|
type NotificationBase = {
|
|
|
directory?: string
|
|
directory?: string
|
|
@@ -44,19 +43,10 @@ function pruneNotifications(list: Notification[]) {
|
|
|
export const { use: useNotification, provider: NotificationProvider } = createSimpleContext({
|
|
export const { use: useNotification, provider: NotificationProvider } = createSimpleContext({
|
|
|
name: "Notification",
|
|
name: "Notification",
|
|
|
init: () => {
|
|
init: () => {
|
|
|
- let idlePlayer: ReturnType<typeof makeAudioPlayer> | undefined
|
|
|
|
|
- let errorPlayer: ReturnType<typeof makeAudioPlayer> | undefined
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- idlePlayer = makeAudioPlayer(idleSound)
|
|
|
|
|
- errorPlayer = makeAudioPlayer(errorSound)
|
|
|
|
|
- } catch (err) {
|
|
|
|
|
- console.log("Failed to load audio", err)
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
const globalSDK = useGlobalSDK()
|
|
const globalSDK = useGlobalSDK()
|
|
|
const globalSync = useGlobalSync()
|
|
const globalSync = useGlobalSync()
|
|
|
const platform = usePlatform()
|
|
const platform = usePlatform()
|
|
|
|
|
+ const settings = useSettings()
|
|
|
|
|
|
|
|
const [store, setStore, _, ready] = persisted(
|
|
const [store, setStore, _, ready] = persisted(
|
|
|
Persist.global("notification", ["notification.v1"]),
|
|
Persist.global("notification", ["notification.v1"]),
|
|
@@ -93,16 +83,20 @@ export const { use: useNotification, provider: NotificationProvider } = createSi
|
|
|
const match = Binary.search(syncStore.session, sessionID, (s) => s.id)
|
|
const match = Binary.search(syncStore.session, sessionID, (s) => s.id)
|
|
|
const session = match.found ? syncStore.session[match.index] : undefined
|
|
const session = match.found ? syncStore.session[match.index] : undefined
|
|
|
if (session?.parentID) break
|
|
if (session?.parentID) break
|
|
|
- try {
|
|
|
|
|
- idlePlayer?.play()
|
|
|
|
|
- } catch {}
|
|
|
|
|
|
|
+
|
|
|
|
|
+ playSound(soundSrc(settings.sounds.agent()))
|
|
|
|
|
+
|
|
|
append({
|
|
append({
|
|
|
...base,
|
|
...base,
|
|
|
type: "turn-complete",
|
|
type: "turn-complete",
|
|
|
session: sessionID,
|
|
session: sessionID,
|
|
|
})
|
|
})
|
|
|
|
|
+
|
|
|
const href = `/${base64Encode(directory)}/session/${sessionID}`
|
|
const href = `/${base64Encode(directory)}/session/${sessionID}`
|
|
|
- void platform.notify("Response ready", session?.title ?? sessionID, href)
|
|
|
|
|
|
|
+ if (settings.notifications.agent()) {
|
|
|
|
|
+ void platform.notify("Response ready", session?.title ?? sessionID, href)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
break
|
|
break
|
|
|
}
|
|
}
|
|
|
case "session.error": {
|
|
case "session.error": {
|
|
@@ -111,9 +105,9 @@ export const { use: useNotification, provider: NotificationProvider } = createSi
|
|
|
const match = sessionID ? Binary.search(syncStore.session, sessionID, (s) => s.id) : undefined
|
|
const match = sessionID ? Binary.search(syncStore.session, sessionID, (s) => s.id) : undefined
|
|
|
const session = sessionID && match?.found ? syncStore.session[match.index] : undefined
|
|
const session = sessionID && match?.found ? syncStore.session[match.index] : undefined
|
|
|
if (session?.parentID) break
|
|
if (session?.parentID) break
|
|
|
- try {
|
|
|
|
|
- errorPlayer?.play()
|
|
|
|
|
- } catch {}
|
|
|
|
|
|
|
+
|
|
|
|
|
+ playSound(soundSrc(settings.sounds.errors()))
|
|
|
|
|
+
|
|
|
const error = "error" in event.properties ? event.properties.error : undefined
|
|
const error = "error" in event.properties ? event.properties.error : undefined
|
|
|
append({
|
|
append({
|
|
|
...base,
|
|
...base,
|
|
@@ -121,9 +115,13 @@ export const { use: useNotification, provider: NotificationProvider } = createSi
|
|
|
session: sessionID ?? "global",
|
|
session: sessionID ?? "global",
|
|
|
error,
|
|
error,
|
|
|
})
|
|
})
|
|
|
|
|
+
|
|
|
const description = session?.title ?? (typeof error === "string" ? error : "An error occurred")
|
|
const description = session?.title ?? (typeof error === "string" ? error : "An error occurred")
|
|
|
const href = sessionID ? `/${base64Encode(directory)}/session/${sessionID}` : `/${base64Encode(directory)}`
|
|
const href = sessionID ? `/${base64Encode(directory)}/session/${sessionID}` : `/${base64Encode(directory)}`
|
|
|
- void platform.notify("Session error", description, href)
|
|
|
|
|
|
|
+ if (settings.notifications.errors()) {
|
|
|
|
|
+ void platform.notify("Session error", description, href)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
break
|
|
break
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|