oauth-codex 3.2.2__tar.gz → 4.0.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.
- oauth_codex-4.0.0/PKG-INFO +195 -0
- oauth_codex-4.0.0/README.md +179 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/pyproject.toml +9 -2
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/_sdk_client.py +8 -11
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/_version.py +1 -1
- oauth_codex-4.0.0/src/oauth_codex/core_types.py +64 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/resources/chat/completions.py +64 -31
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/resources/responses/input_tokens.py +12 -6
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/resources/vector_stores/__init__.py +3 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/resources/vector_stores/vector_stores.py +23 -2
- oauth_codex-4.0.0/src/oauth_codex.egg-info/PKG-INFO +195 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex.egg-info/SOURCES.txt +1 -5
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex.egg-info/requires.txt +2 -0
- oauth_codex-4.0.0/tests/test_backend_tool_loop_contract.py +367 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/tests/test_beta_chat_completions.py +25 -8
- oauth_codex-4.0.0/tests/test_client_authentication.py +57 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/tests/test_client_resource_surface.py +37 -1
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/tests/test_public_api_docstrings.py +2 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/tests/test_public_surface.py +10 -0
- oauth_codex-3.2.2/PKG-INFO +0 -219
- oauth_codex-3.2.2/README.md +0 -205
- oauth_codex-3.2.2/src/oauth_codex/_engine.py +0 -3686
- oauth_codex-3.2.2/src/oauth_codex/_module_client.py +0 -90
- oauth_codex-3.2.2/src/oauth_codex/_streaming.py +0 -94
- oauth_codex-3.2.2/src/oauth_codex/_types.py +0 -38
- oauth_codex-3.2.2/src/oauth_codex/compat_store.py +0 -402
- oauth_codex-3.2.2/src/oauth_codex/core_types.py +0 -179
- oauth_codex-3.2.2/src/oauth_codex.egg-info/PKG-INFO +0 -219
- oauth_codex-3.2.2/tests/test_client_authentication.py +0 -20
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/setup.cfg +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/__init__.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/_base_client.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/_exceptions.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/_models.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/_resource.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/auth/__init__.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/auth/_oauth.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/auth/_provider.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/auth/config.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/auth/pkce.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/auth/store.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/auth/token_manager.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/errors.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/py.typed +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/resources/__init__.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/resources/_wrappers.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/resources/beta.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/resources/chat/__init__.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/resources/files.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/resources/models.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/resources/responses/__init__.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/resources/responses/_helpers.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/resources/responses/responses.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/resources/responses.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/resources/vector_stores/file_batches.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/resources/vector_stores/files.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/store.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/tooling.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/types/__init__.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/types/chat/__init__.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/types/chat/completions.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/types/file_deleted.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/types/file_object.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/types/responses/__init__.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/types/responses/input_token_count_response.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/types/responses/response.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/types/responses/response_stream_event.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/types/shared/__init__.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/types/shared/model_capabilities.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/types/shared/usage.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/types/vector_stores/__init__.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/types/vector_stores/vector_store.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/types/vector_stores/vector_store_deleted.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/types/vector_stores/vector_store_file.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/types/vector_stores/vector_store_file_batch.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/types/vector_stores/vector_store_search_response.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex/version.py +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex.egg-info/dependency_links.txt +0 -0
- {oauth_codex-3.2.2 → oauth_codex-4.0.0}/src/oauth_codex.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: oauth-codex
|
|
3
|
+
Version: 4.0.0
|
|
4
|
+
Summary: Codex OAuth-based Python SDK with resource-style Client and AsyncClient APIs
|
|
5
|
+
Author: Codex
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: httpx>=0.27.0
|
|
9
|
+
Requires-Dist: keyring>=25.0.0
|
|
10
|
+
Requires-Dist: pydantic>=2.8.0
|
|
11
|
+
Provides-Extra: dev
|
|
12
|
+
Requires-Dist: build>=1.2.0; extra == "dev"
|
|
13
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
14
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
15
|
+
Requires-Dist: twine>=5.0.0; extra == "dev"
|
|
16
|
+
|
|
17
|
+
[English](README.md) | [한국어](README.ko.md)
|
|
18
|
+
|
|
19
|
+
# oauth-codex
|
|
20
|
+
|
|
21
|
+
OAuth PKCE-based Python SDK for the Codex backend.
|
|
22
|
+
|
|
23
|
+
## Highlights
|
|
24
|
+
|
|
25
|
+
- Resource-style clients: `Client` and `AsyncClient`
|
|
26
|
+
- OAuth PKCE only, with interactive login and automatic token refresh
|
|
27
|
+
- OpenAI-style `chat.completions.create(...)`
|
|
28
|
+
- Lower-level `responses.create(...)`, `responses.parse(...)`, and `responses.stream(...)`
|
|
29
|
+
- Callable tool loop helpers via `client.beta.chat.completions.run_tools(...)`
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install oauth-codex
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Requires Python 3.11 or newer.
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
### Synchronous Client
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from oauth_codex import Client
|
|
45
|
+
|
|
46
|
+
client = Client()
|
|
47
|
+
client.authenticate()
|
|
48
|
+
|
|
49
|
+
completion = client.chat.completions.create(
|
|
50
|
+
model="gpt-5.3-codex",
|
|
51
|
+
messages=[{"role": "user", "content": "Hello from oauth-codex"}],
|
|
52
|
+
)
|
|
53
|
+
print(completion.choices[0].message.content)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Asynchronous Client
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
import asyncio
|
|
60
|
+
|
|
61
|
+
from oauth_codex import AsyncClient
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
async def main():
|
|
65
|
+
client = AsyncClient()
|
|
66
|
+
await client.authenticate()
|
|
67
|
+
|
|
68
|
+
completion = await client.chat.completions.create(
|
|
69
|
+
model="gpt-5.3-codex",
|
|
70
|
+
messages=[{"role": "user", "content": "Hello async"}],
|
|
71
|
+
)
|
|
72
|
+
print(completion.choices[0].message.content)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
asyncio.run(main())
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Authentication
|
|
79
|
+
|
|
80
|
+
This SDK uses OAuth PKCE only. API keys are not supported.
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
client = Client()
|
|
84
|
+
client.authenticate()
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
On first authentication, the SDK prints an authorization URL, waits for the browser sign-in flow, and asks you to paste the localhost callback URL back into the terminal. Tokens are stored locally and refreshed automatically on later requests.
|
|
88
|
+
|
|
89
|
+
## Main API Surface
|
|
90
|
+
|
|
91
|
+
### Chat Completions
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
response = client.chat.completions.create(
|
|
95
|
+
model="gpt-5.3-codex",
|
|
96
|
+
messages=[{"role": "user", "content": "Write a sorting function"}],
|
|
97
|
+
)
|
|
98
|
+
print(response.choices[0].message.content)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Responses Resource
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
response = client.responses.create(
|
|
105
|
+
model="gpt-5.3-codex",
|
|
106
|
+
input=[{"role": "user", "content": "Analyze this code snippet."}],
|
|
107
|
+
)
|
|
108
|
+
print(response.output_text)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Streaming
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
for event in client.responses.stream(
|
|
115
|
+
model="gpt-5.3-codex",
|
|
116
|
+
input=[{"role": "user", "content": "Say hello in three words"}],
|
|
117
|
+
):
|
|
118
|
+
if event.type == "text_delta" and event.delta:
|
|
119
|
+
print(event.delta, end="", flush=True)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Structured Output
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
from pydantic import BaseModel
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class Summary(BaseModel):
|
|
129
|
+
title: str
|
|
130
|
+
score: int
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
response = client.responses.parse(
|
|
134
|
+
model="gpt-5.3-codex",
|
|
135
|
+
input=[{"role": "user", "content": "Return JSON with title and score"}],
|
|
136
|
+
response_format=Summary,
|
|
137
|
+
)
|
|
138
|
+
print(response.parsed)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Tool Execution
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
def add(a: int, b: int) -> int:
|
|
145
|
+
return a + b
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
completion = client.beta.chat.completions.run_tools(
|
|
149
|
+
model="gpt-5.3-codex",
|
|
150
|
+
messages=[{"role": "user", "content": "What is 2 + 3?"}],
|
|
151
|
+
tools=[add],
|
|
152
|
+
)
|
|
153
|
+
print(completion.choices[0].message.content)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Available Namespaces
|
|
157
|
+
|
|
158
|
+
- `client.chat.completions`
|
|
159
|
+
- `client.responses`
|
|
160
|
+
- `client.files`
|
|
161
|
+
- `client.vector_stores`
|
|
162
|
+
- `client.vector_stores.files`
|
|
163
|
+
- `client.vector_stores.file_batches`
|
|
164
|
+
- `client.models`
|
|
165
|
+
- `client.beta.chat.completions`
|
|
166
|
+
|
|
167
|
+
`AsyncClient` exposes the same namespaces with async methods.
|
|
168
|
+
|
|
169
|
+
## Removed In 4.0
|
|
170
|
+
|
|
171
|
+
- `authenticate_on_init`
|
|
172
|
+
- `generate`, `agenerate`, `stream`, `astream`
|
|
173
|
+
- legacy `OAuthCodexClient` and `AsyncOAuthCodexClient`
|
|
174
|
+
- module-level proxy usage such as `oauth_codex.responses.create(...)`
|
|
175
|
+
|
|
176
|
+
## Error Handling
|
|
177
|
+
|
|
178
|
+
The package exports OpenAI-style exception classes such as `AuthenticationError`, `RateLimitError`, `APIConnectionError`, and `APIStatusError`.
|
|
179
|
+
|
|
180
|
+
## Documentation
|
|
181
|
+
|
|
182
|
+
- English: [`docs/en/index.md`](docs/en/index.md)
|
|
183
|
+
- Korean: [`docs/ko/index.md`](docs/ko/index.md)
|
|
184
|
+
|
|
185
|
+
## Development
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
pip install -e .[dev]
|
|
189
|
+
pytest -q
|
|
190
|
+
python -m build
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Changelog
|
|
194
|
+
|
|
195
|
+
[`CHANGELOG.md`](CHANGELOG.md)
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
[English](README.md) | [한국어](README.ko.md)
|
|
2
|
+
|
|
3
|
+
# oauth-codex
|
|
4
|
+
|
|
5
|
+
OAuth PKCE-based Python SDK for the Codex backend.
|
|
6
|
+
|
|
7
|
+
## Highlights
|
|
8
|
+
|
|
9
|
+
- Resource-style clients: `Client` and `AsyncClient`
|
|
10
|
+
- OAuth PKCE only, with interactive login and automatic token refresh
|
|
11
|
+
- OpenAI-style `chat.completions.create(...)`
|
|
12
|
+
- Lower-level `responses.create(...)`, `responses.parse(...)`, and `responses.stream(...)`
|
|
13
|
+
- Callable tool loop helpers via `client.beta.chat.completions.run_tools(...)`
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install oauth-codex
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Requires Python 3.11 or newer.
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
### Synchronous Client
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from oauth_codex import Client
|
|
29
|
+
|
|
30
|
+
client = Client()
|
|
31
|
+
client.authenticate()
|
|
32
|
+
|
|
33
|
+
completion = client.chat.completions.create(
|
|
34
|
+
model="gpt-5.3-codex",
|
|
35
|
+
messages=[{"role": "user", "content": "Hello from oauth-codex"}],
|
|
36
|
+
)
|
|
37
|
+
print(completion.choices[0].message.content)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Asynchronous Client
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
import asyncio
|
|
44
|
+
|
|
45
|
+
from oauth_codex import AsyncClient
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
async def main():
|
|
49
|
+
client = AsyncClient()
|
|
50
|
+
await client.authenticate()
|
|
51
|
+
|
|
52
|
+
completion = await client.chat.completions.create(
|
|
53
|
+
model="gpt-5.3-codex",
|
|
54
|
+
messages=[{"role": "user", "content": "Hello async"}],
|
|
55
|
+
)
|
|
56
|
+
print(completion.choices[0].message.content)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
asyncio.run(main())
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Authentication
|
|
63
|
+
|
|
64
|
+
This SDK uses OAuth PKCE only. API keys are not supported.
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
client = Client()
|
|
68
|
+
client.authenticate()
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
On first authentication, the SDK prints an authorization URL, waits for the browser sign-in flow, and asks you to paste the localhost callback URL back into the terminal. Tokens are stored locally and refreshed automatically on later requests.
|
|
72
|
+
|
|
73
|
+
## Main API Surface
|
|
74
|
+
|
|
75
|
+
### Chat Completions
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
response = client.chat.completions.create(
|
|
79
|
+
model="gpt-5.3-codex",
|
|
80
|
+
messages=[{"role": "user", "content": "Write a sorting function"}],
|
|
81
|
+
)
|
|
82
|
+
print(response.choices[0].message.content)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Responses Resource
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
response = client.responses.create(
|
|
89
|
+
model="gpt-5.3-codex",
|
|
90
|
+
input=[{"role": "user", "content": "Analyze this code snippet."}],
|
|
91
|
+
)
|
|
92
|
+
print(response.output_text)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Streaming
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
for event in client.responses.stream(
|
|
99
|
+
model="gpt-5.3-codex",
|
|
100
|
+
input=[{"role": "user", "content": "Say hello in three words"}],
|
|
101
|
+
):
|
|
102
|
+
if event.type == "text_delta" and event.delta:
|
|
103
|
+
print(event.delta, end="", flush=True)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Structured Output
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from pydantic import BaseModel
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class Summary(BaseModel):
|
|
113
|
+
title: str
|
|
114
|
+
score: int
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
response = client.responses.parse(
|
|
118
|
+
model="gpt-5.3-codex",
|
|
119
|
+
input=[{"role": "user", "content": "Return JSON with title and score"}],
|
|
120
|
+
response_format=Summary,
|
|
121
|
+
)
|
|
122
|
+
print(response.parsed)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Tool Execution
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
def add(a: int, b: int) -> int:
|
|
129
|
+
return a + b
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
completion = client.beta.chat.completions.run_tools(
|
|
133
|
+
model="gpt-5.3-codex",
|
|
134
|
+
messages=[{"role": "user", "content": "What is 2 + 3?"}],
|
|
135
|
+
tools=[add],
|
|
136
|
+
)
|
|
137
|
+
print(completion.choices[0].message.content)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Available Namespaces
|
|
141
|
+
|
|
142
|
+
- `client.chat.completions`
|
|
143
|
+
- `client.responses`
|
|
144
|
+
- `client.files`
|
|
145
|
+
- `client.vector_stores`
|
|
146
|
+
- `client.vector_stores.files`
|
|
147
|
+
- `client.vector_stores.file_batches`
|
|
148
|
+
- `client.models`
|
|
149
|
+
- `client.beta.chat.completions`
|
|
150
|
+
|
|
151
|
+
`AsyncClient` exposes the same namespaces with async methods.
|
|
152
|
+
|
|
153
|
+
## Removed In 4.0
|
|
154
|
+
|
|
155
|
+
- `authenticate_on_init`
|
|
156
|
+
- `generate`, `agenerate`, `stream`, `astream`
|
|
157
|
+
- legacy `OAuthCodexClient` and `AsyncOAuthCodexClient`
|
|
158
|
+
- module-level proxy usage such as `oauth_codex.responses.create(...)`
|
|
159
|
+
|
|
160
|
+
## Error Handling
|
|
161
|
+
|
|
162
|
+
The package exports OpenAI-style exception classes such as `AuthenticationError`, `RateLimitError`, `APIConnectionError`, and `APIStatusError`.
|
|
163
|
+
|
|
164
|
+
## Documentation
|
|
165
|
+
|
|
166
|
+
- English: [`docs/en/index.md`](docs/en/index.md)
|
|
167
|
+
- Korean: [`docs/ko/index.md`](docs/ko/index.md)
|
|
168
|
+
|
|
169
|
+
## Development
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
pip install -e .[dev]
|
|
173
|
+
pytest -q
|
|
174
|
+
python -m build
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Changelog
|
|
178
|
+
|
|
179
|
+
[`CHANGELOG.md`](CHANGELOG.md)
|
|
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "oauth-codex"
|
|
7
|
-
|
|
8
|
-
description = "Codex OAuth-based Python SDK with
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Codex OAuth-based Python SDK with resource-style Client and AsyncClient APIs"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
11
11
|
authors = [{ name = "Codex" }]
|
|
@@ -17,8 +17,10 @@ dependencies = [
|
|
|
17
17
|
|
|
18
18
|
[project.optional-dependencies]
|
|
19
19
|
dev = [
|
|
20
|
+
"build>=1.2.0",
|
|
20
21
|
"pytest>=8.0.0",
|
|
21
22
|
"pytest-asyncio>=0.23.0",
|
|
23
|
+
"twine>=5.0.0",
|
|
22
24
|
]
|
|
23
25
|
|
|
24
26
|
[tool.setuptools]
|
|
@@ -27,9 +29,14 @@ package-dir = {"" = "src"}
|
|
|
27
29
|
[tool.setuptools.packages.find]
|
|
28
30
|
where = ["src"]
|
|
29
31
|
|
|
32
|
+
[tool.setuptools.dynamic]
|
|
33
|
+
version = {attr = "oauth_codex._version.__version__"}
|
|
34
|
+
|
|
30
35
|
[tool.setuptools.package-data]
|
|
31
36
|
oauth_codex = ["py.typed"]
|
|
32
37
|
|
|
33
38
|
[tool.pytest.ini_options]
|
|
34
39
|
addopts = "-q"
|
|
40
|
+
asyncio_mode = "auto"
|
|
35
41
|
pythonpath = ["src"]
|
|
42
|
+
testpaths = ["tests"]
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from collections.abc import AsyncIterator, Iterator, Mapping
|
|
4
|
-
from types import SimpleNamespace
|
|
5
4
|
from typing import Any, cast
|
|
6
5
|
|
|
7
6
|
import httpx
|
|
@@ -33,16 +32,6 @@ def _with_auth_headers(
|
|
|
33
32
|
if auth_headers:
|
|
34
33
|
merged.update(auth_headers)
|
|
35
34
|
return merged
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def _to_namespace(value: Any) -> Any:
|
|
39
|
-
if isinstance(value, dict):
|
|
40
|
-
return SimpleNamespace(**{k: _to_namespace(v) for k, v in value.items()})
|
|
41
|
-
if isinstance(value, list):
|
|
42
|
-
return [_to_namespace(v) for v in value]
|
|
43
|
-
return value
|
|
44
|
-
|
|
45
|
-
|
|
46
35
|
def _payload_without_none(values: dict[str, Any]) -> dict[str, Any]:
|
|
47
36
|
payload = {k: v for k, v in values.items() if v is not None}
|
|
48
37
|
payload.pop("self", None)
|
|
@@ -131,8 +120,12 @@ class Client(SyncAPIClient):
|
|
|
131
120
|
self._chat: Chat | None = None
|
|
132
121
|
self._beta: Beta | None = None
|
|
133
122
|
self._auth_provider: SyncAuthProvider | None = None
|
|
123
|
+
self._vector_file_batches: dict[str, dict[str, Any]] = {}
|
|
134
124
|
self._engine = _SyncEngine(self)
|
|
135
125
|
|
|
126
|
+
def authenticate(self) -> None:
|
|
127
|
+
self.auth.ensure_valid(interactive=True)
|
|
128
|
+
|
|
136
129
|
@property
|
|
137
130
|
def auth(self) -> SyncAuthProvider:
|
|
138
131
|
if self._auth_provider is None:
|
|
@@ -232,8 +225,12 @@ class AsyncClient(AsyncAPIClient):
|
|
|
232
225
|
self._chat: AsyncChat | None = None
|
|
233
226
|
self._beta: AsyncBeta | None = None
|
|
234
227
|
self._auth_provider: AsyncAuthProvider | None = None
|
|
228
|
+
self._vector_file_batches: dict[str, dict[str, Any]] = {}
|
|
235
229
|
self._engine = _AsyncEngine(self)
|
|
236
230
|
|
|
231
|
+
async def authenticate(self) -> None:
|
|
232
|
+
await self.auth.aensure_valid(interactive=True)
|
|
233
|
+
|
|
237
234
|
@property
|
|
238
235
|
def auth(self) -> AsyncAuthProvider:
|
|
239
236
|
if self._auth_provider is None:
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
__title__ = "oauth-codex"
|
|
2
|
-
__version__ = "
|
|
2
|
+
__version__ = "4.0.0"
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Core public data types used by oauth-codex.
|
|
2
|
+
|
|
3
|
+
`Message` represents a single Responses API input message dictionary, and
|
|
4
|
+
`listMessage` is the list container commonly passed to resource methods such as
|
|
5
|
+
`client.chat.completions.create(...)` and `client.responses.create(...)`.
|
|
6
|
+
|
|
7
|
+
Recommended minimal message shape:
|
|
8
|
+
|
|
9
|
+
[{"role": "user", "content": "hello"}]
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from dataclasses import dataclass
|
|
15
|
+
from typing import Any, Callable, Literal, Protocol, TypeAlias
|
|
16
|
+
|
|
17
|
+
#: A single response input message item (for example role/content dict).
|
|
18
|
+
Message: TypeAlias = dict[str, Any]
|
|
19
|
+
#: List of response input messages accepted by resource-style client methods.
|
|
20
|
+
listMessage: TypeAlias = list[Message]
|
|
21
|
+
ValidationMode: TypeAlias = Literal["warn", "error", "ignore"]
|
|
22
|
+
TruncationMode: TypeAlias = Literal["auto", "disabled"]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class OAuthTokens:
|
|
27
|
+
access_token: str
|
|
28
|
+
api_key: str | None = None
|
|
29
|
+
refresh_token: str | None = None
|
|
30
|
+
id_token: str | None = None
|
|
31
|
+
token_type: str = "Bearer"
|
|
32
|
+
scope: str | None = None
|
|
33
|
+
expires_at: float | None = None
|
|
34
|
+
account_id: str | None = None
|
|
35
|
+
last_refresh: float | None = None
|
|
36
|
+
|
|
37
|
+
def is_expired(self, *, leeway_seconds: int = 0) -> bool:
|
|
38
|
+
if self.expires_at is None:
|
|
39
|
+
return False
|
|
40
|
+
import time
|
|
41
|
+
|
|
42
|
+
return time.time() + max(leeway_seconds, 0) >= self.expires_at
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class ToolResult:
|
|
47
|
+
tool_call_id: str
|
|
48
|
+
name: str
|
|
49
|
+
output: dict[str, Any]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
ToolSchema = dict[str, Any]
|
|
53
|
+
ToolInput: TypeAlias = ToolSchema | Callable[..., Any]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class TokenStore(Protocol):
|
|
57
|
+
def load(self) -> OAuthTokens | None:
|
|
58
|
+
...
|
|
59
|
+
|
|
60
|
+
def save(self, tokens: OAuthTokens) -> None:
|
|
61
|
+
...
|
|
62
|
+
|
|
63
|
+
def delete(self) -> None:
|
|
64
|
+
...
|