Skip to content

LAN 观察页连接修复 + 轮末工作计时器 + 语音提醒 - #41

Merged
Jaxton07 merged 3 commits into
mainfrom
feat/lan-web-conn-sync-ux
Aug 29, 2026
Merged

LAN 观察页连接修复 + 轮末工作计时器 + 语音提醒#41
Jaxton07 merged 3 commits into
mainfrom
feat/lan-web-conn-sync-ux

Conversation

@Jaxton07

Copy link
Copy Markdown
Owner

三个独立特性/修复批次:

轮末工作计时器(codex/claude code 同款)

轮开始即显示、运行中 1s 心跳跳动、run 结束定格,与文件变更 chip 同行且恒在首位;无变更轮为纯计时幽灵行。历史轮次从 jsonl 推导(deriveTurnTimings),时间数据零存储改动。

LAN 观察页四项体验修复

  • 心跳改命名事件 ping(注释帧不触发 EventSource 事件,半开连接僵死)+ 客户端 50s 无帧 watchdog 主动重连;重连才重拉快照,retry: 1500 加快重连;onerror 延迟 3s 显示「重连中」防闪烁
  • 正文重放拼接:种子含 in-flight partial 的同文重复 → healing 升级为新增字节计数器 + 差量渲染兜底气泡
  • MetaGroup 圆点行对齐桌面端两行布局
  • Composer 同位单按钮(运行中停止/有输入发送),停止钮黑白化

语音提醒(headless UI 插件体系 + 内置 voice-alerts)

人不在电脑旁时的召回提示音,5s 安静窗口防抖过滤跨会话频道互相唤醒的自动循环噪音:

  • 任务完成(全部打开会话连续安静)→ done 音;权限审批持续未处理 → approval 音(优先于完成音、同批一次、新请求升级)
  • 插件体系新增 headless 类型(activate/cleanup 生命周期)、音频资产 dataurl 内联(CSP media-src data:)、暴露 useUiPreferencesStore
  • 主窗口 backgroundThrottling: false(锁屏/息屏不节流提醒计时)
  • 开关 = UI 插件面板启用(内置插件,免二次确认)

测试全绿:311 desktop + 441 全仓;端到端 CDP 冒烟覆盖防抖取消/审批优先/热重载/锁屏节流场景。

连接稳定性(lan/server.ts + lan-web/store.ts):
- 心跳从 SSE 注释帧(: ping)改为命名事件 ping——注释帧不触发
  EventSource 任何 JS 事件,客户端无法判活,半开连接僵死到
  TCP 超时;客户端任意帧刷新 lastFrameAt,50s 无帧 watchdog
  主动断开重连
- onerror 延迟 3s 才显示「重连中」(移动端锁屏/切网杀连接是
  常态,EventSource 秒级自动重连,防状态药丸闪烁);服务端
  下发 retry: 1500 加快自动重连
- 重连才重拉快照,首次连接跳过双拉;snapshot 加 seq 稳定性
  双重校验(防未来异步化引入 seq/消息竞态)

正文重放拼接(lan-web/store-pure.ts + ChatView.tsx):
- 根因:重连/中途进入时种子含 in-flight partial 正文(SDK
  session.messages 实时含流式中消息)但无流式容器,后续
  text_delta 全部空转 → 误标 streamHealing → assistantTail
  兜底气泡与消息流同文重复,run 边界才自愈
- streamHealing 升级为「种子后新增字节数」计数器,兜底气泡
  改差量渲染(healingTailSuffix 只显示增长部分);标记加
  view.agentActive 守卫;重种子清标记

MetaGroup 圆点行(MetaGroup.tsx + styles.css):
- 对齐桌面端两行布局:状态行 + 独立圆点行(working 期实时
  追加,flex-wrap 换行不挤占统计行,展开组时隐藏)

Composer 同位单按钮(Composer.tsx + icons.tsx + styles.css):
- 与桌面端同构:运行中且无输入 → 停止;有输入 → 发送
  (followUp 排队);停止钮改黑白色调,StopIcon 与桌面端
  同形(满幅圆角方块,占钮面 ~31%,修方块过小)

测试:store-pure 补 healing 计数/守卫/差量/重种子清除 5 例;
lan-server 补 SSE 握手(retry 字段 + 命名 ping 帧)1 例
(pingMs 可注入)。PITFALLS 记两条坑(SSE 心跳必须命名事件
帧 / 增量帧不可重放)。
轮开始即显示、运行中 1s 心跳跳动、run 结束定格,与文件变更 chip
同行且恒在首位;无变更轮为纯计时幽灵行。历史轮次从 jsonl 推导。

时间数据零存储改动,只补映射链路:
- shared/transcript/turn-timings.ts 新增 deriveTurnTimings:按 user
  消息切轮,endedAt = 轮内各时刻取 max
- reducer:tool_execution_end 盖 UIToolCall.endedAt;agent_end(非重试)/
  agent_settled 盖 state.runEndedAt、agent_start 清——运行中末帧 ≤
  定格值,单调不回退
- backend messages + shared mapping:历史回放透传 toolResult timestamp
- chat-rows:传 turnTimings 则每轮必产行;lan-web 不传保持旧行为
- TurnDiffChip:timer 子组件(role=timer,42s/3m 05s/1h 02m 格式)
  + 纯计时行 + live 呼吸动画(reduced-motion 关)

已知取舍:正文收尾轮历史回放 endedAt = 最后 LLM 请求发起时刻,低估
最后一段输出时长;工具收尾轮准确。彻底精确需 custom entry 持久化,暂不做。
人不在电脑旁时的召回提示音,两个场景都带 5s 安静窗口防抖:
全部打开会话连续安静(任务完成)播 done 音;权限审批持续未
处理播 approval 音(优先于完成音,同批只播一次,新请求出现才
升级提醒)。窗口内任何会话复工即作废重来——过滤跨会话频道
互相唤醒的自动循环噪音。开关 = UI 插件面板的插件启用。

插件体系基建(通用,通知/音效/监控类插件可复用):
- manifest 新增 headless 字段(与 slots/contributions 至少其一):
  入口导出 activate(): () => void,加载时调用,禁用/卸载/热重载
  时调 cleanup;registry 增 cleanups 生命周期(+5 单测)
- 构建器资产 loader 支持音频(mp3/m4a/aac/ogg/wav dataurl 内联),
  CSP 补 media-src 'self' data:
- host API 暴露 useUiPreferencesStore(五处同步:host-api/env.d.ts/
  build SHIM/percho-ui.d.ts/SPEC)

voice-alerts 内置插件(builtin 随包分发,启用免二次确认):
- 全局安静检测状态机:working = 打开会话 agentActive/压缩中且
  无 pending(等审批不算产出);审批音播后清完成标记防补响
- 音频 AI 生成(任务已完成 / 有任务等待审批),替换文件即热重载

主窗口 backgroundThrottling: false——锁屏/息屏/后台时 Chromium
不节流提醒计时(实测 hide 态 5s 计时准点触发)

文档:SPEC §11 headless 章节、INDEX 速查与硬约束同步、PITFALLS
记 CDP 冒烟注入 store 需完整对象形状(畸形 session 曾炸 TabPill)
@Jaxton07
Jaxton07 merged commit 06799ef into main Aug 29, 2026
1 check passed
@Jaxton07
Jaxton07 deleted the feat/lan-web-conn-sync-ux branch August 29, 2026 12:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant