Skip to content

fix: always-queue + ACK mailbox for reliable Codex→Claude delivery (fixes #223)#237

Closed
RyanZhang33 wants to merge 1 commit into
raysonmeng:masterfrom
RyanZhang33:master
Closed

fix: always-queue + ACK mailbox for reliable Codex→Claude delivery (fixes #223)#237
RyanZhang33 wants to merge 1 commit into
raysonmeng:masterfrom
RyanZhang33:master

Conversation

@RyanZhang33

Copy link
Copy Markdown

问题

Codex→Claude 消息在 Claude 会话 idle 时静默丢失(Issue #223)。根因:pushNotification 使用 fire-and-forget JSON-RPC notification,idle 丢弃不抛异常,回退队列永远不会被填充。

修复方案(三层防护)

  1. Always-queue:queueFallbackMessage 在 pushViaChannel 之前执行,get_messages 始终可用
  2. ACK 邮箱:get_messages 返回未 ack 消息但不删除,只有显式传入 ack_ids 才签收并清理,保证 at-least-once delivery
  3. 溢出保护:邮箱满时优先驱逐已 ack 条目,再驱逐最旧未 ack 条目

修改文件

src/claude-adapter.ts(+109/-49 行)

  • pushNotification: 先入队再推送
  • pushViaChannel: 移除冗余 queueFallbackMessage 调用
  • queueFallbackMessage: 支持 acked 优先驱逐
  • drainMessages: 新增 ack_ids 参数,消息保留不一次性清空
  • get_messages 工具 schema: 新增可选 ack_ids 参数
  • 文件注释和 CLAUDE_INSTRUCTIONS 更新

测试

字母接力测试:13 轮往返(Claude→Codex 13 次,Codex→Claude 39 条消息),0 丢失。get_messages 在 5 次连续调用中稳定返回相同消息(未签收前),签收后立即清空。

Messages from Codex were silently lost when Claude was idle because
pushNotification used fire-and-forget JSON-RPC notifications that
resolve when bytes hit the stdio pipe, with no delivery confirmation.
When the session was idle, the push was silently dropped and the
fallback queue never activated (no error was thrown).

Three-layer fix in claude-adapter.ts:

1. Always-queue: queueFallbackMessage() now runs before pushViaChannel(),
   so get_messages always has messages regardless of push outcome.

2. ACK mailbox: Messages are no longer drained-and-cleared atomically.
   get_messages returns un-acked messages but keeps them in the mailbox;
   only an explicit ack_ids parameter removes them. This guarantees
   at-least-once delivery across multiple get_messages calls.

3. Overflow eviction: When the mailbox is full, already-acked entries
   are evicted first before dropping oldest un-acked messages.

Also updated file header comment and CLAUDE_INSTRUCTIONS to reflect
the new delivery semantics.

Fixes raysonmeng#223
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for the PR! Before we can merge it, please sign our lightweight Contributor License Agreement — it keeps the project able to offer a future commercial edition alongside the open-source one. Reply here with:


I have read the CLA Document and I hereby sign the CLA


RyanZhang33 seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@github-actions github-actions Bot locked and limited conversation to collaborators Jul 13, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant