Add notification ding when agent needs attention#2373
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ApprovabilityVerdict: Needs human review New feature introducing notification sounds with audio playback, settings UI, and state monitoring. While well-implemented with tests and disabled by default, this adds substantial new user-facing capability that benefits from human review. You can customize Macroscope's approvability policy. Learn more. |
|
@juliusmarminge Could you take a look at this when you have the time? Thanks! It’s off by default, doesn’t use any OS level notification APIs. Just a Ding. It should work across all the environments. |
19959e3 to
71b56d0
Compare
Opt-in audible ding (not a desktop/OS notification or popup) that plays when an agent finishes a turn, requests approval, or asks a question. Per-device settings with focus-aware playback and a 5s throttle. New "Notifications" section in Settings with master toggle, three event sub-toggles, focus rule, and a Play Sound preview button.
`latestTurn.state` is not a reliable end-of-turn signal: the projector flips it to "completed" on every `thread.turn-diff-completed` event, which fires mid-turn whenever a checkpoint is captured for a git repo (see ProviderRuntimeIngestion turn.diff.updated handling). The next session-set running event then flips it back, producing running -> completed -> running oscillations through a single turn and spurious notification dings on the first mid-turn diff capture. Switch turn-end detection to `session.orchestrationStatus`, which the provider keeps as "running" continuously through tool calls and only transitions out at actual turn end. "starting" is treated as still active so session restarts/resumes mid-turn don't trigger.
71b56d0 to
e962104
Compare
What Changed
Adds an opt-in audible ding that plays when an agent needs the user's attention.
Important
This is strictly an in-app sound effect — not a desktop notification, not a native OS notification, not a popup or toast. There's no permission flow, no system tray icon, no notification center entry. It just plays a short bell through the page's audio output.
New per-device (
ClientSettings) controls in a new Notifications section in Settings → General:Play soundpreview buttoncompleted/error/interruptedAlways/Window not focused/Window not focused or viewing a different threadBehaviour:
console.warnif browser autoplay is blocked or the audio asset fails to load. The Play sound preview button surfaces errors via toast since it's an explicit user action.Why
When an agent runs a long task, it's common to switch to another window or another thread while waiting. Without an audible cue, you keep glancing back to check if it's finished or needs an approval. A short ding closes that loop without hijacking attention the way a popup or system notification would.
Keeping it as an in-app sound (rather than the Notifications API) avoids the permission prompt, works identically across browser and Electron, and stays scoped to the app — the user is always in T3 Code when they hear it.
UI Changes
New Notifications section in Settings → General, between General and Providers:
The bell sound that plays (a short servant-bell ring):
notification.mp3
Implementation notes
apps/web/src/notificationSound.ts:deriveNotificationTriggers(prevShells, nextShells, events)— rising-edge detection onlatestTurn.state,hasPendingApprovals || hasActionableProposedPlan,hasPendingUserInput. Skips archived threads. Requiresprevto exist (no spurious dings on initial bootstrap).shouldPlay(triggers, settings, focusContext, nowMs, lastPlayAtMs)— applies sub-toggle filters, focus rule, and 5s throttle.notificationSound.test.ts).notificationSoundManagersingleton owns a singleHTMLAudioElementfor/sounds/notification.mp3(~54 KB MP3 bundled inapps/web/public/sounds/). Lazy-initialized; SSR-safe guards ondocument/windowaccess.apps/web/src/environments/runtime/service.tsat bothapplyRecoveredEventBatchandapplyShellEventpaths so server-pushed shell upserts (the common case for fresh approvals / turn-end) reliably trigger.useLocation().pathnamein__root.tsx; the manager itself is non-React and exposes asetCurrentThreadAccessorinjection point.packages/contracts/src/settings.tsuse the existingSchema.withDecodingDefaultpattern;ClientSettingsPatchupdated in lockstep. Backward-compatible — missing fields decode to defaults.useSettingsRestoreso "Restore defaults" wipes them.Verification
bun fmt— cleanbun lint— 0 errors (pre-existing warnings unrelated)bun typecheck— clean for@t3tools/contractsand@t3tools/webbun run test— 998/998 pass (28 new innotificationSound.test.ts)Checklist
Note
Add notification sound when agent needs attention
notificationSoundManagersingleton (notificationSound.ts) that plays an audio chime when thread state transitions occur: agent turn ends, approval requested, or question asked.deriveNotificationTriggersto diff previous and current thread shell maps andshouldPlayto enforce user settings, focus rules, and a 5-second throttle.NotificationSoundBootstrapcomponent in the root app shell (__root.tsx) to wire thread state changes to sound playback for authenticated users.notificationSoundEnabled,notificationSoundOnTurnEnd,notificationSoundOnApproval,notificationSoundOnQuestion,notificationSoundFocusRule) with a Settings UI section including per-scenario toggles, a focus rule selector, and a test-sound button.Macroscope summarized e962104.