This document describes the timeout layers used by the adapter after the streaming reliability fix in PR #11.
| Layer | Default | Behavior |
|---|---|---|
Codex provider stream_idle_timeout_ms |
360000 ms |
Maximum time Codex waits without receiving activity from the adapter's Responses SSE stream. init writes this value into ~/.codex/config.toml. |
| Adapter downstream SSE keep-alive | 15 seconds |
Sends an SSE comment frame (: keep-alive) while no Responses event is available, so the Codex-facing connection does not remain silent. |
| Non-stream upstream request timeout | 300 seconds |
CODEX_OPENCODE_TIMEOUT_SECONDS is a total deadline for a normal non-stream OpenCode Go request. |
| Stream upstream connect timeout | 300 seconds |
CODEX_OPENCODE_TIMEOUT_SECONDS limits establishment of the upstream streaming connection. |
| Stream upstream read timeout | 300 seconds |
The same variable limits the gap between successful upstream body reads. It is not a total stream-duration limit. |
A healthy streaming response may run longer than CODEX_OPENCODE_TIMEOUT_SECONDS as long as the upstream continues to deliver body data before each read timeout expires.
The downstream 15-second keep-alive protects only the adapter-to-Codex connection. It does not create upstream model output and does not prevent the upstream read timeout from firing when OpenCode Go sends no bytes for the configured read-timeout period.
The default relationship is intentional:
adapter SSE keep-alive: 15 seconds
upstream per-read timeout: 300 seconds
Codex stream idle timeout: 360 seconds
This allows the adapter to detect a truly stalled upstream before Codex treats the downstream stream as lost, while keep-alive comments prevent ordinary model thinking gaps from looking like downstream inactivity.
codex-opencode-adapter init writes:
[model_providers.opencode_go_adapter]
request_max_retries = 0
stream_max_retries = 0
stream_idle_timeout_ms = 360000Existing installations are not changed merely by updating the binary. If ~/.codex/config.toml still contains stream_idle_timeout_ms = 120000, rerun init for the project or update that provider value manually.
The variable has different semantics by request type:
- non-stream: total upstream request deadline;
- stream: upstream connection timeout plus per-read idle timeout;
- stream: no total response-duration deadline.
Increasing it allows a longer gap between upstream stream reads, but also makes a genuinely stalled upstream take longer to fail. It does not control the 15-second downstream SSE keep-alive or Codex's stream_idle_timeout_ms.
When a long stream disconnects, record:
- The current
stream_idle_timeout_msin~/.codex/config.toml. - The current
CODEX_OPENCODE_TIMEOUT_SECONDSvalue. - Whether
: keep-alivecomment frames continued to arrive downstream. - The time since the last upstream body chunk.
- The last Responses event emitted before termination.
Interpretation:
- no downstream keep-alive within roughly 15 seconds: inspect the adapter process or downstream response path;
- downstream keep-alives continue, but no upstream body bytes arrive for the read-timeout period: upstream stream stall or network issue;
- stream ends at a fixed total duration despite regular upstream chunks: regression in the dedicated streaming client behavior;
- Codex disconnects while keep-alives are arriving: inspect the effective Codex provider configuration and client behavior.
The repository includes tests that verify:
- downstream SSE emits keep-alive comments while the Responses stream is idle;
- generated provider configuration uses the 360-second Codex idle timeout;
- a streaming upstream request can outlive the normal non-stream total timeout when chunks continue arriving.