mirror of
https://github.com/openai/codex.git
synced 2026-09-08 15:50:34 +00:00
## Why Awaiting a bounded consumer event queue can stall the in-process app-server worker when notifications are not being drained, preventing it from delivering a request response queued behind them. ## What changed - Use an unbounded queue for caller-facing in-process events while keeping command and embedded-runtime queues bounded. - Preserve all events in order instead of dropping best-effort events and emitting lag markers when the consumer queue fills. - Document that callers can await requests without concurrently draining notifications. ## Testing Add a regression test that fills a capacity-one client with unread settings notifications, verifies subsequent requests complete, and then confirms the notifications remain readable in order. GitOrigin-RevId: 6ca6cfb9349dfa04a613236836f813c1f799783e
67 lines
2.3 KiB
Markdown
67 lines
2.3 KiB
Markdown
# codex-app-server-client
|
|
|
|
Shared in-process app-server client used by conversational CLI surfaces:
|
|
|
|
- `codex-exec`
|
|
- `codex-tui`
|
|
|
|
## Purpose
|
|
|
|
This crate centralizes startup and lifecycle management for an in-process
|
|
`codex-app-server` runtime, so CLI clients do not need to duplicate:
|
|
|
|
- app-server bootstrap and initialize handshake
|
|
- in-memory request/event transport wiring
|
|
- lifecycle orchestration around caller-provided startup identity
|
|
- graceful shutdown behavior
|
|
|
|
## Startup identity
|
|
|
|
Callers pass both the app-server `SessionSource` and the initialize
|
|
`client_info.name` explicitly when starting the facade.
|
|
|
|
That keeps thread metadata (for example in `thread/list` and `thread/read`)
|
|
aligned with the originating runtime without baking TUI/exec-specific policy
|
|
into the shared client layer.
|
|
|
|
## Transport model
|
|
|
|
The in-process path uses typed channels:
|
|
|
|
- client -> server: `ClientRequest` / `ClientNotification`
|
|
- server -> client: `InProcessServerEvent`
|
|
- `ServerRequest`
|
|
- `ServerNotification`
|
|
- `LegacyNotification`
|
|
|
|
JSON serialization is still used at external transport boundaries
|
|
(stdio/websocket), but the in-process hot path is typed.
|
|
|
|
Typed requests still receive app-server responses through the JSON-RPC
|
|
result envelope internally. That is intentional: the in-process path is
|
|
meant to preserve app-server semantics while removing the process
|
|
boundary, not to introduce a second response contract.
|
|
|
|
## Bootstrap behavior
|
|
|
|
The client facade starts an already-initialized in-process runtime, but
|
|
thread bootstrap still follows normal app-server flow:
|
|
|
|
- caller sends `thread/start` or `thread/resume`
|
|
- app-server returns the immediate typed response
|
|
- richer session metadata may arrive later as a `SessionConfigured`
|
|
legacy event
|
|
|
|
Surfaces such as TUI and exec may therefore need a short bootstrap
|
|
phase where they reconcile startup response data with later events.
|
|
|
|
## Backpressure and shutdown
|
|
|
|
- Command queues and the embedded runtime remain bounded, using
|
|
`DEFAULT_IN_PROCESS_CHANNEL_CAPACITY` by default.
|
|
- The facade's local consumer event queue is unbounded and preserves notification
|
|
order. This keeps the worker draining the bounded runtime while a caller waits
|
|
for a request, preventing unread notifications from blocking its response.
|
|
- `shutdown()` performs a bounded graceful shutdown and then aborts if timeout
|
|
is exceeded.
|