LangChain ChatModel for OpenAI Codex Plus / Pro (ChatGPT-account subscription protocol, not api.openai.com).
Project description
langchain-codex-plus
LangChain ChatModel for OpenAI's ChatGPT-account-backed Codex —
the subscription protocol (Codex Plus / Pro plans), NOT the public
api.openai.com API.
What this is
OpenAI's Codex CLI signs you in with a ChatGPT account (browser OAuth) and routes traffic through:
https://chatgpt.com/backend-api/codex/responses
— a different protocol than api.openai.com/v1/chat/completions. It
has its own request shape, its own auth (OAuth bearer instead of
OPENAI_API_KEY), and exposes quota-window utilization via response
headers (x-codex-primary-*, x-codex-secondary-*).
This package wraps that protocol in a LangChain BaseChatModel so
you can use a Codex Plus subscription from any LangChain-built agent
the way you'd use ChatOpenAI or ChatAnthropic.
What this is NOT
- Not for
api.openai.comtraffic — uselangchain-openaifor that. - Not for Claude — use
langchain-anthropicorlangchain-claude-code. - Not a re-implementation of the Codex CLI's agent loop — just the chat-model surface.
Status
Alpha. v0.0.1. 134 tests + a gated real-account smoke test pass.
Auth
Run codex login once. The CLI writes OAuth credentials to
$CODEX_HOME/auth.json (defaults to ~/.codex/auth.json). This
package reads the file directly — there's no separate setup.
from langchain_codex_plus import ChatCodexPlus
llm = ChatCodexPlus(model="gpt-5.4")
llm.invoke("Say ok.")
When the access token expires (~1h TTL), a 401 response triggers an
automatic refresh against auth.openai.com/oauth/token, then the
call retries once. Permanent refresh failures (expired / revoked /
already-used refresh token) raise CodexAuthRefreshError with
permanent=True — the operator must re-run codex login. Opt out
with auto_refresh=False if you want to handle 401s yourself.
Tool calling
Use bind_tools exactly like ChatOpenAI.bind_tools:
from langchain_core.tools import tool
from langchain_codex_plus import ChatCodexPlus
@tool
def get_weather(location: str) -> str:
"""Look up the weather."""
return f"sunny in {location}"
llm = ChatCodexPlus().bind_tools([get_weather])
msg = llm.invoke("Weather in Boston?")
# msg.tool_calls → [{"name": "get_weather", "args": {"location": "Boston"}, "id": "call_..."}]
Send tool results back via ToolMessage(content=..., tool_call_id=...) —
the protocol layer serializes them as Codex function_call_output
entries.
Multimodal
HumanMessage content can be a list mixing text and image blocks:
from langchain_core.messages import HumanMessage
llm.invoke([HumanMessage(content=[
{"type": "text", "text": "What's in this image?"},
{"type": "image_url", "image_url": "https://example.com/cat.png"},
])])
Both LangChain image-block conventions are accepted ({type: image_url, image_url: {url, detail}} and {type: image, source_type: "url"|"base64", ...}). Base64 data is auto-encoded as a data: URL.
Stop sequences
Codex's /codex/responses rejects the stop parameter, so we match
client-side. Streaming uses a buffered matcher so stop sequences
split across SSE chunks (the common tokenization case) still
truncate cleanly:
llm.invoke("Count from 1 to 100", stop=["50"])
# → "1, 2, 3, ... 49, "
Rate-limit hook
Every successful /codex/responses response carries quota headers
(x-codex-primary-* / -secondary-*). The chat model parses these
into a CodexRateLimits dataclass and (optionally) calls a callback
so your monitoring layer can persist them:
from langchain_codex_plus import ChatCodexPlus, CodexRateLimits
def on_rate_limits(rl: CodexRateLimits) -> None:
print(f"5h: {rl.primary.used_percent}% / 7d: {rl.secondary.used_percent}%")
llm = ChatCodexPlus(model="gpt-5.4", rate_limit_callback=on_rate_limits)
Callback exceptions are caught and logged — they never break the response path.
License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file langchain_codex_plus-0.0.1.tar.gz.
File metadata
- Download URL: langchain_codex_plus-0.0.1.tar.gz
- Upload date:
- Size: 131.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63fdb5870969b62cbedc7193f8e7a1ad029021eb3815fcd6a5e3f278da8efc7e
|
|
| MD5 |
408fadfc2150e4a8e107f6d833cd1952
|
|
| BLAKE2b-256 |
052e575a90189e259f3753d32dadce58c91654d945fc882165f427a853450e9d
|
Provenance
The following attestation bundles were made for langchain_codex_plus-0.0.1.tar.gz:
Publisher:
publish.yml on jasoncarreira/langchain-codex-plus
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
langchain_codex_plus-0.0.1.tar.gz -
Subject digest:
63fdb5870969b62cbedc7193f8e7a1ad029021eb3815fcd6a5e3f278da8efc7e - Sigstore transparency entry: 1589456344
- Sigstore integration time:
-
Permalink:
jasoncarreira/langchain-codex-plus@a02fae7c8857d6ed42f411e0cef004a411ab2f6b -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/jasoncarreira
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a02fae7c8857d6ed42f411e0cef004a411ab2f6b -
Trigger Event:
push
-
Statement type:
File details
Details for the file langchain_codex_plus-0.0.1-py3-none-any.whl.
File metadata
- Download URL: langchain_codex_plus-0.0.1-py3-none-any.whl
- Upload date:
- Size: 33.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7cb7d8346427a6f14139adc543bf6d0d07d742e3cb6144116b95edc89fc41a02
|
|
| MD5 |
858727ac42bcede1f3986df71fdd3d8a
|
|
| BLAKE2b-256 |
47655c1b40db498d5127c7aacb2619f95db61af0039d4e28768d45979613b5d1
|
Provenance
The following attestation bundles were made for langchain_codex_plus-0.0.1-py3-none-any.whl:
Publisher:
publish.yml on jasoncarreira/langchain-codex-plus
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
langchain_codex_plus-0.0.1-py3-none-any.whl -
Subject digest:
7cb7d8346427a6f14139adc543bf6d0d07d742e3cb6144116b95edc89fc41a02 - Sigstore transparency entry: 1589456402
- Sigstore integration time:
-
Permalink:
jasoncarreira/langchain-codex-plus@a02fae7c8857d6ed42f411e0cef004a411ab2f6b -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/jasoncarreira
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a02fae7c8857d6ed42f411e0cef004a411ab2f6b -
Trigger Event:
push
-
Statement type: