@redonvn/event-ws-cliproxyapi-sdk 0.1.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/README.md +428 -0
- package/dist/claude/client.d.ts +8 -0
- package/dist/claude/client.js +16 -0
- package/dist/claude/index.d.ts +2 -0
- package/dist/claude/index.js +1 -0
- package/dist/client.d.ts +19 -0
- package/dist/client.js +96 -0
- package/dist/cliproxy/client.d.ts +41 -0
- package/dist/cliproxy/client.js +43 -0
- package/dist/cliproxy/index.d.ts +2 -0
- package/dist/cliproxy/index.js +1 -0
- package/dist/codec.d.ts +8 -0
- package/dist/codec.js +79 -0
- package/dist/errors/index.d.ts +13 -0
- package/dist/errors/index.js +26 -0
- package/dist/gemini/client.d.ts +9 -0
- package/dist/gemini/client.js +19 -0
- package/dist/gemini/index.d.ts +2 -0
- package/dist/gemini/index.js +1 -0
- package/dist/http/client.d.ts +260 -0
- package/dist/http/client.js +591 -0
- package/dist/http/index.d.ts +2 -0
- package/dist/http/index.js +2 -0
- package/dist/http/types.d.ts +783 -0
- package/dist/http/types.js +1 -0
- package/dist/http-client.d.ts +259 -0
- package/dist/http-client.js +557 -0
- package/dist/http-types.d.ts +677 -0
- package/dist/http-types.js +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/management/client.d.ts +187 -0
- package/dist/management/client.js +399 -0
- package/dist/management/index.d.ts +2 -0
- package/dist/management/index.js +1 -0
- package/dist/openai/client.d.ts +10 -0
- package/dist/openai/client.js +23 -0
- package/dist/openai/index.d.ts +2 -0
- package/dist/openai/index.js +1 -0
- package/dist/shared/errors.d.ts +13 -0
- package/dist/shared/errors.js +26 -0
- package/dist/shared/http.d.ts +29 -0
- package/dist/shared/http.js +125 -0
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.js +2 -0
- package/dist/shared/types.d.ts +789 -0
- package/dist/shared/types.js +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +2 -0
- package/dist/types.d.ts +101 -0
- package/dist/types.js +1 -0
- package/dist/utils/index.d.ts +0 -0
- package/dist/utils/index.js +2 -0
- package/dist/ws/client.d.ts +20 -0
- package/dist/ws/client.js +114 -0
- package/dist/ws/codec.d.ts +8 -0
- package/dist/ws/codec.js +100 -0
- package/dist/ws/index.d.ts +3 -0
- package/dist/ws/index.js +3 -0
- package/dist/ws/types.d.ts +101 -0
- package/dist/ws/types.js +1 -0
- package/package.json +29 -0
package/README.md
ADDED
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
# event-ws-CLIProxyAPI-sdk
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for CLIProxyAPI covering:
|
|
4
|
+
- WebSocket relay (provider-side) via `/v1/ws`
|
|
5
|
+
- Full HTTP client for public and management APIs
|
|
6
|
+
|
|
7
|
+
## Endpoints (Full List + Function)
|
|
8
|
+
|
|
9
|
+
WebSocket relay
|
|
10
|
+
- `GET /v1/ws`: WebSocket relay endpoint for provider-side request/response and streaming.
|
|
11
|
+
|
|
12
|
+
Public (no management key)
|
|
13
|
+
- `GET /`: Health/info root. Returns server message + key endpoints list.
|
|
14
|
+
- `GET /management.html`: Management UI HTML (if enabled on server).
|
|
15
|
+
- `GET /keep-alive`: Keep-alive heartbeat (only if server enabled it). Requires local password when set.
|
|
16
|
+
- OAuth callbacks (used by browser auth flows):
|
|
17
|
+
- `GET /anthropic/callback`: Persist Anthropic OAuth callback.
|
|
18
|
+
- `GET /codex/callback`: Persist Codex OAuth callback.
|
|
19
|
+
- `GET /google/callback`: Persist Gemini OAuth callback.
|
|
20
|
+
- `GET /iflow/callback`: Persist iFlow OAuth callback.
|
|
21
|
+
- `GET /antigravity/callback`: Persist Antigravity OAuth callback.
|
|
22
|
+
- `POST /v1internal:method`: Gemini CLI handler (localhost only). For `generateContent` / `streamGenerateContent`.
|
|
23
|
+
|
|
24
|
+
OpenAI-compatible (`/v1`)
|
|
25
|
+
- `GET /v1/models`: List models (OpenAI or Claude depending on User-Agent).
|
|
26
|
+
- `POST /v1/chat/completions`: Chat Completions (OpenAI-compatible, supports stream).
|
|
27
|
+
- `POST /v1/completions`: Completions (OpenAI-compatible, supports stream).
|
|
28
|
+
- `POST /v1/messages`: Claude-style messages (supports stream).
|
|
29
|
+
- `POST /v1/messages/count_tokens`: Claude token counting.
|
|
30
|
+
- `POST /v1/responses`: OpenAI Responses API (supports stream).
|
|
31
|
+
- `POST /v1/responses/compact`: OpenAI Responses Compact (non-stream).
|
|
32
|
+
|
|
33
|
+
CLIProxy simplified (`/v1/cliproxy`)
|
|
34
|
+
- `GET /v1/cliproxy/auths`: List authenticated accounts and supported models.
|
|
35
|
+
- `GET /v1/cliproxy/models`: List available models (format: openai/claude/gemini/generic).
|
|
36
|
+
- `POST /v1/cliproxy/chat`: Simplified chat proxy (maps to OpenAI chat).
|
|
37
|
+
|
|
38
|
+
Gemini-compatible (`/v1beta`)
|
|
39
|
+
- `GET /v1beta/models`: List Gemini models.
|
|
40
|
+
- `POST /v1beta/models/*action`: Gemini generate/stream endpoints (e.g. `:generateContent`, `:streamGenerateContent`).
|
|
41
|
+
- `GET /v1beta/models/*action`: Gemini GET actions.
|
|
42
|
+
|
|
43
|
+
Management (`/v0/management`, requires management key)
|
|
44
|
+
- `GET /v0/management/usage`: Usage snapshot (in-memory stats).
|
|
45
|
+
- `GET /v0/management/usage/export`: Export usage snapshot.
|
|
46
|
+
- `POST /v0/management/usage/import`: Import usage snapshot.
|
|
47
|
+
- `GET /v0/management/config`: Full config JSON.
|
|
48
|
+
- `GET /v0/management/config.yaml`: Config YAML.
|
|
49
|
+
- `PUT /v0/management/config.yaml`: Replace config YAML (validates then saves).
|
|
50
|
+
- `GET /v0/management/latest-version`: Latest release version (from GitHub).
|
|
51
|
+
- `GET /v0/management/debug`: Debug flag.
|
|
52
|
+
- `PUT /v0/management/debug`: Update debug flag.
|
|
53
|
+
- `PATCH /v0/management/debug`: Update debug flag.
|
|
54
|
+
- `GET /v0/management/logging-to-file`: Logging-to-file flag.
|
|
55
|
+
- `PUT /v0/management/logging-to-file`: Update logging-to-file.
|
|
56
|
+
- `PATCH /v0/management/logging-to-file`: Update logging-to-file.
|
|
57
|
+
- `GET /v0/management/logs-max-total-size-mb`: Logs max size.
|
|
58
|
+
- `PUT /v0/management/logs-max-total-size-mb`: Update logs max size.
|
|
59
|
+
- `PATCH /v0/management/logs-max-total-size-mb`: Update logs max size.
|
|
60
|
+
- `GET /v0/management/error-logs-max-files`: Error logs max files.
|
|
61
|
+
- `PUT /v0/management/error-logs-max-files`: Update error logs max files.
|
|
62
|
+
- `PATCH /v0/management/error-logs-max-files`: Update error logs max files.
|
|
63
|
+
- `GET /v0/management/usage-statistics-enabled`: Usage stats enabled.
|
|
64
|
+
- `PUT /v0/management/usage-statistics-enabled`: Update usage stats enabled.
|
|
65
|
+
- `PATCH /v0/management/usage-statistics-enabled`: Update usage stats enabled.
|
|
66
|
+
- `GET /v0/management/proxy-url`: Proxy URL.
|
|
67
|
+
- `PUT /v0/management/proxy-url`: Update proxy URL.
|
|
68
|
+
- `PATCH /v0/management/proxy-url`: Update proxy URL.
|
|
69
|
+
- `DELETE /v0/management/proxy-url`: Clear proxy URL.
|
|
70
|
+
- `POST /v0/management/api-call`: Test outbound API call using an auth entry.
|
|
71
|
+
- `GET /v0/management/quota-exceeded/switch-project`: Switch project flag.
|
|
72
|
+
- `PUT /v0/management/quota-exceeded/switch-project`: Update switch project flag.
|
|
73
|
+
- `PATCH /v0/management/quota-exceeded/switch-project`: Update switch project flag.
|
|
74
|
+
- `GET /v0/management/quota-exceeded/switch-preview-model`: Switch preview model flag.
|
|
75
|
+
- `PUT /v0/management/quota-exceeded/switch-preview-model`: Update switch preview model flag.
|
|
76
|
+
- `PATCH /v0/management/quota-exceeded/switch-preview-model`: Update switch preview model flag.
|
|
77
|
+
- `GET /v0/management/api-keys`: List API keys.
|
|
78
|
+
- `PUT /v0/management/api-keys`: Replace API keys.
|
|
79
|
+
- `PATCH /v0/management/api-keys`: Patch API keys.
|
|
80
|
+
- `DELETE /v0/management/api-keys`: Delete API keys.
|
|
81
|
+
- `GET /v0/management/gemini-api-key`: List Gemini keys.
|
|
82
|
+
- `PUT /v0/management/gemini-api-key`: Replace Gemini keys.
|
|
83
|
+
- `PATCH /v0/management/gemini-api-key`: Patch Gemini keys.
|
|
84
|
+
- `DELETE /v0/management/gemini-api-key`: Delete Gemini keys.
|
|
85
|
+
- `GET /v0/management/logs`: Read log lines.
|
|
86
|
+
- `DELETE /v0/management/logs`: Clear logs.
|
|
87
|
+
- `GET /v0/management/request-error-logs`: List request error logs.
|
|
88
|
+
- `GET /v0/management/request-error-logs/:name`: Download a request error log.
|
|
89
|
+
- `GET /v0/management/request-log-by-id/:id`: Download request log by request ID.
|
|
90
|
+
- `GET /v0/management/request-log`: Request log enabled flag.
|
|
91
|
+
- `PUT /v0/management/request-log`: Update request log enabled flag.
|
|
92
|
+
- `PATCH /v0/management/request-log`: Update request log enabled flag.
|
|
93
|
+
- `GET /v0/management/ws-auth`: WebSocket auth enabled flag.
|
|
94
|
+
- `PUT /v0/management/ws-auth`: Update WebSocket auth enabled flag.
|
|
95
|
+
- `PATCH /v0/management/ws-auth`: Update WebSocket auth enabled flag.
|
|
96
|
+
- `GET /v0/management/ampcode`: Amp CLI config.
|
|
97
|
+
- `GET /v0/management/ampcode/upstream-url`: Amp upstream URL.
|
|
98
|
+
- `PUT /v0/management/ampcode/upstream-url`: Update Amp upstream URL.
|
|
99
|
+
- `PATCH /v0/management/ampcode/upstream-url`: Update Amp upstream URL.
|
|
100
|
+
- `DELETE /v0/management/ampcode/upstream-url`: Clear Amp upstream URL.
|
|
101
|
+
- `GET /v0/management/ampcode/upstream-api-key`: Amp upstream API key.
|
|
102
|
+
- `PUT /v0/management/ampcode/upstream-api-key`: Update Amp upstream API key.
|
|
103
|
+
- `PATCH /v0/management/ampcode/upstream-api-key`: Update Amp upstream API key.
|
|
104
|
+
- `DELETE /v0/management/ampcode/upstream-api-key`: Clear Amp upstream API key.
|
|
105
|
+
- `GET /v0/management/ampcode/restrict-management-to-localhost`: Restrict Amp management to localhost.
|
|
106
|
+
- `PUT /v0/management/ampcode/restrict-management-to-localhost`: Update restriction.
|
|
107
|
+
- `PATCH /v0/management/ampcode/restrict-management-to-localhost`: Update restriction.
|
|
108
|
+
- `GET /v0/management/ampcode/model-mappings`: List Amp model mappings.
|
|
109
|
+
- `PUT /v0/management/ampcode/model-mappings`: Replace Amp model mappings.
|
|
110
|
+
- `PATCH /v0/management/ampcode/model-mappings`: Patch Amp model mappings.
|
|
111
|
+
- `DELETE /v0/management/ampcode/model-mappings`: Delete Amp model mappings.
|
|
112
|
+
- `GET /v0/management/ampcode/force-model-mappings`: Force model mappings flag.
|
|
113
|
+
- `PUT /v0/management/ampcode/force-model-mappings`: Update force model mappings.
|
|
114
|
+
- `PATCH /v0/management/ampcode/force-model-mappings`: Update force model mappings.
|
|
115
|
+
- `GET /v0/management/ampcode/upstream-api-keys`: List Amp upstream API keys.
|
|
116
|
+
- `PUT /v0/management/ampcode/upstream-api-keys`: Replace Amp upstream API keys.
|
|
117
|
+
- `PATCH /v0/management/ampcode/upstream-api-keys`: Patch Amp upstream API keys.
|
|
118
|
+
- `DELETE /v0/management/ampcode/upstream-api-keys`: Delete Amp upstream API keys.
|
|
119
|
+
- `GET /v0/management/request-retry`: Request retry count.
|
|
120
|
+
- `PUT /v0/management/request-retry`: Update request retry count.
|
|
121
|
+
- `PATCH /v0/management/request-retry`: Update request retry count.
|
|
122
|
+
- `GET /v0/management/max-retry-interval`: Max retry interval.
|
|
123
|
+
- `PUT /v0/management/max-retry-interval`: Update max retry interval.
|
|
124
|
+
- `PATCH /v0/management/max-retry-interval`: Update max retry interval.
|
|
125
|
+
- `GET /v0/management/force-model-prefix`: Force model prefix flag.
|
|
126
|
+
- `PUT /v0/management/force-model-prefix`: Update force model prefix.
|
|
127
|
+
- `PATCH /v0/management/force-model-prefix`: Update force model prefix.
|
|
128
|
+
- `GET /v0/management/routing/strategy`: Routing strategy.
|
|
129
|
+
- `PUT /v0/management/routing/strategy`: Update routing strategy.
|
|
130
|
+
- `PATCH /v0/management/routing/strategy`: Update routing strategy.
|
|
131
|
+
- `GET /v0/management/claude-api-key`: List Claude keys.
|
|
132
|
+
- `PUT /v0/management/claude-api-key`: Replace Claude keys.
|
|
133
|
+
- `PATCH /v0/management/claude-api-key`: Patch Claude keys.
|
|
134
|
+
- `DELETE /v0/management/claude-api-key`: Delete Claude keys.
|
|
135
|
+
- `GET /v0/management/codex-api-key`: List Codex keys.
|
|
136
|
+
- `PUT /v0/management/codex-api-key`: Replace Codex keys.
|
|
137
|
+
- `PATCH /v0/management/codex-api-key`: Patch Codex keys.
|
|
138
|
+
- `DELETE /v0/management/codex-api-key`: Delete Codex keys.
|
|
139
|
+
- `GET /v0/management/openai-compatibility`: List OpenAI compatibility configs.
|
|
140
|
+
- `PUT /v0/management/openai-compatibility`: Replace OpenAI compatibility configs.
|
|
141
|
+
- `PATCH /v0/management/openai-compatibility`: Patch OpenAI compatibility configs.
|
|
142
|
+
- `DELETE /v0/management/openai-compatibility`: Delete OpenAI compatibility configs.
|
|
143
|
+
- `GET /v0/management/vertex-api-key`: List Vertex compatibility keys.
|
|
144
|
+
- `PUT /v0/management/vertex-api-key`: Replace Vertex compatibility keys.
|
|
145
|
+
- `PATCH /v0/management/vertex-api-key`: Patch Vertex compatibility keys.
|
|
146
|
+
- `DELETE /v0/management/vertex-api-key`: Delete Vertex compatibility keys.
|
|
147
|
+
- `GET /v0/management/oauth-excluded-models`: List OAuth excluded models.
|
|
148
|
+
- `PUT /v0/management/oauth-excluded-models`: Replace OAuth excluded models.
|
|
149
|
+
- `PATCH /v0/management/oauth-excluded-models`: Patch OAuth excluded models.
|
|
150
|
+
- `DELETE /v0/management/oauth-excluded-models`: Delete OAuth excluded models.
|
|
151
|
+
- `GET /v0/management/oauth-model-alias`: List OAuth model alias.
|
|
152
|
+
- `PUT /v0/management/oauth-model-alias`: Replace OAuth model alias.
|
|
153
|
+
- `PATCH /v0/management/oauth-model-alias`: Patch OAuth model alias.
|
|
154
|
+
- `DELETE /v0/management/oauth-model-alias`: Delete OAuth model alias.
|
|
155
|
+
- `GET /v0/management/auth-files`: List auth files.
|
|
156
|
+
- `GET /v0/management/auth-files/models`: Get models for an auth file.
|
|
157
|
+
- `GET /v0/management/model-definitions/:channel`: Get static model definitions.
|
|
158
|
+
- `GET /v0/management/auth-files/download`: Download auth file.
|
|
159
|
+
- `POST /v0/management/auth-files`: Upload auth file.
|
|
160
|
+
- `DELETE /v0/management/auth-files`: Delete auth file.
|
|
161
|
+
- `PATCH /v0/management/auth-files/status`: Enable/disable auth file.
|
|
162
|
+
- `POST /v0/management/vertex/import`: Import Vertex credentials.
|
|
163
|
+
- OAuth token helpers:
|
|
164
|
+
- `GET /v0/management/anthropic-auth-url`: Start Anthropic OAuth.
|
|
165
|
+
- `GET /v0/management/codex-auth-url`: Start Codex OAuth.
|
|
166
|
+
- `GET /v0/management/gemini-cli-auth-url`: Start Gemini CLI OAuth.
|
|
167
|
+
- `GET /v0/management/antigravity-auth-url`: Start Antigravity OAuth.
|
|
168
|
+
- `GET /v0/management/qwen-auth-url`: Start Qwen OAuth.
|
|
169
|
+
- `GET /v0/management/kimi-auth-url`: Start Kimi OAuth.
|
|
170
|
+
- `GET /v0/management/iflow-auth-url`: Start iFlow OAuth.
|
|
171
|
+
- `POST /v0/management/iflow-auth-url`: Submit iFlow cookie token.
|
|
172
|
+
- `POST /v0/management/oauth-callback`: Post OAuth callback data.
|
|
173
|
+
- `GET /v0/management/get-auth-status`: Poll OAuth status.
|
|
174
|
+
|
|
175
|
+
## Install
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
npm i
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Build
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
npm run build
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Exports
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
import {
|
|
191
|
+
// WS relay
|
|
192
|
+
CliproxyWSProvider,
|
|
193
|
+
CliproxyWSClient,
|
|
194
|
+
decodeRequest,
|
|
195
|
+
encodeResponse,
|
|
196
|
+
encodeChunk,
|
|
197
|
+
encodeError,
|
|
198
|
+
type HTTPRequest,
|
|
199
|
+
type HTTPResponse,
|
|
200
|
+
type ProviderOptions,
|
|
201
|
+
type ProviderEvent,
|
|
202
|
+
type WSRequestContext,
|
|
203
|
+
|
|
204
|
+
// HTTP clients by service
|
|
205
|
+
CliproxyClient,
|
|
206
|
+
OpenAIClient,
|
|
207
|
+
ClaudeClient,
|
|
208
|
+
GeminiClient,
|
|
209
|
+
ManagementClient,
|
|
210
|
+
|
|
211
|
+
// Primary request types
|
|
212
|
+
type PrimaryOpenAIChatRequest,
|
|
213
|
+
type PrimaryClaudeRequest,
|
|
214
|
+
type PrimaryGeminiRequest,
|
|
215
|
+
type PrimaryCliproxyRequest
|
|
216
|
+
} from 'event-ws-cliproxyapi-sdk';
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Types (Events and Protocol)
|
|
220
|
+
|
|
221
|
+
### Events (SDK level)
|
|
222
|
+
|
|
223
|
+
- `ProviderEvent`
|
|
224
|
+
- `ws:open` – WebSocket connected
|
|
225
|
+
- `ws:close` – WebSocket closed
|
|
226
|
+
- `request` – server sent an `http_request`
|
|
227
|
+
- `error` – handler error
|
|
228
|
+
|
|
229
|
+
### Protocol messages (WS level)
|
|
230
|
+
|
|
231
|
+
- `WSMessageType`
|
|
232
|
+
- `http_request` (server → client)
|
|
233
|
+
- `http_response` (client → server)
|
|
234
|
+
- `stream_start` / `stream_chunk` / `stream_end` (client → server)
|
|
235
|
+
- `error` (client → server)
|
|
236
|
+
- `ping` / `pong`
|
|
237
|
+
|
|
238
|
+
### Request/Response types
|
|
239
|
+
|
|
240
|
+
- `HTTPRequest`
|
|
241
|
+
- `method`, `url`, `headers`, `body`, `sent_at`
|
|
242
|
+
- `HTTPResponse`
|
|
243
|
+
- `status`, `headers`, `body`
|
|
244
|
+
|
|
245
|
+
### Helper context
|
|
246
|
+
|
|
247
|
+
- `WSRequestContext`
|
|
248
|
+
- `respond(resp)`
|
|
249
|
+
- `streamStart(status?, headers?)`
|
|
250
|
+
- `streamChunk(chunk)`
|
|
251
|
+
- `streamEnd()`
|
|
252
|
+
- `error(message, status?)`
|
|
253
|
+
|
|
254
|
+
## Usage (Provider Relay)
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
import { CliproxyWSProvider } from 'event-ws-cliproxyapi-sdk';
|
|
258
|
+
|
|
259
|
+
const provider = new CliproxyWSProvider({
|
|
260
|
+
baseUrl: 'http://127.0.0.1:8317',
|
|
261
|
+
accessKey: 'andev'
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
await provider.connect({
|
|
265
|
+
onEvent: (ev) => {
|
|
266
|
+
if (ev.type === 'ws:open') console.log('ws open');
|
|
267
|
+
if (ev.type === 'ws:close') console.log('ws close', ev.code, ev.reason);
|
|
268
|
+
},
|
|
269
|
+
onRequest: async (req, ctx) => {
|
|
270
|
+
if (req.url === '/v1/cliproxy/chat') {
|
|
271
|
+
ctx.streamStart(200, { 'Content-Type': 'text/plain' });
|
|
272
|
+
ctx.streamChunk('hello ');
|
|
273
|
+
ctx.streamChunk('world');
|
|
274
|
+
ctx.streamEnd();
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
ctx.respond({ status: 404, body: 'not found' });
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
provider.close();
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Usage (HTTP Client)
|
|
285
|
+
|
|
286
|
+
```ts
|
|
287
|
+
import { CliproxyClient, OpenAIClient, ClaudeClient, GeminiClient, ManagementClient } from 'event-ws-cliproxyapi-sdk';
|
|
288
|
+
|
|
289
|
+
const cliproxy = new CliproxyClient({
|
|
290
|
+
baseUrl: 'http://127.0.0.1:8317',
|
|
291
|
+
accessKey: 'your-access-key',
|
|
292
|
+
managementKey: 'your-management-key'
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// Public: list auths
|
|
296
|
+
const auths = await cliproxy.getCliproxyAuths();
|
|
297
|
+
|
|
298
|
+
// OpenAI-compatible chat
|
|
299
|
+
const openai = new OpenAIClient({ baseUrl: 'http://127.0.0.1:8317', accessKey: 'your-access-key' });
|
|
300
|
+
await openai.postChatCompletions({
|
|
301
|
+
model: 'gpt-4o-mini',
|
|
302
|
+
messages: [
|
|
303
|
+
{ role: 'user', content: [{ type: 'text', text: 'hello' }] }
|
|
304
|
+
]
|
|
305
|
+
});
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## Response Types
|
|
309
|
+
|
|
310
|
+
OpenAI-compatible
|
|
311
|
+
- `OpenAIChatCompletionResponse` (non-stream)
|
|
312
|
+
- `OpenAIChatCompletionChunk` (stream)
|
|
313
|
+
- `OpenAICompletionResponse` (non-stream)
|
|
314
|
+
- `OpenAICompletionChunk` (stream)
|
|
315
|
+
- `OpenAIResponsesResponse` (non-stream)
|
|
316
|
+
- `OpenAIResponsesChunk` (stream)
|
|
317
|
+
|
|
318
|
+
Claude-compatible
|
|
319
|
+
- `ClaudeMessagesResponse` (non-stream)
|
|
320
|
+
- `ClaudeStreamEvent` (stream)
|
|
321
|
+
|
|
322
|
+
Gemini-compatible
|
|
323
|
+
- `GeminiGenerateContentResponse` (non-stream)
|
|
324
|
+
- `GeminiStreamChunk` (stream)
|
|
325
|
+
|
|
326
|
+
Errors
|
|
327
|
+
- `OpenAIErrorResponse` (OpenAI-style `{ error: { message, type, code? } }`)
|
|
328
|
+
- `ErrorResponse` (management `{ error: string, message?: string }`)
|
|
329
|
+
- `StatusResponse` (status polling `{ status: "ok" | "error" | "wait", error?: string }`)
|
|
330
|
+
- `APIError` (thrown by service clients on non-2xx)
|
|
331
|
+
|
|
332
|
+
## Response Examples (OK / Failed)
|
|
333
|
+
|
|
334
|
+
OpenAI Chat Completions (OK, non-stream):
|
|
335
|
+
```json
|
|
336
|
+
{
|
|
337
|
+
"id": "chatcmpl_123",
|
|
338
|
+
"object": "chat.completion",
|
|
339
|
+
"created": 1730000000,
|
|
340
|
+
"model": "gpt-4o-mini",
|
|
341
|
+
"choices": [
|
|
342
|
+
{
|
|
343
|
+
"index": 0,
|
|
344
|
+
"message": { "role": "assistant", "content": "hello" },
|
|
345
|
+
"finish_reason": "stop"
|
|
346
|
+
}
|
|
347
|
+
],
|
|
348
|
+
"usage": { "total_tokens": 10 }
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
OpenAI Chat Completions (Failed):
|
|
353
|
+
```json
|
|
354
|
+
{
|
|
355
|
+
"error": {
|
|
356
|
+
"message": "Invalid request: Missing model",
|
|
357
|
+
"type": "invalid_request_error",
|
|
358
|
+
"code": "invalid_request_error"
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Claude Messages (OK, non-stream):
|
|
364
|
+
```json
|
|
365
|
+
{
|
|
366
|
+
"id": "msg_123",
|
|
367
|
+
"type": "message",
|
|
368
|
+
"role": "assistant",
|
|
369
|
+
"model": "claude-3-5-sonnet",
|
|
370
|
+
"content": [{ "type": "text", "text": "hello" }],
|
|
371
|
+
"stop_reason": "end_turn",
|
|
372
|
+
"usage": { "input_tokens": 5, "output_tokens": 5 }
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Claude Messages (Failed):
|
|
377
|
+
```json
|
|
378
|
+
{ "error": "invalid request" }
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Gemini GenerateContent (OK, non-stream):
|
|
382
|
+
```json
|
|
383
|
+
{
|
|
384
|
+
"candidates": [
|
|
385
|
+
{
|
|
386
|
+
"content": {
|
|
387
|
+
"role": "model",
|
|
388
|
+
"parts": [{ "text": "hello" }]
|
|
389
|
+
},
|
|
390
|
+
"finishReason": "STOP",
|
|
391
|
+
"index": 0
|
|
392
|
+
}
|
|
393
|
+
]
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
Gemini GenerateContent (Failed):
|
|
398
|
+
```json
|
|
399
|
+
{ "error": "invalid request" }
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
Management (Failed):
|
|
403
|
+
```json
|
|
404
|
+
{ "error": "invalid management key" }
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## Image + Text in One Message
|
|
408
|
+
|
|
409
|
+
```ts
|
|
410
|
+
await openai.postChatCompletions({
|
|
411
|
+
model: 'gpt-4o-mini',
|
|
412
|
+
messages: [
|
|
413
|
+
{
|
|
414
|
+
role: 'user',
|
|
415
|
+
content: [
|
|
416
|
+
{ type: 'text', text: 'describe this image' },
|
|
417
|
+
{ type: 'image_url', image_url: { url: 'https://example.com/cat.jpg' } }
|
|
418
|
+
]
|
|
419
|
+
}
|
|
420
|
+
]
|
|
421
|
+
});
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
## Notes
|
|
425
|
+
|
|
426
|
+
- For WS relay, if `ws-auth: true`, pass `accessKey` as `Authorization: Bearer ...`.
|
|
427
|
+
- Management APIs require `managementKey` (or local password for `/keep-alive` if enabled).
|
|
428
|
+
- HTTP client returns `Response` for streaming endpoints; parse SSE or chunks based on your client.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ClaudeMessagesRequest, ModelListResponse } from '../shared/types.js';
|
|
2
|
+
import type { RequestOptions } from '../shared/http.js';
|
|
3
|
+
import { BaseHttpClient } from '../shared/http.js';
|
|
4
|
+
export declare class ClaudeClient extends BaseHttpClient {
|
|
5
|
+
getModels(options?: RequestOptions): Promise<ModelListResponse>;
|
|
6
|
+
postMessages(body: ClaudeMessagesRequest, options?: RequestOptions): Promise<Response>;
|
|
7
|
+
postMessagesCountTokens(body: ClaudeMessagesRequest, options?: RequestOptions): Promise<Response>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BaseHttpClient } from '../shared/http.js';
|
|
2
|
+
export class ClaudeClient extends BaseHttpClient {
|
|
3
|
+
// GET /v1/models (Claude response when User-Agent starts with "claude-cli")
|
|
4
|
+
getModels(options) {
|
|
5
|
+
const headers = { ...(options?.headers ?? {}), 'User-Agent': 'claude-cli' };
|
|
6
|
+
return this.requestJson('GET', '/v1/models', undefined, { ...options, headers }, 'access');
|
|
7
|
+
}
|
|
8
|
+
// POST /v1/messages
|
|
9
|
+
postMessages(body, options) {
|
|
10
|
+
return this.requestRaw('POST', '/v1/messages', JSON.stringify(body), options, 'access');
|
|
11
|
+
}
|
|
12
|
+
// POST /v1/messages/count_tokens
|
|
13
|
+
postMessagesCountTokens(body, options) {
|
|
14
|
+
return this.requestRaw('POST', '/v1/messages/count_tokens', JSON.stringify(body), options, 'access');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { ClaudeClient } from './client.js';
|
|
2
|
+
export type { ClaudeMessageRole, ClaudeContentText, ClaudeContentImage, ClaudeContentBlock, ClaudeMessage, ClaudeMessagesRequest, ClaudeUsage, ClaudeMessagesResponse, ClaudeStreamEventType, ClaudeStreamEvent, ClaudeCompatibleRequest, ClaudeCompatibleResponse } from '../shared/types.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ClaudeClient } from './client.js';
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { HTTPRequest, ProviderEvent, ProviderOptions, WSRequestContext } from './types.js';
|
|
2
|
+
export interface ProviderHandlers {
|
|
3
|
+
onRequest: (req: HTTPRequest, ctx: WSRequestContext) => void | Promise<void>;
|
|
4
|
+
onEvent?: (ev: ProviderEvent) => void;
|
|
5
|
+
}
|
|
6
|
+
export declare class CliproxyWSProvider {
|
|
7
|
+
private ws?;
|
|
8
|
+
private options;
|
|
9
|
+
private handlers?;
|
|
10
|
+
constructor(options: ProviderOptions);
|
|
11
|
+
connect(handlers: ProviderHandlers): Promise<void>;
|
|
12
|
+
close(): void;
|
|
13
|
+
private handleMessage;
|
|
14
|
+
private handleClose;
|
|
15
|
+
private buildContext;
|
|
16
|
+
private sendMessage;
|
|
17
|
+
}
|
|
18
|
+
export declare class CliproxyWSClient extends CliproxyWSProvider {
|
|
19
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import WebSocket from 'ws';
|
|
2
|
+
import { decodeRequest, encodeChunk, encodeError, encodeResponse } from './codec.js';
|
|
3
|
+
export class CliproxyWSProvider {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
this.options = options;
|
|
6
|
+
}
|
|
7
|
+
connect(handlers) {
|
|
8
|
+
this.handlers = handlers;
|
|
9
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN)
|
|
10
|
+
return Promise.resolve();
|
|
11
|
+
const base = this.options.baseUrl.replace(/\/+$/, '');
|
|
12
|
+
const url = `${base.replace(/^http/, 'ws')}/v1/ws`;
|
|
13
|
+
const headers = {};
|
|
14
|
+
if (this.options.accessKey)
|
|
15
|
+
headers['Authorization'] = `Bearer ${this.options.accessKey}`;
|
|
16
|
+
this.ws = new WebSocket(url, { headers });
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
const ws = this.ws;
|
|
19
|
+
const onOpen = () => {
|
|
20
|
+
this.handlers?.onEvent?.({ type: 'ws:open' });
|
|
21
|
+
resolve();
|
|
22
|
+
};
|
|
23
|
+
const onErr = (err) => reject(err);
|
|
24
|
+
ws.once('open', onOpen);
|
|
25
|
+
ws.once('error', onErr);
|
|
26
|
+
ws.on('message', (raw) => this.handleMessage(raw.toString()));
|
|
27
|
+
ws.on('close', (code, reason) => this.handleClose(code, reason.toString()));
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
close() {
|
|
31
|
+
this.ws?.close();
|
|
32
|
+
}
|
|
33
|
+
handleMessage(raw) {
|
|
34
|
+
let msg;
|
|
35
|
+
try {
|
|
36
|
+
msg = JSON.parse(raw);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (!msg || !msg.id || !msg.type)
|
|
42
|
+
return;
|
|
43
|
+
if (msg.type === 'ping') {
|
|
44
|
+
this.sendMessage('pong', msg.id);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (msg.type !== 'http_request')
|
|
48
|
+
return;
|
|
49
|
+
const req = decodeRequest(msg.payload);
|
|
50
|
+
const ctx = this.buildContext(msg.id);
|
|
51
|
+
this.handlers?.onEvent?.({ type: 'request', requestId: msg.id, request: req });
|
|
52
|
+
try {
|
|
53
|
+
const result = this.handlers?.onRequest(req, ctx);
|
|
54
|
+
if (result && typeof result.then === 'function') {
|
|
55
|
+
result.catch((err) => {
|
|
56
|
+
ctx.error(err?.message ?? 'provider error');
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
ctx.error(err instanceof Error ? err.message : 'provider error');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
handleClose(code, reason) {
|
|
65
|
+
this.handlers?.onEvent?.({ type: 'ws:close', code, reason });
|
|
66
|
+
}
|
|
67
|
+
buildContext(requestId) {
|
|
68
|
+
return {
|
|
69
|
+
requestId,
|
|
70
|
+
respond: (resp) => {
|
|
71
|
+
this.sendMessage('http_response', requestId, encodeResponse(resp));
|
|
72
|
+
},
|
|
73
|
+
streamStart: (status, headers) => {
|
|
74
|
+
const payload = encodeResponse({ status: status ?? 200, headers, body: '' });
|
|
75
|
+
this.sendMessage('stream_start', requestId, payload);
|
|
76
|
+
},
|
|
77
|
+
streamChunk: (chunk) => {
|
|
78
|
+
this.sendMessage('stream_chunk', requestId, encodeChunk(chunk));
|
|
79
|
+
},
|
|
80
|
+
streamEnd: () => {
|
|
81
|
+
this.sendMessage('stream_end', requestId);
|
|
82
|
+
},
|
|
83
|
+
error: (message, status) => {
|
|
84
|
+
this.sendMessage('error', requestId, encodeError(message, status));
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
sendMessage(type, id, payload) {
|
|
89
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN)
|
|
90
|
+
return;
|
|
91
|
+
const msg = (payload === undefined ? { id, type } : { id, type, payload });
|
|
92
|
+
this.ws.send(JSON.stringify(msg));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export class CliproxyWSClient extends CliproxyWSProvider {
|
|
96
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { CliproxyAuthsQuery, CliproxyAuthsResponse, CliproxyChatRequest, CliproxyModelsQuery, CliproxyModelsResponse, KeepAliveResponse, RootResponse } from '../shared/types.js';
|
|
2
|
+
import type { RequestOptions } from '../shared/http.js';
|
|
3
|
+
import { BaseHttpClient } from '../shared/http.js';
|
|
4
|
+
export declare class CliproxyClient extends BaseHttpClient {
|
|
5
|
+
getRoot(): Promise<RootResponse>;
|
|
6
|
+
getManagementHtml(): Promise<Response>;
|
|
7
|
+
keepAlive(): Promise<KeepAliveResponse>;
|
|
8
|
+
anthropicCallback(query: {
|
|
9
|
+
code?: string;
|
|
10
|
+
state?: string;
|
|
11
|
+
error?: string;
|
|
12
|
+
error_description?: string;
|
|
13
|
+
}): Promise<Response>;
|
|
14
|
+
codexCallback(query: {
|
|
15
|
+
code?: string;
|
|
16
|
+
state?: string;
|
|
17
|
+
error?: string;
|
|
18
|
+
error_description?: string;
|
|
19
|
+
}): Promise<Response>;
|
|
20
|
+
googleCallback(query: {
|
|
21
|
+
code?: string;
|
|
22
|
+
state?: string;
|
|
23
|
+
error?: string;
|
|
24
|
+
error_description?: string;
|
|
25
|
+
}): Promise<Response>;
|
|
26
|
+
iflowCallback(query: {
|
|
27
|
+
code?: string;
|
|
28
|
+
state?: string;
|
|
29
|
+
error?: string;
|
|
30
|
+
error_description?: string;
|
|
31
|
+
}): Promise<Response>;
|
|
32
|
+
antigravityCallback(query: {
|
|
33
|
+
code?: string;
|
|
34
|
+
state?: string;
|
|
35
|
+
error?: string;
|
|
36
|
+
error_description?: string;
|
|
37
|
+
}): Promise<Response>;
|
|
38
|
+
getCliproxyAuths(query?: CliproxyAuthsQuery): Promise<CliproxyAuthsResponse>;
|
|
39
|
+
getCliproxyModels(query?: CliproxyModelsQuery): Promise<CliproxyModelsResponse>;
|
|
40
|
+
postCliproxyChat(body: CliproxyChatRequest, options?: RequestOptions): Promise<Response>;
|
|
41
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { BaseHttpClient } from '../shared/http.js';
|
|
2
|
+
export class CliproxyClient extends BaseHttpClient {
|
|
3
|
+
// GET /
|
|
4
|
+
getRoot() {
|
|
5
|
+
return this.requestJson('GET', '/');
|
|
6
|
+
}
|
|
7
|
+
// GET /management.html
|
|
8
|
+
getManagementHtml() {
|
|
9
|
+
return this.requestRaw('GET', '/management.html');
|
|
10
|
+
}
|
|
11
|
+
// GET /keep-alive (local password if configured)
|
|
12
|
+
keepAlive() {
|
|
13
|
+
return this.requestJson('GET', '/keep-alive', undefined, undefined, 'local');
|
|
14
|
+
}
|
|
15
|
+
// OAuth callbacks
|
|
16
|
+
anthropicCallback(query) {
|
|
17
|
+
return this.requestRaw('GET', '/anthropic/callback', undefined, { query });
|
|
18
|
+
}
|
|
19
|
+
codexCallback(query) {
|
|
20
|
+
return this.requestRaw('GET', '/codex/callback', undefined, { query });
|
|
21
|
+
}
|
|
22
|
+
googleCallback(query) {
|
|
23
|
+
return this.requestRaw('GET', '/google/callback', undefined, { query });
|
|
24
|
+
}
|
|
25
|
+
iflowCallback(query) {
|
|
26
|
+
return this.requestRaw('GET', '/iflow/callback', undefined, { query });
|
|
27
|
+
}
|
|
28
|
+
antigravityCallback(query) {
|
|
29
|
+
return this.requestRaw('GET', '/antigravity/callback', undefined, { query });
|
|
30
|
+
}
|
|
31
|
+
// GET /v1/cliproxy/auths
|
|
32
|
+
getCliproxyAuths(query) {
|
|
33
|
+
return this.requestJson('GET', '/v1/cliproxy/auths', undefined, { query: query }, 'access');
|
|
34
|
+
}
|
|
35
|
+
// GET /v1/cliproxy/models
|
|
36
|
+
getCliproxyModels(query) {
|
|
37
|
+
return this.requestJson('GET', '/v1/cliproxy/models', undefined, { query: query }, 'access');
|
|
38
|
+
}
|
|
39
|
+
// POST /v1/cliproxy/chat
|
|
40
|
+
postCliproxyChat(body, options) {
|
|
41
|
+
return this.requestRaw('POST', '/v1/cliproxy/chat', JSON.stringify(body), options, 'access');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { CliproxyClient } from './client.js';
|