Skip to content

Add notification ding when agent needs attention#2373

Open
D3OXY wants to merge 3 commits intopingdotgg:mainfrom
D3OXY:feat/notification-ding
Open

Add notification ding when agent needs attention#2373
D3OXY wants to merge 3 commits intopingdotgg:mainfrom
D3OXY:feat/notification-ding

Conversation

@D3OXY
Copy link
Copy Markdown
Contributor

@D3OXY D3OXY commented Apr 27, 2026

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 effectnot 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:

  • Notification sound — master toggle + a Play sound preview button
  • When agent finishes — fires on turn completed / error / interrupted
  • When approval requested — fires when the agent asks to run a command, edit a file, or proposes a plan
  • When question asked — fires when the agent asks a clarifying question
  • Play sound when — focus rule: Always / Window not focused / Window not focused or viewing a different thread

Behaviour:

  • All toggles default to off — fully opt-in.
  • Rising-edge only — no double-dings if another approval lands while one is already pending.
  • Throttled to one ding per 5 seconds across all event types and threads.
  • Archived threads suppressed.
  • Silent-fail + console.warn if 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:

image

The bell sound that plays (a short servant-bell ring):

notification.mp3

Implementation notes

  • Pure derivation in apps/web/src/notificationSound.ts:
    • deriveNotificationTriggers(prevShells, nextShells, events) — rising-edge detection on latestTurn.state, hasPendingApprovals || hasActionableProposedPlan, hasPendingUserInput. Skips archived threads. Requires prev to exist (no spurious dings on initial bootstrap).
    • shouldPlay(triggers, settings, focusContext, nowMs, lastPlayAtMs) — applies sub-toggle filters, focus rule, and 5s throttle.
    • Both fully unit-tested (28 tests in notificationSound.test.ts).
  • Side-effecting notificationSoundManager singleton owns a single HTMLAudioElement for /sounds/notification.mp3 (~54 KB MP3 bundled in apps/web/public/sounds/). Lazy-initialized; SSR-safe guards on document / window access.
  • Wired into apps/web/src/environments/runtime/service.ts at both applyRecoveredEventBatch and applyShellEvent paths so server-pushed shell upserts (the common case for fresh approvals / turn-end) reliably trigger.
  • Current-thread accessor wired via useLocation().pathname in __root.tsx; the manager itself is non-React and exposes a setCurrentThreadAccessor injection point.
  • Schema additions in packages/contracts/src/settings.ts use the existing Schema.withDecodingDefault pattern; ClientSettingsPatch updated in lockstep. Backward-compatible — missing fields decode to defaults.
  • New settings included in useSettingsRestore so "Restore defaults" wipes them.

Verification

  • bun fmt — clean
  • bun lint — 0 errors (pre-existing warnings unrelated)
  • bun typecheck — clean for @t3tools/contracts and @t3tools/web
  • bun run test — 998/998 pass (28 new in notificationSound.test.ts)

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Add notification sound when agent needs attention

  • Adds a notification chime that plays when an agent turn ends, an approval is requested, or a question is asked, using a new NotificationSoundManager in notificationSound.ts.
  • Detects sound triggers by comparing before/after thread shell snapshots on thread-upserted events and after recovered event batches in runtime/service.ts.
  • Adds five new fields to ClientSettingsSchema in settings.ts: a master toggle, per-event toggles (turn end, approval, question), and a focus rule (always, unfocused-only, unfocused-or-different-thread).
  • Exposes these controls in the General Settings panel with a test playback button and integrates current thread tracking via a new NotificationSoundBootstrap component in __root.tsx.
  • Behavioral Change: notification sounds default to disabled (notificationSoundEnabled: false); the focus rule defaults to unfocused-or-different-thread.

Macroscope summarized a274cfc.

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.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 27, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3c302c9c-14ae-4406-ad4b-65359879948c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added the size:XL 500-999 changed lines (additions + deletions). label Apr 27, 2026
@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp Bot commented Apr 27, 2026

Approvability

Verdict: Needs human review

This PR introduces a complete new notification sound feature with settings UI, audio playback logic, and event-processing integration. While well-tested and disabled by default, the scope of new user-facing capability and the author being new to this codebase warrants human review.

You can customize Macroscope's approvability policy. Learn more.

D3OXY added 2 commits April 27, 2026 22:36
…ture

ClientSettings shape now requires the 5 notification fields; the desktop
test fixture was missed in the initial change.
`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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL 500-999 changed lines (additions + deletions).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant