From 474e80b646265214d52f4d7f201bd8ae729b2871 Mon Sep 17 00:00:00 2001 From: Danielle Maywood Date: Wed, 4 Mar 2026 16:23:31 +0000 Subject: [PATCH] feat(site): add completion chime for agent tasks (#22608) --- .../pages/AgentsPage/AgentDetail/TopBar.tsx | 4 +- .../AgentDetail/useAgentChime.test.ts | 142 ++++++++++++++++++ .../AgentsPage/AgentDetail/useAgentChime.ts | 94 ++++++++++++ site/src/pages/AgentsPage/AgentsPage.tsx | 26 +++- site/src/pages/AgentsPage/ChimeButton.tsx | 41 +++++ site/static/chime.wav | Bin 0 -> 30912 bytes 6 files changed, 305 insertions(+), 2 deletions(-) create mode 100644 site/src/pages/AgentsPage/AgentDetail/useAgentChime.test.ts create mode 100644 site/src/pages/AgentsPage/AgentDetail/useAgentChime.ts create mode 100644 site/src/pages/AgentsPage/ChimeButton.tsx create mode 100644 site/static/chime.wav diff --git a/site/src/pages/AgentsPage/AgentDetail/TopBar.tsx b/site/src/pages/AgentsPage/AgentDetail/TopBar.tsx index f3afc97b21..6538a04af1 100644 --- a/site/src/pages/AgentsPage/AgentDetail/TopBar.tsx +++ b/site/src/pages/AgentsPage/AgentDetail/TopBar.tsx @@ -29,6 +29,7 @@ import { useDashboard } from "modules/dashboard/useDashboard"; import type { FC } from "react"; import { useNavigate } from "react-router"; import { toast } from "sonner"; +import { ChimeButton } from "../ChimeButton"; import { WebPushButton } from "../WebPushButton"; interface DiffStatsBadgeProps { @@ -265,7 +266,8 @@ export const AgentDetailTopBar: FC = ({ )} - + + {" "}
{ + beforeEach(() => { + localStorage.clear(); + }); + + it("defaults to true when nothing is stored", () => { + expect(getChimeEnabled()).toBe(true); + }); + + it("returns true when stored as 'true'", () => { + localStorage.setItem("agents.chime-on-completion", "true"); + expect(getChimeEnabled()).toBe(true); + }); + + it("returns false when stored as 'false'", () => { + localStorage.setItem("agents.chime-on-completion", "false"); + expect(getChimeEnabled()).toBe(false); + }); + + it("setChimeEnabled persists the value", () => { + setChimeEnabled(false); + expect(localStorage.getItem("agents.chime-on-completion")).toBe("false"); + expect(getChimeEnabled()).toBe(false); + + setChimeEnabled(true); + expect(localStorage.getItem("agents.chime-on-completion")).toBe("true"); + expect(getChimeEnabled()).toBe(true); + }); +}); + +// --------------------------------------------------------------------------- +// maybePlayChime +// --------------------------------------------------------------------------- + +describe("maybePlayChime", () => { + let playSpy: ReturnType; + + beforeEach(() => { + localStorage.clear(); + playSpy = vi + .spyOn(HTMLMediaElement.prototype, "play") + .mockResolvedValue(undefined); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + // -- Chime SHOULD play -- + + it("chimes on running → waiting when viewing a different chat", () => { + vi.spyOn(document, "hidden", "get").mockReturnValue(false); + maybePlayChime("running", "waiting", "chat-1", "chat-2"); + expect(playSpy).toHaveBeenCalledTimes(1); + }); + + it("chimes on running → pending when viewing a different chat", () => { + vi.spyOn(document, "hidden", "get").mockReturnValue(false); + maybePlayChime("running", "pending", "chat-1", "chat-2"); + expect(playSpy).toHaveBeenCalledTimes(1); + }); + + it("chimes on pending → waiting (watchChats skips running)", () => { + vi.spyOn(document, "hidden", "get").mockReturnValue(false); + maybePlayChime("pending", "waiting", "chat-1", "chat-2"); + expect(playSpy).toHaveBeenCalledTimes(1); + }); + + it("chimes on running → waiting when tab is hidden (same chat)", () => { + vi.spyOn(document, "hidden", "get").mockReturnValue(true); + maybePlayChime("running", "waiting", "chat-1", "chat-1"); + expect(playSpy).toHaveBeenCalledTimes(1); + }); + + it("chimes on running → waiting when tab is hidden (no active chat)", () => { + vi.spyOn(document, "hidden", "get").mockReturnValue(true); + maybePlayChime("running", "waiting", "chat-1", undefined); + expect(playSpy).toHaveBeenCalledTimes(1); + }); + + // -- Chime should NOT play -- + + it("does NOT chime when viewing the finishing chat on a visible tab", () => { + vi.spyOn(document, "hidden", "get").mockReturnValue(false); + maybePlayChime("running", "waiting", "chat-1", "chat-1"); + expect(playSpy).not.toHaveBeenCalled(); + }); + + it("does NOT chime when preference is disabled", () => { + setChimeEnabled(false); + vi.spyOn(document, "hidden", "get").mockReturnValue(true); + maybePlayChime("running", "waiting", "chat-1", "chat-2"); + expect(playSpy).not.toHaveBeenCalled(); + }); + + it("does NOT chime on running → error", () => { + vi.spyOn(document, "hidden", "get").mockReturnValue(true); + maybePlayChime("running", "error", "chat-1", "chat-2"); + expect(playSpy).not.toHaveBeenCalled(); + }); + + it("does NOT chime on waiting → running (wrong direction)", () => { + vi.spyOn(document, "hidden", "get").mockReturnValue(true); + maybePlayChime("waiting", "running", "chat-1", "chat-2"); + expect(playSpy).not.toHaveBeenCalled(); + }); + + it("does NOT chime when previous status is undefined", () => { + vi.spyOn(document, "hidden", "get").mockReturnValue(true); + maybePlayChime(undefined, "waiting", "chat-1", "chat-2"); + expect(playSpy).not.toHaveBeenCalled(); + }); + + it("does NOT chime when status has not changed", () => { + vi.spyOn(document, "hidden", "get").mockReturnValue(true); + maybePlayChime("running", "running", "chat-1", "chat-2"); + expect(playSpy).not.toHaveBeenCalled(); + }); + + it("does NOT chime on error → waiting", () => { + vi.spyOn(document, "hidden", "get").mockReturnValue(true); + maybePlayChime("error", "waiting", "chat-1", "chat-2"); + expect(playSpy).not.toHaveBeenCalled(); + }); + + it("does NOT chime on pending → pending (no change)", () => { + vi.spyOn(document, "hidden", "get").mockReturnValue(true); + maybePlayChime("pending", "pending", "chat-1", "chat-2"); + expect(playSpy).not.toHaveBeenCalled(); + }); +}); diff --git a/site/src/pages/AgentsPage/AgentDetail/useAgentChime.ts b/site/src/pages/AgentsPage/AgentDetail/useAgentChime.ts new file mode 100644 index 0000000000..c2339c13d0 --- /dev/null +++ b/site/src/pages/AgentsPage/AgentDetail/useAgentChime.ts @@ -0,0 +1,94 @@ +const CHIME_PREFERENCE_KEY = "agents.chime-on-completion"; + +export function getChimeEnabled(): boolean { + try { + const stored = localStorage.getItem(CHIME_PREFERENCE_KEY); + // Default to enabled when no preference has been saved. + return stored === null ? true : stored === "true"; + } catch { + return true; + } +} + +export function setChimeEnabled(enabled: boolean): void { + try { + localStorage.setItem(CHIME_PREFERENCE_KEY, String(enabled)); + } catch { + // Silently ignore storage errors (e.g. private browsing + // quota exceeded). + } +} + +/** + * Play the completion chime audio file. The file is a short, + * warm two-tone bell sound shipped as a static asset. + * + * A single Audio element is reused across calls so the browser + * only fetches the file once. + */ +let chimeAudio: HTMLAudioElement | null = null; + +function playChime(): void { + try { + if (!chimeAudio) { + chimeAudio = new Audio("/chime.wav"); + chimeAudio.volume = 0.5; + } + // Reset to the start in case a previous play hasn't + // finished yet. + chimeAudio.currentTime = 0; + void chimeAudio.play(); + } catch { + // Silently ignore playback errors (e.g. autoplay policy + // blocks, missing file, etc.). + } +} + +/** + * Check whether a chat status transition should trigger a chime + * and play it if so. A chime fires when a chat reaches a + * terminal state ("waiting" or "error") from a non-terminal + * state, meaning the agent just finished work. The previous + * status may be "running" (seen via the per-chat WebSocket) or + * "pending" (when only the watchChats WebSocket is active and + * the intermediate "running" status was never pushed to the + * chat list). The chime is suppressed when the chat is + * currently visible to the user. + */ +export function maybePlayChime( + prevStatus: string | undefined, + nextStatus: string, + chatID: string, + activeChatID: string | undefined, +): void { + if (prevStatus === nextStatus) { + return; + } + + // Terminal states that indicate the agent finished. + const isTerminal = nextStatus === "waiting" || nextStatus === "pending"; + if (!isTerminal) { + return; + } + + // Only chime when transitioning from a non-terminal state. + // "running" is the expected previous state, but "pending" can + // appear when the watchChats WebSocket skips the intermediate + // "running" status (it only publishes the final state change). + const wasActive = prevStatus === "running" || prevStatus === "pending"; + if (!wasActive) { + return; + } + + // Skip when the user is looking at this exact chat. + const isViewingThisChat = !document.hidden && chatID === activeChatID; + if (isViewingThisChat) { + return; + } + + if (!getChimeEnabled()) { + return; + } + + playChime(); +} diff --git a/site/src/pages/AgentsPage/AgentsPage.tsx b/site/src/pages/AgentsPage/AgentsPage.tsx index 529fab36c8..9b8955e790 100644 --- a/site/src/pages/AgentsPage/AgentsPage.tsx +++ b/site/src/pages/AgentsPage/AgentsPage.tsx @@ -45,6 +45,7 @@ import { toast } from "sonner"; import { cn } from "utils/cn"; import { pageTitle } from "utils/page"; import { AgentChatInput } from "./AgentChatInput"; +import { maybePlayChime } from "./AgentDetail/useAgentChime"; import { AgentsSidebar } from "./AgentsSidebar"; import { ConfigureAgentsDialog } from "./ConfigureAgentsDialog"; import { @@ -353,6 +354,12 @@ const AgentsPage: FC = () => { navigate("/agents"); }; + // Track the active chat ID in a ref so the watchChats + // WebSocket handler can read it without re-subscribing on + // every navigation. + const activeChatIDRef = useRef(agentId); + activeChatIDRef.current = agentId; + useEffect(() => { const ws = watchChats(); ws.addEventListener("open", () => { @@ -375,6 +382,21 @@ const AgentsPage: FC = () => { const chatEvent = sse.data; const updatedChat = chatEvent.chat; + // Read the previous status from the query cache, which + // is synchronously updated by both the per-chat WebSocket + // (via updateSidebarChat) and this handler. This avoids + // the async-lag of a useEffect-based status map. + const currentChats = queryClient.getQueryData(chatsKey); + const prevStatus = currentChats?.find( + (c) => c.id === updatedChat.id, + )?.status; + maybePlayChime( + prevStatus, + updatedChat.status, + updatedChat.id, + activeChatIDRef.current, + ); + if (chatEvent.kind === "deleted") { queryClient.setQueryData( chatsKey, @@ -447,7 +469,9 @@ const AgentsPage: FC = () => { }, ); }); - return () => ws.close(); + return () => { + ws.close(); + }; }, [queryClient]); useEffect(() => { diff --git a/site/src/pages/AgentsPage/ChimeButton.tsx b/site/src/pages/AgentsPage/ChimeButton.tsx new file mode 100644 index 0000000000..982d18fca1 --- /dev/null +++ b/site/src/pages/AgentsPage/ChimeButton.tsx @@ -0,0 +1,41 @@ +import { Button } from "components/Button/Button"; +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "components/Tooltip/Tooltip"; +import { Volume2Icon, VolumeOffIcon } from "lucide-react"; +import { type FC, useState } from "react"; +import { getChimeEnabled, setChimeEnabled } from "./AgentDetail/useAgentChime"; + +export const ChimeButton: FC = () => { + const [enabled, setEnabled] = useState(getChimeEnabled); + + const handleClick = () => { + const next = !enabled; + setEnabled(next); + setChimeEnabled(next); + }; + + return ( + + + + + + {enabled ? "Disable completion sound" : "Enable completion sound"} + + + ); +}; diff --git a/site/static/chime.wav b/site/static/chime.wav new file mode 100644 index 0000000000000000000000000000000000000000..0e74704bce0db610c43b8329546a6e238ef28fcb GIT binary patch literal 30912 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 literal 0 HcmV?d00001