Add sounds for completed turns and user input requests#3892
Add sounds for completed turns and user input requests#3892jakeleventhal wants to merge 5 commits into
Conversation
- Add interaction sound cue detection with hydration-safe tests - Play bloom and success cues from the web app
|
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 This PR adds a new feature (completion sounds) enabled by default for all users, with a new external dependency. New user-facing features warrant human review even when well-implemented. You can customize Macroscope's approvability policy. Learn more. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Avoid advancing known thread sound state during settings hydration so turn completion and input cues are not dropped before the preference is ready. Co-authored-by: Cursor <cursoragent@cursor.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 9626d08. Configure here.
| if (latestTurn?.state !== "completed" || latestTurn.completedAt === null) { | ||
| return null; | ||
| } | ||
| return `${latestTurn.turnId}:${latestTurn.completedAt}`; |
There was a problem hiding this comment.
Interrupted finished turns skip sound
Medium Severity
completedTurn only treats latestTurn.state === "completed" as finished. Shell snapshots often end turns as interrupted with a non-null completedAt (session teardown races and interrupt handling), which resolveThreadAwarenessPhase already counts as completed. Those finishes never emit the success cue.
Reviewed by Cursor Bugbot for commit 9626d08. Configure here.
| merged.set(key, state); | ||
| } | ||
| } | ||
| return merged; |
There was a problem hiding this comment.
Hydration freeze drops mid-window transitions
Medium Severity
While settings hydrate, captureThreadSoundStateWhileSettingsHydrating never updates baseline state for threads already in the map. If a turn completes and a new one starts, or pending input appears then clears, before hydration ends, the first post-hydration diff matches the frozen baseline and no success or bloom cue plays.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 9626d08. Configure here.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9626d0808d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const previous = previousStateRef.current; | ||
| if (completionSoundEnabled && previous !== null) { | ||
| for (const cue of deriveInteractionSoundCues(previous, threads)) { | ||
| play(cue); |
There was a problem hiding this comment.
Unlock audio from a user gesture before background cues
In browsers that require AudioContext.resume() to happen during a user activation, the first call to play() here runs later from a shell-state effect, not from the click/keydown that submitted the prompt. If no prior Cuelume sound has already unlocked the shared context, completion/input cues can be silently blocked and never heard; prime or resume the sound engine from an explicit user interaction before relying on background notifications.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ac5b546dc8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (latestTurn?.state !== "completed" || latestTurn.completedAt === null) { | ||
| return null; | ||
| } | ||
| return `${latestTurn.turnId}:${latestTurn.completedAt}`; |
There was a problem hiding this comment.
Track completed turns without mutable timestamps
When a provider turn.completed is processed, ProviderRuntimeIngestion emits thread.session-set while CheckpointReactor can later emit thread.turn-diff-completed for the same turn; the projector/reducer update latestTurn.completedAt from those events. If thread.session-set settles the turn first, this timestamp-based key changes again when the checkpoint event arrives, so deriveInteractionSoundCues treats the same completed turn as a new completion and plays a second success cue. Use stable turn identity, or separately remember notified turn ids, so checkpoint timestamp corrections do not replay completion sounds.
Useful? React with 👍 / 👎.


Summary
Screen.Recording.2026-07-11.at.6.57.13.PM.mov
successcue when a turn completesbloomcue when a thread begins requesting user inputUser impact
Users receive an audible signal when agent work finishes or pauses for input, including when the affected thread is not currently open.
Validation
vp test apps/web/src/interactionSounds.test.tsvp checkvp run typecheckNote
Low Risk
UI-only feedback with conservative hydration guards; no auth, data, or server behavior changes beyond a persisted client preference defaulting to on.
Overview
Adds optional audible feedback when agent work finishes or pauses for the user, including for threads that are not currently open.
A root-level
InteractionSoundCoordinatorwatches global thread shells and usescuelumeto play asuccesscue when a turn newly completes andbloomwhen a thread starts needing user input or approvals.interactionSoundscompares prior vs current per-thread snapshots so cues are not replayed on unchanged state, and defers playback until client settings have hydrated so initial load does not spam sounds.enableCompletionSoundsis added to client settings (defaults on), with a Completion sound toggle in General settings and restore-defaults support. Desktop client settings tests are updated for the new field.Reviewed by Cursor Bugbot for commit ac5b546. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add sounds for completed turns and user input requests
cuelume-basedInteractionSoundCoordinatorcomponent in routes/__root.tsx that plays asuccesssound when a thread's latest turn completes and abloomsound when a thread starts requesting user input or approvals.enableCompletionSoundsboolean field toClientSettingsSchema(defaulting totrue) and exposes a toggle in the General settings panel.Macroscope summarized ac5b546.