gpt-codex-client 0.1.0__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.
- gpt_codex_client-0.1.0/.github/workflows/ci.yml +27 -0
- gpt_codex_client-0.1.0/.github/workflows/release.yml +38 -0
- gpt_codex_client-0.1.0/.gitignore +14 -0
- gpt_codex_client-0.1.0/AGENTS.md +18 -0
- gpt_codex_client-0.1.0/CHANGELOG.md +8 -0
- gpt_codex_client-0.1.0/LICENSE +22 -0
- gpt_codex_client-0.1.0/PKG-INFO +164 -0
- gpt_codex_client-0.1.0/README.md +137 -0
- gpt_codex_client-0.1.0/README.zh-CN.md +135 -0
- gpt_codex_client-0.1.0/docs/authentication.md +31 -0
- gpt_codex_client-0.1.0/docs/chat-compatibility.md +18 -0
- gpt_codex_client-0.1.0/docs/errors.md +15 -0
- gpt_codex_client-0.1.0/docs/index.md +18 -0
- gpt_codex_client-0.1.0/docs/models.md +22 -0
- gpt_codex_client-0.1.0/docs/release.md +16 -0
- gpt_codex_client-0.1.0/docs/responses.md +14 -0
- gpt_codex_client-0.1.0/docs/streaming.md +13 -0
- gpt_codex_client-0.1.0/docs/structured-output.md +22 -0
- gpt_codex_client-0.1.0/docs/tool-calls.md +20 -0
- gpt_codex_client-0.1.0/mkdocs.yml +25 -0
- gpt_codex_client-0.1.0/pyproject.toml +77 -0
- gpt_codex_client-0.1.0/src/gpt_codex_client/__init__.py +68 -0
- gpt_codex_client-0.1.0/src/gpt_codex_client/_async_auth.py +160 -0
- gpt_codex_client-0.1.0/src/gpt_codex_client/_async_client.py +183 -0
- gpt_codex_client-0.1.0/src/gpt_codex_client/_async_models.py +83 -0
- gpt_codex_client-0.1.0/src/gpt_codex_client/_async_responses.py +146 -0
- gpt_codex_client-0.1.0/src/gpt_codex_client/_async_stream.py +108 -0
- gpt_codex_client-0.1.0/src/gpt_codex_client/_auth.py +290 -0
- gpt_codex_client-0.1.0/src/gpt_codex_client/_chat.py +224 -0
- gpt_codex_client-0.1.0/src/gpt_codex_client/_client.py +182 -0
- gpt_codex_client-0.1.0/src/gpt_codex_client/_config.py +196 -0
- gpt_codex_client-0.1.0/src/gpt_codex_client/_converters.py +178 -0
- gpt_codex_client-0.1.0/src/gpt_codex_client/_errors.py +126 -0
- gpt_codex_client-0.1.0/src/gpt_codex_client/_models.py +110 -0
- gpt_codex_client-0.1.0/src/gpt_codex_client/_responses.py +193 -0
- gpt_codex_client-0.1.0/src/gpt_codex_client/_stream.py +170 -0
- gpt_codex_client-0.1.0/src/gpt_codex_client/_types.py +228 -0
- gpt_codex_client-0.1.0/src/gpt_codex_client/py.typed +1 -0
- gpt_codex_client-0.1.0/tests/test_auth.py +155 -0
- gpt_codex_client-0.1.0/tests/test_chat_models_async.py +202 -0
- gpt_codex_client-0.1.0/tests/test_config.py +58 -0
- gpt_codex_client-0.1.0/tests/test_responses.py +265 -0
- gpt_codex_client-0.1.0/uv.lock +1296 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
fail-fast: false
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: astral-sh/setup-uv@v5
|
|
18
|
+
- uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: ${{ matrix.python-version }}
|
|
21
|
+
- run: uv sync --all-extras --dev
|
|
22
|
+
- run: uv run ruff format --check
|
|
23
|
+
- run: uv run ruff check src tests
|
|
24
|
+
- run: uv run mypy src/gpt_codex_client tests --strict
|
|
25
|
+
- run: uv run pytest -q
|
|
26
|
+
- run: uv build
|
|
27
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
id-token: write
|
|
11
|
+
pages: write
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
publish:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- uses: astral-sh/setup-uv@v5
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.13"
|
|
22
|
+
- run: uv sync --all-extras --dev
|
|
23
|
+
- run: uv run ruff format --check
|
|
24
|
+
- run: uv run ruff check src tests
|
|
25
|
+
- run: uv run mypy src/gpt_codex_client tests --strict
|
|
26
|
+
- run: uv run pytest -q
|
|
27
|
+
- name: Check tag matches package version
|
|
28
|
+
run: |
|
|
29
|
+
VERSION=$(uv run python -c "import gpt_codex_client; print(gpt_codex_client.__version__)")
|
|
30
|
+
test "v${VERSION}" = "${GITHUB_REF_NAME}"
|
|
31
|
+
- run: uv build
|
|
32
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
33
|
+
- uses: softprops/action-gh-release@v2
|
|
34
|
+
with:
|
|
35
|
+
files: dist/*
|
|
36
|
+
generate_release_notes: true
|
|
37
|
+
- run: uv run mkdocs gh-deploy --force
|
|
38
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This repository is a typed Python package using a `src/` layout and `uv`.
|
|
4
|
+
|
|
5
|
+
## Local Checks
|
|
6
|
+
|
|
7
|
+
Run these before publishing:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
uv run ruff format --check
|
|
11
|
+
uv run ruff check src tests
|
|
12
|
+
uv run mypy src/gpt_codex_client tests --strict
|
|
13
|
+
uv run pytest -q
|
|
14
|
+
uv build
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Default tests must not call live OAuth or ChatGPT/Codex endpoints. Use `httpx.MockTransport` for integration-style coverage.
|
|
18
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 gpt-codex-client contributors
|
|
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.
|
|
22
|
+
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gpt-codex-client
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: OpenAI SDK-style Python client for ChatGPT/Codex OAuth-backed Responses workflows.
|
|
5
|
+
Project-URL: Homepage, https://github.com/HC-Zhou/gpt-codex-client
|
|
6
|
+
Project-URL: Documentation, https://hc-zhou.github.io/gpt-codex-client/
|
|
7
|
+
Project-URL: Issues, https://github.com/HC-Zhou/gpt-codex-client/issues
|
|
8
|
+
Author: gpt-codex-client contributors
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: chatgpt,codex,openai,responses,sdk
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: httpx<1,>=0.27
|
|
24
|
+
Provides-Extra: pydantic
|
|
25
|
+
Requires-Dist: pydantic>=2; extra == 'pydantic'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# gpt-codex-client
|
|
29
|
+
|
|
30
|
+
English | [简体中文](README.zh-CN.md)
|
|
31
|
+
|
|
32
|
+
`gpt-codex-client` is an OpenAI SDK-style Python client for ChatGPT/Codex
|
|
33
|
+
OAuth-backed workflows. It is intentionally not an API-key client for
|
|
34
|
+
`api.openai.com`; it uses a local token cache compatible with
|
|
35
|
+
`~/.codex/auth.json` and requires an account that can access the relevant
|
|
36
|
+
ChatGPT/Codex backend.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
uv add gpt-codex-client
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from gpt_codex_client import CodexClient
|
|
44
|
+
|
|
45
|
+
with CodexClient(no_browser=True) as client:
|
|
46
|
+
response = client.responses.create(
|
|
47
|
+
model="gpt-5.5",
|
|
48
|
+
input="Write a short Python function that reverses a string.",
|
|
49
|
+
)
|
|
50
|
+
print(response.output_text)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## List Models
|
|
54
|
+
|
|
55
|
+
`client.models.list()` reads the public OpenAI Codex model registry from the
|
|
56
|
+
`openai/codex` GitHub repository instead of the ChatGPT/Codex backend `/models`
|
|
57
|
+
endpoint.
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from gpt_codex_client import CodexClient
|
|
61
|
+
|
|
62
|
+
with CodexClient() as client:
|
|
63
|
+
models = client.models.list()
|
|
64
|
+
for model in models:
|
|
65
|
+
print(model.id)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The registry source is:
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
https://raw.githubusercontent.com/openai/codex/main/codex-rs/models-manager/models.json
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Set `GPT_CODEX_CLIENT_MODELS_MANIFEST_URL` or pass `models_manifest_url=` to
|
|
75
|
+
use another compatible registry.
|
|
76
|
+
|
|
77
|
+
## Authentication
|
|
78
|
+
|
|
79
|
+
The client lazily authenticates on the first request. By default it reads and
|
|
80
|
+
writes `~/.codex/auth.json` with `0600` permissions.
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from gpt_codex_client import login
|
|
84
|
+
|
|
85
|
+
login(no_browser=True)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The default OAuth client id follows the ChatGPT/Codex sign-in flow used by the
|
|
89
|
+
official Codex clients. If OpenAI issues a different client id for your app, set
|
|
90
|
+
`GPT_CODEX_CLIENT_OAUTH_CLIENT_ID` or pass `auth_client_id=` to `CodexClient`.
|
|
91
|
+
|
|
92
|
+
For automation, pass a `login_handler` that receives the authorization URL and
|
|
93
|
+
returns the final redirect URL:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from gpt_codex_client import login
|
|
97
|
+
|
|
98
|
+
token = login(login_handler=lambda url: input(f"Open {url}\nRedirect URL: "))
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Responses
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
with CodexClient() as client:
|
|
105
|
+
response = client.responses.create(
|
|
106
|
+
model="gpt-5.5",
|
|
107
|
+
input="Summarize this repository.",
|
|
108
|
+
reasoning={"effort": "medium"},
|
|
109
|
+
text={"verbosity": "low"},
|
|
110
|
+
)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Streaming returns a context manager and iterator:
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
with CodexClient() as client:
|
|
117
|
+
with client.responses.create(model="gpt-5.5", input="Say hi", stream=True) as stream:
|
|
118
|
+
for event in stream:
|
|
119
|
+
if event.type == "response.output_text.delta":
|
|
120
|
+
print(event.data.get("delta"), end="")
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Structured Output
|
|
124
|
+
|
|
125
|
+
Install the optional extra when using Pydantic models:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
uv add "gpt-codex-client[pydantic]"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from pydantic import BaseModel
|
|
133
|
+
from gpt_codex_client import CodexClient
|
|
134
|
+
|
|
135
|
+
class Result(BaseModel):
|
|
136
|
+
title: str
|
|
137
|
+
|
|
138
|
+
parsed = CodexClient().responses.parse(
|
|
139
|
+
model="gpt-5.5",
|
|
140
|
+
input="Return JSON with a title.",
|
|
141
|
+
text_format=Result,
|
|
142
|
+
)
|
|
143
|
+
print(parsed.parsed.title)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Chat Compatibility
|
|
147
|
+
|
|
148
|
+
The chat compatibility layer converts Chat Completions-style messages and
|
|
149
|
+
function tools into Responses requests:
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
completion = CodexClient().chat.completions.create(
|
|
153
|
+
model="gpt-5.5",
|
|
154
|
+
messages=[{"role": "user", "content": "Hello"}],
|
|
155
|
+
)
|
|
156
|
+
print(completion.choices[0].message.content)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Development
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
uv sync --all-extras --dev
|
|
163
|
+
uv run pytest -q
|
|
164
|
+
```
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# gpt-codex-client
|
|
2
|
+
|
|
3
|
+
English | [简体中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
`gpt-codex-client` is an OpenAI SDK-style Python client for ChatGPT/Codex
|
|
6
|
+
OAuth-backed workflows. It is intentionally not an API-key client for
|
|
7
|
+
`api.openai.com`; it uses a local token cache compatible with
|
|
8
|
+
`~/.codex/auth.json` and requires an account that can access the relevant
|
|
9
|
+
ChatGPT/Codex backend.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
uv add gpt-codex-client
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from gpt_codex_client import CodexClient
|
|
17
|
+
|
|
18
|
+
with CodexClient(no_browser=True) as client:
|
|
19
|
+
response = client.responses.create(
|
|
20
|
+
model="gpt-5.5",
|
|
21
|
+
input="Write a short Python function that reverses a string.",
|
|
22
|
+
)
|
|
23
|
+
print(response.output_text)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## List Models
|
|
27
|
+
|
|
28
|
+
`client.models.list()` reads the public OpenAI Codex model registry from the
|
|
29
|
+
`openai/codex` GitHub repository instead of the ChatGPT/Codex backend `/models`
|
|
30
|
+
endpoint.
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from gpt_codex_client import CodexClient
|
|
34
|
+
|
|
35
|
+
with CodexClient() as client:
|
|
36
|
+
models = client.models.list()
|
|
37
|
+
for model in models:
|
|
38
|
+
print(model.id)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The registry source is:
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
https://raw.githubusercontent.com/openai/codex/main/codex-rs/models-manager/models.json
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Set `GPT_CODEX_CLIENT_MODELS_MANIFEST_URL` or pass `models_manifest_url=` to
|
|
48
|
+
use another compatible registry.
|
|
49
|
+
|
|
50
|
+
## Authentication
|
|
51
|
+
|
|
52
|
+
The client lazily authenticates on the first request. By default it reads and
|
|
53
|
+
writes `~/.codex/auth.json` with `0600` permissions.
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from gpt_codex_client import login
|
|
57
|
+
|
|
58
|
+
login(no_browser=True)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The default OAuth client id follows the ChatGPT/Codex sign-in flow used by the
|
|
62
|
+
official Codex clients. If OpenAI issues a different client id for your app, set
|
|
63
|
+
`GPT_CODEX_CLIENT_OAUTH_CLIENT_ID` or pass `auth_client_id=` to `CodexClient`.
|
|
64
|
+
|
|
65
|
+
For automation, pass a `login_handler` that receives the authorization URL and
|
|
66
|
+
returns the final redirect URL:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from gpt_codex_client import login
|
|
70
|
+
|
|
71
|
+
token = login(login_handler=lambda url: input(f"Open {url}\nRedirect URL: "))
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Responses
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
with CodexClient() as client:
|
|
78
|
+
response = client.responses.create(
|
|
79
|
+
model="gpt-5.5",
|
|
80
|
+
input="Summarize this repository.",
|
|
81
|
+
reasoning={"effort": "medium"},
|
|
82
|
+
text={"verbosity": "low"},
|
|
83
|
+
)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Streaming returns a context manager and iterator:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
with CodexClient() as client:
|
|
90
|
+
with client.responses.create(model="gpt-5.5", input="Say hi", stream=True) as stream:
|
|
91
|
+
for event in stream:
|
|
92
|
+
if event.type == "response.output_text.delta":
|
|
93
|
+
print(event.data.get("delta"), end="")
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Structured Output
|
|
97
|
+
|
|
98
|
+
Install the optional extra when using Pydantic models:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
uv add "gpt-codex-client[pydantic]"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from pydantic import BaseModel
|
|
106
|
+
from gpt_codex_client import CodexClient
|
|
107
|
+
|
|
108
|
+
class Result(BaseModel):
|
|
109
|
+
title: str
|
|
110
|
+
|
|
111
|
+
parsed = CodexClient().responses.parse(
|
|
112
|
+
model="gpt-5.5",
|
|
113
|
+
input="Return JSON with a title.",
|
|
114
|
+
text_format=Result,
|
|
115
|
+
)
|
|
116
|
+
print(parsed.parsed.title)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Chat Compatibility
|
|
120
|
+
|
|
121
|
+
The chat compatibility layer converts Chat Completions-style messages and
|
|
122
|
+
function tools into Responses requests:
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
completion = CodexClient().chat.completions.create(
|
|
126
|
+
model="gpt-5.5",
|
|
127
|
+
messages=[{"role": "user", "content": "Hello"}],
|
|
128
|
+
)
|
|
129
|
+
print(completion.choices[0].message.content)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Development
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
uv sync --all-extras --dev
|
|
136
|
+
uv run pytest -q
|
|
137
|
+
```
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# gpt-codex-client
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 简体中文
|
|
4
|
+
|
|
5
|
+
`gpt-codex-client` 是一个 OpenAI SDK 风格的 Python 客户端,用于
|
|
6
|
+
ChatGPT/Codex OAuth 登录支持的工作流。它不是面向 `api.openai.com` 的
|
|
7
|
+
API Key 客户端;它读取和写入兼容 `~/.codex/auth.json` 的本地 token 缓存,
|
|
8
|
+
并要求账号具备对应 ChatGPT/Codex 后端访问权限。
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
uv add gpt-codex-client
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
from gpt_codex_client import CodexClient
|
|
16
|
+
|
|
17
|
+
with CodexClient(no_browser=True) as client:
|
|
18
|
+
response = client.responses.create(
|
|
19
|
+
model="gpt-5.5",
|
|
20
|
+
input="Write a short Python function that reverses a string.",
|
|
21
|
+
)
|
|
22
|
+
print(response.output_text)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## 获取模型列表
|
|
26
|
+
|
|
27
|
+
`client.models.list()` 会读取 OpenAI Codex 仓库中的公开模型注册表,
|
|
28
|
+
而不是调用 ChatGPT/Codex 后端的 `/models` 接口。
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from gpt_codex_client import CodexClient
|
|
32
|
+
|
|
33
|
+
with CodexClient() as client:
|
|
34
|
+
models = client.models.list()
|
|
35
|
+
for model in models:
|
|
36
|
+
print(model.id)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
模型注册表来源:
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
https://raw.githubusercontent.com/openai/codex/main/codex-rs/models-manager/models.json
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
如果需要使用其他兼容的注册表,可以设置
|
|
46
|
+
`GPT_CODEX_CLIENT_MODELS_MANIFEST_URL`,或在构造客户端时传入
|
|
47
|
+
`models_manifest_url=`。
|
|
48
|
+
|
|
49
|
+
## 认证
|
|
50
|
+
|
|
51
|
+
客户端会在首次请求时懒加载认证。默认读取并写入 `~/.codex/auth.json`,
|
|
52
|
+
保存权限为 `0600`。
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from gpt_codex_client import login
|
|
56
|
+
|
|
57
|
+
login(no_browser=True)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
默认 OAuth client id 与官方 Codex 客户端使用的 ChatGPT/Codex 登录流程一致。
|
|
61
|
+
如果你有自己的已注册 client id,可以设置 `GPT_CODEX_CLIENT_OAUTH_CLIENT_ID`,
|
|
62
|
+
或在构造 `CodexClient` 时传入 `auth_client_id=`。
|
|
63
|
+
|
|
64
|
+
自动化场景可以传入 `login_handler`,它会收到授权 URL,并返回最终 redirect URL:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from gpt_codex_client import login
|
|
68
|
+
|
|
69
|
+
token = login(login_handler=lambda url: input(f"Open {url}\nRedirect URL: "))
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Responses
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
with CodexClient() as client:
|
|
76
|
+
response = client.responses.create(
|
|
77
|
+
model="gpt-5.5",
|
|
78
|
+
input="Summarize this repository.",
|
|
79
|
+
reasoning={"effort": "medium"},
|
|
80
|
+
text={"verbosity": "low"},
|
|
81
|
+
)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
流式调用会返回 context manager 和 iterator:
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
with CodexClient() as client:
|
|
88
|
+
with client.responses.create(model="gpt-5.5", input="Say hi", stream=True) as stream:
|
|
89
|
+
for event in stream:
|
|
90
|
+
if event.type == "response.output_text.delta":
|
|
91
|
+
print(event.data.get("delta"), end="")
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## 结构化输出
|
|
95
|
+
|
|
96
|
+
使用 Pydantic 模型时安装可选 extra:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
uv add "gpt-codex-client[pydantic]"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from pydantic import BaseModel
|
|
104
|
+
from gpt_codex_client import CodexClient
|
|
105
|
+
|
|
106
|
+
class Result(BaseModel):
|
|
107
|
+
title: str
|
|
108
|
+
|
|
109
|
+
parsed = CodexClient().responses.parse(
|
|
110
|
+
model="gpt-5.5",
|
|
111
|
+
input="Return JSON with a title.",
|
|
112
|
+
text_format=Result,
|
|
113
|
+
)
|
|
114
|
+
print(parsed.parsed.title)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Chat 兼容层
|
|
118
|
+
|
|
119
|
+
Chat 兼容层会把 Chat Completions 风格的 messages 和 function tools
|
|
120
|
+
转换为 Responses 请求:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
completion = CodexClient().chat.completions.create(
|
|
124
|
+
model="gpt-5.5",
|
|
125
|
+
messages=[{"role": "user", "content": "Hello"}],
|
|
126
|
+
)
|
|
127
|
+
print(completion.choices[0].message.content)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## 开发
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
uv sync --all-extras --dev
|
|
134
|
+
uv run pytest -q
|
|
135
|
+
```
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Authentication
|
|
2
|
+
|
|
3
|
+
The default token cache is `~/.codex/auth.json`. Tokens are saved with `0600`
|
|
4
|
+
permissions.
|
|
5
|
+
|
|
6
|
+
```python
|
|
7
|
+
from gpt_codex_client import login
|
|
8
|
+
|
|
9
|
+
login(no_browser=True)
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Automation can provide a handler:
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
login(login_handler=lambda url: input(f"Open {url}\nRedirect URL: "))
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`finish_login()` validates OAuth `state` before exchanging an authorization
|
|
19
|
+
code. `get_token()` returns a cached token, refreshes expired tokens when a
|
|
20
|
+
refresh token exists, and falls back to login if refresh fails.
|
|
21
|
+
|
|
22
|
+
The default OAuth client id follows the ChatGPT/Codex sign-in flow used by the
|
|
23
|
+
official Codex clients. Override it only when you have a registered client id:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
export GPT_CODEX_CLIENT_OAUTH_CLIENT_ID="app_..."
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
client = CodexClient(auth_client_id="app_...")
|
|
31
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Chat Compatibility
|
|
2
|
+
|
|
3
|
+
The chat layer accepts Chat Completions-style messages and function tools and
|
|
4
|
+
converts them into a Responses request.
|
|
5
|
+
|
|
6
|
+
```python
|
|
7
|
+
completion = client.chat.completions.create(
|
|
8
|
+
model="model",
|
|
9
|
+
messages=[
|
|
10
|
+
{"role": "system", "content": "Be concise."},
|
|
11
|
+
{"role": "user", "content": "Hello"},
|
|
12
|
+
],
|
|
13
|
+
)
|
|
14
|
+
print(completion.choices[0].message.content)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
System and developer messages are folded into `instructions`.
|
|
18
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Errors
|
|
2
|
+
|
|
3
|
+
All package exceptions derive from `CodexError`.
|
|
4
|
+
|
|
5
|
+
- `AuthError`: OAuth, token cache, 401, or 403 failures.
|
|
6
|
+
- `InvalidRequestError`: non-retryable 4xx request failures.
|
|
7
|
+
- `RateLimitError`: 429 responses, including `retry_after`.
|
|
8
|
+
- `ServerError`: 5xx responses.
|
|
9
|
+
- `APITimeoutError`: request timeout.
|
|
10
|
+
- `APIConnectionError`: transport-level failures.
|
|
11
|
+
- `StreamError`: stream lifecycle failures.
|
|
12
|
+
|
|
13
|
+
429 and 5xx responses are retried with exponential backoff up to
|
|
14
|
+
`max_retries`.
|
|
15
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
`gpt-codex-client` provides a typed Python client with an OpenAI SDK-style
|
|
4
|
+
surface:
|
|
5
|
+
|
|
6
|
+
```python
|
|
7
|
+
from gpt_codex_client import CodexClient
|
|
8
|
+
|
|
9
|
+
client = CodexClient()
|
|
10
|
+
response = client.responses.create(
|
|
11
|
+
model="gpt-5.5",
|
|
12
|
+
input="Write a compact project summary.",
|
|
13
|
+
)
|
|
14
|
+
print(response.output_text)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
This package targets ChatGPT/Codex OAuth-backed backend behavior, not standard
|
|
18
|
+
API-key access to `api.openai.com`.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Models
|
|
2
|
+
|
|
3
|
+
```python
|
|
4
|
+
models = client.models.list()
|
|
5
|
+
for model in models:
|
|
6
|
+
print(model.id)
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
The list is read from the OpenAI Codex model registry:
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
https://raw.githubusercontent.com/openai/codex/main/codex-rs/models-manager/models.json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The result is cached in memory for five minutes. Pass `force_refresh=True` to
|
|
16
|
+
fetch it again. Set `GPT_CODEX_CLIENT_MODELS_MANIFEST_URL` to point at another
|
|
17
|
+
compatible registry during tests or if the upstream location changes. You can
|
|
18
|
+
also pass `models_manifest_url=` when constructing a client:
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
client = CodexClient(models_manifest_url="https://example.test/models.json")
|
|
22
|
+
```
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Release
|
|
2
|
+
|
|
3
|
+
1. Update `CHANGELOG.md`.
|
|
4
|
+
2. Ensure `src/gpt_codex_client/__init__.py` and `pyproject.toml` versions match.
|
|
5
|
+
3. Run:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
uv run ruff format --check
|
|
9
|
+
uv run ruff check src tests
|
|
10
|
+
uv run mypy src/gpt_codex_client tests --strict
|
|
11
|
+
uv run pytest -q
|
|
12
|
+
uv build
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
4. Tag `vX.Y.Z` and push the tag.
|
|
16
|
+
|