feat: 通知音效系统 — 生成完成 + 等待操作提示音#4176
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7d3d442a49
ℹ️ 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".
参考 notification-sound PR (esengine#4176) 的 SoundSelect 样式, 将原生 <select> 替换为 AnchoredPopover + trigger 按钮 + 勾选图标的自定义下拉组件。
- Add sound.ts: notification sound core module (synth + WAV playback) - Add 4 Mixkit WAV sound effects - bridge.ts: add onTurnDone() for agent:turn-done event - tabs.go: emit agent:turn-done event on TurnDone - App.tsx: playSuccessChime on generation complete - AskCard/ApprovalModal: playAttentionChime on user confirmation - SettingsPanel: two sound selectors (success + attention) in General section - SoundSelect: custom dropdown component with AnchoredPopover - i18n: EN/ZH notification sound labels - Default: off, can be toggled to synth or WAV sounds
7d3d442 to
e9bd6f5
Compare
SivanCola
left a comment
There was a problem hiding this comment.
Thanks for adding this. I found two issues that should be fixed before merge:
-
The frontend build currently fails in
SoundSelect.tsx.labelKeyis typed as plainstring, butuseT()only accepts theDictKeyunion, so botht(selected.labelKey)andt(opt.labelKey)produce TS2345. Please typelabelKeyasDictKeyor use anas const satisfies ...shape for the options. -
The success chime currently plays for failed turns too.
TurnDonealready carriesErrthrough the existingturn_donewire event, but the newagent:turn-doneevent drops that payload andApp.tsxcallsplaySuccessChime()unconditionally. Please reuseonEventand gate one.kind === "turn_done" && !e.err, or include the outcome in the new event so model errors/panics/rate limits do not play a success sound.
Validation I ran:
cd desktop && go test ./...passedcd desktop/frontend && pnpm buildfailed on theSoundSelect.tsxtyping issue above
SivanCola
left a comment
There was a problem hiding this comment.
Thanks for the update. The SoundSelect.tsx typing issue is fixed now: labelKey is typed as DictKey, and the previous TS2345 errors are gone.
One requested change is still outstanding: the success chime still plays for failed turns. The PR still emits a separate payload-less agent:turn-done event from tabs.go, and App.tsx still calls playSuccessChime() unconditionally from that event. Since the existing turn_done wire event already carries err, please gate the sound on the existing event, e.g. only play when e.kind === "turn_done" && !e.err, or include the outcome/error in the new event before deciding which sound to play.
Validation I ran on the updated head:
cd desktop && go test ./...passedcd desktop/frontend && pnpm buildno longer reports theSoundSelect.tsxerrors; it still stops on missing local Wails generated modules in this checkout (../../wailsjs/...), which appears unrelated to this PR update.
SivanCola
left a comment
There was a problem hiding this comment.
Pushed a small follow-up fix to this PR.
What changed:
- Reused the existing
turn_donewire event instead of adding a separate payload-lessagent:turn-donechannel. - Play the success chime only when
turn_donehas noerr, so failed turns no longer sound like successful completions. - Removed the extra bridge helper and Go event emit.
Validation:
cd desktop && go test ./...passedcd desktop && wails generate modulecd desktop/frontend && pnpm buildpassed
|
approve |
…nces counter Fixes esengine#4176 When a plan is approved, the controller emits a plan-seed todo_write event (frontend shows the list) but did not initialize the agent's todoState. The agent's todoState is only set when the model calls todo_write itself, which it may skip since the plan-seed already displays the list. When the model then calls complete_step, advanceCanonicalTodo checks len(todoState) == 0 and returns early — no synthetic todo_write event is emitted, so the frontend counter stays at 0/x. Fix: after seedPlanTodos emits the plan-seed events, also call the new Agent.SeedTodoState() to initialize the agent's canonical todo list from the parsed plan. SeedTodoState is a no-op when the agent already has a todoState (e.g. the model already called todo_write), avoiding overwrites.

概述
新增通知音效系统,两个场景各有独立的音效选择(默认关闭):
改动清单
验证方式