ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Apache Maka 桌面端消息队列:从 streaming 竞态到 Composer 排队语义的完整实现解析

Apache Maka 桌面端消息队列:从 streaming 竞态到 Composer 排队语义的完整实现解析 Apache Maka 桌面端消息队列从 streaming 竞态到 Composer 排队语义的完整实现解析【免费下载链接】makaApache Maka (Incubating) is a high-performance agent workspace that keeps a complete record of everything it did.项目地址: https://gitcode.com/GitHub_Trending/mak/maka导读本文以 docs/desktop-message-queue.md 为骨架深入解析 Apache Maka 桌面端apps/desktop如何通过一套以 Runtime Host 为权威的持久化消息队列解决 composer 提交时因streaming渲染竞态导致的session_busy失败与重复 toast 问题。读完本文你将理解 Maka 中current_turn/next_turn双队列语义、pending plate 的交互契约、四个核心 IPC 操作的调用链以及“提交路由读取同步引用而非依赖 React 渲染”的竞态修复思路并可对照源码与 e2e 测试验证其行为。背景问题streamingprop 渲染竞态在引入消息队列之前Maka 桌面端依靠渲染出的streamingprop 来决定一次 composer 提交到底应该开启一个 root turn还是steer转向当前活跃的 turn。这个决策看似简单却存在一个时间窗口竞态用户第一次发送消息主进程与 Runtime Host 之间完成一次 IPC 往返往返结束后Runtime Host 一侧已经拥有一个活跃的 turn但 React 尚未把新的streaming值渲染到界面上渲染器侧的决策状态是陈旧的用户在这个窗口内第二次提交提交路由仍按“无活跃 turn”走 root-turn 路径于是以session_busy失败连续突发提交还会产生重复的错误 toast体验进一步恶化。这个问题的根源在于提交路由的判定依据渲染输出落后于系统的真实状态Runtime Host 的 turn 所有权。文档给出的结论很明确判定不能只依赖上一次 React render 的结果。Runtime Host 的持久化消息语义双队列权威投影修复方案建立在 Runtime Host 已经具备的持久化消息语义之上而不是在渲染器里另起一套本地队列。文档明确了四条基础事实它们也是理解后续所有设计的前提语义说明current_turn队列中排在current_turn下的消息会在下一个 provider boundary 被作为 steering 消费即“steer 进当前活跃 turn”next_turn每条被接受的消息在next_turn队列中排队一个后继 turn即当前 turn 结束后依序执行queue projections 是权威的渲染器展示的排队内容必须以 Runtime Host 下发的投影为准投影携带规范化内容mutation 只返回队列状态投影中包含规范化的排队消息内容而任何队列变更操作的结果只返回队列状态不返回完整消息体这套语义在源码中有完整对应。MessagePlacement类型定义在 packages/runtime-host/src/protocol/message.tsexport type MessagePlacement current_turn | next_turn;同文件的协议校验逻辑还体现了一条强约束当一次turn.message.submit携带 skill 编排或精确的 turn 编排意图时placement必须是current_turn因为这类提交要么开启自己的 Turn、要么失败关闭next_turn无法描述这种语义见 message.ts。可见双队列不仅是 UI 层概念而是协议层强类型约束。Desktop 行为设计Send 永远是 Send基于上述语义桌面端的行为模型被设计为无模式切换Turn 活跃期间composer 提交就是排队 follow-up没有“排队模式”与“直接发送模式”的切换Send 永远是 SendShiftEnter将 draft steer 进当前活跃 turn 一次用于用户确实想立即干预当前 turn 的场景排队消息渲染在 composer card 上方的 pending plate 中按发送顺序排列第一个在顶部。pending plate 中每个条目提供三类操作操作行为拖拽 hover grip重新排序 follow-up 队列Promote立即发送将该条目 steer 进当前活跃 turnRetract收回草稿将该条目恢复到 composer draft 中队列内容与所有变更操作都是Runtime Host 操作渲染器只是镜像权威投影。也就是说UI 上的每一次重排、提升、收回最终都会落到四个 IPC 操作之一turn.message.submit—— 提交消息入队或 steerqueue.entry.promote—— 提升排队条目为 steeringqueue.entry.retract—— 收回排队条目到草稿queue.entries.reorder—— 重排排队条目另外相同的活跃 toast 会复用同一个 toast 实例而不是堆叠出多个重复提示。源码级调用链从 pending plate 到 Runtime Host下面把整条链路在仓库中走一遍方便读者按图索骥。1. 协议注册表四个操作名定义在 packages/runtime-host/src/protocol/operations.ts 与 L352queue.entries.reorder, queue.entry.promote, queue.entry.retract, queue.entry.update, queue.retract, // ... turn.message.submit,值得注意的是协议层还注册了queue.entry.update编辑排队条目与queue.retract两个扩展操作这与本文末尾“Deliberate Scope”章节的边界划分相呼应详见后文。2. 主进程 IPC 客户端桌面主进程通过 apps/desktop/src/main/runtime-host-client.ts 暴露类型安全的封装方法每个请求都会自动带上originHostEpochsubmitMessage(input) { return this.request(turn.message.submit, { ...input, originHostEpoch: this.connection.hostEpoch }); } retractQueueEntry(input) { return this.request(queue.entry.retract, { ...input, originHostEpoch: this.connection.hostEpoch }); } promoteQueueEntry(input) { return this.request(queue.entry.promote, { ...input, originHostEpoch: this.connection.hostEpoch }); } reorderQueueEntries(input) { return this.request(queue.entries.reorder, { ...input, originHostEpoch: this.connection.hostEpoch }); }originHostEpoch用于标识消息来源的 host 代际是跨进程边界维持消息归属正确性的关键字段。3. Runtime Host 侧的消息协调器服务端由 packages/runtime-host/src/server/message-coordinator.ts 统一分发队列操作queue.retract: (input) this.retract(input), queue.entry.retract: (input) this.retractQueuedEntry(input), queue.entry.promote: (input) this.promoteQueuedEntry(input), queue.entry.update: (input) this.updateQueuedEntry(input), queue.entries.reorder: (input) this.reorderQueuedEntries(input),协调器内部维护queueRevision见 message-coordinator.ts每次变更使 revision 自增投影中携带 revision 供渲染器做乐观更新与冲突判定。当队列容量耗尽时返回session_busymessage-coordinator.ts——这正是本文开头竞态问题中那个错误码的来源如今它只会在真正容量满时出现而不是竞态误报。4. 渲染器 UI 组件pending plate 由 packages/ui/src/composer-message-queue.tsx 中的ComposerMessageQueue组件实现它按current_turn与next_turn两个分组渲染L76-L78并通过data-queue-placement属性暴露分组信息供测试定位e2e 中即用[data-queue-placementnext_turn]选择器断言见 apps/desktop/e2e/workhub-layout.spec.ts。组件对“本地发送尚未收到回执”的情况做了专门处理projectComposerMessageQueue会把处于pendingSteering或transientPlacement next_turn的本地暂态消息与宿主投影合并标记为state: localcomposer-message-queue.tsx保证用户在回执到达前仍能看到自己刚发出的内容。拖拽重排通过 HTML5 Drag Drop 实现且只允许同一 placement 分组内的条目互相重排L99-L115执行重排前会拦截所有其他队列操作直到请求落定避免本地覆盖与宿主投影冲突。5. App Shell 接线apps/desktop/src/renderer/app-shell.tsx 中提升操作被接为对window.maka.sessions.promoteQueueEntry(sessionId, entryId)的调用收回操作同理走retractQueueEntryapp-shell.tsx。竞态修复同步引用而非渲染结果文档给出的修复方案只有一句话但分量很重提交路由读取同步的 live-turn ref 和最新的 session catalog snapshot在提交发生的瞬间而不只依赖之前的 React render。这意味着提交判定被从“渲染驱动的派生状态”迁移为“提交瞬间的快照查询”live-turn ref一个同步更新的引用始终反映“当前是否存在活跃 turn”不经过渲染管线session catalog snapshot在提交瞬间取的最新会话目录快照保证 routing 决策看到的是最新会话归属关系。这两个数据源在提交发生时被同步读取因此即使 React 尚未重渲染streaming值路由也能做出与 Runtime Host 实际状态一致的决策从根上消除session_busy竞态误报。配合“相同 toast 复用同一实例”的策略突发多次提交也不会产生重复的错误提示。边界范围Deliberate Scope文档明确划定了当前实现的边界避免过度承诺当前 per-entry 队列变更仅限于reorder重排、promote-to-steering提升为 steering、retract-to-draft收回草稿原地编辑排队条目in-place edit、暂停队列pausing the queue、跨会话移动cross-session moves三项能力仍需要单独的 Runtime Host 协议与持久化durability评审不在本设计范围内。需要指出的是从源码结构看部分边界能力已出现早期实现痕迹协议注册表已包含queue.entry.updateoperations.tsruntime-host-client.ts与composer-message-queue.tsx也已具备updateQueueEntry/beginEdit/commitEdit的完整代码路径runtime-host-client.ts、composer-message-queue.tsx但这些仍应视为演进中的能力其持久化语义是否最终纳入正式范围应以 Runtime Host 协议与 durability 评审结论为准。测试与验证仓库中为该消息队列配套了多层测试可作为理解行为契约的活文档单元测试 apps/desktop/src/main/tests/message-queue-ui-state.test.ts覆盖投影合并、current_turn/next_turn分组、transient 状态等 UI 状态机IPC 层测试 apps/desktop/src/main/tests/runtime-host-client-operations.test.ts 与runtime-host-client-uds.test.ts验证操作名、入参与回执契约服务端协调器测试 packages/runtime-host/src/tests/message-coordinator.test.ts、execution-host-queue.test.ts验证排队、提升、收回、重排的持久化语义e2e 测试 apps/desktop/e2e/side-chat-followups.spec.ts、apps/desktop/e2e/workhub-layout.spec.ts验证真实桌面窗口中 follow-up 的排队渲染与交互Storybook 组件样例 apps/desktop/stories/composer-message-queue.stories.tsx可直接查看 pending plate 的视觉与交互形态。小结Maka 桌面端的消息队列本质上是一次权威归属的迁移把“composer 提交该走哪条路”的判定权从渲染器基于streamingprop 的派生状态迁移到 Runtime Host 的持久化双队列语义之上。渲染器只负责镜像权威投影、提供 pending plate 的拖拽/提升/收回交互而所有变更都通过四个明确的 IPC 操作落到服务端。这既消除了session_busy竞态误报也为未来的原地编辑、队列暂停等能力预留了协议边界——它们仍需独立评审其持久化语义后再正式放开。【免费下载链接】makaApache Maka (Incubating) is a high-performance agent workspace that keeps a complete record of everything it did.项目地址: https://gitcode.com/GitHub_Trending/mak/maka创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表