ARTICLE DETAIL

资讯详情

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

oh-my-openagent Team Mailbox Fallback Wake:团队消息递送失败时的确定性唤醒回退机制解析

oh-my-openagent Team Mailbox Fallback Wake:团队消息递送失败时的确定性唤醒回退机制解析 oh-my-openagent Team Mailbox Fallback Wake团队消息递送失败时的确定性唤醒回退机制解析【免费下载链接】oh-my-openagentOmO: Just type mass ulw keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent导读本文以 oh-my-openagentOmO仓库中的 Issue 5317 验证证据文档为主线系统讲解 Team Mode 下邮件信箱mailbox的 fallback wake回退唤醒机制当团队消息无法通过实时通道递送时系统如何通过确定性 prompt-gate 回退与信箱注入保证消息不丢失、不重复、不扰乱正在运行的会话。读完本文你将掌握 mailbox 的磁盘落地模型、peer_message注入信封、消费租约与确认ack语义以及围绕唤醒保留hold与过时唤醒取消cancellation的完整回归验证方法论。一、背景为什么需要 fallback wake在 oh-my-openagent 的 Team Mode 中成员之间通过 team mailbox 传递消息核心调用面由 packages/team-core/src/team-mailbox/index.ts 导出包括sendMessage、listUnreadMessages、pollAndBuildInjection、ackMessages、reserveMessageForDelivery等原语。消息递送存在两条路径实时递送live delivery成员会话空闲时消息通过 idle-injection 协调器直接唤醒wake会话并注入上下文回退递送fallback delivery实时递送被阻塞例如接收方会话正处于活跃回合、prompt-gate 判定当前不该打扰时消息在信箱中排队等待下一个可注入时机以排队唤醒queued fallback wake的形式投递。Issue 5317 的验证目标正是这两条路径衔接处的确定性行为排队中的 fallback wake 是否会被准时分发、是否会被过时取消、是否会被错误地重复分发。二、Issue 5317 验证了什么依据 .omo/evidence/20260828-issue-5317-team-message-fallback-wake/README.md本轮验证覆盖三个层面确定性 prompt-gate 回退与信箱注入在模块接缝module seam处以确定性方式驱动保留空闲接收方门控 → 发送 → 确认未读 → 释放阻塞器的完整链路聚焦与关联测试、类型检查与构建对修复点做聚焦回归同时对受影响的关联模块做全量回归真实环境验证使用一次性disposableOpenCode 1.18.4 容器、CI-Bun 1.4.0 本地 bundle以真实 Team Mode 运行并观察team_create、team_send_message工具注册、SSE 连接与宿主会话状态。三、测试过程与三轮红绿迭代3.1 RED排队 fallback wake 超时第一轮failing-first暴露的缺陷记录在 verification.txtmessaging.test.ts: timed out waiting for queued fallback mailbox wake corrected gate-blocker path: 1 failed即当 prompt-gate 阻塞实时递送后消息进入排队状态但排队的 fallback wake 迟迟未被分发测试等待超时。这是预约reservation→ 唤醒wake状态转换失败导致的。3.2 REVIEW RED二次递送与已确认消息的幽灵唤醒评审review阶段又发现两类更微妙的缺陷第二次递送与已接受的实时 prompt 重叠fallback wake 在接收方正在处理实时 prompt 时被再次分发造成上下文重叠已确认消息仍分发其排队的 fallback wake消息已被精确确认exact-message ack但排队中的唤醒仍被派发形成幽灵投递。这两类问题对应到源码中即是唤醒分发必须尊重pendingInjectedMessageIds与已消费台账consumed ledger否则会造成同一消息多次进入接收方上下文。3.3 GREEN聚焦与关联回归全绿修复后各门禁结果最终 post-merge 数据见 README门禁结果focused messaging40/40 通过related messaging/idle-wake/prompt-route68/68 通过prompt gate core70/70 通过typecheck / build通过Senpi 包门禁2419 通过1 个 Windows-only 跳过一次性 OpenCode 双次发送完成且无 NDJSON 错误3.4 真实服务器验证在一次性 Docker 容器OpenCode 1.18.4 CI-Bun 1.4.0 本地dist/index.js中健康检查healthyteam_create与team_send_message均已注册SSEserver.connected已连接宿主会话数保持7933 → 7933容器运行前后不变证明 disposable 容器未污染宿主实时递送早期预约释放数为 0live-delivery hold 被正确保留fallback 在阻塞器过期后正确分发。四、源码级机制mailbox 的磁盘落地与唤醒分发4.1 信箱目录结构与消息文件信箱以文件系统为存储介质路径由 packages/team-core/src/team-registry/paths.ts 的getInboxDir决定base_dir/runtime/teamRunId/inboxes/memberName/每个未读消息是messageId.json消息进入递送预约后重命名为.delivering-messageId.json确认消费后移动到processed/messageId.json。base_dir默认是~/.omo也可通过配置覆盖。所有路径段经过resolveContainedPath校验防止路径穿越TeamPathTraversalError。消息结构由 packages/team-core/src/types.ts 的MessageSchema定义messageIdUUID、from、to、kind、body上限 32KB、timestamp、可选的summary、references、correlationId与color。4.2 发送与背压控制sendMessagepackages/team-core/src/team-mailbox/send.ts在写盘前做多重校验广播to: *仅限 lead 角色否则抛BroadcastNotPermittedError负载超过message_payload_max_bytes默认 32768 字节抛PayloadTooLargeError团队处于 deleting/deleted 状态抛TeamDeletingError收件人未知或不活跃抛InvalidRecipientError未读信箱总字节超过recipient_unread_max_bytes默认 262144 字节抛RecipientBackpressureError背压消息 ID 已存在未预约或已预约抛DuplicateMessageIdError。写盘通过withLockinboxDir.lock串行化保证并发写者互不覆盖——这一点由 send.test.ts 的4 个并发写者写入 4 个不同文件用例验证。值得注意的是对于预约中的收件人消息会直接以.delivering-预约形态落盘reservedRecipients分支这正是预约 → 唤醒转换的起点。4.3 轮询与注入peer_message信封packages/team-core/src/team-mailbox/poll.ts 的pollAndBuildInjection是唤醒分发的前置环节它列出未读消息排除已在pendingInjectedMessageIds中的消息并将每条消息序列化为peer_message信封buildEnvelope携带from、timestamp、messageId、kind、correlationId等属性。同时通过运行时状态机保证同一 turn marker 内不重复注入lastInjectedTurnMarker存在 pending 消息时返回reason: pending ack避免在确认前重复投递。MessageSchema中消息正文上限 32KB与发送侧的message_payload_max_bytes默认值一致构成端到端约束闭环。4.4 唤醒协调器IdleInjectionCoordinator真正的 wake 由 packages/omo-senpi/src/extension/idle-injection-coordinator.ts 的IdleInjectionCoordinator承担。它是父会话的单一注入队列任务完成、团队消息、DAG 运行摘要、ulw 续跑等通知全部入队在批次窗口内合并为恰好一次omo-senpi:wake注入customType: omo-senpi:wake再以steer或followUp方式送入运行中的回合。关键设计确定性排序SOURCE_RANK规定了混合批次中先注入哪些来源——任务完成最先、DAG 摘要最后、team-message排在第 1 位回执契约已接受的注入必有且仅有一个回执——成功触发onFlushed失败触发onDeliveryFailed被拒绝协调器已退休则无回执由生产者自行走持久化失败路径退休即取消会话关闭时retire()取消已武装的批次窗口定时器、清空队列并给所有待注入项发失败回执保证任何回调都无法触达已失效的生成器issue #7932 的教训。这条源码脉络印证了 README 中保留已接受的实时递送 hold、仅在阻塞器过期后分发 fallback的修复目标fallback wake 必须经由协调器排队而不是绕过批次窗口直接投递。4.5 消费租约与确认消费租约consumer-lease.ts 的withInboxConsumerLease通过.consumer.lock租约文件串行化同一信箱的消费方支持staleAfterMs过期回收死进程租约可被立即重获见 consumer-lease.test.ts确认ack.ts 的ackMessages将未读文件或预约文件原子地rename到processed/且对已确认的消息重复确认幂等ack.test.ts 验证了两次 ack 不报错、不残留消费台账consumed-ledger.ts 的isMessageConsumed通过检查processed/id.json是否存在判定消息是否已消费。这三者共同支撑了exact-message ack 后取消过时唤醒的修复一旦消息落入processed/任何排队的 wake 都应被判定为过时并取消。4.6 预约回收与待交付恢复packages/team-core/src/team-mailbox/reservation.ts 定义了递送预约的三态文件迁移id.json未读→.delivering-id.json预约中→processed/id.json已消费。reclaimStaleReservations会把超过staleTtlMs的预约文件恢复为未读文件防止预约永久卡死。packages/team-core/src/team-mailbox/pending-delivery-recovery.ts 则提供两类关键恢复原语findDeliveredMessageIds通过client.session.messages读取接收方会话历史检测peer_message messageId...信封是否真的进入了上下文。未返回的消息意味着wake 被接受但从未进入上下文此时 ack 会静默丢消息因此必须重新排队而非确认——任何读取错误都返回空集合loss-safe 答案调用方重排而不是 ackrequeuePendingLiveDeliveries把确认未达的预约消息恢复为未读文件供下一轮 poll-injection 或 wake-hint 重新投递。这两条路径正是 README 中保留 filesystem errors、不把不可读信箱条目变成虚假确认的实现依据。五、为什么这样就够了修复清单背后的验证推理README 的 Why it is enough 部分逐条说明了各回归用例所覆盖的缺陷面结合源码可以对应到具体机制回归覆盖点对应机制失败的预约 → 唤醒转换reservation 三态迁移 pollAndBuildInjection的 pending 过滤保留已接受的 prompt hold协调器批次窗口 lastInjectedTurnMarker防重exact-message ack 后取消唤醒ackMessages迁移到processed/ 消费台账判定ack 旧的可合并消息不 strand 新消息消息级去重按messageId独立处理非按批次transient 校验错误排队重试而非取消 wake协调器的onDeliveryFailed回执走持久化失败路径团队状态缺失时取消过时条目sendMessage的TeamDeletingError/ runtime 状态检查pending ack 的消息取消冗余 queued wakependingInjectedMessageIds去重分类的发送前连接失败保留 fallback 队列条目wake 接受后才清理队列项可重试队列失败最多 3 次capped retry三上限预约槽读取保持可见.delivering-文件在getUnreadSizeBytes中被计入重试分类不再清除保守分发 hold修复 REVIEW RED 的重叠分发问题fallback wake 采用 capped exponential backoff替代全局丢弃策略延迟的持久条目轮转在无关 prompt 之后明确的 host/network 不可达与连接超时进入 durable retry连接分类器connection classifier判定无资格的 fetch 错误不进入重试路径因可能发生在 OpenCode 已接受请求之后只有错误本身或其 cause 上的明确连接码可重试exact-message 读取保留文件系统错误inbox.ts 的readUnreadMessageById读取失败抛错而非返回 undefined最后一条值得展开readUnreadMessageById会依次尝试未读路径与预约路径读取过程中若出现 ENOENT 之外的真实错误如权限问题会记录team-mailbox-exact-message-read-failed并重新抛出而不是吞掉错误返回未找到。这保证了不可读的信箱条目绝不会被误判为消息已读/可确认与 README 中Exact-message reads preserve filesystem errors instead of turning an unreadable inbox entry into a false acknowledgement完全对应。六、验证证据的组织方式本仓库将验证证据沉淀为两层主证据.omo/evidence/20260828-issue-5317-team-message-fallback-wake/——包含 README测试范围、观察结果、充分性论证、省略项、manual-qa.txt确定性模块表面与真实 OpenCode 表面的逐项检查清单、verification.txtfailing-first 与修复后的数值门禁Senpi 适配器子证据.omo/evidence/omo-senpi-adapter/20260828-issue-5317-team-message-fallback-wake/——包含 live-driver.json真实 Senpi 驱动结果为PASS、ultrawork 注入被观测到、comment checker 通过、真实 agent 目录未被触碰、package-gate 与 self-test 记录。文档同时明确记录了省略项凭据、宿主配置、请求头与含密钥的日志未做完整 provider turn确定性竞态在模块接缝处覆盖完整套件中无关的 OAuth 回调失败以 scoped gates 记录替代。这种测了什么、为什么够、省了什么的三段式证据结构本身即是一种可复用的回归验证模板。七、如何复现与深入7.1 运行 mailbox 相关测试仓库使用 bun 作为测试运行器可在仓库根目录执行聚焦测试# 聚焦 team-mailbox 全模块测试 bun test packages/team-core/src/team-mailbox # 聚焦消息发送/确认/轮询注入 bun test packages/team-core/src/team-mailbox/send.test.ts bun test packages/team-core/src/team-mailbox/ack.test.ts bun test packages/team-core/src/team-mailbox/poll.test.ts # idle 唤醒协调器 bun test packages/omo-senpi/src/extension/idle-injection-coordinator.test.ts bun test packages/omo-senpi/src/components/memory/kibitzer/delivery-idle.test.ts # 类型检查与构建 bun run typecheck bun run build7.2 关键配置项Team Mode 的 mailbox 行为由 packages/team-core/src/config.ts 的TeamModeConfigSchema控制常用项及默认值配置项默认值说明enabledfalse是否启用 Team Modebase_dir~/.omo团队运行时数据根目录message_payload_max_bytes32768单条消息负载上限与MessageSchema.body上限一致recipient_unread_max_bytes262144单收件人未读信箱背压上限mailbox_poll_interval_ms3000信箱轮询间隔最小 500msmax_parallel_members4最大并行成员数1~8max_members8团队最大成员数1~8max_messages_per_run10000单次运行最大消息数max_wall_clock_minutes120单次运行最大墙钟时间max_member_turns500单成员最大回合数7.3 真实环境验证的复现前提真实服务器验证依赖一次性 OpenCode 容器OpenCode 1.18.4与 CI-Bun 1.4.0 本地 bundle验证目标是工具面tool surface真实验证 模块接缝确定性覆盖的组合容器化运行证明 shipped 工具面可用模块级测试证明 hold 保留与过时唤醒取消。复现时注意保持宿主 OpenCode 会话数与容器运行前后一致本证据中为 7933以确认 disposable 容器不产生宿主副作用。八、结论Issue 5317 的修复与验证为 oh-my-openagent 的 Team Mode 消息递送建立了明确的正确性契约不丢wake 被接受但未进入上下文的消息必须重新排队pending-delivery-recovery不可读的条目保留错误而非虚假确认不重同一 turn marker、同一pendingInjectedMessageIds、已消费台账三重去重配合协调器的单次注入契约不扰fallback wake 尊重实时递送 hold仅在阻塞器过期后分发过时唤醒消息已 ack、团队已删除、协调器已退休一律取消可恢复可重试失败走 capped exponential backoff 的 durable 重试路径明确连接类错误才可重试无资格错误不进重试。这套从磁盘文件状态机到唤醒协调器、再到三层证据验证failing-first → review 修正 → post-merge 重跑的完整链路为后续 Team Mode 消息可靠性相关的改动提供了一个可直接参照的回归基准。【免费下载链接】oh-my-openagentOmO: Just type mass ulw keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表