Skip to content

fix(#223): opt-in AGENTBRIDGE_ALWAYS_QUEUE mirrors Codex replies to fallback queue#234

Open
Seller-1990 wants to merge 2 commits into
raysonmeng:masterfrom
Seller-1990:fix/223-always-queue-fallback
Open

fix(#223): opt-in AGENTBRIDGE_ALWAYS_QUEUE mirrors Codex replies to fallback queue#234
Seller-1990 wants to merge 2 commits into
raysonmeng:masterfrom
Seller-1990:fix/223-always-queue-fallback

Conversation

@Seller-1990

Copy link
Copy Markdown

Problem (fixes #223)

Codex→Claude replies ride a fire-and-forget notifications/claude/channel notification. When the Claude session is idle, the push is silently dropped upstream (Claude Code #61797 — closed stale). Because nothing throws, pushViaChannel's catch never runs, the fallback queue is never populated, and get_messages stays pending=0. The reply is unrecoverable: not rendered in-band, not pullable.

Net effect: Claude→Codex works; Codex→Claude is lossy whenever Claude is idle. require_reply: true does not help — the reply rides the same channel.

I reproduced this on macOS (CC 2.1.205 + Codex 0.142.4): daemon logs Pushed notification ✅ while get_messages returns empty on the same live adapter instance, dropped=0/pending=0 — matching the three repros in #223.

Fix

Opt-in AGENTBRIDGE_ALWAYS_QUEUE=1. When set, after the channel push, real Codex replies (ids not prefixed system_) are also mirrored into the fallback queue, so get_messages becomes a reliable pull path even for idle sessions.

  • Channel push still fires → mid-turn liveness unchanged.
  • System messages (system_* ids) are excluded so the queue isn't flooded with turn-start/turn-complete notifications.
  • A failed push still queues exactly once (no double-queue).
  • Off by default → delivery behavior is completely unchanged for anyone not setting the flag.

Why opt-in (not always-on)

Mirroring unconditionally would double-deliver when the channel push succeeds mid-turn (rendered once + drained once). Gating behind an env var keeps the default path byte-for-byte identical while giving idle-heavy setups a reliable fallback.

Changes

  • src/claude-adapter.ts: mirror-to-queue branch in pushViaChannel, gated on the flag + non-system id; header doc updated.
  • src/unit-test/message-delivery.test.ts: 4 tests — mirror on real reply, exclude system ids, no double-queue on push failure, default stays push-only.
  • Rebuilt committed bundles (plugins/agentbridge/server/{bridge-server,daemon}.js) via bun run build:plugin per CONTRIBUTING.

Validation

  • bun run typecheck — clean
  • bun run test:unit — 1543 pass / 0 fail (4 new)

Manual reproduction

With AGENTBRIDGE_ALWAYS_QUEUE=1, send a Codex reply while the Claude session is idle: it now surfaces via get_messages instead of being lost. Without the flag, behavior is unchanged.

…plies to fallback queue

The Codex->Claude reply rides a fire-and-forget notifications/claude/channel
notification. When the Claude session is idle the push is silently dropped
upstream (Claude Code #61797), so pushViaChannel's catch never fires, the
fallback queue is never populated, and get_messages stays empty -- the reply is
unrecoverable (see raysonmeng#223).

This adds an opt-in AGENTBRIDGE_ALWAYS_QUEUE=1 flag. When set, real Codex
replies (non-"system_" ids) are also mirrored into the fallback queue after the
channel push, so get_messages becomes a reliable pull path even for idle
sessions. The channel push still fires (mid-turn liveness is unchanged), system
messages are excluded to avoid flooding the queue, and a failed push still
queues exactly once (no double-queue). Off by default -> delivery unchanged.

- src/claude-adapter.ts: mirror-to-queue after push when flag is set
- src/unit-test/message-delivery.test.ts: 4 tests
- rebuilt committed bundles via bun run build:plugin

Validation: bun run typecheck clean; bun run test:unit 1543 pass / 0 fail.
@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


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

…nmeng#223 shim

Per Codex review feedback:
- Note that system_ id prefix is used because BridgeMessage lacks a
  structural kind field; prefer such a field if added in the future.
- Note that ALWAYS_QUEUE extends the fallback queue retention window
  (same data class, longer lifetime).
- Rebuilt bundle.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Codex→Claude replies silently lost when Claude is idle (push-only regression of #29; no queue fallback)

1 participant