claude-codex-proxy 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +227 -0
- package/bin/cli.js +113 -0
- package/docs/ACCOUNTS.md +202 -0
- package/docs/API.md +244 -0
- package/docs/ARCHITECTURE.md +119 -0
- package/docs/CLAUDE_INTEGRATION.md +163 -0
- package/docs/OAUTH.md +83 -0
- package/docs/OPENCLAW.md +33 -0
- package/docs/legal.md +9 -0
- package/images/demo-screenshot.png +0 -0
- package/images/f757093f-507b-4453-994e-f8275f8b07a9.png +0 -0
- package/package.json +56 -0
- package/public/css/style.css +791 -0
- package/public/index.html +838 -0
- package/public/js/app.js +619 -0
- package/src/account-manager.js +526 -0
- package/src/account-rotation/index.js +93 -0
- package/src/account-rotation/rate-limits.js +293 -0
- package/src/account-rotation/strategies/base-strategy.js +48 -0
- package/src/account-rotation/strategies/index.js +31 -0
- package/src/account-rotation/strategies/round-robin-strategy.js +42 -0
- package/src/account-rotation/strategies/sticky-strategy.js +97 -0
- package/src/claude-config.js +154 -0
- package/src/cli/accounts.js +551 -0
- package/src/direct-api.js +214 -0
- package/src/format-converter.js +563 -0
- package/src/index.js +45 -0
- package/src/middleware/credentials.js +116 -0
- package/src/middleware/sse.js +130 -0
- package/src/model-api.js +189 -0
- package/src/model-mapper.js +88 -0
- package/src/oauth.js +623 -0
- package/src/response-streamer.js +469 -0
- package/src/routes/accounts-route.js +296 -0
- package/src/routes/api-routes.js +102 -0
- package/src/routes/chat-route.js +239 -0
- package/src/routes/claude-config-route.js +114 -0
- package/src/routes/logs-route.js +43 -0
- package/src/routes/messages-route.js +164 -0
- package/src/routes/models-route.js +115 -0
- package/src/routes/settings-route.js +154 -0
- package/src/server-settings.js +70 -0
- package/src/server.js +57 -0
- package/src/signature-cache.js +106 -0
- package/src/thinking-utils.js +312 -0
- package/src/utils/logger.js +170 -0
package/docs/API.md
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# API Reference
|
|
2
|
+
|
|
3
|
+
## Main Endpoints
|
|
4
|
+
|
|
5
|
+
### Chat Completions (OpenAI-compatible)
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
POST /v1/chat/completions
|
|
9
|
+
Content-Type: application/json
|
|
10
|
+
|
|
11
|
+
{
|
|
12
|
+
"model": "gpt-5.2",
|
|
13
|
+
"messages": [{"role": "user", "content": "Hello"}],
|
|
14
|
+
"tools": [...],
|
|
15
|
+
"stream": true
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Messages (Anthropic-compatible)
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
POST /v1/messages
|
|
23
|
+
Content-Type: application/json
|
|
24
|
+
|
|
25
|
+
{
|
|
26
|
+
"model": "claude-sonnet-4-5",
|
|
27
|
+
"max_tokens": 1024,
|
|
28
|
+
"system": "You are helpful.",
|
|
29
|
+
"messages": [{"role": "user", "content": "Hello"}],
|
|
30
|
+
"tools": [...],
|
|
31
|
+
"stream": true
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Models
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
GET /v1/models
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Token Counting
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
POST /v1/messages/count_tokens
|
|
45
|
+
Content-Type: application/json
|
|
46
|
+
|
|
47
|
+
{
|
|
48
|
+
"messages": [...],
|
|
49
|
+
"tools": [...]
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Account Management
|
|
54
|
+
|
|
55
|
+
Common endpoints:
|
|
56
|
+
|
|
57
|
+
| Endpoint | Method | Description |
|
|
58
|
+
|----------|--------|-------------|
|
|
59
|
+
| `/accounts` | GET | List all accounts |
|
|
60
|
+
| `/accounts/status` | GET | Get account status summary |
|
|
61
|
+
| `/accounts/add` | POST | Start OAuth flow (returns URL) |
|
|
62
|
+
| `/accounts/switch` | POST | Switch active account |
|
|
63
|
+
| `/accounts/models` | GET | Get models for account |
|
|
64
|
+
| `/accounts/quota` | GET | Get quota info |
|
|
65
|
+
| `/accounts/quota/all` | GET | Refresh all quotas |
|
|
66
|
+
| `/accounts/usage` | GET | Get usage stats |
|
|
67
|
+
|
|
68
|
+
(Additional maintenance endpoints exist for token refresh/import/removal; see the source if you need them.)
|
|
69
|
+
|
|
70
|
+
### Add Account
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
POST /accounts/add
|
|
74
|
+
Content-Type: application/json
|
|
75
|
+
|
|
76
|
+
# Optional: specify callback port
|
|
77
|
+
{"port": 1455}
|
|
78
|
+
|
|
79
|
+
# Response
|
|
80
|
+
{
|
|
81
|
+
"status": "oauth_url",
|
|
82
|
+
"oauth_url": "https://auth.openai.com/oauth/authorize?...",
|
|
83
|
+
"state": "...",
|
|
84
|
+
"callback_port": 1455
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Switch Account
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
POST /accounts/switch
|
|
92
|
+
Content-Type: application/json
|
|
93
|
+
|
|
94
|
+
{"email": "user@gmail.com"}
|
|
95
|
+
|
|
96
|
+
# Response
|
|
97
|
+
{"success": true, "message": "Switched to account: user@gmail.com"}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### OAuth Callback
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
GET /auth/callback?code=...&state=...
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Claude CLI Configuration
|
|
107
|
+
|
|
108
|
+
| Endpoint | Method | Description |
|
|
109
|
+
|----------|--------|-------------|
|
|
110
|
+
| `/claude/config` | GET | View current config |
|
|
111
|
+
| `/claude/config/proxy` | POST | Configure for proxy |
|
|
112
|
+
| `/claude/config/direct` | POST | Configure for direct API |
|
|
113
|
+
|
|
114
|
+
### Configure Proxy Mode
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
POST /claude/config/proxy
|
|
118
|
+
|
|
119
|
+
# Response
|
|
120
|
+
{
|
|
121
|
+
"success": true,
|
|
122
|
+
"message": "Claude CLI configured to use proxy at http://localhost:8081",
|
|
123
|
+
"config": {...}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Health
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
GET /health
|
|
131
|
+
|
|
132
|
+
# Response
|
|
133
|
+
{
|
|
134
|
+
"status": "ok",
|
|
135
|
+
"total": 2,
|
|
136
|
+
"active": "active@example.com",
|
|
137
|
+
"accounts": [...]
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Error Responses
|
|
142
|
+
|
|
143
|
+
### Authentication Error
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"type": "error",
|
|
148
|
+
"error": {
|
|
149
|
+
"type": "authentication_error",
|
|
150
|
+
"message": "No active account with valid credentials"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Rate Limit Error
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"type": "error",
|
|
160
|
+
"error": {
|
|
161
|
+
"type": "rate_limit_error",
|
|
162
|
+
"message": "Rate limited: ..."
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Streaming Events
|
|
168
|
+
|
|
169
|
+
Anthropic SSE format:
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
event: message_start
|
|
173
|
+
data: {"type":"message_start","message":{...}}
|
|
174
|
+
|
|
175
|
+
event: content_block_start
|
|
176
|
+
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
|
|
177
|
+
|
|
178
|
+
event: content_block_delta
|
|
179
|
+
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello"}}
|
|
180
|
+
|
|
181
|
+
event: content_block_stop
|
|
182
|
+
data: {"type":"content_block_stop","index":0}
|
|
183
|
+
|
|
184
|
+
event: message_delta
|
|
185
|
+
data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{...}}
|
|
186
|
+
|
|
187
|
+
event: message_stop
|
|
188
|
+
data: {"type":"message_stop"}
|
|
189
|
+
|
|
190
|
+
data: [DONE]
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Tool Calling
|
|
194
|
+
|
|
195
|
+
### Request with Tools
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
{
|
|
199
|
+
"model": "claude-sonnet-4-5",
|
|
200
|
+
"messages": [
|
|
201
|
+
{"role": "user", "content": "What's the weather in Tokyo?"}
|
|
202
|
+
],
|
|
203
|
+
"tools": [{
|
|
204
|
+
"name": "get_weather",
|
|
205
|
+
"description": "Get weather for a location",
|
|
206
|
+
"input_schema": {
|
|
207
|
+
"type": "object",
|
|
208
|
+
"properties": {
|
|
209
|
+
"location": {"type": "string"}
|
|
210
|
+
},
|
|
211
|
+
"required": ["location"]
|
|
212
|
+
}
|
|
213
|
+
}]
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Response with Tool Use
|
|
218
|
+
|
|
219
|
+
```json
|
|
220
|
+
{
|
|
221
|
+
"id": "msg_...",
|
|
222
|
+
"type": "message",
|
|
223
|
+
"role": "assistant",
|
|
224
|
+
"content": [{
|
|
225
|
+
"type": "tool_use",
|
|
226
|
+
"id": "toolu_...",
|
|
227
|
+
"name": "get_weather",
|
|
228
|
+
"input": {"location": "Tokyo"}
|
|
229
|
+
}],
|
|
230
|
+
"stop_reason": "tool_use"
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Tool Result
|
|
235
|
+
|
|
236
|
+
```json
|
|
237
|
+
{
|
|
238
|
+
"messages": [
|
|
239
|
+
{"role": "user", "content": "What's the weather?"},
|
|
240
|
+
{"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_123", "name": "get_weather", "input": {"location": "Tokyo"}}]},
|
|
241
|
+
{"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_123", "content": "Sunny, 22°C"}]}
|
|
242
|
+
]
|
|
243
|
+
}
|
|
244
|
+
```
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
┌──────────────────┐ ┌─────────────────────┐ ┌────────────────────────────┐
|
|
7
|
+
│ Claude Code │────▶│ This Proxy Server │────▶│ ChatGPT Codex backend │
|
|
8
|
+
│ (Anthropic │ │ (Anthropic format) │ │ (internal API) │
|
|
9
|
+
│ API format) │ │ │ │ │
|
|
10
|
+
└──────────────────┘ └─────────────────────┘ └────────────────────────────┘
|
|
11
|
+
│
|
|
12
|
+
▼
|
|
13
|
+
┌─────────────────────┐
|
|
14
|
+
│ Account Manager │
|
|
15
|
+
│ (local storage) │
|
|
16
|
+
│ │
|
|
17
|
+
└─────────────────────┘
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Key Discovery
|
|
21
|
+
|
|
22
|
+
This proxy forwards requests from Anthropic-compatible clients (like Claude Code) to the ChatGPT Codex backend, handling authentication, format conversion, and streaming.
|
|
23
|
+
|
|
24
|
+
## Project Structure
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
codex-claude-proxy/
|
|
28
|
+
├── package.json
|
|
29
|
+
├── README.md
|
|
30
|
+
├── docs/
|
|
31
|
+
│ ├── ARCHITECTURE.md
|
|
32
|
+
│ ├── API.md
|
|
33
|
+
│ ├── OAUTH.md
|
|
34
|
+
│ ├── ACCOUNTS.md
|
|
35
|
+
│ └── CLAUDE_INTEGRATION.md
|
|
36
|
+
├── public/
|
|
37
|
+
│ ├── index.html
|
|
38
|
+
│ ├── css/style.css
|
|
39
|
+
│ └── js/app.js # Web UI logic
|
|
40
|
+
└── src/
|
|
41
|
+
├── index.js # App entrypoint
|
|
42
|
+
├── server.js # Express server setup
|
|
43
|
+
├── routes/api-routes.js # API route registrations
|
|
44
|
+
└── ... # OAuth, accounts, converters, upstream clients
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
(See the `src/` directory for the full implementation; this doc focuses on the high-level shape.)
|
|
48
|
+
|
|
49
|
+
## Module Responsibilities
|
|
50
|
+
|
|
51
|
+
| File | Purpose |
|
|
52
|
+
|------|---------|
|
|
53
|
+
| `index.js` | Entry point (starts server) |
|
|
54
|
+
| `server.js` | Express server, routes, request handling (CORS restricted) |
|
|
55
|
+
| `routes/api-routes.js` | API route registrations (mounted by server) |
|
|
56
|
+
| `oauth.js` | OAuth 2.0 PKCE flow, token exchange |
|
|
57
|
+
| `account-manager.js` | Account persistence, switching, token refresh |
|
|
58
|
+
| `format-converter.js` | Convert between Anthropic and OpenAI Responses API formats |
|
|
59
|
+
| `response-streamer.js` | Parse SSE events, convert to Anthropic streaming format |
|
|
60
|
+
| `direct-api.js` | HTTP client for ChatGPT backend |
|
|
61
|
+
| `server-settings.js` | Server-wide settings persistence |
|
|
62
|
+
| `model-api.js` | Fetch models, usage, quota |
|
|
63
|
+
| `claude-config.js` | Read/write Claude Code settings |
|
|
64
|
+
|
|
65
|
+
## Data Flow
|
|
66
|
+
|
|
67
|
+
### Request Flow
|
|
68
|
+
|
|
69
|
+
1. Claude Code sends Anthropic-format request to `/v1/messages`
|
|
70
|
+
2. The proxy maps the requested model to an upstream target
|
|
71
|
+
3. If the mapped path requires ChatGPT auth, the account manager loads/refreshes credentials
|
|
72
|
+
4. Request is converted and sent upstream
|
|
73
|
+
5. Response is streamed back as Anthropic SSE events
|
|
74
|
+
|
|
75
|
+
### Web UI Account/Quota Flow
|
|
76
|
+
|
|
77
|
+
1. Web UI loads account list from `/accounts`
|
|
78
|
+
2. Web UI fetches quota snapshots from `/accounts/quota/all`
|
|
79
|
+
3. Quota values are merged into account rows for table + modal views
|
|
80
|
+
4. Remaining quota is rendered from normalized usage percentages
|
|
81
|
+
5. On mobile/tablet, sidebar navigation auto-closes after tab change and account table uses horizontal scrolling
|
|
82
|
+
|
|
83
|
+
### Format Conversion
|
|
84
|
+
|
|
85
|
+
**Anthropic → OpenAI Responses API:**
|
|
86
|
+
- `messages` → `input` array with `type: 'message'`
|
|
87
|
+
- `system` → `instructions`
|
|
88
|
+
- `tools` → OpenAI function format
|
|
89
|
+
- `tool_use` → `function_call` input item
|
|
90
|
+
- `tool_result` → `function_call_output` input item
|
|
91
|
+
|
|
92
|
+
**OpenAI → Anthropic:**
|
|
93
|
+
- `output_text` → `{ type: 'text', text: ... }`
|
|
94
|
+
- `function_call` → `{ type: 'tool_use', id, name, input }`
|
|
95
|
+
- SSE events converted to Anthropic streaming format
|
|
96
|
+
|
|
97
|
+
## Available Models
|
|
98
|
+
|
|
99
|
+
| Model | Description |
|
|
100
|
+
|-------|-------------|
|
|
101
|
+
| `gpt-5.3-codex` | Latest agentic coding model |
|
|
102
|
+
| `gpt-5.2-codex` | Frontier agentic coding model |
|
|
103
|
+
| `gpt-5.2` | General-purpose frontier model |
|
|
104
|
+
|
|
105
|
+
## Model Mapping
|
|
106
|
+
|
|
107
|
+
Claude model names are automatically mapped:
|
|
108
|
+
|
|
109
|
+
| Claude Model | Codex Model |
|
|
110
|
+
|--------------|-------------|
|
|
111
|
+
| `claude-opus-4-5` | `gpt-5.3-codex` |
|
|
112
|
+
| `claude-sonnet-4-5` | `gpt-5.2` |
|
|
113
|
+
| `claude-haiku-4` | routed by server setting |
|
|
114
|
+
|
|
115
|
+
Haiku routing is controlled by a server-wide setting (`/settings/haiku-model`).
|
|
116
|
+
|
|
117
|
+
## Data Storage
|
|
118
|
+
|
|
119
|
+
Account and configuration files are stored under your home directory (platform-specific). See `docs/ACCOUNTS.md` and `docs/CLAUDE_INTEGRATION.md` for details.
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Claude Code Integration
|
|
2
|
+
|
|
3
|
+
## Setup
|
|
4
|
+
|
|
5
|
+
### Automatic Configuration
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
curl -X POST http://localhost:8081/claude/config/proxy
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Updates `~/.claude/settings.json`:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"env": {
|
|
16
|
+
"ANTHROPIC_BASE_URL": "http://localhost:8081",
|
|
17
|
+
"ANTHROPIC_API_KEY": "any-key",
|
|
18
|
+
"ANTHROPIC_MODEL": "claude-sonnet-4-5",
|
|
19
|
+
"ANTHROPIC_DEFAULT_OPUS_MODEL": "claude-opus-4-5",
|
|
20
|
+
"ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-sonnet-4-5",
|
|
21
|
+
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "claude-haiku-4"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Manual Configuration
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
export ANTHROPIC_BASE_URL=http://localhost:8081
|
|
30
|
+
export ANTHROPIC_API_KEY=any-key
|
|
31
|
+
claude
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Using Claude Code
|
|
35
|
+
|
|
36
|
+
When prompted about API key:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
Detected a custom API key in your environment
|
|
40
|
+
ANTHROPIC_API_KEY: any-key
|
|
41
|
+
Do you want to use this API key?
|
|
42
|
+
❯ 1. Yes <-- Choose this
|
|
43
|
+
2. No (recommended)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## How It Works
|
|
47
|
+
|
|
48
|
+
### Request Flow
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
Claude Code (Anthropic format)
|
|
52
|
+
↓
|
|
53
|
+
Proxy Server
|
|
54
|
+
↓
|
|
55
|
+
Format Conversion
|
|
56
|
+
↓
|
|
57
|
+
ChatGPT Backend API
|
|
58
|
+
↓
|
|
59
|
+
Response Stream
|
|
60
|
+
↓
|
|
61
|
+
Format Conversion
|
|
62
|
+
↓
|
|
63
|
+
Claude Code (Anthropic format)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Format Conversion
|
|
67
|
+
|
|
68
|
+
**Anthropic → OpenAI Responses API:**
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
// Anthropic request
|
|
72
|
+
{
|
|
73
|
+
"model": "claude-sonnet-4-5",
|
|
74
|
+
"system": "You are helpful.",
|
|
75
|
+
"messages": [
|
|
76
|
+
{"role": "user", "content": "Hello"},
|
|
77
|
+
{"role": "assistant", "content": [{"type": "tool_use", "id": "t1", "name": "fn", "input": {}}]},
|
|
78
|
+
{"role": "user", "content": [{"type": "tool_result", "tool_use_id": "t1", "content": "result"}]}
|
|
79
|
+
],
|
|
80
|
+
"tools": [...]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Converted to OpenAI Responses API
|
|
84
|
+
{
|
|
85
|
+
"model": "gpt-5.2-codex",
|
|
86
|
+
"instructions": "You are helpful.",
|
|
87
|
+
"input": [
|
|
88
|
+
{"type": "message", "role": "user", "content": "Hello"},
|
|
89
|
+
{"type": "function_call", "id": "fc_t1", "call_id": "fc_t1", "name": "fn", "arguments": "{}"},
|
|
90
|
+
{"type": "function_call_output", "call_id": "fc_t1", "output": "result"}
|
|
91
|
+
],
|
|
92
|
+
"tools": [...],
|
|
93
|
+
"store": false,
|
|
94
|
+
"stream": true
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Key Conversions:**
|
|
99
|
+
- `system` → `instructions`
|
|
100
|
+
- `messages` → `input` array
|
|
101
|
+
- `tool_use` → `function_call` + `function_call_output` items
|
|
102
|
+
- Tool IDs prefixed with `fc_` for API compatibility
|
|
103
|
+
|
|
104
|
+
### Streaming Events
|
|
105
|
+
|
|
106
|
+
OpenAI Responses API → Anthropic SSE:
|
|
107
|
+
|
|
108
|
+
| OpenAI Event | Anthropic Event |
|
|
109
|
+
|--------------|-----------------|
|
|
110
|
+
| `response.output_item.added` | `message_start`, `content_block_start` |
|
|
111
|
+
| `response.output_text.delta` | `content_block_delta` (text_delta) |
|
|
112
|
+
| `response.function_call_arguments.delta` | `content_block_delta` (input_json_delta) |
|
|
113
|
+
| `response.completed` | `message_delta`, `message_stop` |
|
|
114
|
+
|
|
115
|
+
## Tool Calling
|
|
116
|
+
|
|
117
|
+
Works natively via OpenAI Responses API:
|
|
118
|
+
|
|
119
|
+
1. Claude Code sends tools in Anthropic format
|
|
120
|
+
2. Proxy converts to OpenAI function format
|
|
121
|
+
3. ChatGPT executes and returns function calls
|
|
122
|
+
4. Proxy converts back to Anthropic `tool_use` blocks
|
|
123
|
+
5. Claude Code processes and returns tool results
|
|
124
|
+
|
|
125
|
+
## View Configuration
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
curl http://localhost:8081/claude/config
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Revert to Direct API
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
curl -X POST http://localhost:8081/claude/config/direct \
|
|
135
|
+
-H "Content-Type: application/json" \
|
|
136
|
+
-d '{"apiKey":"sk-ant-..."}'
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Troubleshooting
|
|
140
|
+
|
|
141
|
+
### Claude Code hangs
|
|
142
|
+
|
|
143
|
+
1. Check proxy health: `curl http://localhost:8081/health`
|
|
144
|
+
2. Verify config: `cat ~/.claude/settings.json`
|
|
145
|
+
3. Re-configure: `curl -X POST http://localhost:8081/claude/config/proxy`
|
|
146
|
+
|
|
147
|
+
### "No active account" error
|
|
148
|
+
|
|
149
|
+
Add an account first:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
curl -X POST http://localhost:8081/accounts/import
|
|
153
|
+
# or use WebUI
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Tool calls not working
|
|
157
|
+
|
|
158
|
+
Ensure you're using the direct API mode (not CLI subprocess). Check:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
curl http://localhost:8081/health
|
|
162
|
+
# Should show accounts with valid tokens
|
|
163
|
+
```
|
package/docs/OAUTH.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# OAuth Implementation
|
|
2
|
+
|
|
3
|
+
This proxy uses **OAuth 2.0 with PKCE** for secure authentication with ChatGPT.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
### Desktop (Browser)
|
|
8
|
+
```bash
|
|
9
|
+
codex-claude-proxy accounts add
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
### Headless/VM (No Browser)
|
|
13
|
+
```bash
|
|
14
|
+
codex-claude-proxy accounts add --no-browser
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Headless/VM Workflow
|
|
18
|
+
|
|
19
|
+
When running on a server without a browser (VM, Docker, SSH):
|
|
20
|
+
|
|
21
|
+
1. Run the command with `--no-browser`:
|
|
22
|
+
```bash
|
|
23
|
+
codex-claude-proxy accounts add --no-browser
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
2. It prints a URL like:
|
|
27
|
+
```
|
|
28
|
+
https://auth.openai.com/oauth/authorize?response_type=code&...
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
3. Copy the URL and open it in a browser on **any other device** (your laptop, phone, etc.)
|
|
32
|
+
|
|
33
|
+
4. Complete the ChatGPT login
|
|
34
|
+
|
|
35
|
+
5. After successful login, you'll be redirected to a localhost URL that looks like:
|
|
36
|
+
```
|
|
37
|
+
http://localhost:1455/auth/callback?code=ABC123...
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
6. Copy that entire URL (or just the `code` parameter) and paste it back in the terminal
|
|
41
|
+
|
|
42
|
+
7. The proxy exchanges the code for tokens and saves your account
|
|
43
|
+
|
|
44
|
+
## OAuth Config
|
|
45
|
+
|
|
46
|
+
- **Client ID**: `app_EMoamEEZ73f0CkXaXp7hrann`
|
|
47
|
+
- **Auth URL**: `https://auth.openai.com/oauth/authorize`
|
|
48
|
+
- **Token URL**: `https://auth.openai.com/oauth/token`
|
|
49
|
+
- **Callback Port**: `1455`
|
|
50
|
+
|
|
51
|
+
## Features
|
|
52
|
+
|
|
53
|
+
- **PKCE**: Secure code exchange with SHA256 challenge
|
|
54
|
+
- **Auto-Refresh**: Tokens refresh automatically before expiry
|
|
55
|
+
- **Multi-Account**: Uses `prompt=login` to force account selection
|
|
56
|
+
- **Headless Support**: Works on servers without browsers
|
|
57
|
+
|
|
58
|
+
## Managing Accounts
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# List accounts
|
|
62
|
+
codex-claude-proxy accounts list
|
|
63
|
+
|
|
64
|
+
# Add account (browser)
|
|
65
|
+
codex-claude-proxy accounts add
|
|
66
|
+
|
|
67
|
+
# Add account (headless)
|
|
68
|
+
codex-claude-proxy accounts add --no-browser
|
|
69
|
+
|
|
70
|
+
# Clear all accounts
|
|
71
|
+
codex-claude-proxy accounts clear
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Troubleshooting
|
|
75
|
+
|
|
76
|
+
### "Port already in use"
|
|
77
|
+
The `--no-browser` mode works independently of the server - you can add accounts even while the proxy is running.
|
|
78
|
+
|
|
79
|
+
### "Invalid state" error
|
|
80
|
+
This happens if you use a code from an old session. Generate a fresh URL and try again.
|
|
81
|
+
|
|
82
|
+
### Same account keeps getting selected
|
|
83
|
+
Clear cookies at `auth.openai.com` or use a private/incognito window.
|
package/docs/OPENCLAW.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Using with OpenClaw
|
|
2
|
+
|
|
3
|
+
[OpenClaw](https://docs.openclaw.ai/) is an AI agent gateway. This proxy provides the Anthropic-compatible API it needs.
|
|
4
|
+
|
|
5
|
+
## Quick Integration
|
|
6
|
+
|
|
7
|
+
1. **Add Provider** to `~/.openclaw/openclaw.json`:
|
|
8
|
+
```json
|
|
9
|
+
{
|
|
10
|
+
"codex-proxy": {
|
|
11
|
+
"baseUrl": "http://127.0.0.1:8081",
|
|
12
|
+
"apiKey": "test",
|
|
13
|
+
"api": "anthropic-messages",
|
|
14
|
+
"models": [
|
|
15
|
+
{ "id": "claude-sonnet-4-5", "name": "GPT-5.2 Codex" },
|
|
16
|
+
{ "id": "claude-opus-4-5", "name": "GPT-5.3 Codex" }
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
2. **Set Primary Model**:
|
|
22
|
+
```bash
|
|
23
|
+
openclaw models set codex-proxy/claude-sonnet-4-5
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Key Benefits
|
|
27
|
+
- **Multi-Account**: Proxy handles rate limits by switching ChatGPT accounts.
|
|
28
|
+
- **SSE Streaming**: Full real-time response support.
|
|
29
|
+
- **Tool Calling**: Native support for agentic workflows.
|
|
30
|
+
|
|
31
|
+
## Troubleshooting
|
|
32
|
+
- Use `127.0.0.1` instead of `localhost`.
|
|
33
|
+
- Verify proxy health: `curl http://127.0.0.1:8081/health`.
|
package/docs/legal.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Legal
|
|
2
|
+
|
|
3
|
+
- **Not affiliated with OpenAI or Anthropic.** This is an independent open-source project and is not endorsed by, sponsored by, or affiliated with OpenAI or Anthropic.
|
|
4
|
+
|
|
5
|
+
- "ChatGPT", "OpenAI", and "Codex" are trademarks of OpenAI.
|
|
6
|
+
|
|
7
|
+
- "Claude" and "Anthropic" are trademarks of Anthropic PBC.
|
|
8
|
+
|
|
9
|
+
- Software is provided "as is", without warranty. You are responsible for complying with all applicable Terms of Service and Acceptable Use Policies.
|
|
Binary file
|
|
Binary file
|