Repository navigation
Fix codex_app_server provider against a real Codex app-server (busy-loop wedge, sandbox shape, auth flag) - #558
Conversation
Three defects that only appear against a real `codex app-server`
(the in-process fake server models none of them):
1. request() parked non-matching messages in _pending, which
next_message() drains before reading the queue — so the first
interleaved notification (a real server emits e.g. configWarning /
account/updated before responses) was returned forever in a
100%-CPU busy loop and the actual response was never read. Stash
non-matching messages locally during the request and restore them
to the front of _pending, in order, when the response arrives.
2. thread/start sent sandbox as a {"mode": ..., "networkAccess": ...}
map. ThreadStartParams.sandbox is a SandboxMode string enum in
current app-server versions (verified against the server's
generated JSON schema for Codex 0.160.1 and 0.164.0-alpha.9); the
map form is rejected with -32600. Send "read-only". The existing
test asserted the broken map shape and is corrected.
3. _ensure_authenticated() treated requiresOpenaiAuth as a
logged-out signal. Current servers return requiresOpenaiAuth=true
together with a valid ChatGPT account — the flag describes the
auth mode. Only a missing account fails the boundary now (the
account type check below is unchanged).
Tests: the fake server gains a notify_first scenario (unsolicited
notifications ahead of account/read and thread/start responses) and a
chatgpt_requires_auth_flag account/read variant. New tests cover all
three defects; each fails against the unfixed code (the notification
test via a join-timeout assertion, so the wedged code fails instead
of hanging the suite).
|
Adding the disclosure that should have been in the original submission: Disclosure: this contribution was written by Árbol, an AI assistant working under the direction of the account holder, who set the acceptance criteria and verified the results before submission. |
|
|
1 similar comment
|
|
Summary
The
codex_app_serverprovider fails against a realcodex app-serverin three independent ways. All three were found by running the provider against the real server (Codex 0.160.1, ChatGPT subscription auth) and each is verified against the server's own generated JSON schema or a live protocol session. The in-process fake server in the test suite models none of the three real-server behaviors, which is why the existing tests all pass while the provider is broken in production.The three defects
1.
request()wedges in a 100%-CPU busy loop on the first interleaved notification._AppServerSession.request()parked any non-matching message inself._pending, andnext_message()drains_pendingbefore reading the message queue. A real app-server emits notifications (e.g.configWarning,account/updated) before responses, so the first interleaved notification was returned bynext_message()forever; the actual response was never read from the queue and the request deadline was never consulted (the_pendingpath has no deadline check). Fix: stash non-matching messages in a local list during the request and restore them to the front of_pending, in order, in afinallyblock when the response arrives.2.
thread/startsends the obsolete sandbox map form, rejected with -32600.The provider sent
"sandbox": {"mode": "read-only", "networkAccess": false}. In current app-server versions,ThreadStartParams.sandboxis theSandboxModestring enum ("read-only" | "workspace-write" | "danger-full-access") — confirmed in the generated JSON schema of both Codex 0.160.1 and 0.164.0-alpha.9. Fix: send"sandbox": "read-only". Note the existing testtest_thread_is_non_interactive_and_read_onlyasserted the broken map shape; this PR corrects that assertion.3. A valid ChatGPT login is misread as logged-out.
_ensure_authenticated()raisedCodexAuthErrorwheneveraccount/readreturnedrequiresOpenaiAuth: true. Current servers returnrequiresOpenaiAuth: truetogether with a valid ChatGPT account — the flag describes the auth mode, not a missing login. Fix: only a missing account fails the boundary; the existing account-type check (type == "chatgpt") is unchanged.Tests
The fake server gains two behaviors a real server has and it lacked:
notify_firstscenario: pushes an unsolicited notification ahead of theaccount/readandthread/startresponses.chatgpt_requires_auth_flagscenario:account/readreturns a valid ChatGPT account withrequiresOpenaiAuth: True.New/corrected tests cover all three defects. Each fails against the unfixed code: the auth-flag and sandbox tests fail immediately; the notification test runs
generate()in a thread and fails on a join-timeout assertion, so the wedged code fails the test instead of hanging the suite.Results (Python 3.12, unittest):
tests/test_codex_app_server_llm.py: 26 tests, OK.test_llm_ensemble,test_llm_config_optional_params,test_reasoning_effort_config,test_valid_configs: 49 tests total, OK.Live re-verification (2026-10-29)
Against both installed servers (Codex 0.164.0-alpha.9 on PATH and 0.160.1), a patched-provider session now completes
initialize→account/read(auth check passes) →thread/start(accepted, thread id issued) →turn/start, with server notifications flowing — i.e. all three fixed behaviors hold against the real protocol. The turn itself then errored server-side (responseStreamDisconnected: Connection refused) because this machine's Codex config routes the model provider through a local gateway (127.0.0.1:17321) that is not running in the test environment; that failure is downstream of, and unrelated to, the three fixes, and is identical for both server versions. End-to-end generation with these fixes was previously verified live on the same setup (exact-token smoke test, Codex 0.160.1).