codex-as-api 0.2.1__py3-none-any.whl

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.
@@ -0,0 +1,543 @@
1
+ Metadata-Version: 2.4
2
+ Name: codex-as-api
3
+ Version: 0.2.1
4
+ Summary: Use ChatGPT/Codex OAuth as a local OpenAI-compatible API server.
5
+ Project-URL: Homepage, https://github.com/Eunho-J/codex-as-api
6
+ Project-URL: Repository, https://github.com/Eunho-J/codex-as-api
7
+ Author: Eunho-J
8
+ License: Apache-2.0
9
+ Keywords: api,chatgpt,codex,llm,oauth,openai
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Requires-Python: >=3.10
20
+ Provides-Extra: dev
21
+ Requires-Dist: mypy; extra == 'dev'
22
+ Requires-Dist: pytest; extra == 'dev'
23
+ Requires-Dist: ruff; extra == 'dev'
24
+ Provides-Extra: server
25
+ Requires-Dist: fastapi>=0.100; extra == 'server'
26
+ Requires-Dist: pydantic>=2.0; extra == 'server'
27
+ Requires-Dist: uvicorn>=0.23; extra == 'server'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # codex-as-api
31
+
32
+ Use ChatGPT / Codex OAuth as a local OpenAI-compatible API server.
33
+
34
+ ## What it does
35
+
36
+ Runs a lightweight HTTP server on `localhost` that translates standard OpenAI API calls into authenticated requests against the ChatGPT / Codex backend using your existing `~/.codex/auth.json` OAuth credentials. Supports streaming, tool calling, reasoning, image generation, and Codex-specific features like `prompt_cache_key` and subagent headers.
37
+
38
+ Python, Rust, and TypeScript (npm) implementations are provided — identical functionality, same endpoints, same behavior.
39
+
40
+ ## Prerequisites
41
+
42
+ Install the official Codex CLI and log in so that `~/.codex/auth.json` exists:
43
+
44
+ ```bash
45
+ npm install -g @openai/codex
46
+ codex login
47
+ ```
48
+
49
+ The server reads that file to obtain and refresh ChatGPT OAuth tokens automatically.
50
+
51
+ ## Install & Run
52
+
53
+ ### Python
54
+
55
+ ```bash
56
+ git clone https://github.com/Eunho-J/codex-as-api.git
57
+ cd codex-as-api
58
+ pip install -e ".[server]"
59
+ codex-as-api
60
+ ```
61
+
62
+ Or with `uv`:
63
+
64
+ ```bash
65
+ uv pip install -e ".[server]"
66
+ codex-as-api
67
+ ```
68
+
69
+ ### Rust
70
+
71
+ ```bash
72
+ cd rust
73
+ cargo build --release
74
+ ./target/release/codex-as-api
75
+ ```
76
+
77
+ ### TypeScript (npm)
78
+
79
+ Install from npm and run:
80
+
81
+ ```bash
82
+ npm install -g codex-as-api
83
+ codex-as-api
84
+ ```
85
+
86
+ Or use `npx` without installing:
87
+
88
+ ```bash
89
+ npx codex-as-api
90
+ ```
91
+
92
+ Or from source:
93
+
94
+ ```bash
95
+ cd ts
96
+ npm install
97
+ npm run build
98
+ node dist/cli.js
99
+ ```
100
+
101
+ Can also be used as a library:
102
+
103
+ ```typescript
104
+ import { ChatGPTOAuthProvider, createApp } from "codex-as-api";
105
+
106
+ // Use the provider directly
107
+ const provider = new ChatGPTOAuthProvider({ model: "gpt-5.5" });
108
+ const response = await provider.chat(
109
+ [
110
+ { role: "system", content: "You are helpful." },
111
+ { role: "user", content: "Hello!" },
112
+ ],
113
+ );
114
+ console.log(response.content);
115
+
116
+ // Or create an Express app
117
+ const app = createApp();
118
+ app.listen(18080);
119
+ ```
120
+
121
+ All versions bind to `127.0.0.1:18080` (localhost only) by default.
122
+
123
+ ## Configuration
124
+
125
+ Environment variables (Python, Rust, and TypeScript):
126
+
127
+ | Variable | Default | Description |
128
+ |----------|---------|-------------|
129
+ | `CODEX_AS_API_HOST` | `127.0.0.1` | Bind address |
130
+ | `CODEX_AS_API_PORT` | `18080` | Listen port |
131
+ | `CODEX_AS_API_MODEL` | `gpt-5.5` | Model identifier passed to Codex backend |
132
+ | `CODEX_AS_API_AUTH_PATH` | `~/.codex/auth.json` | Path to OAuth credentials file |
133
+
134
+ ### Supported Models
135
+
136
+ | Model | Description |
137
+ |-------|-------------|
138
+ | `gpt-5.5` | Frontier model for complex coding, research, and real-world work |
139
+ | `gpt-5.4` | Strong model for everyday coding |
140
+ | `gpt-5.4-mini` | Small, fast, and cost-efficient model for simpler coding tasks |
141
+ | `gpt-5.3-codex` | Coding-optimized model |
142
+ | `gpt-5.3-codex-spark` | Ultra-fast coding model |
143
+ | `gpt-5.2` | Previous generation model |
144
+
145
+ To use a different port:
146
+
147
+ ```bash
148
+ CODEX_AS_API_PORT=9000 codex-as-api
149
+ ```
150
+
151
+ To expose on all interfaces (e.g. for remote access):
152
+
153
+ ```bash
154
+ CODEX_AS_API_HOST=0.0.0.0 codex-as-api
155
+ ```
156
+
157
+ ## API Endpoints
158
+
159
+ ### `POST /v1/chat/completions`
160
+
161
+ Standard OpenAI chat completions. Supports streaming (`stream: true`) and non-streaming.
162
+
163
+ ```bash
164
+ curl http://localhost:18080/v1/chat/completions \
165
+ -H "Content-Type: application/json" \
166
+ -d '{
167
+ "model": "gpt-5.5",
168
+ "messages": [
169
+ {"role": "system", "content": "You are a helpful assistant."},
170
+ {"role": "user", "content": "Hello"}
171
+ ]
172
+ }'
173
+ ```
174
+
175
+ Streaming:
176
+
177
+ ```bash
178
+ curl http://localhost:18080/v1/chat/completions \
179
+ -H "Content-Type: application/json" \
180
+ -d '{
181
+ "model": "gpt-5.5",
182
+ "messages": [
183
+ {"role": "system", "content": "You are a helpful assistant."},
184
+ {"role": "user", "content": "Hello"}
185
+ ],
186
+ "stream": true
187
+ }'
188
+ ```
189
+
190
+ With tools:
191
+
192
+ ```bash
193
+ curl http://localhost:18080/v1/chat/completions \
194
+ -H "Content-Type: application/json" \
195
+ -d '{
196
+ "model": "gpt-5.5",
197
+ "messages": [
198
+ {"role": "system", "content": "You have access to tools."},
199
+ {"role": "user", "content": "What is the weather in Seoul?"}
200
+ ],
201
+ "tools": [
202
+ {
203
+ "type": "function",
204
+ "function": {
205
+ "name": "get_weather",
206
+ "description": "Get current weather",
207
+ "parameters": {
208
+ "type": "object",
209
+ "properties": {"city": {"type": "string"}},
210
+ "required": ["city"]
211
+ }
212
+ }
213
+ }
214
+ ]
215
+ }'
216
+ ```
217
+
218
+ ### `POST /v1/messages`
219
+
220
+ Anthropic Messages API compatible endpoint. Supports streaming (`stream: true`) and non-streaming. The client's model name is reflected in responses, but the server always uses the configured `CODEX_AS_API_MODEL` for the backend call.
221
+
222
+ ```bash
223
+ curl http://localhost:18080/v1/messages \
224
+ -H "Content-Type: application/json" \
225
+ -H "x-api-key: unused" \
226
+ -H "anthropic-version: 2023-06-01" \
227
+ -d '{
228
+ "model": "claude-sonnet-4-6",
229
+ "max_tokens": 200,
230
+ "system": "You are a helpful assistant.",
231
+ "messages": [
232
+ {"role": "user", "content": "Hello!"}
233
+ ]
234
+ }'
235
+ ```
236
+
237
+ Streaming:
238
+
239
+ ```bash
240
+ curl -N http://localhost:18080/v1/messages \
241
+ -H "Content-Type: application/json" \
242
+ -H "x-api-key: unused" \
243
+ -H "anthropic-version: 2023-06-01" \
244
+ -d '{
245
+ "model": "claude-sonnet-4-6",
246
+ "max_tokens": 200,
247
+ "stream": true,
248
+ "system": "You are a helpful assistant.",
249
+ "messages": [
250
+ {"role": "user", "content": "Hello!"}
251
+ ]
252
+ }'
253
+ ```
254
+
255
+ ### `POST /v1/images/generations`
256
+
257
+ Generate images via the Codex image generation tool.
258
+
259
+ ```bash
260
+ curl http://localhost:18080/v1/images/generations \
261
+ -H "Content-Type: application/json" \
262
+ -d '{
263
+ "model": "gpt-5.5",
264
+ "prompt": "a futuristic city at sunset",
265
+ "size": "1024x1024"
266
+ }'
267
+ ```
268
+
269
+ ### `POST /v1/inspect`
270
+
271
+ Inspect images with a text prompt (custom endpoint).
272
+
273
+ ```bash
274
+ curl http://localhost:18080/v1/inspect \
275
+ -H "Content-Type: application/json" \
276
+ -d '{
277
+ "prompt": "Describe what you see",
278
+ "images": [{"image_url": "data:image/png;base64,iVBORw0KGgo..."}]
279
+ }'
280
+ ```
281
+
282
+ ### `POST /v1/compact`
283
+
284
+ Compact a conversation into a checkpoint for continuation (custom endpoint).
285
+
286
+ ```bash
287
+ curl http://localhost:18080/v1/compact \
288
+ -H "Content-Type: application/json" \
289
+ -d '{
290
+ "messages": [
291
+ {"role": "system", "content": "You are a helpful assistant."},
292
+ {"role": "user", "content": "Summarize our conversation so far."},
293
+ {"role": "assistant", "content": "We discussed the project architecture."}
294
+ ]
295
+ }'
296
+ ```
297
+
298
+ ### `GET /health`
299
+
300
+ Health check. Returns auth availability and configured model.
301
+
302
+ ```bash
303
+ curl http://localhost:18080/health
304
+ # {"status":"ok","auth_available":true,"model":"gpt-5.5"}
305
+ ```
306
+
307
+ ## Codex-Specific Features
308
+
309
+ These features are extensions beyond the standard OpenAI API, designed for Codex CLI compatibility.
310
+
311
+ ### `prompt_cache_key`
312
+
313
+ Enables prefix-cache stickiness on the Codex backend. When multiple requests share the same `prompt_cache_key`, the backend can reuse cached KV computations for the shared prefix, reducing latency and cost.
314
+
315
+ **When to use:** Set a stable key per conversation or session. All turns within the same session should share one key.
316
+
317
+ ```bash
318
+ curl http://localhost:18080/v1/chat/completions \
319
+ -H "Content-Type: application/json" \
320
+ -d '{
321
+ "model": "gpt-5.5",
322
+ "messages": [
323
+ {"role": "system", "content": "You are a helpful assistant."},
324
+ {"role": "user", "content": "Hello"}
325
+ ],
326
+ "prompt_cache_key": "session-abc-123"
327
+ }'
328
+ ```
329
+
330
+ ### `reasoning_effort`
331
+
332
+ Controls how much compute the model spends on reasoning. Valid values: `none`, `minimal`, `low`, `medium`, `high`, `xhigh`.
333
+
334
+ ```bash
335
+ curl http://localhost:18080/v1/chat/completions \
336
+ -H "Content-Type: application/json" \
337
+ -d '{
338
+ "model": "gpt-5.5",
339
+ "messages": [
340
+ {"role": "system", "content": "Solve this step by step."},
341
+ {"role": "user", "content": "Prove that sqrt(2) is irrational."}
342
+ ],
343
+ "reasoning_effort": "high"
344
+ }'
345
+ ```
346
+
347
+ ### `previous_response_id`
348
+
349
+ Chains responses together on the backend. Pass the response ID from a previous turn to maintain server-side conversation state.
350
+
351
+ ```bash
352
+ curl http://localhost:18080/v1/chat/completions \
353
+ -H "Content-Type: application/json" \
354
+ -d '{
355
+ "model": "gpt-5.5",
356
+ "messages": [
357
+ {"role": "system", "content": "You are a helpful assistant."},
358
+ {"role": "user", "content": "Continue from where we left off."}
359
+ ],
360
+ "previous_response_id": "resp_abc123"
361
+ }'
362
+ ```
363
+
364
+ ### `subagent` / `x-openai-subagent`
365
+
366
+ Identifies the request as coming from a specific subagent type. Values used by Codex CLI: `review`, `compact`, `memory_consolidation`, `collab_spawn`.
367
+
368
+ Can be passed as a body field or HTTP header:
369
+
370
+ ```bash
371
+ # As body field
372
+ curl http://localhost:18080/v1/chat/completions \
373
+ -H "Content-Type: application/json" \
374
+ -d '{
375
+ "model": "gpt-5.5",
376
+ "messages": [{"role": "system", "content": "Review this code."}, {"role": "user", "content": "..."}],
377
+ "subagent": "review"
378
+ }'
379
+
380
+ # As HTTP header
381
+ curl http://localhost:18080/v1/chat/completions \
382
+ -H "Content-Type: application/json" \
383
+ -H "x-openai-subagent: review" \
384
+ -d '{
385
+ "model": "gpt-5.5",
386
+ "messages": [{"role": "system", "content": "Review this code."}, {"role": "user", "content": "..."}]
387
+ }'
388
+ ```
389
+
390
+ ### `memgen_request` / `x-openai-memgen-request`
391
+
392
+ Flags the request as a memory generation/consolidation request. Can be passed as a body field (`bool`) or HTTP header (`"true"/"false"`):
393
+
394
+ ```bash
395
+ curl http://localhost:18080/v1/chat/completions \
396
+ -H "Content-Type: application/json" \
397
+ -H "x-openai-memgen-request: true" \
398
+ -d '{
399
+ "model": "gpt-5.5",
400
+ "messages": [{"role": "system", "content": "Consolidate memories."}, {"role": "user", "content": "..."}]
401
+ }'
402
+ ```
403
+
404
+ ## Using with OpenAI SDKs
405
+
406
+ Point the base URL to your local server:
407
+
408
+ ### Python (openai SDK)
409
+
410
+ ```python
411
+ from openai import OpenAI
412
+
413
+ client = OpenAI(
414
+ base_url="http://localhost:18080/v1",
415
+ api_key="unused",
416
+ )
417
+
418
+ response = client.chat.completions.create(
419
+ model="gpt-5.5",
420
+ messages=[
421
+ {"role": "system", "content": "You are a helpful assistant."},
422
+ {"role": "user", "content": "Hello!"},
423
+ ],
424
+ extra_body={"prompt_cache_key": "my-session"},
425
+ )
426
+ print(response.choices[0].message.content)
427
+ ```
428
+
429
+ ### Node.js (openai SDK)
430
+
431
+ ```typescript
432
+ import OpenAI from "openai";
433
+
434
+ const client = new OpenAI({
435
+ baseURL: "http://localhost:18080/v1",
436
+ apiKey: "unused",
437
+ });
438
+
439
+ const response = await client.chat.completions.create({
440
+ model: "gpt-5.5",
441
+ messages: [
442
+ { role: "system", content: "You are a helpful assistant." },
443
+ { role: "user", content: "Hello!" },
444
+ ],
445
+ });
446
+ console.log(response.choices[0].message.content);
447
+ ```
448
+
449
+ ### curl (streaming)
450
+
451
+ ```bash
452
+ curl -N http://localhost:18080/v1/chat/completions \
453
+ -H "Content-Type: application/json" \
454
+ -d '{
455
+ "model": "gpt-5.5",
456
+ "messages": [
457
+ {"role": "system", "content": "You are a helpful assistant."},
458
+ {"role": "user", "content": "Tell me a joke."}
459
+ ],
460
+ "stream": true,
461
+ "prompt_cache_key": "joke-session"
462
+ }'
463
+ ```
464
+
465
+ ## Using with Claude Code
466
+
467
+ The `/v1/messages` endpoint is compatible with [Claude Code](https://claude.ai/code). Claude Code sends the model name from its environment variables directly to the server, and the server passes it through to the Codex backend. You must set `ANTHROPIC_MODEL` (and per-role overrides) to a model the Codex backend supports (e.g., `gpt-5.5`).
468
+
469
+ ```bash
470
+ # Minimal setup
471
+ ANTHROPIC_BASE_URL=http://localhost:18080 \
472
+ ANTHROPIC_API_KEY=unused \
473
+ ANTHROPIC_MODEL=gpt-5.5 \
474
+ claude
475
+ ```
476
+
477
+ ```bash
478
+ # Full setup — override all roles so Claude Code never sends claude-* model names
479
+ ANTHROPIC_BASE_URL=http://localhost:18080 \
480
+ ANTHROPIC_API_KEY=unused \
481
+ ANTHROPIC_MODEL=gpt-5.5 \
482
+ ANTHROPIC_DEFAULT_OPUS_MODEL=gpt-5.5 \
483
+ ANTHROPIC_DEFAULT_SONNET_MODEL=gpt-5.4 \
484
+ ANTHROPIC_DEFAULT_HAIKU_MODEL=gpt-5.4-mini \
485
+ CLAUDE_CODE_SUBAGENT_MODEL=gpt-5.4 \
486
+ claude
487
+ ```
488
+
489
+ These are all Claude Code environment variables — they control what model name Claude Code sends in requests. The server passes the model name through to the Codex backend as-is.
490
+
491
+ ## Architecture
492
+
493
+ ```
494
+ Client (OpenAI SDK / curl)
495
+ |
496
+ v
497
+ HTTP Server (FastAPI / Axum / Express)
498
+ |
499
+ +---> ChatGPTOAuthProvider
500
+ |
501
+ +---> ~/.codex/auth.json (OAuth tokens, auto-refresh)
502
+ +---> https://chatgpt.com/backend-api/codex/responses
503
+ ```
504
+
505
+ The provider handles:
506
+ - Token loading and automatic refresh on 401
507
+ - OpenAI Responses API over SSE
508
+ - `prompt_cache_key` passthrough for prefix-cache stickiness
509
+ - Reasoning content streaming (`reasoning_content`, `reasoning`)
510
+ - Tool call streaming
511
+ - Codex-specific headers (`x-openai-subagent`, `x-openai-memgen-request`)
512
+ - `previous_response_id` for response chaining
513
+ - Image generation and inspection
514
+ - Remote conversation compaction
515
+
516
+ ## Tests
517
+
518
+ ### Python
519
+
520
+ ```bash
521
+ pip install -e ".[dev,server]"
522
+ pip install httpx
523
+ pytest tests/ -v
524
+ ```
525
+
526
+ ### Rust
527
+
528
+ ```bash
529
+ cd rust
530
+ cargo test
531
+ ```
532
+
533
+ ### TypeScript
534
+
535
+ ```bash
536
+ cd ts
537
+ npm install
538
+ npm test
539
+ ```
540
+
541
+ ## License
542
+
543
+ Apache License 2.0 — derived from [OpenAI Codex CLI](https://github.com/openai/codex) (Apache-2.0, Copyright 2025 OpenAI).
@@ -0,0 +1,11 @@
1
+ codex_as_api/__init__.py,sha256=FmrMH_SUCXFKh8x5N94nzpr74DUct3TkI2azbziWF3Y,108
2
+ codex_as_api/anthropic_adapter.py,sha256=0Xz3RuwMVDRNEjAFZC-tyk_CY_z7XL2372R6R2_Plmg,16721
3
+ codex_as_api/auth.py,sha256=5MXS_GtOsbK8uR6A2Q4Tio11fSRLrWw_Qz1I-xo4Tb0,9061
4
+ codex_as_api/messages.py,sha256=J07EkbDykpBTWlo1Q9Aw2ihbg8MznCc18OAYsNFonJw,3243
5
+ codex_as_api/protocol.py,sha256=0W4JeszUOTrhmVfnqkAR7f2qJYeYEv1ZBoo62uz1FNk,3931
6
+ codex_as_api/provider.py,sha256=1tpu_bwmrDVyeYY07R562YB_g9gMCrQ2OgiqKu-H8dY,31024
7
+ codex_as_api/server.py,sha256=NvichHPbq76Xck23DHf2aX4xlBfxbQSEmv0nDQJRbLM,23206
8
+ codex_as_api-0.2.1.dist-info/METADATA,sha256=6gRcrb8qPDAIlZ961-7cDN17DtN6_goZvEmvB-vhxpo,14164
9
+ codex_as_api-0.2.1.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
10
+ codex_as_api-0.2.1.dist-info/entry_points.txt,sha256=oXvO_wkCY79td6-3W_kmfjhA7PkT2eYTwxREU7Q5x-8,58
11
+ codex_as_api-0.2.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ codex-as-api = codex_as_api.server:main