Skip to content

fix(codex-auth-helper): serve async clients on successive event loops; support Pydantic AI 2.66 (1.13.0) - #81

Merged
fswair merged 1 commit into
mainfrom
fix/codex-client-loop
Nov 7, 2026
Merged

fswair merged 1 commit into
mainfrom
fix/codex-client-loop

Conversation

@fswair

@fswair fswair commented Nov 7, 2026

Copy link
Copy Markdown
Member

Summary

Fix: codex-auth-helper async clients now work on successive event loops.

The HTTP clients the helper owns (the Codex API client and the token-refresh client) kept their pooled connections bound to the first event loop. A request on a later loop, for example a second asyncio.run, or a host such as Kedi that closes its shared loop between runs, reused one of those connections and failed with RuntimeError: Event loop is closed. Closing the client afterwards reported the same error.

Pydantic AI already refreshes the clients its providers own in this situation, but never a client passed in through OpenAIProvider(openai_client=...), which is how create_codex_responses_model builds the model. So the fix belongs here:

  • Both owned clients remember the loop they last ran on and are replaced once that loop has stopped. A loop that still runs is left alone, matching Pydantic AI.
  • The SDK client is now built with the public DefaultAsyncHttpxClient. The SDK's default wrapper closes itself from its finalizer on whatever loop runs then, so a replaced client would have tried to close on the wrong loop.
  • close() skips a client whose loop has stopped; its connections went with that loop.
  • Borrowed clients (http_client=, auth_http_client=) are never replaced or closed, as before.

Pydantic AI 2.66. Support widens to pydantic-ai-slim<=2.66.0, and Harness moves to 0.66.0. The CI and Makefile matrices add 2.64.0, 2.65.0 and 2.66.0. Versions are bumped to 1.13.0.

Testing

  • New tests/codex_auth_helper/test_event_loops.py runs real keep-alive HTTP requests across successive asyncio.run calls and fails on main for both the SDK client and the token refresh client.
  • The pre-commit hook passed: version ordering, ruff, coverage thresholds, and build verification including the full Pydantic AI matrix 2.9.0–2.66.0.
  • make tests, check, check-formatted, check-coverage, docs-build, release-check and check-langchain-stack pass.
  • Checked end to end with Kedi and a real Codex login: run_main() twice on one runtime, a second runtime closed in between, then a clean aclose().

🤖 Generated with Claude Code

…; support Pydantic AI 2.66 (1.13.0)

The HTTP clients the helper owns for the Codex API and for token refresh kept
connections bound to the first event loop. A request on a later loop, such as a
second asyncio.run, reused one and failed with 'Event loop is closed'. Both are
now replaced once the loop they last ran on has stopped, as Pydantic AI does for
the clients its providers own. The SDK client is built with the public
DefaultAsyncHttpxClient, whose lack of a closing finalizer keeps a replaced
client from closing on the wrong loop.

Pydantic AI support widens to 2.66.0 and Harness to 0.66.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Nov 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@fswair
fswair merged commit 908ac2a into main Nov 7, 2026
70 checks passed
@fswair
fswair deleted the fix/codex-client-loop branch November 7, 2026 18:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant