mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-10-07 16:19:09 +00:00
* feat: add browser notifications for agent run completion Request notification permission when a user starts their first agent run from the home page. A toggle in Profile Settings lets users enable/disable desktop notifications. When a run transitions from running to a terminal state (finished/error/interrupted), a browser notification is fired — suppressed for the thread the user is currently viewing. Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com> * fix: notify for active thread when page is in background tab Only suppress the notification for the active thread when the page is actually visible. If the user switched to another browser tab, the notification fires even for the thread they have open. Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com> --------- Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
62 lines
1.7 KiB
TypeScript
62 lines
1.7 KiB
TypeScript
import type { AgentThread } from "./agents/types"
|
|
|
|
export const NOTIFICATIONS_PREF_KEY = "open-swe-notifications-enabled"
|
|
|
|
export function notificationsSupported(): boolean {
|
|
return typeof window !== "undefined" && "Notification" in window
|
|
}
|
|
|
|
export function getNotificationPermission(): NotificationPermission | null {
|
|
if (!notificationsSupported()) return null
|
|
return Notification.permission
|
|
}
|
|
|
|
export function notificationsEnabled(): boolean {
|
|
if (!notificationsSupported()) return false
|
|
if (Notification.permission !== "granted") return false
|
|
try {
|
|
return localStorage.getItem(NOTIFICATIONS_PREF_KEY) === "true"
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
|
|
export async function requestNotificationPermission(): Promise<NotificationPermission | null> {
|
|
if (!notificationsSupported()) return null
|
|
if (Notification.permission === "granted") return "granted"
|
|
if (Notification.permission === "denied") return "denied"
|
|
return Notification.requestPermission()
|
|
}
|
|
|
|
export function setNotificationsPref(enabled: boolean) {
|
|
try {
|
|
localStorage.setItem(NOTIFICATIONS_PREF_KEY, String(enabled))
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
}
|
|
|
|
export function showRunNotification(thread: AgentThread) {
|
|
if (!notificationsEnabled()) return
|
|
const statusLabel =
|
|
thread.status === "error"
|
|
? "encountered an error"
|
|
: thread.status === "interrupted"
|
|
? "was interrupted"
|
|
: "finished"
|
|
const title = thread.title || "Agent run"
|
|
const body = `Run ${statusLabel}.`
|
|
try {
|
|
const n = new Notification(title, {
|
|
body,
|
|
icon: "/logo-mark.png",
|
|
tag: `run-${thread.id}`,
|
|
})
|
|
n.onclick = () => {
|
|
window.focus()
|
|
n.close()
|
|
}
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
}
|