[Feature] 灵动岛:主窗口聚焦且正在查看会话时,会话完成不播提示音,与开始提示音行为不对称
- Dominant language
- TypeScript
- Stars
- 2.7k
- Forks
- 401
- Avg merge
- 21h 48m
- Merged PRs (30d)
- 776
Description
### 现象
主窗口聚焦、且当前正在查看某个会话时:
- 该会话**开始运行**:灵动岛播放开始提示音 ✅
- 该会话**完成**:灵动岛**不播放**完成提示音 ❌
用户感知为「完成音时好时坏」,实际是聚焦 + 正在查看时被固定抑制。
### 复现步骤
1. 启用灵动岛及其声音(Settings → Agent Island,声音总开关开启,complete 事件配置了音效)。
2. 保持主窗口聚焦,停留在某会话页面。
3. 在该会话发送一条消息让 agent 运行 → 能听到开始音。
4. 保持聚焦并停留在该会话,等待其完成 → 听不到完成音。
5. 对照组:切到其它会话或让窗口失焦后再等完成 → 完成音正常播放。
### 源码定位
声音决策:`apps/desktop/src/main/agent-island/service.ts` 的 `getAgentIslandSoundEventForTransition()`(L1603-1633):
```ts
for (const session of next.sessions) {
if (!session.attention || session.phase !== 'completed') continue; // ← 完成音要求 attention
...
if (prev?.phase !== 'completed') return 'complete';
}
for (const session of next.sessions) {
if (session.phase !== 'running') continue; // ← 开始音不看 attention / 焦点
...
if (!prev || prev.phase !== 'running') return 'start';
}
```
完成时 `attention` 来自 `unread`,`unread` 由 smart suppress 决定:`apps/desktop/src/main/agent-island/state.ts` L1415-1418:
```ts
function shouldSmartSuppressSession(state, session) {
if (isPermissionApprovalSession(session)) return false;
return state.appFocused && state.visibleSessionIds.has(session.sessionId);
}
```
链路:会话完成 → `completeAgentIslandSession`(state.ts L1154-1184)→ 聚焦且正在查看该会话时 `shouldSmartSuppressSession` 返回 true → `unread=false` → display state 中 `attention=false` → `'complete'` 分支的 `if (!session.attention) continue` 直接跳过 → 完成音被抑制。
- `appFocused` 来源:`bootstrap-electron.ts` `syncAppFocusState()` → `service.ts setAppFocused`;
- `visibleSessionIds` 来源:renderer 上报当前查看的会话(`MainLayout.tsx` / `OrcaSplitView.tsx` / `WorkdirBrowseRoute.tsx`)。
例外:error 结束走 `forceUnread: true`(state.ts L598 附近),所以聚焦时错误音仍会响。
### 为什么归为体验优化而非 Bug
完成音的抑制是 smart suppress 的**有意设计**(用户正盯着该会话,完成状态已经看见,不额外打扰;同一机制也抑制灵动岛的自动展开)。但存在两点体验问题:
1. **不对称**:四类音中 attention / error / complete 三类都以 `attention` 为门槛,唯独 start 完全豁免且无注释说明——同一个正在查看的会话,「开跑」响、「跑完」不响,直觉相反(完成通常比开始更值得声音反馈)。
2. **不透明**:设置页配置了 complete 音效后没有任何提示说明「聚焦查看时不响」,用户容易误判为声音功能故障。
### 可选改进方向(供讨论)
- **方向 A(声音与 attention 解耦)**:聚焦查看时仍播完成音,仅保留对 reveal / 未读标记的抑制——smart suppress 只管「不打扰视觉」,不管声音。满足「听到任务跑完了」的即时反馈诉求。
- **方向 B(补齐对称)**:给 `'start'` 分支补上与 `shouldSmartSuppressSession` 等价的判断,聚焦查看该会话时开始音也不响,行为统一为「正看着的会话不出声」。
- **方向 C(可配置)**:在 Agent Island 声音设置中加「聚焦查看时是否静音」高级选项(需按 `docs/configuration-design-principles.md` 评估可见性层级)。
任一方向改动落点:`service.ts` 的 `getAgentIslandSoundEventForTransition` / `playSoundForDisplayTransition`,以及 smart suppress 与声音判定的解耦;改动为纯主进程逻辑,按仓规需同步补单测。
Contributor guide
Research direction
Read getAgentIslandSoundEventForTransition() in apps/desktop/src/main/agent-island/service.ts together with shouldSmartSuppressSession() and completeAgentIslandSession() in state.ts. First resolve which sound behavior is intended among the proposed directions, then add the corresponding main-process tests and verify completion and start sounds for focused and visible sessions, including the error exception.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- electron, typescript
- Domain
- desktop
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100