glmproxy 2.5.1
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 +434 -0
- package/anthropic.js +734 -0
- package/bin/cli.js +406 -0
- package/lib/constants.js +18 -0
- package/lib/core.js +1434 -0
- package/lib/fallback-models.json +10 -0
- package/lib/prompts.js +113 -0
- package/main.js +10 -0
- package/openai.js +425 -0
- package/package.json +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 eequaled
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
# GLM Proxy
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<b>A lightweight local proxy that exposes AutoClaw's AI models through<br>OpenAI-compatible and Anthropic-compatible APIs.</b>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen" alt="Node.js >=18">
|
|
9
|
+
<img src="https://img.shields.io/badge/license-MIT-blue" alt="License MIT">
|
|
10
|
+
<img src="https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey" alt="Platform">
|
|
11
|
+
<img src="https://img.shields.io/npm/v/glmproxy" alt="npm version">
|
|
12
|
+
<img src="https://img.shields.io/npm/dm/glmproxy" alt="npm downloads">
|
|
13
|
+
<img src="https://github.com/eequaled/GLM_proxy/actions/workflows/ci.yml/badge.svg" alt="CI">
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
> **v2.5.1** — one interactive CLI, shared core in `lib/`, zero dependencies. Install with `npm i -g glmproxy` or run with `npx glmproxy`.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Models are fetched automatically
|
|
21
|
+
|
|
22
|
+
Point any OpenAI-compatible harness at `http://127.0.0.1:18791/v1` and it can pull the **live model catalog** through `GET /v1/models` — no config to maintain. The list is re-read from AutoClaw's runtime catalog on every request, so models AutoClaw adds or removes show up without a proxy restart. The Anthropic entrypoint (`/v1/models` on port `18792`) serves the same catalog in Anthropic's list shape.
|
|
23
|
+
|
|
24
|
+
**GLM-5.3-Flash (known as "OX-alpha")** is in the proxy too — served through the local-agent route (see [Models](#models) for the exact caveats).
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
Two API formats, one launcher. `node bin/cli.js` asks which one you want with an arrow-key menu and starts the right proxy. Flags skip the menu.
|
|
29
|
+
|
|
30
|
+
| Format | Flag | Default port | Use with |
|
|
31
|
+
|--------|------|--------------|----------|
|
|
32
|
+
| OpenAI (`/v1/chat/completions`) | `--openai` (default) | `18791` | OpenCode, Cursor, Continue, LiteLLM, Python/JS SDKs |
|
|
33
|
+
| Anthropic (`/v1/messages`) | `--anthropic` | `18792` | Claude Code CLI, Anthropic SDK |
|
|
34
|
+
|
|
35
|
+
## Screenshots
|
|
36
|
+
|
|
37
|
+
### 1. Prerequisites — AutoClaw running as your background service
|
|
38
|
+
|
|
39
|
+
Make sure **AutoClaw is running and you're logged in**. The proxy reads auth from AutoClaw's local token file — as long as the AutoClaw desktop app is open, the proxy works.
|
|
40
|
+
|
|
41
|
+
<p align="center">
|
|
42
|
+
<i>Screenshot: AutoClaw desktop app running and logged in (background service)</i>
|
|
43
|
+
<br>
|
|
44
|
+
<img src="./screenshots/autoclaw-background.png" alt="AutoClaw running as background service" width="700">
|
|
45
|
+
</p>
|
|
46
|
+
|
|
47
|
+
### 2. Proxy in action — it works
|
|
48
|
+
|
|
49
|
+
Start the proxy and watch it handle requests from your tool of choice.
|
|
50
|
+
|
|
51
|
+
<p align="center">
|
|
52
|
+
<i>ignore claude code here</i>
|
|
53
|
+
<br>
|
|
54
|
+
<img src="./screenshots/image.png" alt="Proxy terminal showing successful operation" width="700">
|
|
55
|
+
</p>
|
|
56
|
+
|
|
57
|
+
## How it works
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
Your App AutoClaw Proxy CLI AutoClaw Backend
|
|
61
|
+
(OpenAI SDK) ───▶ localhost:18791 (menu) ───▶ autoglm-api.autoglm.ai
|
|
62
|
+
localhost:18792 (menu)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
AutoClaw handles authentication automatically. As long as AutoClaw is running and you're logged in, the proxy will work — no manual token setup needed.
|
|
66
|
+
|
|
67
|
+
The proxy speaks AutoClaw's native upstream dialect (client headers, bare model ids, and the app's system-prompt banner injected into every request — without that banner the cloud returns 400 `"invalid request"`). When the cloud fails, requests fall back to AutoClaw's own desktop agent over a local WebSocket (`127.0.0.1:18789`).
|
|
68
|
+
|
|
69
|
+
## Prerequisites
|
|
70
|
+
|
|
71
|
+
- [AutoClaw](https://autoclaw.com) installed, running, and logged in (Windows / macOS only)
|
|
72
|
+
- Node.js 18+
|
|
73
|
+
|
|
74
|
+
## Quick Start
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npm start
|
|
78
|
+
# or: node bin/cli.js
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
You get an interactive menu: arrow keys to move, Enter to pick. Choose the format, port, host, and auth key, and the proxy starts. Ctrl+C quits cleanly and restores your terminal. The menu also offers **Model Doctor** (catalog + credit-tier routing) and **Test Models** (live health check) without starting a proxy.
|
|
82
|
+
|
|
83
|
+
Skip the menu with flags:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
node bin/cli.js --anthropic --port 3001 --key mykey
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Or feed config through env vars — the CLI leaves existing env vars alone:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
PORT=3001 PROXY_KEY=mykey RATE_LIMIT=50 node bin/cli.js
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Without a TTY (piped stdin, CI), the CLI skips the menu and starts the OpenAI format on port 18791 using your env vars or the defaults.
|
|
96
|
+
|
|
97
|
+
### npm commands
|
|
98
|
+
|
|
99
|
+
| Command | What it does |
|
|
100
|
+
|---------|--------------|
|
|
101
|
+
| `npm start` | Launch the interactive CLI (`node bin/cli.js`) |
|
|
102
|
+
| `npm run anthropic` | Start the Anthropic proxy directly (`node anthropic.js`), bypassing the menu |
|
|
103
|
+
| `npm test` | Run the pen-test suite (`tests/pen-test-p1` through `p5`), plus the error-taxonomy tests (`tests/taxonomy.mjs`) and runtime-catalog refresh test (`tests/catalog-refresh.mjs`) |
|
|
104
|
+
|
|
105
|
+
### Direct entry points (optional)
|
|
106
|
+
|
|
107
|
+
You can still run either proxy directly without the CLI:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
node openai.js # OpenAI format, port 18791
|
|
111
|
+
node anthropic.js # Anthropic format, port 18792
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
They read the same env vars and respect `HOST`, `PORT`, `PROXY_KEY`, `RATE_LIMIT`, etc.
|
|
115
|
+
|
|
116
|
+
### Options
|
|
117
|
+
|
|
118
|
+
| Variable / Flag | Default | Description |
|
|
119
|
+
|-----------------|---------|-------------|
|
|
120
|
+
| `PORT` / `--port` | `18791` (OpenAI), `18792` (Anthropic) | Port this proxy listens on |
|
|
121
|
+
| `HOST` / `--host` | `127.0.0.1` | Bind address |
|
|
122
|
+
| `PROXY_KEY` / `--key` | `mewmew` | API key clients must send |
|
|
123
|
+
| `RATE_LIMIT` / `--rate-limit` | `30` | Max requests per second per client IP |
|
|
124
|
+
| `MAX_MESSAGES` / `--max-messages` | unlimited (`0`/unset) | Max message / entity limit in request payload (explicit values: 128, 256, 512, 1024). Leave unlimited if your harness compresses or batches history — raise it if you hit `413 / payload too large` |
|
|
125
|
+
| `LOG_LEVEL` | `info` | `debug` / `info` / `silent` |
|
|
126
|
+
| `PREFER_LOCAL` | off | Set to `1` to use the local AutoClaw gateway first, skipping cloud attempts |
|
|
127
|
+
| `TRUSTED_PROXIES` | empty | Comma-separated IPs whose `X-Forwarded-For` header is trusted for rate limiting |
|
|
128
|
+
| `MAX_BODY_BYTES` | `52428800` | Max request body (50 MB) |
|
|
129
|
+
| `JSONL_LOG` | off | Write structured JSONL request log when `true` |
|
|
130
|
+
| `JSONL_FILE` | `proxy_requests.jsonl` (Anthropic: `proxy_requests_anthropic.jsonl`) | JSONL output path |
|
|
131
|
+
| `JSONL_MAX_BYTES` | `10485760` | Rotate JSONL log when it exceeds this (10 MB) |
|
|
132
|
+
| `UPSTREAM_TIMEOUT_MS` | `120000` | Per-attempt upstream budget (idle-based; the vendor allows up to 20 min — raise this for slow thinking models) |
|
|
133
|
+
| `GATEWAY_MIN_PROTOCOL` / `GATEWAY_MAX_PROTOCOL` | `3` / `4` | Local-gateway WS protocol range offered on connect (the proxy self-heals to the gateway's expected protocol on mismatch) |
|
|
134
|
+
| `LOCAL_GATEWAY_HOST` / `LOCAL_GATEWAY_PORT` | `127.0.0.1` / `18789` | Where the AutoClaw desktop gateway is expected |
|
|
135
|
+
| `FALLBACK_MODELS_PATH` | empty | Path to an external fallback model catalog JSON (`{"models":[...]}`) — defaults to the shipped `lib/fallback-models.json` |
|
|
136
|
+
| `AUTOCLAW_SYSTEM_BANNER` | built-in | Override the system-prompt banner injected into cloud requests (keep the `## Tooling` line intact) |
|
|
137
|
+
| `--anthropic` | — | Run in Anthropic API format |
|
|
138
|
+
| `--openai` | — | Run in OpenAI API format (default) |
|
|
139
|
+
| `--doctor` | — | Scan AutoClaw's current runtime model catalog and show Anthropic routing |
|
|
140
|
+
| `--test-models` / `--test` | — | Live health check: test every catalog model through the full pipeline |
|
|
141
|
+
| `--help`, `-h` | — | Show CLI help |
|
|
142
|
+
|
|
143
|
+
### JSONL Request Logging
|
|
144
|
+
|
|
145
|
+
Set `JSONL_LOG=true` (or `LOG_LEVEL=debug`) to write one JSON line per request:
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{"ts":"2026-07-29T03:41:00.000Z","model":"zai_auto","status":200,"ip":"127.0.0.1","latencyMs":423}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The Anthropic variant writes to `proxy_requests_anthropic.jsonl`.
|
|
152
|
+
|
|
153
|
+
Alongside the JSONL stream, a compact ring log (`proxy_requests.json`, last 50 entries) records every terminal outcome — including `via: "local"` and the cloud verdict (`cloud_status` / `cloud_error`) when the cloud rejected a request that the local agent ended up serving.
|
|
154
|
+
|
|
155
|
+
### Model doctor
|
|
156
|
+
|
|
157
|
+
Run the doctor to scan AutoClaw's live model catalog with **credit tiers** fetched from its remote model-config (falling back to the runtime file, then built-ins), and print the Claude alias routing map computed by the same resolver the Anthropic proxy uses:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
node bin/cli.js --doctor
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Anthropic routing follows credit tiers: opus → High, sonnet → Medium, haiku → Low. UI display names can differ from API ids (the API's `zaicoding_glm-5.3` shows as "GLM-5.2" in AutoClaw's UI).
|
|
164
|
+
|
|
165
|
+
### Model health test
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
node bin/cli.js --test-models
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Spawns a throwaway proxy on a test port and fires a minimal prompt at **every model in the catalog**, reporting live status per model:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
✔ working [cloud ok] (1.2s) → PONG
|
|
175
|
+
✔ working [cloud 402 → local agent] (38.4s) → PONG 🦞
|
|
176
|
+
✗ failed (404) (0.9s) → Model ... is not recognized by AutoClaw upstream
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The cloud verdict comes from the isolated test ring log: a `[cloud ok]` tag means the cloud served it; `[cloud NNN → local agent]` means the cloud rejected it (HTTP NNN) and AutoClaw's desktop-agent fallback answered. Zero-usage responses are the local-agent signature. The test uses isolated log files so it never clobbers your running proxy's records.
|
|
180
|
+
|
|
181
|
+
## Self-hosting behind a reverse proxy
|
|
182
|
+
|
|
183
|
+
The proxy binds to `127.0.0.1` by default. To run it on a server (e.g. a VPS) and expose it with TLS, bind to all interfaces and put a reverse proxy in front:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
node bin/cli.js --host 0.0.0.0 --port 18791 --key change-me
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Caddy** (automatic HTTPS):
|
|
190
|
+
|
|
191
|
+
```caddy
|
|
192
|
+
glm.example.com {
|
|
193
|
+
reverse_proxy 127.0.0.1:18791
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**nginx**:
|
|
198
|
+
|
|
199
|
+
```nginx
|
|
200
|
+
server {
|
|
201
|
+
listen 443 ssl;
|
|
202
|
+
server_name glm.example.com;
|
|
203
|
+
# ssl_certificate / ssl_certificate_key ...
|
|
204
|
+
|
|
205
|
+
location / {
|
|
206
|
+
proxy_pass http://127.0.0.1:18791;
|
|
207
|
+
proxy_set_header X-Forwarded-For $remote_addr;
|
|
208
|
+
proxy_set_header Host $host;
|
|
209
|
+
proxy_http_version 1.1;
|
|
210
|
+
proxy_set_header Connection ""; # keep streaming (SSE) working
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Rate limiting keys off the client IP. When proxied, pass `X-Forwarded-For` and list the proxy's address in `TRUSTED_PROXIES` (comma-separated) so the real client IP is used — otherwise every client shares one bucket:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
TRUSTED_PROXIES=127.0.0.1 node bin/cli.js --host 0.0.0.0
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
> The proxy needs a logged-in AutoClaw account running on the same machine (it reads the local token file), so a public endpoint is effectively a shared account — only expose it to people you trust.
|
|
222
|
+
|
|
223
|
+
## API
|
|
224
|
+
|
|
225
|
+
### `GET /healthz`
|
|
226
|
+
|
|
227
|
+
Returns token status and upstream info.
|
|
228
|
+
|
|
229
|
+
```json
|
|
230
|
+
{
|
|
231
|
+
"ok": true,
|
|
232
|
+
"status": "live",
|
|
233
|
+
"upstream": "https://autoglm-api.autoglm.ai/autoclaw-proxy/proxy/autoclaw",
|
|
234
|
+
"port": 18791
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### `GET /v1/models`
|
|
239
|
+
|
|
240
|
+
Lists available models in OpenAI format (OpenAI proxy) or Anthropic format (Anthropic proxy). The catalog is **re-read from AutoClaw's runtime file on every call** — no restart needed when AutoClaw's model list changes:
|
|
241
|
+
|
|
242
|
+
```json
|
|
243
|
+
{
|
|
244
|
+
"object": "list",
|
|
245
|
+
"data": [
|
|
246
|
+
{
|
|
247
|
+
"id": "zai_auto",
|
|
248
|
+
"object": "model",
|
|
249
|
+
"owned_by": "autoclaw",
|
|
250
|
+
"name": "Auto",
|
|
251
|
+
"context_window": 1048576,
|
|
252
|
+
"max_tokens": 393216
|
|
253
|
+
}
|
|
254
|
+
]
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Any OpenAI-compatible harness pointed at `http://127.0.0.1:18791/v1` will pick this list up automatically.
|
|
259
|
+
|
|
260
|
+
### `POST /v1/chat/completions` — OpenAI proxy
|
|
261
|
+
|
|
262
|
+
OpenAI-compatible chat completions. Supports both streaming (`stream: true`) and non-streaming.
|
|
263
|
+
|
|
264
|
+
**Headers:**
|
|
265
|
+
```
|
|
266
|
+
Authorization: Bearer mewmew
|
|
267
|
+
Content-Type: application/json
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### `POST /v1/messages` — Anthropic proxy
|
|
271
|
+
|
|
272
|
+
Anthropic-compatible Messages API. Supports both streaming and non-streaming. Claude model names are automatically mapped to the best available AutoClaw model:
|
|
273
|
+
|
|
274
|
+
| Claude model | Routes to |
|
|
275
|
+
|---|---|
|
|
276
|
+
| `claude-opus-*` | First available GLM-5.3 / GLM-5 model |
|
|
277
|
+
| `claude-sonnet-*` | `zai_auto` (or next available GLM-5 model) |
|
|
278
|
+
| `claude-haiku-*` | `zai_glm-5-turbo` (or DeepSeek / Auto fallback) |
|
|
279
|
+
|
|
280
|
+
## Error handling
|
|
281
|
+
|
|
282
|
+
Every failure maps to a semantically correct status with a machine-readable `code` — no more generic blobs:
|
|
283
|
+
|
|
284
|
+
| Situation | HTTP | `code` |
|
|
285
|
+
|-----------|------|--------|
|
|
286
|
+
| Bad client input (bad JSON / oversized / wrong Content-Type) | `400` / `413` / `415` | `invalid_request` |
|
|
287
|
+
| Model out of credits or free quota (upstream 402/403/810000) | `402` | `quota_exhausted` |
|
|
288
|
+
| AutoClaw token expired | `401` | `token_expired` |
|
|
289
|
+
| Model unknown upstream | `404` | `model_not_found` |
|
|
290
|
+
| Upstream rate limit | `429` | `rate_limited_by_upstream` |
|
|
291
|
+
| Upstream returned garbage or died | `502` | `upstream_failure` |
|
|
292
|
+
| AutoClaw not running (no token file) | `503` | `no_token` |
|
|
293
|
+
| Upstream timeout (2 min) | `504` | `upstream_timeout` |
|
|
294
|
+
|
|
295
|
+
Quota errors are remembered for 60s per model: repeat requests fail instantly instead of replaying doomed cloud + fallback attempts.
|
|
296
|
+
|
|
297
|
+
## Local gateway fallback
|
|
298
|
+
|
|
299
|
+
When the cloud upstream fails (and it's not a plain 404/429), the proxy re-runs your prompt through **AutoClaw's own desktop agent** over a local WebSocket (`127.0.0.1:18789`). Responses served this way are logged with `via: "local"` in the JSONL log. Caveats: it's a full agentic run (slower, tools included), and it shares your account's credits — quota walls stop it too. Set `PREFER_LOCAL=1` to skip the cloud attempt entirely while credits are exhausted.
|
|
300
|
+
|
|
301
|
+
## Models
|
|
302
|
+
|
|
303
|
+
| ID | Name | Context | Max Output | Notes |
|
|
304
|
+
|----|------|---------|------------|-------|
|
|
305
|
+
| `zai_auto` | Auto | 1M | 393K | Routes to AutoClaw's optimal model |
|
|
306
|
+
| `zaicoding_glm-5.3` | GLM-5.3 | 1M | 307K | Latest GLM coding model |
|
|
307
|
+
| `zai_glm-5-turbo` | GLM-5-Turbo | 200K | 131K | Zhipu AI GLM-5 Turbo |
|
|
308
|
+
| `zai_glm-5.3-flash` | GLM-5.3-Flash ("OX-alpha") | 1M | 131K | Newest GLM flash model. The cloud upstream 400s it, so it's served via the local-agent fallback; it now appears in `/v1/models` and in the built-in fallback catalog |
|
|
309
|
+
| `tdpsk_deepseek-v4-flash-202605` | Deepseek-V4-Flash | 1M | 393K | Fast DeepSeek model |
|
|
310
|
+
| `tdpsk_deepseek-v4-pro-202606` | DeepSeek-V4-Pro | 1M | 393K | Deep reasoning model |
|
|
311
|
+
|
|
312
|
+
> GLM 5.3 new in the proxy? Maybe. Supposedly in the UI it's 5.2 but in the API it's 5.3. We'll never know, but it's a win-win xd.
|
|
313
|
+
|
|
314
|
+
All models include `reasoning_content` in responses when the upstream model reasons. The model list is loaded dynamically from AutoClaw's `openclaw.runtime.json` (re-read on every `/v1/models` call, so the catalog stays live), with a built-in fallback if that file isn't readable. Run `node bin/cli.js --doctor` to inspect the current catalog after an AutoClaw update.
|
|
315
|
+
|
|
316
|
+
## Integrations
|
|
317
|
+
|
|
318
|
+
### OpenCode
|
|
319
|
+
|
|
320
|
+
```json
|
|
321
|
+
{
|
|
322
|
+
"provider": {
|
|
323
|
+
"autoclaw": {
|
|
324
|
+
"npm": "@ai-sdk/openai-compatible",
|
|
325
|
+
"name": "AutoClaw",
|
|
326
|
+
"options": {
|
|
327
|
+
"baseURL": "http://localhost:18791/v1",
|
|
328
|
+
"apiKey": "mewmew"
|
|
329
|
+
},
|
|
330
|
+
"models": {
|
|
331
|
+
"zai_auto": { "name": "AutoClaw Auto" },
|
|
332
|
+
"zaicoding_glm-5.3": { "name": "AutoClaw GLM-5.3" },
|
|
333
|
+
"zai_glm-5-turbo": { "name": "AutoClaw GLM-5 Turbo" },
|
|
334
|
+
"tdpsk_deepseek-v4-flash-202605": { "name": "AutoClaw Deepseek-V4-Flash" },
|
|
335
|
+
"tdpsk_deepseek-v4-pro-202606": { "name": "AutoClaw DeepSeek-V4-Pro" }
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Or add it as a custom model directly in the UI:
|
|
343
|
+
- **API Format**: OpenAI Chat Completions
|
|
344
|
+
- **URL**: `http://localhost:18791/v1`
|
|
345
|
+
- **Model ID**: `zai_auto` (or any model from the table above)
|
|
346
|
+
- **API Key**: `mewmew`
|
|
347
|
+
|
|
348
|
+
### Claude Code CLI
|
|
349
|
+
|
|
350
|
+
Add to `~/.claude/settings.json`:
|
|
351
|
+
|
|
352
|
+
```json
|
|
353
|
+
{
|
|
354
|
+
"env": {
|
|
355
|
+
"ANTHROPIC_BASE_URL": "http://localhost:18792",
|
|
356
|
+
"ANTHROPIC_AUTH_TOKEN": "mewmew"
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Python
|
|
362
|
+
|
|
363
|
+
```python
|
|
364
|
+
from openai import OpenAI
|
|
365
|
+
|
|
366
|
+
client = OpenAI(base_url="http://localhost:18791/v1", api_key="mewmew")
|
|
367
|
+
|
|
368
|
+
# Streaming
|
|
369
|
+
with client.chat.completions.stream(
|
|
370
|
+
model="zai_auto",
|
|
371
|
+
messages=[{"role": "user", "content": "Hello!"}],
|
|
372
|
+
) as stream:
|
|
373
|
+
for text in stream.text_stream:
|
|
374
|
+
print(text, end="", flush=True)
|
|
375
|
+
|
|
376
|
+
# Non-streaming
|
|
377
|
+
response = client.chat.completions.create(
|
|
378
|
+
model="zai_auto",
|
|
379
|
+
messages=[{"role": "user", "content": "What is 2+2?"}],
|
|
380
|
+
stream=False,
|
|
381
|
+
)
|
|
382
|
+
print(response.choices[0].message.content)
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### JavaScript
|
|
386
|
+
|
|
387
|
+
```javascript
|
|
388
|
+
import OpenAI from "openai";
|
|
389
|
+
|
|
390
|
+
const client = new OpenAI({
|
|
391
|
+
baseURL: "http://localhost:18791/v1",
|
|
392
|
+
apiKey: "mewmew",
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
const stream = await client.chat.completions.create({
|
|
396
|
+
model: "zai_auto",
|
|
397
|
+
messages: [{ role: "user", content: "Hello!" }],
|
|
398
|
+
stream: true,
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
for await (const chunk of stream) {
|
|
402
|
+
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### Cursor / Continue / Other Tools
|
|
407
|
+
|
|
408
|
+
Any tool that supports OpenAI-compatible providers works. Point it at `http://localhost:18791/v1` with API key `mewmew` and you're set. Harnesses that probe for available models will get the live list from `/v1/models` automatically.
|
|
409
|
+
|
|
410
|
+
## Notes
|
|
411
|
+
|
|
412
|
+
- Only one AutoClaw account can be active at a time — multi-account pooling isn't supported
|
|
413
|
+
- `PROXY_KEY` is just a local password for this proxy, not your AutoClaw credentials — set it to whatever you want. The default key `mewmew` is for **localhost-only use**: change it via `--key` / `PROXY_KEY` if you bind beyond `127.0.0.1` (see [Self-hosting](#self-hosting-behind-a-reverse-proxy))
|
|
414
|
+
- On a 401, the proxy invalidates its cached token and you can retry immediately
|
|
415
|
+
- Upstream 400 "invalid request" gets one retry after a 2s delay (a known upstream hiccup); quota/plan errors are never retried
|
|
416
|
+
- The cloud upstream requires AutoClaw's app system-prompt banner in every request. their new verification — the proxy injects it automatically (and never duplicates it). but it doesnt change much in practice/ my own testing and others testing. since it will be overridden by the harnesses own system prompt.
|
|
417
|
+
- When cloud fails, requests fall back to AutoClaw's local desktop agent (`via: "local"` in logs) unless the model just failed permanently there too
|
|
418
|
+
- The token file is watched for changes — AutoClaw can rotate auth mid-session without a restart
|
|
419
|
+
- AutoClaw's client identity (`X-Version` app version, platform, channel) is loaded dynamically from its runtime file — the same file that feeds the model catalog — so an AutoClaw app update is picked up without editing or restarting the proxy
|
|
420
|
+
- Rate limit is enforced per client IP (default 30 req/s); X-Forwarded-For is only honored from `TRUSTED_PROXIES`
|
|
421
|
+
- The fallback model catalog lives in `lib/fallback-models.json` (override with `FALLBACK_MODELS_PATH`) — the built-in list is only a last resort when AutoClaw's runtime file is unreadable
|
|
422
|
+
- The local-gateway connect self-heals: if the gateway bumps its WS protocol, the proxy reconnects with the expected version automatically
|
|
423
|
+
- The ring log records cloud verdicts alongside local fallbacks, so every response is attributable
|
|
424
|
+
- No dependencies at all: the interactive menu is hand-rolled on Node's built-in `readline`, so there's zero `node_modules` and zero install step
|
|
425
|
+
|
|
426
|
+
## Special Thanks
|
|
427
|
+
|
|
428
|
+
<p align="center">
|
|
429
|
+
<img src="./screenshots/jarona.png" alt="Special thanks to Jarona" width="200">
|
|
430
|
+
</p>
|
|
431
|
+
|
|
432
|
+
## License
|
|
433
|
+
|
|
434
|
+
MIT License + Jarona Rights™ (sorry to keep u waiting)
|