Download src/hooks/use-agent-notification.ts from SaylorTwift/openhands: direct link, hf CLI and curl.
- Browser
- Download file 1.86 kB
-
https://huggingface.co/SaylorTwift/openhands/resolve/main/src/hooks/use-agent-notification.ts
- Command line
-
hf download hf://SaylorTwift/openhands/src/hooks/use-agent-notification.ts
-
curl -L -o use-agent-notification.ts https://huggingface.co/SaylorTwift/openhands/resolve/main/src/hooks/use-agent-notification.ts
1.86 kB
| import { useEffect, useRef } from "react"; | |
| import { AgentState } from "#/types/agent-state"; | |
| import { useSettings } from "#/hooks/query/use-settings"; | |
| import notificationSound from "#/assets/notification.mp3"; | |
| const NOTIFICATION_STATES: AgentState[] = [ | |
| AgentState.AWAITING_USER_INPUT, | |
| AgentState.FINISHED, | |
| AgentState.AWAITING_USER_CONFIRMATION, | |
| ]; | |
| /** | |
| * Hook that plays a notification sound when the agent transitions into a | |
| * state that requires user attention. The browser tab title itself is | |
| * managed by `useAppTitle`, which prefixes the title with an emoji that | |
| * reflects the current agent state. | |
| */ | |
| export function useAgentNotification(curAgentState: AgentState) { | |
| const { data: settings } = useSettings(); | |
| const audioRef = useRef<HTMLAudioElement | undefined>(undefined); | |
| const prevStateRef = useRef<AgentState | undefined>(undefined); | |
| // Initialize audio only in browser environment, inside useEffect to | |
| // avoid side effects during render (React 18 strict mode, SSR safety). | |
| useEffect(() => { | |
| if (typeof window !== "undefined" && !audioRef.current) { | |
| audioRef.current = new Audio(notificationSound); | |
| audioRef.current.volume = 0.5; | |
| } | |
| }, []); | |
| const isSoundEnabled = settings?.enable_sound_notifications ?? false; | |
| // Trigger notification only on actual state transitions into a | |
| // notification-worthy state — not when unrelated deps (e.g. settings) change. | |
| useEffect(() => { | |
| if (prevStateRef.current === curAgentState) return; | |
| prevStateRef.current = curAgentState; | |
| if (!NOTIFICATION_STATES.includes(curAgentState)) return; | |
| if (isSoundEnabled && audioRef.current) { | |
| audioRef.current.currentTime = 0; | |
| audioRef.current.play().catch(() => { | |
| // Ignore autoplay errors (browsers may block autoplay) | |
| }); | |
| } | |
| }, [curAgentState, isSoundEnabled]); | |
| } | |