langchain-codex-plus 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- langchain_codex_plus-0.0.1/.github/workflows/publish.yml +53 -0
- langchain_codex_plus-0.0.1/.gitignore +10 -0
- langchain_codex_plus-0.0.1/LICENSE +21 -0
- langchain_codex_plus-0.0.1/PKG-INFO +156 -0
- langchain_codex_plus-0.0.1/README.md +128 -0
- langchain_codex_plus-0.0.1/langchain_codex_plus/__init__.py +77 -0
- langchain_codex_plus-0.0.1/langchain_codex_plus/codex_auth.py +452 -0
- langchain_codex_plus-0.0.1/langchain_codex_plus/codex_chat_model.py +1155 -0
- langchain_codex_plus-0.0.1/langchain_codex_plus/codex_protocol.py +803 -0
- langchain_codex_plus-0.0.1/langchain_codex_plus/py.typed +0 -0
- langchain_codex_plus-0.0.1/langchain_codex_plus/rate_limits.py +202 -0
- langchain_codex_plus-0.0.1/pyproject.toml +65 -0
- langchain_codex_plus-0.0.1/tests/__init__.py +0 -0
- langchain_codex_plus-0.0.1/tests/conftest.py +163 -0
- langchain_codex_plus-0.0.1/tests/test_codex_auth.py +203 -0
- langchain_codex_plus-0.0.1/tests/test_codex_chat_model.py +419 -0
- langchain_codex_plus-0.0.1/tests/test_codex_protocol.py +364 -0
- langchain_codex_plus-0.0.1/tests/test_multimodal.py +211 -0
- langchain_codex_plus-0.0.1/tests/test_oauth_refresh.py +450 -0
- langchain_codex_plus-0.0.1/tests/test_rate_limits.py +191 -0
- langchain_codex_plus-0.0.1/tests/test_stop_sequences.py +263 -0
- langchain_codex_plus-0.0.1/tests/test_tool_calling.py +430 -0
- langchain_codex_plus-0.0.1/uv.lock +1175 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
# Triggered by pushing a version tag (e.g. ``v0.0.1``). PyPI Trusted
|
|
4
|
+
# Publishing uses GitHub's OIDC token to authenticate — no API tokens
|
|
5
|
+
# stored anywhere. The ``pypi`` environment adds an extra gate (you
|
|
6
|
+
# can require manual approval on it in the repo settings).
|
|
7
|
+
on:
|
|
8
|
+
push:
|
|
9
|
+
tags:
|
|
10
|
+
- "v*"
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
name: Build distributions
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- name: Install uv
|
|
19
|
+
uses: astral-sh/setup-uv@v3
|
|
20
|
+
with:
|
|
21
|
+
enable-cache: true
|
|
22
|
+
- name: Set up Python
|
|
23
|
+
run: uv python install 3.12
|
|
24
|
+
- name: Build sdist + wheel
|
|
25
|
+
run: uv build
|
|
26
|
+
- name: Upload dist artifact
|
|
27
|
+
uses: actions/upload-artifact@v4
|
|
28
|
+
with:
|
|
29
|
+
name: python-package-distributions
|
|
30
|
+
path: dist/
|
|
31
|
+
|
|
32
|
+
publish:
|
|
33
|
+
name: Publish to PyPI (trusted publishing)
|
|
34
|
+
needs: build
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
# Must match the environment name configured on the PyPI pending
|
|
37
|
+
# publisher. If you skipped the environment field there, remove
|
|
38
|
+
# this line.
|
|
39
|
+
environment:
|
|
40
|
+
name: pypi
|
|
41
|
+
url: https://pypi.org/p/langchain-codex-plus
|
|
42
|
+
permissions:
|
|
43
|
+
# Required for trusted publishing — PyPI verifies the GH OIDC
|
|
44
|
+
# token, which only this job is allowed to mint.
|
|
45
|
+
id-token: write
|
|
46
|
+
steps:
|
|
47
|
+
- name: Download dist artifact
|
|
48
|
+
uses: actions/download-artifact@v4
|
|
49
|
+
with:
|
|
50
|
+
name: python-package-distributions
|
|
51
|
+
path: dist/
|
|
52
|
+
- name: Publish to PyPI
|
|
53
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jason Carreira
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: langchain-codex-plus
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: LangChain ChatModel for OpenAI Codex Plus / Pro (ChatGPT-account subscription protocol, not api.openai.com).
|
|
5
|
+
Project-URL: Homepage, https://github.com/jasoncarreira/langchain-codex-plus
|
|
6
|
+
Project-URL: Issues, https://github.com/jasoncarreira/langchain-codex-plus/issues
|
|
7
|
+
Author: Jason Carreira
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: chatgpt,codex,langchain,oauth,openai,subscription
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Requires-Dist: httpx>=0.27.0
|
|
20
|
+
Requires-Dist: langchain-core>=0.3.0
|
|
21
|
+
Requires-Dist: pydantic>=2.0
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# langchain-codex-plus
|
|
30
|
+
|
|
31
|
+
LangChain `ChatModel` for OpenAI's **ChatGPT-account-backed Codex** —
|
|
32
|
+
the subscription protocol (Codex Plus / Pro plans), NOT the public
|
|
33
|
+
`api.openai.com` API.
|
|
34
|
+
|
|
35
|
+
## What this is
|
|
36
|
+
|
|
37
|
+
OpenAI's Codex CLI signs you in with a **ChatGPT account** (browser
|
|
38
|
+
OAuth) and routes traffic through:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
https://chatgpt.com/backend-api/codex/responses
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
— a different protocol than `api.openai.com/v1/chat/completions`. It
|
|
45
|
+
has its own request shape, its own auth (OAuth bearer instead of
|
|
46
|
+
`OPENAI_API_KEY`), and exposes quota-window utilization via response
|
|
47
|
+
headers (`x-codex-primary-*`, `x-codex-secondary-*`).
|
|
48
|
+
|
|
49
|
+
This package wraps that protocol in a LangChain `BaseChatModel` so
|
|
50
|
+
you can use a Codex Plus subscription from any LangChain-built agent
|
|
51
|
+
the way you'd use `ChatOpenAI` or `ChatAnthropic`.
|
|
52
|
+
|
|
53
|
+
## What this is NOT
|
|
54
|
+
|
|
55
|
+
* Not for `api.openai.com` traffic — use `langchain-openai` for that.
|
|
56
|
+
* Not for Claude — use `langchain-anthropic` or `langchain-claude-code`.
|
|
57
|
+
* Not a re-implementation of the Codex CLI's agent loop — just the
|
|
58
|
+
chat-model surface.
|
|
59
|
+
|
|
60
|
+
## Status
|
|
61
|
+
|
|
62
|
+
Alpha. v0.0.1. 134 tests + a gated real-account smoke test pass.
|
|
63
|
+
|
|
64
|
+
## Auth
|
|
65
|
+
|
|
66
|
+
Run `codex login` once. The CLI writes OAuth credentials to
|
|
67
|
+
`$CODEX_HOME/auth.json` (defaults to `~/.codex/auth.json`). This
|
|
68
|
+
package reads the file directly — there's no separate setup.
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from langchain_codex_plus import ChatCodexPlus
|
|
72
|
+
|
|
73
|
+
llm = ChatCodexPlus(model="gpt-5.4")
|
|
74
|
+
llm.invoke("Say ok.")
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
When the access token expires (~1h TTL), a 401 response triggers an
|
|
78
|
+
automatic refresh against `auth.openai.com/oauth/token`, then the
|
|
79
|
+
call retries once. Permanent refresh failures (expired / revoked /
|
|
80
|
+
already-used refresh token) raise `CodexAuthRefreshError` with
|
|
81
|
+
`permanent=True` — the operator must re-run `codex login`. Opt out
|
|
82
|
+
with `auto_refresh=False` if you want to handle 401s yourself.
|
|
83
|
+
|
|
84
|
+
## Tool calling
|
|
85
|
+
|
|
86
|
+
Use `bind_tools` exactly like `ChatOpenAI.bind_tools`:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from langchain_core.tools import tool
|
|
90
|
+
from langchain_codex_plus import ChatCodexPlus
|
|
91
|
+
|
|
92
|
+
@tool
|
|
93
|
+
def get_weather(location: str) -> str:
|
|
94
|
+
"""Look up the weather."""
|
|
95
|
+
return f"sunny in {location}"
|
|
96
|
+
|
|
97
|
+
llm = ChatCodexPlus().bind_tools([get_weather])
|
|
98
|
+
msg = llm.invoke("Weather in Boston?")
|
|
99
|
+
# msg.tool_calls → [{"name": "get_weather", "args": {"location": "Boston"}, "id": "call_..."}]
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Send tool results back via `ToolMessage(content=..., tool_call_id=...)` —
|
|
103
|
+
the protocol layer serializes them as Codex `function_call_output`
|
|
104
|
+
entries.
|
|
105
|
+
|
|
106
|
+
## Multimodal
|
|
107
|
+
|
|
108
|
+
`HumanMessage` content can be a list mixing text and image blocks:
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
from langchain_core.messages import HumanMessage
|
|
112
|
+
|
|
113
|
+
llm.invoke([HumanMessage(content=[
|
|
114
|
+
{"type": "text", "text": "What's in this image?"},
|
|
115
|
+
{"type": "image_url", "image_url": "https://example.com/cat.png"},
|
|
116
|
+
])])
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Both LangChain image-block conventions are accepted (`{type: image_url,
|
|
120
|
+
image_url: {url, detail}}` and `{type: image, source_type: "url"|"base64",
|
|
121
|
+
...}`). Base64 data is auto-encoded as a `data:` URL.
|
|
122
|
+
|
|
123
|
+
## Stop sequences
|
|
124
|
+
|
|
125
|
+
Codex's `/codex/responses` rejects the `stop` parameter, so we match
|
|
126
|
+
client-side. Streaming uses a buffered matcher so stop sequences
|
|
127
|
+
split across SSE chunks (the common tokenization case) still
|
|
128
|
+
truncate cleanly:
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
llm.invoke("Count from 1 to 100", stop=["50"])
|
|
132
|
+
# → "1, 2, 3, ... 49, "
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Rate-limit hook
|
|
136
|
+
|
|
137
|
+
Every successful `/codex/responses` response carries quota headers
|
|
138
|
+
(`x-codex-primary-*` / `-secondary-*`). The chat model parses these
|
|
139
|
+
into a `CodexRateLimits` dataclass and (optionally) calls a callback
|
|
140
|
+
so your monitoring layer can persist them:
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
from langchain_codex_plus import ChatCodexPlus, CodexRateLimits
|
|
144
|
+
|
|
145
|
+
def on_rate_limits(rl: CodexRateLimits) -> None:
|
|
146
|
+
print(f"5h: {rl.primary.used_percent}% / 7d: {rl.secondary.used_percent}%")
|
|
147
|
+
|
|
148
|
+
llm = ChatCodexPlus(model="gpt-5.4", rate_limit_callback=on_rate_limits)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Callback exceptions are caught and logged — they never break the
|
|
152
|
+
response path.
|
|
153
|
+
|
|
154
|
+
## License
|
|
155
|
+
|
|
156
|
+
MIT. See `LICENSE`.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# langchain-codex-plus
|
|
2
|
+
|
|
3
|
+
LangChain `ChatModel` for OpenAI's **ChatGPT-account-backed Codex** —
|
|
4
|
+
the subscription protocol (Codex Plus / Pro plans), NOT the public
|
|
5
|
+
`api.openai.com` API.
|
|
6
|
+
|
|
7
|
+
## What this is
|
|
8
|
+
|
|
9
|
+
OpenAI's Codex CLI signs you in with a **ChatGPT account** (browser
|
|
10
|
+
OAuth) and routes traffic through:
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
https://chatgpt.com/backend-api/codex/responses
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
— a different protocol than `api.openai.com/v1/chat/completions`. It
|
|
17
|
+
has its own request shape, its own auth (OAuth bearer instead of
|
|
18
|
+
`OPENAI_API_KEY`), and exposes quota-window utilization via response
|
|
19
|
+
headers (`x-codex-primary-*`, `x-codex-secondary-*`).
|
|
20
|
+
|
|
21
|
+
This package wraps that protocol in a LangChain `BaseChatModel` so
|
|
22
|
+
you can use a Codex Plus subscription from any LangChain-built agent
|
|
23
|
+
the way you'd use `ChatOpenAI` or `ChatAnthropic`.
|
|
24
|
+
|
|
25
|
+
## What this is NOT
|
|
26
|
+
|
|
27
|
+
* Not for `api.openai.com` traffic — use `langchain-openai` for that.
|
|
28
|
+
* Not for Claude — use `langchain-anthropic` or `langchain-claude-code`.
|
|
29
|
+
* Not a re-implementation of the Codex CLI's agent loop — just the
|
|
30
|
+
chat-model surface.
|
|
31
|
+
|
|
32
|
+
## Status
|
|
33
|
+
|
|
34
|
+
Alpha. v0.0.1. 134 tests + a gated real-account smoke test pass.
|
|
35
|
+
|
|
36
|
+
## Auth
|
|
37
|
+
|
|
38
|
+
Run `codex login` once. The CLI writes OAuth credentials to
|
|
39
|
+
`$CODEX_HOME/auth.json` (defaults to `~/.codex/auth.json`). This
|
|
40
|
+
package reads the file directly — there's no separate setup.
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from langchain_codex_plus import ChatCodexPlus
|
|
44
|
+
|
|
45
|
+
llm = ChatCodexPlus(model="gpt-5.4")
|
|
46
|
+
llm.invoke("Say ok.")
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
When the access token expires (~1h TTL), a 401 response triggers an
|
|
50
|
+
automatic refresh against `auth.openai.com/oauth/token`, then the
|
|
51
|
+
call retries once. Permanent refresh failures (expired / revoked /
|
|
52
|
+
already-used refresh token) raise `CodexAuthRefreshError` with
|
|
53
|
+
`permanent=True` — the operator must re-run `codex login`. Opt out
|
|
54
|
+
with `auto_refresh=False` if you want to handle 401s yourself.
|
|
55
|
+
|
|
56
|
+
## Tool calling
|
|
57
|
+
|
|
58
|
+
Use `bind_tools` exactly like `ChatOpenAI.bind_tools`:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from langchain_core.tools import tool
|
|
62
|
+
from langchain_codex_plus import ChatCodexPlus
|
|
63
|
+
|
|
64
|
+
@tool
|
|
65
|
+
def get_weather(location: str) -> str:
|
|
66
|
+
"""Look up the weather."""
|
|
67
|
+
return f"sunny in {location}"
|
|
68
|
+
|
|
69
|
+
llm = ChatCodexPlus().bind_tools([get_weather])
|
|
70
|
+
msg = llm.invoke("Weather in Boston?")
|
|
71
|
+
# msg.tool_calls → [{"name": "get_weather", "args": {"location": "Boston"}, "id": "call_..."}]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Send tool results back via `ToolMessage(content=..., tool_call_id=...)` —
|
|
75
|
+
the protocol layer serializes them as Codex `function_call_output`
|
|
76
|
+
entries.
|
|
77
|
+
|
|
78
|
+
## Multimodal
|
|
79
|
+
|
|
80
|
+
`HumanMessage` content can be a list mixing text and image blocks:
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from langchain_core.messages import HumanMessage
|
|
84
|
+
|
|
85
|
+
llm.invoke([HumanMessage(content=[
|
|
86
|
+
{"type": "text", "text": "What's in this image?"},
|
|
87
|
+
{"type": "image_url", "image_url": "https://example.com/cat.png"},
|
|
88
|
+
])])
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Both LangChain image-block conventions are accepted (`{type: image_url,
|
|
92
|
+
image_url: {url, detail}}` and `{type: image, source_type: "url"|"base64",
|
|
93
|
+
...}`). Base64 data is auto-encoded as a `data:` URL.
|
|
94
|
+
|
|
95
|
+
## Stop sequences
|
|
96
|
+
|
|
97
|
+
Codex's `/codex/responses` rejects the `stop` parameter, so we match
|
|
98
|
+
client-side. Streaming uses a buffered matcher so stop sequences
|
|
99
|
+
split across SSE chunks (the common tokenization case) still
|
|
100
|
+
truncate cleanly:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
llm.invoke("Count from 1 to 100", stop=["50"])
|
|
104
|
+
# → "1, 2, 3, ... 49, "
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Rate-limit hook
|
|
108
|
+
|
|
109
|
+
Every successful `/codex/responses` response carries quota headers
|
|
110
|
+
(`x-codex-primary-*` / `-secondary-*`). The chat model parses these
|
|
111
|
+
into a `CodexRateLimits` dataclass and (optionally) calls a callback
|
|
112
|
+
so your monitoring layer can persist them:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from langchain_codex_plus import ChatCodexPlus, CodexRateLimits
|
|
116
|
+
|
|
117
|
+
def on_rate_limits(rl: CodexRateLimits) -> None:
|
|
118
|
+
print(f"5h: {rl.primary.used_percent}% / 7d: {rl.secondary.used_percent}%")
|
|
119
|
+
|
|
120
|
+
llm = ChatCodexPlus(model="gpt-5.4", rate_limit_callback=on_rate_limits)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Callback exceptions are caught and logged — they never break the
|
|
124
|
+
response path.
|
|
125
|
+
|
|
126
|
+
## License
|
|
127
|
+
|
|
128
|
+
MIT. See `LICENSE`.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""langchain-codex-plus: LangChain ChatModel for OpenAI Codex Plus.
|
|
2
|
+
|
|
3
|
+
Wraps OpenAI's ChatGPT-account-backed Codex subscription protocol
|
|
4
|
+
(``chatgpt.com/backend-api/codex/responses``) as a LangChain
|
|
5
|
+
``BaseChatModel``. See README for what this is and isn't.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from langchain_codex_plus.codex_auth import (
|
|
10
|
+
CODEX_API_BASE,
|
|
11
|
+
CODEX_OAUTH_CLIENT_ID,
|
|
12
|
+
REFRESH_TOKEN_URL,
|
|
13
|
+
CodexAuth,
|
|
14
|
+
CodexAuthInvalidError,
|
|
15
|
+
CodexAuthNotFoundError,
|
|
16
|
+
CodexAuthRefreshError,
|
|
17
|
+
arefresh_codex_auth,
|
|
18
|
+
auth_file_path,
|
|
19
|
+
codex_home,
|
|
20
|
+
is_likely_expired,
|
|
21
|
+
load_codex_auth,
|
|
22
|
+
refresh_codex_auth,
|
|
23
|
+
)
|
|
24
|
+
from langchain_codex_plus.codex_chat_model import ChatCodexPlus
|
|
25
|
+
from langchain_codex_plus.codex_protocol import (
|
|
26
|
+
CodexCompletion,
|
|
27
|
+
CodexResponseError,
|
|
28
|
+
CodexToolCall,
|
|
29
|
+
SseEvent,
|
|
30
|
+
ToolChoice,
|
|
31
|
+
build_request_body,
|
|
32
|
+
consume_events,
|
|
33
|
+
parse_error_body,
|
|
34
|
+
parse_sse_stream,
|
|
35
|
+
)
|
|
36
|
+
from langchain_codex_plus.rate_limits import (
|
|
37
|
+
CodexCredits,
|
|
38
|
+
CodexQuotaWindow,
|
|
39
|
+
CodexRateLimits,
|
|
40
|
+
parse_codex_rate_limits,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
__version__ = "0.0.1"
|
|
44
|
+
|
|
45
|
+
__all__ = [
|
|
46
|
+
# codex_auth
|
|
47
|
+
"CODEX_API_BASE",
|
|
48
|
+
"CODEX_OAUTH_CLIENT_ID",
|
|
49
|
+
"REFRESH_TOKEN_URL",
|
|
50
|
+
"CodexAuth",
|
|
51
|
+
"CodexAuthInvalidError",
|
|
52
|
+
"CodexAuthNotFoundError",
|
|
53
|
+
"CodexAuthRefreshError",
|
|
54
|
+
"arefresh_codex_auth",
|
|
55
|
+
"auth_file_path",
|
|
56
|
+
"codex_home",
|
|
57
|
+
"is_likely_expired",
|
|
58
|
+
"load_codex_auth",
|
|
59
|
+
"refresh_codex_auth",
|
|
60
|
+
# codex_protocol
|
|
61
|
+
"CodexCompletion",
|
|
62
|
+
"CodexResponseError",
|
|
63
|
+
"CodexToolCall",
|
|
64
|
+
"SseEvent",
|
|
65
|
+
"ToolChoice",
|
|
66
|
+
"build_request_body",
|
|
67
|
+
"consume_events",
|
|
68
|
+
"parse_error_body",
|
|
69
|
+
"parse_sse_stream",
|
|
70
|
+
# rate_limits
|
|
71
|
+
"CodexCredits",
|
|
72
|
+
"CodexQuotaWindow",
|
|
73
|
+
"CodexRateLimits",
|
|
74
|
+
"parse_codex_rate_limits",
|
|
75
|
+
# chat model
|
|
76
|
+
"ChatCodexPlus",
|
|
77
|
+
]
|