Context - This code parses Server-Sent Events (SSE) from the legacy Chat Completions streaming API (wire_api = "chat"). - The upstream protocol terminates a stream with a final sentinel event: data: [DONE]. - Some of our test stubs/helpers historically end the stream with data: DONE (no brackets). How this was found - GitHub Actions on Windows failed in codex-app-server integration tests with wiremock verification errors (expected multiple POSTs, got 1). Diagnosis - The job logs included: codex_api::sse::chat: Failed to parse ChatCompletions SSE event ... data: DONE. - eventsource_stream surfaces the sentinel as a normal SSE event; it does not automatically close the stream. - The parser previously attempted to JSON-decode every data: payload. The sentinel is not JSON, so we logged and skipped it, then continued polling. - On servers that keep the HTTP connection open after emitting the sentinel (notably wiremock on Windows), skipping the sentinel meant we never emitted ResponseEvent::Completed. - Higher layers wait for completion before progressing (emitting approval requests and issuing follow-up model calls), so the test never reached the subsequent requests and wiremock panicked when its expected-call count was not met. Fix - Treat both data: [DONE] and data: DONE as explicit end-of-stream sentinels. - When a sentinel is seen, flush any pending assistant/reasoning items and emit ResponseEvent::Completed once. Tests - Add a regression unit test asserting we complete on the sentinel even if the underlying connection is not closed. |
||
|---|---|---|
| .. | ||
| src | ||
| tests | ||
| Cargo.toml | ||
| README.md | ||
codex-api
Typed clients for Codex/OpenAI APIs built on top of the generic transport in codex-client.
- Hosts the request/response models and prompt helpers for Responses, Chat Completions, and Compact APIs.
- Owns provider configuration (base URLs, headers, query params), auth header injection, retry tuning, and stream idle settings.
- Parses SSE streams into
ResponseEvent/ResponseStream, including rate-limit snapshots and API-specific error mapping. - Serves as the wire-level layer consumed by
codex-core; higher layers handle auth refresh and business logic.
Core interface
The public interface of this crate is intentionally small and uniform:
-
Prompted endpoints (Chat + Responses)
- Input: a single
Promptplus endpoint-specific options.Prompt(re-exported ascodex_api::Prompt) carries:instructions: String– the fully-resolved system prompt for this turn.input: Vec<ResponseItem>– conversation history and user/tool messages.tools: Vec<serde_json::Value>– JSON tools compatible with the target API.parallel_tool_calls: bool.output_schema: Option<Value>– used to buildtext.formatwhen present.
- Output: a
ResponseStreamofResponseEvent(both re-exported fromcommon).
- Input: a single
-
Compaction endpoint
- Input:
CompactionInput<'a>(re-exported ascodex_api::CompactionInput):model: &str.input: &[ResponseItem]– history to compact.instructions: &str– fully-resolved compaction instructions.
- Output:
Vec<ResponseItem>. CompactClient::compact_input(&CompactionInput, extra_headers)wraps the JSON encoding and retry/telemetry wiring.
- Input:
All HTTP details (URLs, headers, retry/backoff policies, SSE framing) are encapsulated in codex-api and codex-client. Callers construct prompts/inputs using protocol types and work with typed streams of ResponseEvent or compacted ResponseItem values.