proxitor 0.9.0-beta.8 โ†’ 0.9.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 CHANGED
@@ -1,90 +1,70 @@
1
1
  # proxitor
2
2
 
3
3
  <p align="center">
4
- <strong>A transparent proxy between your AI CLI tools and OpenRouter.</strong><br/>
5
- Route by provider. Control costs. Keep streaming. Zero config changes in Claude Code.
4
+ <strong>A friendly proxy between your AI CLI tools and OpenRouter.</strong><br/>
5
+ Route requests to the provider you want. Keep prompt caching alive. Cut costs.<br/>
6
+ Your tools don't even notice.
6
7
  </p>
7
8
 
8
9
  <p align="center">
9
10
  <a href="https://www.npmjs.com/package/proxitor"><img src="https://img.shields.io/npm/v/proxitor?color=6366f1&labelColor=1e2327&label=npm" alt="npm version"></a>
10
- <a href="https://github.com/neiromaster/proxitor/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-22c55e?labelColor=1e2327" alt="MIT License"></a>
11
+ <a href="./LICENSE"><img src="https://img.shields.io/badge/license-MIT-22c55e?labelColor=1e2327" alt="MIT License"></a>
11
12
  <img src="https://img.shields.io/badge/node-%3E%3D22-3b82f6?labelColor=1e2327" alt="Node.js โ‰ฅ 22">
12
- <img src="https://img.shields.io/badge/built_with-TypeScript-3178c6?labelColor=1e2327" alt="TypeScript">
13
13
  </p>
14
14
 
15
- ---
15
+ ๐ŸŒ **English** ยท [ะ ัƒััะบะธะน](./docs/README.ru.md)
16
16
 
17
- ```
18
- Claude Code / Codex
19
- โ”‚
20
- โ”‚ ANTHROPIC_BASE_URL=http://localhost:8828/v1
21
- โ–ผ
22
- โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
23
- โ”‚ proxitor โ”‚ โ† injects provider routing
24
- โ”‚ :8828 โ”‚ โ† streams SSE back unchanged
25
- โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
26
- โ”‚
27
- โ”‚ + X-OpenRouter-* headers
28
- โ–ผ
29
- OpenRouter
30
- โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”
31
- Anthropic DeepInfra Azure ...
32
- ```
17
+ <p align="center"><img src="./docs/assets/proxitor-wizard.gif" alt="proxitor setup wizard" width="640"></p>
33
18
 
34
19
  ---
35
20
 
36
- ## Why
37
-
38
- ### The prompt cache problem
21
+ Proxitor sits between Claude Code (or Codex, or any Anthropic/OpenAI-compatible CLI) and [OpenRouter](https://openrouter.ai). One API key, every model โ€” but **you** decide which provider serves each request, and you make prompt caching actually work.
39
22
 
40
- OpenRouter is convenient โ€” one key, every model. But by default it load-balances across multiple provider instances for the same model. Each request can land on a different provider, and **prompt caching is provider-scoped**: a cache entry built on Anthropic's infrastructure doesn't help when the next request goes to DeepInfra.
23
+ ```
24
+ your AI CLI โ†’ proxitor โ†’ OpenRouter โ†’ the provider you picked
25
+ ```
41
26
 
42
- Claude Code sends a large system prompt on every single request. Without a pinned provider, you pay full token price every time. With proxitor locking `claude-*` to `anthropic`, that system prompt gets cached after the first hit and subsequent requests cost a fraction.
27
+ ## Why you'd want this
43
28
 
44
- ```yaml
45
- # pin all Claude models to Anthropic โ€” prompt cache works reliably
46
- modelOverrides:
47
- "claude-*":
48
- provider:
49
- only: "anthropic"
50
- ```
29
+ OpenRouter is convenient โ€” one key, every model. But it load-balances across providers, and **prompt caching is provider-scoped**: a cache built on Anthropic doesn't help when the next request lands on DeepInfra. Claude Code sends a big system prompt on every request, so without a pinned provider you pay full price every time.
51
30
 
52
- ### Other reasons to use it
31
+ Pin `claude-*` to `anthropic`, and that system prompt gets cached after the first hit. Subsequent requests cost a fraction.
53
32
 
54
- - **Cost control** โ€” route specific models to cheaper providers when caching isn't the priority
55
- - **Automatic fallbacks** โ€” if Anthropic is degraded, fall back to DeepInfra without touching your tools
56
- - **Mixed routing** โ€” `claude-*` on Anthropic, `gpt-*` on Azure, different rules per model
57
- - **Data privacy** โ€” enforce `dataCollection: deny` or ZDR across all requests
33
+ A few other things it's good for:
58
34
 
59
- Proxitor sits between your CLI tools and OpenRouter, injecting all of this transparently. Your tools don't know anything changed.
35
+ - **Cost control** โ€” route specific models to cheaper providers when caching isn't the priority.
36
+ - **Automatic fallbacks** โ€” Anthropic down? Fall back to DeepInfra without touching your tools.
37
+ - **Mixed routing** โ€” `claude-*` on Anthropic, `gpt-*` on Azure, different rules per model.
38
+ - **Privacy** โ€” enforce `dataCollection: deny` or zero-data-retention across everything.
60
39
 
61
- ---
40
+ > Proxitor injects all of this transparently. Your tools see a normal API. Nothing on their side changes.
62
41
 
63
42
  ## Install
64
43
 
44
+ Requires **Node.js 22+**.
45
+
65
46
  ```sh
66
- # npm
67
47
  npm install -g proxitor
68
-
69
- # bun
70
- bun install -g proxitor
71
-
72
- # no install needed
73
- npx proxitor
48
+ # or: bun install -g proxitor
49
+ # or run it once, no install: npx proxitor
74
50
  ```
75
51
 
76
- ---
52
+ ## Quick start
77
53
 
78
- ## Quick Start
54
+ **1. Set it up** โ€” the wizard asks a few questions and writes your config:
55
+
56
+ ```sh
57
+ proxitor config wizard
58
+ ```
79
59
 
80
- **1. Start the proxy**
60
+ **2. Run it**
81
61
 
82
62
  ```sh
83
- OPENROUTER_API_KEY=sk-or-... proxitor
63
+ proxitor
84
64
  # Listening on http://0.0.0.0:8828
85
65
  ```
86
66
 
87
- **2. Point your tools at it**
67
+ **3. Point your tool at it**
88
68
 
89
69
  ```sh
90
70
  # Claude Code
@@ -94,469 +74,59 @@ ANTHROPIC_BASE_URL=http://localhost:8828/v1 claude
94
74
  OPENAI_BASE_URL=http://localhost:8828/v1 codex
95
75
  ```
96
76
 
97
- That's it. Requests flow through proxitor to OpenRouter, SSE streams pass through unchanged.
98
-
99
- ---
100
-
101
- ## Configuration
102
-
103
- Proxitor looks for a config file in this order:
104
-
105
- ```
106
- proxitor.config.yaml โ†’ proxitor.config.yml โ†’ proxitor.config.json
107
- .proxitor.yaml โ†’ .proxitor.yml โ†’ .proxitor.json
108
- ```
109
-
110
- **Priority:** CLI flags > config file > environment variables > defaults
111
-
112
- All defaults are derived from a single Zod schema (`DEFAULTS`) โ€” no hardcoded constants scattered across modules. Config values are validated through Zod on load, including the final merged result.
113
-
114
- See [`proxitor.config.example.yaml`](./proxitor.config.example.yaml) for the complete reference.
115
-
116
- ### Authentication type
117
-
118
- By default, proxitor sends the API key as a `Bearer` token (`Authorization: Bearer sk-...`). If you're using a custom proxy provider that expects an `OAuth` header instead, set `authType` to `oauth`:
119
-
120
- ```yaml
121
- authType: oauth # "bearer" (default) or "oauth"
122
- ```
123
-
124
- This changes the header to `Authorization: OAuth sk-...`.
125
-
126
- ### Custom API URL and data fallback
127
-
128
- When using a custom `openrouterBaseUrl` that points to a third-party service, that service may not support OpenRouter-specific endpoints like `/providers` or `/models/{author}/{slug}/endpoints`. Proxitor handles this automatically:
129
-
130
- - **Automatic fallback** โ€” if the custom API returns an error (4xx/5xx) or an unexpected response format for data endpoints, proxitor falls back to `https://openrouter.ai/api` (no API key needed โ€” these endpoints are public)
131
- - **`openrouterDataUrl`** โ€” set this explicitly to control the primary URL for data fetching, independent of `openrouterBaseUrl` (which is used for proxying requests)
132
-
133
- ```yaml
134
- # Proxy requests go to custom service, data fetching falls back to OpenRouter
135
- # NOTE: do NOT include /v1 in the base URL โ€” request paths like /v1/chat/completions
136
- # are forwarded as-is, so /v1 would be duplicated if included here
137
- openrouterBaseUrl: 'https://custom-service.example.com/api'
138
-
139
- # Explicitly set the primary data URL (optional, defaults to openrouterBaseUrl)
140
- # openrouterDataUrl: 'https://openrouter.ai/api'
141
- ```
142
-
143
- When a fallback occurs, proxitor logs a warning: `Custom API did not return providers, using OpenRouter as fallback`.
144
-
145
- ### Provider routing
146
-
147
- Control which provider handles your requests. All three options accept a string or an array:
148
-
149
- ```yaml
150
- # Strict lock โ€” only this provider, no fallbacks
151
- provider:
152
- only: "anthropic"
153
-
154
- # Restricted pool โ€” load balance between these providers only
155
- provider:
156
- only:
157
- - "anthropic"
158
- - "deepinfra"
159
-
160
- # Priority order โ€” try Anthropic first, fall back to others if unavailable
161
- provider:
162
- order: "anthropic"
163
- allowFallbacks: true
164
-
165
- # Strict order โ€” try in sequence, no fallbacks outside the list
166
- provider:
167
- order:
168
- - "anthropic"
169
- - "deepinfra"
170
- allowFallbacks: false
171
-
172
- # Blacklist โ€” never use these providers
173
- provider:
174
- ignore: "azure"
175
- ```
176
-
177
- | Option | Behavior |
178
- |---|---|
179
- | `only` | Restrict to the listed provider(s). Load balances by price within the list. Never routes outside it โ€” if all are unavailable, the request fails. |
180
- | `order` | Try providers in the specified priority order. If none work, falls back to other available providers (unless `allowFallbacks: false`). |
181
- | `ignore` | Never route to the listed provider(s). |
182
-
183
- Without `provider` set, requests are forwarded unchanged.
184
-
185
- See [OpenRouter's provider routing docs](https://openrouter.ai/docs/guides/routing/provider-selection) for the full list of supported providers and options.
186
-
187
- ### Per-model overrides
188
-
189
- Route different models differently. Keys are exact names or prefix wildcards. More specific matches win.
190
-
191
- ```yaml
192
- provider:
193
- order: "deepinfra" # global default
194
-
195
- modelOverrides:
196
- # Exact match โ€” force this model to Anthropic
197
- "claude-sonnet-4-6":
198
- provider:
199
- only: "anthropic"
200
-
201
- # Wildcard โ€” all claude-* models prefer Anthropic with fallback
202
- "claude-*":
203
- provider:
204
- order:
205
- - "anthropic"
206
- - "deepinfra"
207
-
208
- # GPT models to OpenAI/Azure, plus a custom header
209
- "gpt-*":
210
- provider:
211
- only:
212
- - "openai"
213
- - "azure"
214
- headers:
215
- X-Model-Family: "gpt"
216
- ```
217
-
218
- **Match priority:** exact name > longer prefix > shorter prefix.
219
-
220
- ### Custom headers
221
-
222
- Add headers to all proxied requests, or per-model (merged on top of global):
223
-
224
- ```yaml
225
- headers:
226
- X-Custom-Header: "my-value"
227
- X-Environment: "production"
228
-
229
- modelOverrides:
230
- "claude-*":
231
- headers:
232
- X-Custom-Header: "claude-override" # overrides the global value
233
- X-Extra: "only-for-claude" # added only for this model
234
- ```
235
-
236
- ### Advanced provider options
237
-
238
- ```yaml
239
- provider:
240
- sort: "throughput" # sort by: price | throughput | latency
241
- quantizations:
242
- - "fp8" # filter by quantization level
243
- maxPrice:
244
- prompt: 1 # $/M tokens
245
- completion: 2
246
- requireParameters: true # only use providers that support all request params
247
- dataCollection: "deny" # "allow" | "deny"
248
- zdr: true # Zero Data Retention enforcement
249
- preferredMinThroughput:
250
- p90: 50 # tokens/sec (soft threshold)
251
- preferredMaxLatency:
252
- p90: 3 # seconds (soft threshold)
253
- ```
254
-
255
- ### Prompt caching
256
-
257
- By default, OpenRouter doesn't enable prompt caching โ€” every request pays full token price. Proxitor can inject `cache_control` and `session_id` to make caching work automatically.
258
-
259
- **`cacheControl`** โ€” injects `cache_control: { "type": "ephemeral" }` into the request body. OpenRouter uses this to set cache breakpoints and advance them as conversations grow.
260
-
261
- **`cacheControlTtl`** (`5m` / `1h` / `omit` / `skip`, default absent = passthrough) โ€” controls the `ttl` field on injected `cache_control` (Anthropic endpoints only). TTL only has effect when caching is active (`cacheControl` is `auto`/`always`); it is now set independently of the cache mode in the editor.
262
-
263
- **`sessionId`** โ€” injects `session_id` for provider sticky routing. Without it, OpenRouter only pins to a provider after detecting a cache hit. With it, routing sticks from the **first request** โ€” critical for OpenAI models where delayed caching means 0 cached tokens on the first 1-2 requests.
264
-
265
- Both `cacheControl` and `sessionId` support `auto` / `always` / `skip` modes:
266
-
267
- | Mode | `cacheControl` | `sessionId` |
268
- | --- | --- | --- |
269
- | `auto` (default) | Anthropic models on `/v1/chat/completions`; all models on `/v1/messages` and `/v1/responses` | Passthrough client session ID if present; otherwise generate proxy UUID |
270
- | `always` | All models, all endpoints | Always generate proxy session ID, ignoring client-provided |
271
- | `skip` | Passthrough: leave the client's `cache_control` untouched and inject nothing | Passthrough: leave client session headers untouched |
272
-
273
- `cacheControlTtl` values:
77
+ That's the whole setup. Requests flow through proxitor; streaming responses pass through untouched.
274
78
 
275
- | Value | TTL | Write cost | Use when |
276
- | --- | --- | --- | --- |
277
- | _(absent)_ | Passthrough: preserve client `ttl`, add nothing; per-model absent inherits the global TTL | โ€” | Default |
278
- | `5m` | 5 minutes (Anthropic default) | 1.25ร— | Explicit short cache; high-frequency requests (>1 per 5 min) |
279
- | `1h` | 1 hour | 2.0ร— | Low-frequency or long-running sessions |
280
- | `omit` | Strip the `ttl` field, guaranteeing no TTL (even one sent by the client) | โ€” | Force-disable TTL |
281
- | `skip` | Passthrough: preserve the client's `ttl`, add nothing, ignore an inherited value | โ€” | Ignore global TTL without stripping |
79
+ ## Configuring it
282
80
 
283
- > **Note:** `null` (previously accepted in model overrides to cancel an inherited TTL) is **removed** โ€” migrate to `skip`. `null` was undocumented and unsettable from the UI.
284
-
285
- ```yaml
286
- cacheControl: auto # safe default โ€” Anthropic and safe endpoints only
287
- sessionId: auto # always ensures sticky routing (client header or proxy UUID)
288
-
289
- # Use 1-hour cache for all Anthropic models (higher write cost, longer TTL)
290
- cacheControlTtl: 1h
291
-
292
- # Force caching for all models (may cause 400 on non-Anthropic /v1/chat/completions)
293
- # cacheControl: always
294
-
295
- # Per-model overrides โ€” TTL supports '5m', '1h', 'omit', or 'skip' (passthrough)
296
- modelOverrides:
297
- "gpt-*":
298
- cacheControl: skip # OpenAI caches automatically, no injection needed
299
- sessionId: always # but sticky routing still helps
300
- "claude-opus-*":
301
- cacheControlTtl: skip # passthrough for Opus โ€” ignore the global 1h TTL, use the client ttl
302
- ```
303
-
304
- **Why all three matter:**
305
-
306
- - **Anthropic models** โ€” `cache_control` activates caching, `cacheControlTtl` extends it beyond 5 min, `session_id` prevents provider flip-flopping that would invalidate it
307
- - **OpenAI models** โ€” caching is automatic (no `cache_control` needed), but `session_id` ensures sticky routing from request #1 instead of waiting for a cache hit
308
- - **All models** โ€” `session_id` prevents the provider switch that silently resets cache
309
-
310
- ### Health check
311
-
312
- ```sh
313
- curl http://localhost:8828/health
314
- ```
315
-
316
- ### Cache usage logging
317
-
318
- Proxitor automatically logs cache token usage from upstream responses โ€” both non-streaming JSON and streaming SSE. No configuration needed.
319
-
320
- ```
321
- [abc123] Cache read: 50000, write: 25000 tokens (99.6% hit)
322
- [def456] Cache read: 1088 tokens (90.0% hit)
323
- [ghi789] Cache: no cached tokens
324
- ```
325
-
326
- Supports all three provider formats:
327
-
328
- | Provider format | Fields |
329
- | --- | --- |
330
- | Anthropic | `usage.cache_read_input_tokens` / `usage.cache_creation_input_tokens` |
331
- | OpenAI / OpenRouter | `usage.prompt_tokens_details.cached_tokens` / `cache_write_tokens` |
332
- | Responses API | `usage.input_tokens_details.cached_tokens` / `cache_write_tokens` |
333
-
334
- When both formats are present (e.g., OpenRouter relaying an Anthropic response), Anthropic fields take priority.
335
-
336
- ---
337
-
338
- ## Interactive Config Manager
339
-
340
- Proxitor includes an interactive CLI for managing configuration โ€” global settings, model overrides, and diagnostics โ€” without editing YAML by hand.
341
-
342
- ### Setup wizard
343
-
344
- Run the wizard to create or update your config interactively. If no config exists, any command will offer to launch it automatically.
81
+ The friendly way: an interactive menu โ€” no YAML required.
345
82
 
346
83
  ```sh
347
- proxitor config wizard
84
+ proxitor config # open the menu
85
+ proxitor config wizard # (re)run guided setup
348
86
  ```
349
87
 
350
- The wizard asks for:
351
-
352
- - **OpenRouter API key** โ€” stored in config or set as `OPENROUTER_API_KEY` env var
353
- - **Port** โ€” default `8828` (avoids conflicts with common dev servers on 8080)
354
- - **Listen address** โ€” all interfaces (`0.0.0.0`), localhost only (`127.0.0.1`), or a custom address (IP, hostname, or `unix:/path`)
355
- - **API base URL** โ€” default `https://openrouter.ai/api`; change for self-hosted or custom endpoints
356
- - **Authentication type** โ€” `bearer` (default) or `oauth`; use `oauth` for custom proxy providers that pass tokens in the `Authorization: OAuth ...` header
357
- - **Save location** โ€” project directory, `~/.config/proxitor/`, or `$XDG_CONFIG_HOME/proxitor/`
88
+ From the menu you can set your API key and connection, pick routing per model (with live provider pricing), tune caching, and add or edit model overrides. It pulls live data from OpenRouter, so you browse real models and providers with up-to-date prices.
358
89
 
359
- After collecting the key, base URL, and auth type, the wizard performs a **best-effort upstream probe** (3 s timeout) to verify connectivity. If the upstream is unreachable or the key is rejected, a warning is shown but the config is still saved โ€” this is informational only.
90
+ Prefer to edit a file? The full **[configuration reference](./docs/configuration.md)** covers provider routing, per-model overrides, headers, caching modes, and every option. [`proxitor.config.example.yaml`](./proxitor.config.example.yaml) is a commented template.
360
91
 
361
- If a config already exists, the wizard shows its location and asks whether to reconfigure. All fields are **pre-filled** with current values โ€” press Enter to keep, or type a new value. Existing `modelOverrides`, `provider`, and other fields are preserved โ€” only the wizard fields are updated.
92
+ ## Adding a model override
362
93
 
363
- ### Config menu
94
+ Pin a model โ€” or a wildcard like `claude-*` โ€” to specific providers, straight from the menu. It pulls live pricing and latency for every provider of that model.
364
95
 
365
- `proxitor config` (or `proxitor config menu`) opens an interactive menu that loops until you exit. From there you can manage all settings:
96
+ <p align="center"><img src="./docs/assets/proxitor-add.gif" alt="proxitor: add a model override" width="640"></p>
366
97
 
367
- - **Show current config** โ€” display the resolved configuration
368
- - **API key & connection** โ€” change API key, port, listen address, base URL, auth type
369
- - **Session routing** โ€” set global `sessionId` mode (`auto` / `always` / `skip`)
370
- - **Cache control** โ€” set global `cacheControl` mode and TTL
371
- - **Model overrides** โ€” add, edit, remove, list, or browse models
98
+ ## When something's off
372
99
 
373
100
  ```sh
374
- proxitor config menu # interactive menu
375
- proxitor config add # add a model override
376
- proxitor config edit # edit existing override
377
- proxitor config remove # remove override(s)
378
- proxitor config list # show current overrides
379
- proxitor config list --json # overrides as JSON
380
- proxitor config show # print the resolved config (merged)
381
- proxitor config show --json # same, machine-readable
382
- proxitor config browse # explore models with pricing info
383
- proxitor config wizard # interactive setup wizard
384
- proxitor config validate # validate config file (exit 0 ok, 1 invalid)
385
- proxitor config validate --json # structured JSON result
386
- proxitor doctor # diagnose environment + network + port + version
387
- proxitor doctor --json # machine-readable diagnostic report
388
- proxitor doctor --offline # skip network checks
101
+ proxitor doctor # checks environment, config, key, network, port, version
389
102
  ```
390
103
 
391
- When adding or editing a model override, you can also configure per-model `sessionId` and `cacheControl` โ€” useful for models that need different caching or routing behavior than the global default.
104
+ It prints a clear report and exits non-zero if anything fails โ€” handy from CI too (`--json`, `--offline`, `--timeout`).
392
105
 
393
- In `config edit`, any field (provider, session ID, cache control, cache TTL) can be reset to inherit the global/default value via the **Reset / inherit** prompt option. The global `config cache-control` and `config session-routing` commands support the same reset โ€” it reverts the field to the schema default.
106
+ While proxitor runs, it logs cache usage from upstream so you can see whether caching is actually helping:
394
107
 
395
- ### Add override walkthrough
396
-
397
- ```sh
398
- $ proxitor config add
399
-
400
- โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
401
- โ”‚ Add Model Override โ”‚
402
- โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
403
-
404
- โ—‡ Search for a model
405
- โ”‚ claude
406
- (23 matches)
407
- โ— anthropic/claude-sonnet-4-6 ยท $3.00/$15.00 ยท 200k
408
- โ—‹ anthropic/claude-opus-4-8 ยท $15.00/$75.00 ยท 200k
409
- ...
410
-
411
- โ—‡ Configure provider routing
412
- โ”‚ โ—‹ Use specific providers only
413
- โ—‹ Set provider priority order
414
- โ—‹ Ignore specific providers
415
- โ—‹ Skip provider routing
416
108
  ```
417
-
418
- **"Use specific providers only" / "Ignore specific providers"** โ€” multiselect, pick all that apply:
419
-
420
- ```text
421
- โ—‡ Select providers
422
- โ—ผ anthropic (anthropic) ยท 1.0s ยท 40 t/s
423
- โ—ป google-vertex/global ยท 1.1s ยท 39 t/s
424
- โ—ป amazon-bedrock ยท 1.2s ยท 40 t/s
425
- ```
426
-
427
- **"Set provider priority order"** โ€” pick providers one at a time, then select **โœ“ Done** at the bottom to finish:
428
-
429
- ```text
430
- โ—‡ Select provider #1 (or cancel to finish)
431
- โ”‚ โ— anthropic (anthropic) ยท 1.0s ยท 40 t/s
432
- โ—‹ google-vertex/global ยท 1.1s ยท 39 t/s
433
- โ—‹ amazon-bedrock ยท 1.2s ยท 40 t/s
434
- โ—‹ โœ“ Done
435
-
436
- โ—‡ Select provider #2 (or cancel to finish)
437
- โ”‚ โ— google-vertex/global ยท 1.1s ยท 39 t/s
438
- โ—‹ amazon-bedrock ยท 1.2s ยท 40 t/s
439
- โ—‹ โœ“ Done
440
-
441
- โ—‡ Select provider #3 (or cancel to finish)
442
- โ”‚ โ— โœ“ Done
443
-
444
- โ—‡ Allow fallbacks to other providers? Yes
445
-
446
- โ—‡ Save to config? Yes
447
-
448
- โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
449
- โ”‚ โœ“ Model override saved โ”‚
450
- โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
451
- ```
452
-
453
- The interface uses live data from the OpenRouter API โ€” model search with type-ahead, real provider availability and pricing for each model.
454
-
455
- ---
456
-
457
- ## Diagnostics
458
-
459
- When something doesn't work, `proxitor doctor` runs a battery of checks and prints a report. Sections cover:
460
-
461
- - **Environment** โ€” Node version, platform, TTY
462
- - **Config** โ€” discovery path, validity, override count
463
- - **API key** โ€” resolution (env vs. file; never prints the key)
464
- - **Network** โ€” upstream reachability (with configurable timeout)
465
- - **Port** โ€” availability of the configured port
466
- - **Version** โ€” installed version
467
-
468
- Statuses: `โœ“ ok` / `โš  warn` / `โœ— fail` / `โ“˜ skip`. Exit code is `0` when no `fail`, `1` otherwise โ€” scriptable from CI.
469
-
470
- ```sh
471
- $ proxitor doctor
472
-
473
- โ–ฒ Proxitor Doctor
474
- โ”‚
475
- โ—‡ Environment
476
- โ”‚ โœ“ node-version โ€” v22.4.1
477
- โ”‚ โœ“ platform โ€” darwin arm64
478
- โ”‚ โœ“ tty โ€” true
479
- โ”‚
480
- โ—‡ Config
481
- โ”‚ โœ“ config-found โ€” /Users/u/proj/proxitor.config.yaml
482
- โ”‚ โœ“ config-valid โ€” 12 keys, 3 override(s)
483
- โ”‚
484
- โ—‡ API key
485
- โ”‚ โœ“ api-key โ€” set (env: set, file: set)
486
- โ”‚
487
- โ—‡ Network
488
- โ”‚ โœ“ upstream โ€” https://openrouter.ai/api โ€” 200, 342 models
489
- โ”‚
490
- โ—‡ Port
491
- โ”‚ โœ“ port-8828 โ€” 127.0.0.1:8828
492
- โ”‚
493
- โ—‡ Version
494
- โ”‚ โœ“ version โ€” 0.9.0-beta.5
495
-
496
- โ”” Done. All checks passed.
497
- ```
498
-
499
- Useful flags:
500
-
501
- ```sh
502
- proxitor doctor --json # structured JSON for CI / scripts
503
- proxitor doctor --offline # skip network checks (no upstream, no npm)
504
- proxitor doctor --timeout 5000 # custom per-check network timeout (ms)
109
+ [abc123] Cache read: 50000, write: 25000 tokens (99.6% hit)
505
110
  ```
506
111
 
507
- ---
112
+ Quick health poke: `curl http://localhost:8828/health`.
508
113
 
509
- ## CLI Options
114
+ ## Commands at a glance
510
115
 
511
116
  ```sh
512
- proxitor # start the proxy (default command)
513
- proxitor start # same as above
514
- proxitor up # alias for start
515
- proxitor run # alias for start
516
- proxitor --port 9000 # override port
517
- proxitor --config ./team.yaml # use an explicit config
518
- proxitor config show # print the resolved config
519
- proxitor config show --json # machine-readable config
520
- proxitor config list --json # overrides as JSON
521
- proxitor config wizard # interactive setup
522
- proxitor config validate # check the current config (exit 0/1)
523
- proxitor config validate --json # structured JSON result
524
- proxitor doctor # diagnose environment, network, port, version
525
- proxitor doctor --offline # skip network checks
526
- proxitor --help # full help
527
- proxitor --version # print version
117
+ proxitor # start the proxy (the default command)
118
+ proxitor config # interactive config menu
119
+ proxitor config wizard # guided setup
120
+ proxitor config browse # explore models + pricing
121
+ proxitor doctor # diagnose everything
122
+ proxitor --help # the rest of the flags
528
123
  ```
529
124
 
530
- | Flag | Default | Description |
531
- |---|---|---|
532
- | `-p, --port <port>` | `8828` | Server port (validated: 1-65535) |
533
- | `--host <host>` | `0.0.0.0` | Server host |
534
- | `-c, --config <path>` | auto-discovered | Path to config file |
535
- | `--openrouter-key <key>` / `-k <key>` | `$OPENROUTER_API_KEY` | OpenRouter API key |
536
- | `--verbose` | `false` | Enable verbose logging |
537
- | `--no-config` | | Skip config file discovery |
538
- | `-v, --version` | | Print version |
539
- | `--help` | | Print help |
125
+ Common flags: `--port`, `--host`, `--config <path>`, `--openrouter-key <key>`. Run `proxitor --help` and `proxitor config --help` for the full list.
540
126
 
541
- Subcommands live under `proxitor config <subcommand>`. Run `proxitor config --help` for the full list, or see [Interactive Config Manager](#interactive-config-manager) for the walkthroughs.
127
+ ## Contributing
542
128
 
543
- ---
544
-
545
- ## Development
546
-
547
- ```sh
548
- pnpm install # install dependencies
549
- pnpm dev # build + watch
550
- pnpm test # run tests
551
- pnpm test:e2e # end-to-end tests
552
- pnpm typecheck # TypeScript check
553
- pnpm check:biome # lint + format check
554
- pnpm lint:fix # auto-fix lint issues
555
- pnpm build # production build
556
- pnpm check # typecheck + biome + test (full CI)
557
- ```
558
-
559
- ---
129
+ PRs welcome โ€” see **[CONTRIBUTING.md](./CONTRIBUTING.md)** for setup, tests, commits, and changesets.
560
130
 
561
131
  ## License
562
132