External chat/controller bridge: assistant completion is not always delivered back to the originating user surface immediately

Open 💬 3 comments Opened Mar 26, 2026 by Anju0103
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What variant of Codex are you using?

App / app-server backed session bridged to an external chat surface (OpenClaw -> Discord style flow)

Describe the bug

When an external user message is routed into a live Codex-backed main session, the main agent can successfully process the request, but the assistant result is not always delivered back to the originating user chat immediately.

In practice, the pipeline sometimes behaves like this:

  1. external user sends a message
  2. the message reaches the main Codex-backed session
  3. the main session performs the requested work
  4. the resulting assistant turn is delayed, stale, or not reflected back to the user chat right away
  5. the missing result may only appear later after another interaction, refresh, or unrelated state change

This creates a serious reliability problem for any external chat / bridge / controller workflow, because successful execution inside Codex is not enough if the originating user surface does not receive the completion immediately.

Repro steps

A generalized repro looks like:

  1. Run a Codex-backed main session through app-server / shared-thread style integration.
  2. Attach an external chat/controller surface that forwards user requests into that session.
  3. Send a user request from the external surface.
  4. Let the main session complete the task successfully.
  5. Observe the originating user chat surface.

Expected behavior

For externally-originated requests, the system should guarantee an end-to-end delivery contract:

  • user request is accepted
  • main Codex session receives it
  • main session executes it
  • the resulting assistant output is immediately surfaced back to the originating user chat/controller
  • completion should not depend on a later refresh, local interaction, or another turn

In other words, the pipeline should reliably guarantee:

request -> main execution -> immediate assistant delivery back to user chat

Actual behavior

The main session can finish work, but the external user surface does not always get the assistant result in real time. The result can be delayed or appear to have been dropped until some later interaction causes state to refresh.

Why this matters

For bridged/chat-controller setups, this is not just a UX issue. It breaks the basic trust contract of the system:

  • users think their request was ignored
  • operators cannot rely on Codex completion meaning user-visible completion
  • external orchestrators/controllers cannot safely assume a finished turn was delivered

If Codex wants to support external chat surfaces, local controllers, shared-thread integrations, or app-server bridges reliably, the delivery path back to the originating surface needs to be authoritative and immediate.

Requested fix / investigation

Please investigate the end-to-end event propagation path and close any gaps between:

  • external inbound turn acceptance
  • live/shared-thread state updates
  • assistant turn completion events
  • outbound propagation back to the originating chat/controller surface

A fix should make this path reliable enough that externally-originated turns are not considered complete until the corresponding assistant result is available for immediate downstream delivery.

Related issues

This feels adjacent to, but not fully covered by:

  • #15320 App-server TUI does not fully reflect external live turns on shared thread
  • #14722 Sync CLI and app-server sessions
  • #15299 Support inbound MCP notifications routed into an active Codex CLI session
  • #15355 Interactive CLI/TUI: opt-in local ingress for trusted local controllers
  • #15504 VS Code: support external workflow / local-controller notifications into Codex sessions

Those issues point in a similar direction, but this report is specifically about the missing guarantee that an externally-originated user request results in immediate assistant delivery back to that same user-facing chat surface.

View original on GitHub ↗

3 Comments

github-actions[bot] contributor · 5 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #15320
  • #14722

Powered by Codex Action

etraut-openai contributor · 5 months ago

Please use /feedback to upload your logs and session details and post the thread ID here. Without these details or specific repro steps, it will be difficult for us to investigate further.

devindown · 5 months ago

We ran into the same problem building a multi-agent orchestration layer on top of Codex's app-server.

The core issue is that turn/start completion on the app-server side doesn't guarantee the result is visible to the originating surface. We found three specific failure modes:

  1. Stale active turn absorption — If a previous turn is stuck in waitingOnApproval, new messages get turn/steer-ed into the dead turn instead of starting fresh. The app-server reports success, but the message never produces a visible response.
  1. Thread state desync — The bridge sees turns=active in heartbeat but the actual turn has completed. Without polling thread/read and checking thread.status.activeFlags, there's no way to distinguish "working" from "stuck."
  1. No delivery acknowledgment — turn/start returns a turn ID, but there's no callback or notification confirming the result reached the external surface. You only know it worked if a turn/completed notification arrives, which can be missed if the WebSocket reconnects.

Our solution was a file-based message queue with explicit delivery tracking:

  • Every dispatched message gets a .done marker with thread/turn ID
  • Heartbeat includes activeTurnId + turnStartedAt for stuck detection
  • If turnStartedAt exceeds a threshold (we use 5 min) or activeFlags includes waitingOnApproval, fall back to turn/start instead of turn/steer
  • Processed markers prevent re-dispatch on reconnection

We open-sourced the bridge layer that implements this pattern: https://github.com/HUA-Labs/tap

It's a file-based communication framework for multi-model agent coordination (Claude + Codex + Gemini). The delivery tracking and stale turn recovery described above are part of the bridge module. May or may not be directly applicable to your setup, but the patterns might help.