feat(llm): add openai_codex provider using ChatGPT subscription quota - #1195
Open
LeonWTW wants to merge 1 commit into
Open
feat(llm): add openai_codex provider using ChatGPT subscription quota#1195LeonWTW wants to merge 1 commit into
LeonWTW wants to merge 1 commit into
Conversation
Adds an `openai_codex` provider so a run can be billed to an existing ChatGPT subscription instead of API credits. It is the only provider here that does not authenticate from an env var. It reuses the OAuth token the official Codex app/CLI stores in `~/.codex/auth.json` (overridable with `TRADINGAGENTS_CODEX_AUTH_PATH`) via `ProviderSpec.credentials_fn`, refreshes it when it nears expiry, and writes the rotated refresh token back — not persisting it would log the Codex client itself out. The endpoint also rejects three things the shared OpenAI client sends by default, so `CodexChatOpenAI` overrides them: - `stream: false` and `store: true` are pinned as constructor kwargs; a class-level field default sets the payload but not langchain's streaming dispatch, so the non-streaming path would still be taken. - `temperature` is filtered out in `get_llm`. - Input items with role `system` return 400. Every agent prompt in this repo is a `ChatPromptTemplate` whose first message is a system message, so the first analyst node failed on its first call and the run stalled. `_get_request_payload` relabels those items `developer`, the Responses-API name for the same role. Adding `instructions` does not make `system` acceptable, and only the item list preserves ordering when several system messages reach one call. Because subscription traffic hits transient overload errors far more often than the paid API, the README suggests raising `TRADINGAGENTS_LLM_MAX_RETRIES`. Caveat, stated in the README too: this endpoint is undocumented and unversioned, so OpenAI can change it without notice, and driving subscription credentials from a third-party tool is not clearly sanctioned by OpenAI's terms. Nothing else in the codebase changes behaviour unless the provider is selected. Tests: auth-file resolution/refresh/rotation, provider registration and payload shaping, the CLI login preflight, plus an opt-in live smoke test behind `-m smoke`. `pytest -q` is 614 passed / 5 skipped and `ruff check .` is clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FFuMQCxPhTkWLwrCQ57tTp
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
Author
|
CI is held at https://github.com/LeonWTW/TradingAgents/actions/runs/30714455163 No rush on my side; flagging it only so the approval decision doesn't have to double as a "does it even build" question. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1194 — that issue carries the full rationale; this is the implementation.
Adds an
openai_codexprovider so a run can be billed to an existing ChatGPT subscription instead of API credits. Nothing changes for any other provider: every code path here is behind the new provider name.Why this needs a provider rather than
openai_compatible+backend_urlThe endpoint breaks three assumptions the shared OpenAI client makes:
~/.codex/auth.json, refreshed near expiry, refresh token rotates and must be written back or the Codex client logs outllm_clients/codex_auth.pyviaProviderSpec.credentials_fnstream: false/store: true/temperatureare fineCodexChatOpenAI— first two pinned as constructor kwargs (a class-level field default sets the payload but not langchain's streaming dispatch),temperaturefiltered inget_llmsystemrole is fineChatPromptTemplatestarting with a system message, so the first analyst node fails on its first call_get_request_payloadrelabels those itemsdeveloper, the Responses-API name for the same roleWhat changed
tradingagents/llm_clients/codex_auth.py(new) — resolve, refresh, rotate, persist. Path overridable viaTRADINGAGENTS_CODEX_AUTH_PATH.tradingagents/llm_clients/openai_client.py—CodexChatOpenAI; auth-error messages stay actionable after the file re-read.tradingagents/llm_clients/model_catalog.py,api_key_env.py— registry entry; no API key is read for this provider.tradingagents/graph/trading_graph.py—_get_provider_kwargsforwardsopenai_reasoning_effortforopenai_codexas well.cli/utils.py,cli/main.py— picker entry, login preflight (so an unauthenticated user gets "sign in with the Codex client first" instead of a 401 mid-run), and the reasoning-effort prompt.README.md— provider docs, including the caveats below.Trying it
Subscription traffic hits transient "servers are currently overloaded" errors far more often than the paid API, so the README suggests
TRADINGAGENTS_LLM_MAX_RETRIES=5or higher.Testing
pytest -q→ 614 passed, 5 skipped;ruff check .→ clean.New coverage: auth-file resolution/refresh/rotation (
test_codex_auth.py), provider registration and payload shaping (test_codex_provider.py), CLI preflight (test_codex_cli.py).test_codex_smoke.pydrives the live endpoint with a realChatPromptTemplateand is opt-in behind-m smoke, so CI never calls out. The smoke test matters for the system→developer fix specifically: a bare-stringinvokecarries no system message and passed throughout, which is how that bug survived.Caveats
This endpoint is undocumented and unversioned, so OpenAI can change it without notice, and driving subscription credentials from a third-party tool is not clearly sanctioned by OpenAI's terms. Both points are stated in the README next to the provider. If you would rather gate this further or not carry it at all, say so in #1194 and I will rework or withdraw it.
🤖 Generated with Claude Code
https://claude.ai/code/session_01FFuMQCxPhTkWLwrCQ57tTp