Commit 3bc1f2e
committed
feat: add codex support
Implemented comprehensive support for OpenAI Codex CLI integration,
enabling users to proxy requests through their OpenAI subscription via
the ChatGPT backend API. This feature provides an alternative to the
Claude provider while maintaining full compatibility with the existing
proxy architecture. The implementation uses the OpenAI Responses API
endpoint as documented at
https://platform.openai.com/docs/api-reference/responses/get.
**Complete Codex API Proxy**
- Full reverse proxy to `https://chatgpt.com/backend-api/codex`
- Support for both `/codex/responses` and
`/codex/{session_id}/responses` endpoints
- Compatible with Codex CLI 0.21.0 and authentication flow
- Implements OpenAI Responses API protocol
**OAuth PKCE Authentication Flow**
- Implements complete OpenAI OAuth 2.0 PKCE flow matching official Codex
CLI
- Local callback server on port 1455 for authorization code exchange
- Token refresh and credential management with persistent storage
- Support for `~/.openai.toml` configuration file format
**Intelligent Request/Response Handling**
- Automatic detection and injection of Codex CLI instructions field
- Smart streaming behavior based on user's explicit `stream` parameter
- Session management with flexible session ID handling (auto-generated,
persistent, header-forwarded)
- Request transformation preserving Codex CLI identity headers
**Advanced Configuration**
- Environment variable support: `CODEX__BASE_URL`
- Configurable via TOML: `[codex]` section in configuration files
- Debug logging with request/response capture capabilities
- Comprehensive error handling with proper HTTP status codes
- Enabled by default
**New Components Added:**
- `ccproxy/auth/openai.py` - OAuth token management and credential
storage
- `ccproxy/core/codex_transformers.py` - Request/response transformation
for Codex format
- `ccproxy/api/routes/codex.py` - FastAPI routes for Codex endpoints
- `ccproxy/models/detection.py` - Codex CLI detection and header
management
- `ccproxy/services/codex_detection_service.py` - Runtime detection of
Codex CLI requests
**Enhanced Proxy Service:**
- Extended `ProxyService.handle_codex_request()` with full Codex support
- Intelligent streaming response conversion when user doesn't explicitly
request streaming
- Comprehensive request/response logging for debugging
- Error handling with proper OpenAI-compatible error responses
**Problem Resolved:** Fixed issue where requests without explicit
`stream` field were incorrectly returning streaming responses.
**Solution Implemented:**
- When `"stream"` field is missing: Inject `"stream": true` for upstream
(Codex requirement) but return JSON response to client
- When `"stream": true` explicitly set: Return streaming response to
client
- When `"stream": false` explicitly set: Return JSON response to client
- Smart response conversion: collects streaming data and converts to
single JSON response when user didn't request streaming
**Basic Request (JSON Response):**
```bash
curl -X POST "http://127.0.0.1:8000/codex/responses" \
-H "Content-Type: application/json" \
-d '{
"input": [{"type": "message", "role": "user", "content": [{"type":
"input_text", "text": "Hello!"}]}],
"model": "gpt-5",
"store": false
}'
```
**Streaming Request:**
```bash
curl -X POST "http://127.0.0.1:8000/codex/responses" \
-H "Content-Type: application/json" \
-d '{
"input": [{"type": "message", "role": "user", "content": [{"type":
"input_text", "text": "Hello!"}]}],
"model": "gpt-5",
"stream": true,
"store": false
}'
```
**Environment Variables:**
```bash
export CODEX__BASE_URL="https://chatgpt.com/backend-api/codex"
```
**Configuration File (`~/.ccproxy.toml`):**
```toml
[codex]
base_url = "https://chatgpt.com/backend-api/codex"
```
- Codex CLI: Full compatibility with `codex-cli 0.21.0`
- OpenAI OAuth: Complete PKCE flow implementation
- Session Management: Supports persistent and auto-generated sessions
- Model Support: All Codex-supported models (`gpt-5`, `gpt-4`, etc.)
- Streaming: Both streaming and non-streaming responses
- Error Handling: Proper HTTP status codes and OpenAI-compatible errors
- API Compliance: Follows OpenAI Responses API specification
**New Files:**
- `ccproxy/auth/openai.py` - OpenAI authentication management
- `ccproxy/core/codex_transformers.py` - Codex request/response
transformation
- `ccproxy/api/routes/codex.py` - Codex API endpoints
- `ccproxy/models/detection.py` - Codex detection models
- `ccproxy/services/codex_detection_service.py` - Codex CLI detection
service
**Modified Files:**
- `ccproxy/services/proxy_service.py` - Added `handle_codex_request()`
method
- `ccproxy/config/settings.py` - Added Codex configuration section
- `ccproxy/api/app.py` - Integrated Codex routes
- `ccproxy/api/routes/health.py` - Added Codex health checks
None. This is a purely additive feature that doesn't affect existing
Claude provider functionality.
For users wanting to use Codex provider:
1. Authenticate: Use existing OpenAI credentials or run Codex CLI login
2. Update endpoints: Change from `/v1/messages` to `/codex/responses`
This implementation provides a complete, production-ready OpenAI Codex
proxy solution that maintains the same standards as the existing Claude
provider while offering users choice in their AI provider preferences.1 parent 366f807 commit 3bc1f2e
File tree
29 files changed
+4664
-1646
lines changed- ccproxy
- api
- routes
- auth/openai
- claude_sdk
- cli/commands
- config
- core
- models
- services
- utils
- tests
- fixtures/claude_sdk
- unit
- config
- services
29 files changed
+4664
-1646
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
19 | | - | |
| 19 | + | |
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| |||
58 | 58 | | |
59 | 59 | | |
60 | 60 | | |
| 61 | + | |
61 | 62 | | |
62 | 63 | | |
63 | 64 | | |
| |||
81 | 82 | | |
82 | 83 | | |
83 | 84 | | |
84 | | - | |
| 85 | + | |
85 | 86 | | |
86 | 87 | | |
87 | 88 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
10 | 157 | | |
11 | 158 | | |
12 | 159 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
81 | 81 | | |
82 | 82 | | |
83 | 83 | | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
84 | 92 | | |
85 | 93 | | |
86 | 94 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
4 | 9 | | |
5 | 10 | | |
6 | 11 | | |
7 | 12 | | |
8 | 13 | | |
9 | | - | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
10 | 22 | | |
11 | 23 | | |
12 | 24 | | |
| |||
36 | 48 | | |
37 | 49 | | |
38 | 50 | | |
39 | | - | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
40 | 54 | | |
41 | 55 | | |
42 | 56 | | |
| |||
46 | 60 | | |
47 | 61 | | |
48 | 62 | | |
49 | | - | |
50 | 63 | | |
51 | | - | |
| 64 | + | |
| 65 | + | |
52 | 66 | | |
53 | 67 | | |
54 | 68 | | |
| |||
58 | 72 | | |
59 | 73 | | |
60 | 74 | | |
61 | | - | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
62 | 91 | | |
63 | | - | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
64 | 102 | | |
65 | 103 | | |
66 | 104 | | |
| |||
76 | 114 | | |
77 | 115 | | |
78 | 116 | | |
79 | | - | |
| 117 | + | |
80 | 118 | | |
81 | 119 | | |
82 | 120 | | |
| |||
86 | 124 | | |
87 | 125 | | |
88 | 126 | | |
89 | | - | |
| 127 | + | |
90 | 128 | | |
91 | 129 | | |
92 | 130 | | |
| |||
96 | 134 | | |
97 | 135 | | |
98 | 136 | | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
99 | 158 | | |
100 | 159 | | |
101 | 160 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
21 | 22 | | |
22 | 23 | | |
23 | 24 | | |
| |||
33 | 34 | | |
34 | 35 | | |
35 | 36 | | |
| 37 | + | |
36 | 38 | | |
37 | 39 | | |
38 | 40 | | |
| 41 | + | |
39 | 42 | | |
40 | 43 | | |
41 | 44 | | |
| |||
78 | 81 | | |
79 | 82 | | |
80 | 83 | | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
81 | 89 | | |
82 | 90 | | |
83 | 91 | | |
84 | 92 | | |
85 | 93 | | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
86 | 99 | | |
87 | 100 | | |
88 | 101 | | |
| |||
282 | 295 | | |
283 | 296 | | |
284 | 297 | | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
285 | 301 | | |
286 | 302 | | |
287 | 303 | | |
| |||
0 commit comments