菜单栏状态逻辑
显示内容
- 我们在菜单栏图标和菜单的第一个状态行中显示当前 agent 工作状态。
- 工作活跃时隐藏健康状态;所有会话空闲时返回。
- 菜单中的"Nodes"块仅列出设备(通过 node.list 配对的节点),而非 client/presence 条目。
- 当 provider 使用快照可用时,Context 下会出现"Usage"部分。
状态模型
- 会话(Sessions):事件带有 runId(每次运行)加上负载中的 sessionKey。"main"会话的键是 main;如果缺失,我们回退到最近更新的会话。
- 优先级:main 总是优先。如果 main 活跃,其状态立即显示。如果 main 空闲,显示最近活跃的非 main 会话。我们不会在活动中途翻转;仅在当前会话空闲或 main 变活跃时切换。
- 活动类型(Activity kinds):
- job:高级命令执行(state: started|streaming|done|error)。
- tool:phase: start|result 带有 toolName 和 meta/args。
IconState 枚举(Swift)
- idle
- workingMain(ActivityKind)
- workingOther(ActivityKind)
- overridden(ActivityKind)(调试覆盖)
ActivityKind → 图标
- exec → 💻
- read → 📄
- write → ✍️
- edit → 📝
- attach → 📎
- 默认 → 🛠️
视觉映射
- idle:正常小动物。
- workingMain:带图标的徽章,完全着色,腿部"工作"动画。
- workingOther:带图标的徽章,柔和着色,无跑动。
- overridden:使用选择的图标/着色,无论活动如何。
状态行文本(菜单)
- 工作活跃时:<会话角色> · <活动标签>
- 示例:Main · exec: pnpm test、Other · read: apps/macos/Sources/OpenClaw/AppState.swift。
- 空闲时:回退到健康摘要。
事件摄取
- 来源:control-channel agent 事件(ControlChannel.handleAgentEvent)。
- 解析字段:
- stream: "job" 带有 data.state 用于开始/停止。
- stream: "tool" 带有 data.phase、name、可选 meta/args。
- 标签:
- exec:args.command 的第一行。
- read/write:缩短的路径。
- edit:路径加上从 meta/diff 计数推断的更改类型。
- 回退:工具名称。
调试覆盖
- 设置 ▸ Debug ▸ "Icon override"选择器:
- System (auto)(默认)
- Working: main(按工具类型)
- Working: other(按工具类型)
- Idle
- 通过 @AppStorage("iconOverride") 存储;映射到 IconState.overridden。
测试清单
- 触发 main 会话作业:验证图标立即切换,状态行显示 main 标签。
- 在 main 空闲时触发非 main 会话作业:图标/状态显示非 main;保持稳定直到完成。
- 在其他活跃时启动 main:图标立即翻转到 main。
- 快速工具爆发:确保徽章不闪烁(工具结果上的 TTL 宽限期)。
- 所有会话空闲后健康行重新出现。