ClawX 侧边栏会话注意力机制深度解析:基于 OpenClaw Gateway 会话目录的忙碌与未读状态设计 人工智能AI 应用桌面应用交互助手【免费下载链接】ClawXClawX is a desktop app that provides a graphical interface for OpenClaw AI agents. It turns CLI-based AI orchestration into a desktop experience without using the terminal. China website is https://clawx.com.cn.项目地址https://gitcode.com/gh_mirrors/cl/ClawX点击查看免费下载导读本文聚焦 ClawX 桌面端侧边栏中会话忙碌指示器与未读消息圆点这一核心交互的设计与实现。它建立在 OpenClaw Gateway 会话目录session catalog权威投影之上通过sessions.subscribe/sessions.list事件流、精确键exact-key注意力状态机和基于 Zusland 持久化的本地注意力存储解决了多客户端并发运行、重启恢复、事件乱序、连接丢失等场景下的状态一致性问题。读完本文你将掌握Gateway 会话目录如何作为唯一权威源、busy unread timeago优先级渲染规则、注意力的状态转移表、Gateway epoch 订阅与列表/事件排序的时序护栏以及未来迁移到 Gateway 侧持久化未读的完整路径。1. 权威模型Authority为什么 Gateway 会话行是唯一权威ClawX 中侧边栏的运行状态busy / idle / unread唯一由 OpenClaw Gateway 的会话行session rows推导而不是由渲染进程Renderer自行猜测。这与下列候选方案形成了明确对比详见原文档Rejected Alternatives一节ACP prompt 状态 / ACP timeline 更新它们被限定在某个已初始化的 agent 连接作用域内无法观察整个共享会话目录渠道channel触发的运行或其它 Gateway 客户端发起的运行会被遗漏。Gatewayagent生命周期事件、本地sending状态属于传输/运行时生命周期并不是会话目录的规范投影可能在别处发起的工作上不完整。updatedAt时间戳推断重命名、元数据维护、转录维护等无关活动会造成虚假的未读完成。因此渲染端代码继续通过hostApi、useGatewayStore.rpc与hostEvents使用 Main 进程持有的 Gateway 连接绝不另开一条传输通道。useChatStore.sessions集合仍是渲染端的会话目录catalog注意力attention只增加展示状态不构成第二份会话目录——这样一个投影就能同时覆盖 ClawX 自身的 prompt、渠道触发的任务、以及其它 Gateway 客户端只要 Gateway 把运行投影到同一个目录会话键上即可。上游契约的行为基线bundled OpenClaw 2026.6.10文档给出了该权威模型所依赖的五条上游行为sessions.subscribe开启 Gateway 连接的sessions.changed通知通知在 Gateway 能提供快照时包含一个会话快照session snapshotsessions.list从 active-run 注册表重建hasActiveRun是规范化的恢复快照canonical recovery snapshotOpenClaw WebUI 对可靠事件快照做应用无法安全应用事件时重新加载列表终端状态terminal status覆盖过期的 active-run 布尔值否则布尔值优先running作为兼容性回退。在针对新版 OpenClaw 校验该上游契约时应检查会话列表投影list.ts与 WebUI Gateway reducerevent.ts以及订阅、事件、补丁字段的协议定义。原文档特别注明只给 basename因为上游源码布局可能在版本间变动。2. 目录规范化Catalog Normalization单一白名单归一化器src/stores/chat/session-catalog.ts同时为sessions.list行快照与sessions.changed事件补丁提供共享的白名单归一化器核心函数为normalizeGatewaySessionPatch与normalizeGatewaySessionRow。其归一化规则键key会被trim()处理见源码normalizeSessionKeysession-catalog.ts状态status统一trim().toLowerCase()见parseStatussession-catalog.ts活动时间戳接受有限数值或可解析的字符串时间戳秒级时间戳自动乘以 1000 转为毫秒value 1e12 ? value * 1000 : value见parseUpdatedAtsession-catalog.ts字段映射lastChannel优先于channel映射为ChatSession.channel白名单投影只投影ChatSession已知字段STRING_FIELDS常量覆盖sessionId、label、displayName、derivedTitle、lastMessagePreview、thinkingLevel、model、workspacePath未知载荷属性永远不会进入目录。列表行 vs 事件补丁列表行把归一化器当作完整行快照使用normalizeGatewaySessionRow事件补丁使用同样的字段转换但语义是存在性感知的补丁presence-aware patch载荷情形目录处理属性缺失不合并保留现有值不变显式布尔false尤其hasActiveRun: false保留而不是当作缺失显式null清除对应可选非空ChatSession属性目录不存储字面null类型不支持的值既不复制也不解释为清除sessions.changed的身份与来源选择精确规则文档给出了 7 步精确判定信封键取归一化后的顶层sessionKey若为空则取顶层key嵌套键由session.key归一化得到若两个键都存在且不同 → 拒绝事件请求规范化重载canonical reload否则解析出的键优先嵌套键、其次信封键存在嵌套session对象时以其为行来源否则顶层信封为补丁来源未知行只能从自带非空且不冲突键的嵌套快照插入未知键的部分补丁partial envelope需要重载reason delete只在有合法信封键时被接受并精确删除该键。源码applyGatewaySessionsChangedsession-catalog.ts正是这套规则的落地它先比较信封键与嵌套键是否冲突再处理 cron 运行键、时间戳过期、删除、未知行插入与已知行合并最终返回{ sessions, applied, deletedKey, requiresReload }。Cron 运行键的边界目录与注意力的身份是归一化后的精确会话键。现有 cron 解析parseCronSessionKey可能把 run 作用域的键映射到 base 键用于活动排序但任何包含 cron run 身份的键永远不会作为 base 行注意力被插入、合并或调和——当前 Gateway 列表在重连后无法恢复该关联关系。3. 运行投影Run Projectionbusy / idle / unknown 的判定顺序projectSessionRunState位于 src/stores/chat/session-status.ts对status执行trim().toLowerCase()后按下述精确顺序返回busy、idle或unknown终端状态优先识别到的终端状态即使存在过期的hasActiveRun: true也返回idle。内置终端值done、failed、timeout、killed接受的别名completed、finished、error、aborted、cancelled见TERMINAL_STATUSES集合session-status.ts布尔值次之当hasActiveRun作为布尔存在时true→ busy、false→ idle无视其它非终端状态字符串回退没有布尔值时归一化后的status running返回 busy其余情况返回unknown且不能创建或清除注意力转移。值得注意projectSessionRunState是注意力调和与侧边栏展示共用的同一个辅助函数。事件phase、活动时间戳、ACP 状态、运行时事件都不是该投影的输入——这保证了两个消费方永远看到一致的忙碌判定。4. 注意力状态与转移Attention State And Transitions存储结构src/stores/session-attention.ts定义SessionAttention { observedBusy: boolean; unread: boolean }按精确键存储在bySessionKey记录中。该 store 基于 Zustandpersist中间件持久化键名clawx.session-attention当前版本 1partialize只持久化bySessionKeyvisibleSessionKey仅存内存见 session-attention.tsmigrate与merge都会用sanitizePersistedState清洗整个持久化映射任何条目畸形observedBusy/unread非布尔都会回退为空映射坏本地数据不能阻塞侧边栏见 session-attention.ts。规范转移表Normative文档给出的转移表是判定注意力变更的唯一依据先前注意力Gateway 投影可见 Chat 会话结果任意Busy任意设置observedBusytrue保留已有 unread 位observedBusytrueIdle同一精确键设置observedBusyfalse、unreadfalseobservedBusytrueIdle不同键或无设置observedBusyfalse、unreadtrue无观察到忙碌Idle任意不创建 unread保留已有 unread 状态任意Unknown任意两个注意力字段都保持不变对应的核心实现是reconcileRowssession-attention.tsbusy !previous?.observedBusy时置忙并保留 unreadidle previous?.observedBusy时清忙并按row.key ! visibleSessionKey决定 unread。设计意图解读保留 unread是有意的当另一个运行变忙时spinner 在忙碌期间隐藏旧圆点但完成后若该会话仍不可见unread 会再次显现持久化observedBusy还支撑了重启恢复场景ClawX 观察到 busy、退出、之后收到 idle 的规范化行注意力仍能正确收敛不修剪不 prune过滤、部分或不完整列表不会删除缺失的注意力条目只有精确删除或显式本地会话移除才会删除有序转移折叠一次提交最终的注意力映射避免中间态的 spinner/圆点闪烁。侧边栏尾部的严格优先级busy unread timeago渲染实现在 src/components/layout/Sidebar.tsx 附近projectSessionRunState(s)与attention组合判定实时 busy 投影 → 显示本地化 spinnerrolestatusaria-label{t(chat:sessionList.aiReplying)}隐藏 unread 与时间Idle 且有 unread → 显示本地化蓝色圆点rolestatusaria-label{t(chat:sessionList.unreadReply)}隐藏时间Idle 且已读 → 显示既有相对时间戳与完整时间 title实时投影为 unknown → 依次回退持久化observedBusy显示 spinner → 持久化 unread 显示圆点 → 否则时间保持可见。指示器标签在所有受支持的 Chat 语言环境中本地化且圆点不是唯一的可访问未读指示有rolestatus与aria-label语义标注。注意力绝不改变会话的活动排序。5. 可见会话与已读语义Visible Session And Read Semantics已读的权威是实际挂载的 Chat 会话而不只是currentSessionKeyChat 页面在挂载时及键变化时调用setVisibleSession(currentSessionKey)清理时调用setVisibleSession(null)见 src/pages/Chat/index.tsx设置非空可见键会原子地记录可见性并清除该键的 unread 位源码中setVisibleSession在unread为真时同时更新bySessionKey见 session-attention.ts清除可见性不会把任何会话标记为已读。一个会话在两种情形下被视为已读busy→idle 调和时其精确键正被 Chat 可见挂载用户激活其侧边栏行点击路径在切换/加载并导航到 Chat 之前同步调用markReadsession-attention.ts。深链接与程序化导航由 Chat 可见性 effect 覆盖。Settings 等路由可以保留currentSessionKey但 Chat 已卸载不构成已读权威——在那里完成的任务会变成 unread。6. Gateway Epoch 订阅Gateway Epoch Subscriptionsrc/stores/gateway.ts用${pid ?? none}:${connectedAt ?? none}:${port}标识一个 ready 的 Gateway 运行时见getGatewayRuntimeIdentitygateway.ts。synchronizeGatewaySessionCatalog的逻辑gateway.ts离开 ready/running 状态会清空同步身份lastSynchronizedRuntimeIdentity null这样恢复后的连接会建立新 epoch就绪身份变化时gatewaySessionGeneration 1并推进数字化的会话目录代数generation。对每个就绪 epoch协调器执行初始化 generation 作用域的事件缓冲区清除先前按键与成功列表的时间戳围栏latestSessionEventTsByKey.clear()见synchronizeGatewaySessionGenerationchat.ts对该观察到的身份调用一次sessions.subscriberpc(sessions.subscribe, {})在finally中强制sessions.listloadSessions({ force: true, gatewayGeneration })订阅成功与否都执行订阅或水合失败只记录日志、不阻塞聊天后续就绪 epoch 会重试订阅。关键时序护栏订阅或旧列表挂起期间到达的事件保留给当前 generation强制 epoch 水合不能被较旧的 in-flight 普通加载满足而是等旧航班落地后排队一个后继加载generation 检查围住订阅、列表与回放工作旧 Gateway 的响应不能安装当前状态。周期性的 Gateway 状态调和synchronizeGatewaySessionCatalog被状态轮询调用可以在未改变身份时避免重复订阅。7. 列表与事件排序List And Event Orderingsrc/stores/chat.ts中loadSessions/handleSessionsChanged配合实现如下模型sessions.changed提供低延迟更新sessions.list是启动、重连与不确定性恢复的规范化来源每个列表请求包括普通节流加载在请求 in-flight 期间按到达顺序缓冲会话事件loadSessionsContext.events.push(payload)见 chat.ts。成功的带时间戳列表事务按 6 步处理归一化、过滤、去重列表为候选目录用规范化列表行开始注意力调和排除被无时间戳缓冲事件弄得不确定的精确键当event.ts list.ts时按到达顺序回放有限时间戳缓冲事件——相等被接受相等的 Gateway 时间戳不能证明事件先于快照仅event.ts list.ts被丢弃把已应用的行快照与精确删除表示为有序注意力转移并在内存中折叠发布最终目录与最终注意力结果而不是中间列表/事件状态当应用的事件是部分、不安全或请求规范化恢复时调度一次强制跟进加载。围栏推进规则成功的有限list.ts推进该 epoch 的成功列表下限successful-list floor并把每个安装行的精确键围栏推进到max(existingFence, list.ts)。列表航班之外事件必须具有有限ts低于成功列表下限的事件即使针对不在列表中的键也被丢弃对于已知精确键比其最近接受时间戳更旧的事件被丢弃。两个围栏处都接受相等只拒绝严格更旧的时间戳。每个被接受的快照内部终端状态仍优先于过期hasActiveRun。8. 不确定性与失败恢复Uncertainty And Failure Recovery无时间戳事件unorderable没有有限ts的事件不可排序不会投机合并而是触发一次强制列表恢复能解析出精确键 → 该键注意力保持不动其它可独立排序的键照常调和无法解析安全精确键 → 本次事务所有注意力保持不动缺失或非有限的list.ts→ 同样阻止可靠注意力折叠并调度后续列表。列表失败若sessions.list失败当前 epoch 中、达到上次成功列表下限的有限缓冲事件按到达顺序对现有目录做缩减reduction可靠精确键的注意力转移折叠一次被无时间戳事件触碰的键注意力保留无作用域的不确定性保留全部注意力应用的精确删除仍然清理目录元数据与注意力跟随一次强制重试重试再次失败时保留最可靠的缩减状态而不是编造一个 idle 完成。其它不安全快照畸形身份、嵌套/信封键冲突、未知部分行等不安全快照请求节流的规范化恢复unknown 运行投影保留最后的注意力状态订阅失败不禁用列表加载过期 generation 既不能恢复也不能覆盖更新的 generation。9. 删除与重建化身Delete And Recreate Incarnations精确删除会移除目录行、持久化注意力、缓存的侧边栏标签与活动元数据。在缓冲回放期间删除发生在精确的序列位置因此同键重建会从全新注意力开始之后才折叠后续的 busy / idle 快照。删除还会调用clearSessionLabelHydrationTracking见 src/stores/chat/session-label-hydration.ts它递增内存中的化身计数incarnation该计数被包含进每个水合版本字符串getSessionLabelHydrationVersion返回${incarnation}|${activityVersion}|${backendLabel}并清空 handled / in-flight 记录。因此即使重建行的活动时间戳与后端标签完全相同也会获得新版本旧的异步摘要完成无法把新化身标记为 handled也无法覆盖其标签新的水合可以正常开始该清理在独立处理、成功列表回放与失败列表缩减三种路径中都生效。10. 限制Limitations文档明确列出的边界引用时必须如实陈述ClawX 完全关闭期间开始并完成的运行无法被观察到因此无法产生有依据的 unread 标记针对 OpenClaw 2026.6.10run 作用域的 cron 键在sessions.list暴露可恢复的规范化关系之前不能驱动 base 行注意力但仍可影响活动排序本地注意力只是展示状态不是 Gateway 范围的已读回执——其它客户端打开会话不会清除 ClawX 的本地 unread 位部分或过滤列表中的缺失行不能证明删除因此不修剪注意力未知 Gateway 状态刻意偏向保留最后指示器而不是猜测 idle本地注意力存储不包含消息、工具状态、时间线、运行时图或路由可见性。11. 未来 Gateway 未读迁移Future Gateway Unread Migration当 bundled OpenClaw 版本提供持久化的行级hasActiveRun与unread字段以及可写的sessions.patch时应替换本地 unread 权威而不是把 Gateway unread 叠加到现有 store 之上。迁移自包含的 7 个步骤用源码与契约测试确认升级协议的 list、event、patch、时间戳与删除语义扩展共享白名单行/补丁归一化器以保留显式布尔unread含该协议定义的 false 与 null/omission 行为保留当前 active-run 投影、精确键目录权威、epoch 订阅、规范化水合、事件缓冲与时间戳围栏直接从归一化 Gateway 行渲染 unread不从本地observedBusy转移推断或合并侧边栏激活或可见挂载的 Chat 会话通过现有 Main 属主的 RPC 边界调用sessions.patch({ unread: false })确认精确行仅在具备规范化失败恢复时允许乐观清 UI移除本地转移 store并通过显式的版本化清理退役clawx.session-attention持久化键使旧本地位不会重现在单元与 Electron E2E 覆盖中保持busy unread timeago、可见 Chat 语义、可访问性与精确删除行为。文档特别警示仅因为在未捆绑的上游分支中存在某个类型不应启动迁移——bundled Gateway 必须暴露并持久化 ClawX 使用的完整契约。12. 被否决的替代方案Rejected Alternatives汇总原文档的否决理由便于读者理解设计取舍候选方案否决原因ACP prompt / timeline 状态限定于 ClawX 属主的 agent 连接遗漏渠道或其它客户端的运行Gatewayagent事件或本地sending传输/运行时生命周期不是规范会话目录投影updatedAt推断重命名、元数据、转录维护与无关活动会编造未读完成currentSessionKey作为可见性非 Chat 路由保留它会把隐藏会话错误标记为已读第二份渲染端会话集合复制目录权威产生分歧的合并/删除行为纯事件状态错过通知与重连需要规范sessions.list恢复修剪缺失列表行过滤与部分快照不能证明精确删除把 run 作用域 cron 键折叠进 base 行重连无法重建关联关系猜测完全离线的完成bundled 协议中没有持久证据渲染端属主的 Gateway socket / 协议切换违反 Main 属主的通信边界13. 验证锚点Validation Anchors与测试体系主要实现锚点shared/chat/types.tsChatSession字段定义status、hasActiveRun、channel、updatedAt等与GatewaySessionsChangedPayload载荷形状src/stores/gateway.tsepoch 身份与订阅/水合协调src/stores/chat.tsgeneration 同步与列表/事件缓冲src/stores/chat/session-catalog.ts白名单归一化器src/stores/chat/session-status.tsprojectSessionRunStatesrc/stores/chat/session-label-hydration.ts化身清理src/stores/session-attention.ts状态转移调和与持久化src/components/layout/Sidebar.tsxbusy unread timeago渲染优先级src/pages/Chat/index.tsx可见会话 effect。单元与端到端测试锚点聚焦单元测试tests/unit/session-status.test.ts、tests/unit/session-catalog.test.ts、tests/unit/session-attention.test.ts、tests/unit/session-label-hydration.test.ts、tests/unit/gateway-events.test.ts、tests/unit/gateway-event-dispatch.test.ts、tests/unit/chat-store-session-label-fetch.test.ts、tests/unit/chat-session-management.test.ts、tests/unit/sidebar-session-buckets.test.ts、tests/unit/i18n-locale-parity.test.ts、tests/unit/harness-specs.test.ts。端到端展示与导航由tests/e2e/chat-sidebar-session-attention.spec.ts覆盖。任何通信相关的改动都必须通过任务的 Harness 验证、通信回放/对比scripts/comms/下的 baseline 与 compare 脚本、类型检查、lint、Vite 构建、针对性单元测试与 Electron E2E 测试。14. 一图速览数据流全景OpenClaw Gateway (bundled 2026.6.10) │ sessions.subscribe ──► sessions.changed (event snapshot) │ sessions.list (canonical recovery / startup / reconnect) ▼ Main 进程 Gateway 连接hostApi / useGatewayStore.rpc / hostEvents ▼ Renderer: src/stores/chat.ts —— generation 围栏 事件缓冲 列表/事件排序 src/stores/chat/session-catalog.ts —— 白名单归一化行 / presence-aware 补丁 src/stores/chat/session-status.ts —— projectSessionRunState → busy / idle / unknown src/stores/session-attention.ts —— 精确键 { observedBusy, unread } 转移折叠 持久化(clawx.session-attention v1) ▼ src/pages/Chat/index.tsx —— setVisibleSession已读权威 src/components/layout/Sidebar.tsx —— busy unread timeago 渲染结语ClawX 的侧边栏会话注意力是一套以 Gateway 会话目录为唯一权威 渲染端精确键本地注意力 严谨时序围栏的完整设计sessions.subscribe的低延迟事件与sessions.list的规范化恢复互为补充projectSessionRunState用统一的 busy/idle/unknown 投影同时驱动状态调和与 UI而clawx.session-attention版本 1的持久化注意力支撑了重启恢复场景。对于想要理解桌面客户端如何正确呈现 AI agent 运行状态的读者本文所引用的实现锚点session-catalog.ts、session-status.ts、session-attention.ts、gateway.ts、chat.ts、Sidebar.tsx、Chat/index.tsx与对应测试构成了从协议到像素的完整可追溯链路。赞分享人工智能AI 应用桌面应用交互助手【免费下载链接】ClawXClawX is a desktop app that provides a graphical interface for OpenClaw AI agents. It turns CLI-based AI orchestration into a desktop experience without using the terminal. China website is https://clawx.com.cn.项目地址https://gitcode.com/gh_mirrors/cl/ClawX点击查看免费下载相关推荐Ruffle Flash 模拟器扩展实操指南让 Chrome 里失效的 SWF 页面复活Ruffle Flash 模拟器扩展实操指南让 Chrome 里失效的 SWF 页面复活 Ruffle 是一个用 Rust 写的 Flash 播放器模拟器。它音视频OpenChamber 1.8.6 深度解析基于 Turn 的稳定流式渲染与全新会话侧边栏OpenChamber 1.8.6 深度解析基于 Turn 的稳定流式渲染与全新会话侧边栏 本篇围绕 OpenChamber 1.8.6 版本更新见 chaAI Agent人工智能代码智能体交互助手caveman Hooks 深度解析Claude Code 会话钩子、按会话模式状态与状态栏徽章的实现caveman Hooks 深度解析Claude Code 会话钩子、按会话模式状态与状态栏徽章的实现 caveman 是一个让 Claude Code「像穴人工智能AI 应用AI 技能AI 插件LLMOps开发工具上一篇【亲测免费】 Desmos-Desktop 开源项目教程下一篇OtterWiki 开源项目教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考