@khanglvm/llm-router 1.0.5

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.
@@ -0,0 +1,19 @@
1
+ LLM_ROUTER_TEST_HOST=127.0.0.1
2
+ LLM_ROUTER_TEST_PORT=8787
3
+ LLM_ROUTER_TEST_TIMEOUT_MS=90000
4
+
5
+ # Test hostname/zone for routing tests (use local example for CI/public)
6
+ LLM_ROUTER_TEST_HOSTNAME=router.example.com
7
+ LLM_ROUTER_TEST_ZONE_NAME=example.com
8
+
9
+ LLM_ROUTER_TEST_PROVIDER_KEYS=EXAMPLE
10
+
11
+ LLM_ROUTER_TEST_EXAMPLE_PROVIDER_ID=example
12
+ LLM_ROUTER_TEST_EXAMPLE_NAME="Example Provider"
13
+ LLM_ROUTER_TEST_EXAMPLE_API_KEY=sk-...
14
+ LLM_ROUTER_TEST_EXAMPLE_OPENAI_BASE_URL=https://api.example.com/v1
15
+ LLM_ROUTER_TEST_EXAMPLE_CLAUDE_BASE_URL=https://api.example.com
16
+ LLM_ROUTER_TEST_EXAMPLE_MODELS=model-a,model-b
17
+ LLM_ROUTER_TEST_EXAMPLE_HEADERS_JSON={"X-Env":"local"}
18
+ LLM_ROUTER_TEST_EXAMPLE_OPENAI_HEADERS_JSON={"User-Agent":"Mozilla/5.0"}
19
+ LLM_ROUTER_TEST_EXAMPLE_CLAUDE_HEADERS_JSON={"x-foo":"bar"}
package/README.md ADDED
@@ -0,0 +1,230 @@
1
+ # llm-router
2
+
3
+ `llm-router` is a gateway api proxy for accessing multiple models across any provider that supports OpenAI or Anthropic formats.
4
+
5
+ It supports:
6
+ - local route server `llm-router start`
7
+ - Cloudflare Worker route runtime deployment `llm-router deploy`
8
+ - CLI + TUI management `config`, `start`, `deploy`, `worker-key`
9
+ - Seamless model fallback
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm i -g @khanglvm/llm-router
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ```bash
20
+ # 1) Open config TUI (default behavior) to manage providers, models, fallbacks, and auth
21
+ llm-router
22
+
23
+ # 2) Start local route server
24
+ llm-router start
25
+ ```
26
+
27
+ Local endpoints:
28
+ - Unified (Auto transform): `http://127.0.0.1:8787/route` (or `/` and `/v1`)
29
+ - Anthropic: `http://127.0.0.1:8787/anthropic`
30
+ - OpenAI: `http://127.0.0.1:8787/openai`
31
+
32
+ ## Usage Example
33
+
34
+ ```bash
35
+ # Your AI Agent can help! Ask them to manage api router via this tool for you.
36
+
37
+ # 1) Add provider + models + provider API key. You can ask your AI agent to do it for you, or manually via TUI or command line:
38
+ llm-router config \
39
+ --operation=upsert-provider \
40
+ --provider-id=openrouter \
41
+ --name="OpenRouter" \
42
+ --base-url=https://openrouter.ai/api/v1 \
43
+ --api-key=sk-or-v1-... \
44
+ --models=claude-3-7-sonnet,gpt-4o \
45
+ --format=openai \
46
+ --skip-probe=true
47
+
48
+ # 2) (Optional) Configure model fallback order
49
+ llm-router config \
50
+ --operation=set-model-fallbacks \
51
+ --provider-id=openrouter \
52
+ --model=claude-3-7-sonnet \
53
+ --fallback-models=openrouter/gpt-4o
54
+
55
+ # 3) Set master key (this is your gateway key for client apps)
56
+ llm-router config --operation=set-master-key --master-key=gw_your_gateway_key
57
+
58
+ # 4) Start gateway with auth required
59
+ llm-router start --require-auth=true
60
+ ```
61
+
62
+ Claude Code example (`~/.claude/settings.local.json`):
63
+
64
+ ```json
65
+ {
66
+ "env": {
67
+ "ANTHROPIC_BASE_URL": "http://127.0.0.1:8787/anthropic",
68
+ "ANTHROPIC_AUTH_TOKEN": "gw_your_gateway_key"
69
+ }
70
+ }
71
+ ```
72
+
73
+ ## Smart Fallback Behavior
74
+
75
+ `llm-router` can fail over from a primary model to configured fallback models with status-aware logic:
76
+ - `429` (rate-limited): immediate fallback (no origin retry), with `Retry-After` respected when present.
77
+ - Temporary failures (`408`, `409`, `5xx`, network errors): origin-only bounded retries with jittered backoff, then fallback.
78
+ - Billing/quota exhaustion (`402`, or provider-specific billing signals): immediate fallback with longer origin cooldown memory.
79
+ - Auth and permission failures (`401` and relevant `403` cases): no retry; fallback to other providers/models when possible.
80
+ - Policy/moderation blocks: no retry; cross-provider fallback is disabled by default (`LLM_ROUTER_ALLOW_POLICY_FALLBACK=false`).
81
+ - Invalid client requests (`400`, `413`, `422`): no retry and no fallback short-circuit.
82
+
83
+ ## Main Commands
84
+
85
+ ```bash
86
+ llm-router config
87
+ llm-router start
88
+ llm-router stop
89
+ llm-router reload
90
+ llm-router update
91
+ llm-router deploy
92
+ llm-router worker-key
93
+ ```
94
+
95
+ ## Non-Interactive Config (Agent/CI Friendly)
96
+
97
+ ```bash
98
+ llm-router config \
99
+ --operation=upsert-provider \
100
+ --provider-id=openrouter \
101
+ --name="OpenRouter" \
102
+ --base-url=https://openrouter.ai/api/v1 \
103
+ --api-key=sk-or-v1-... \
104
+ --models=gpt-4o,claude-3-7-sonnet \
105
+ --format=openai \
106
+ --skip-probe=true
107
+ ```
108
+
109
+ Set local auth key:
110
+
111
+ ```bash
112
+ llm-router config --operation=set-master-key --master-key=your_local_key
113
+ # or generate a strong key automatically
114
+ llm-router config --operation=set-master-key --generate-master-key=true
115
+ ```
116
+
117
+ Start with auth required:
118
+
119
+ ```bash
120
+ llm-router start --require-auth=true
121
+ ```
122
+
123
+ ## Cloudflare Worker Deploy
124
+
125
+ Worker project name in `wrangler.toml`: `llm-router-route`.
126
+
127
+ ### Option A: Guided deploy
128
+
129
+ ```bash
130
+ llm-router deploy
131
+ ```
132
+
133
+ If `LLM_ROUTER_CONFIG_JSON` exceeds Cloudflare Free-tier secret size (`5 KB`), deploy now warns and requires explicit confirmation (default is `No`). In non-interactive environments, pass `--allow-large-config=true` to proceed intentionally.
134
+
135
+ `deploy` requires `CLOUDFLARE_API_TOKEN` for Cloudflare API access. Create a **User Profile API token** at <https://dash.cloudflare.com/profile/api-tokens> (do not use Account API Tokens), then choose preset/template `Edit Cloudflare Workers`. If the env var is missing in interactive mode, the CLI will show the guide and prompt for token input securely.
136
+
137
+ For multi-account tokens, set account explicitly in non-interactive runs:
138
+ - `CLOUDFLARE_ACCOUNT_ID=<id>` or
139
+ - `llm-router deploy --account-id=<id>`
140
+
141
+ `llm-router deploy` resolves deploy target from CLI/TUI input (workers.dev or custom route), generates a temporary Wrangler config at runtime, deploys with `--config`, then removes that temporary file. Personal route/account details are not persisted back into repo `wrangler.toml`.
142
+
143
+ For custom domains, the deploy helper now prints a DNS checklist and connectivity commands. Common setup for `llm.example.com`:
144
+ - Create a DNS record in Cloudflare for `llm` (usually `CNAME llm -> @`)
145
+ - Set **Proxy status = Proxied** (orange cloud)
146
+ - Use route target `--route-pattern=llm.example.com/* --zone-name=example.com`
147
+ - Claude Code base URL should be `https://llm.example.com/anthropic` (**no `:8787`**; that port is local-only)
148
+
149
+ ```bash
150
+ llm-router deploy --export-only=true --out=.llm-router.worker.json
151
+ wrangler secret put LLM_ROUTER_CONFIG_JSON < .llm-router.worker.json
152
+ wrangler deploy
153
+ ```
154
+
155
+ Rotate worker auth key quickly:
156
+
157
+ ```bash
158
+ llm-router worker-key --master-key=new_key
159
+ # or generate and rotate immediately
160
+ llm-router worker-key --env=production --generate-master-key=true
161
+ ```
162
+
163
+ If you intentionally need to bypass weak-key checks (not recommended), add `--allow-weak-master-key=true` to `deploy` or `worker-key`.
164
+
165
+ Cloudflare hardening and incident-response checklist: see [`SECURITY.md`](./SECURITY.md).
166
+
167
+ ## Runtime Secrets / Env
168
+
169
+ Primary:
170
+ - `LLM_ROUTER_CONFIG_JSON`
171
+ - `LLM_ROUTER_MASTER_KEY` (optional override)
172
+
173
+ Also supported:
174
+ - `ROUTE_CONFIG_JSON`
175
+ - `LLM_ROUTER_JSON`
176
+
177
+ Optional resilience tuning:
178
+ - `LLM_ROUTER_ORIGIN_RETRY_ATTEMPTS` (default `3`)
179
+ - `LLM_ROUTER_ORIGIN_RETRY_BASE_DELAY_MS` (default `250`)
180
+ - `LLM_ROUTER_ORIGIN_RETRY_MAX_DELAY_MS` (default `3000`)
181
+ - `LLM_ROUTER_ORIGIN_FALLBACK_COOLDOWN_MS` (default `45000`)
182
+ - `LLM_ROUTER_ORIGIN_RATE_LIMIT_COOLDOWN_MS` (default `30000`)
183
+ - `LLM_ROUTER_ORIGIN_BILLING_COOLDOWN_MS` (default `900000`)
184
+ - `LLM_ROUTER_ORIGIN_AUTH_COOLDOWN_MS` (default `600000`)
185
+ - `LLM_ROUTER_ORIGIN_POLICY_COOLDOWN_MS` (default `120000`)
186
+ - `LLM_ROUTER_ALLOW_POLICY_FALLBACK` (default `false`)
187
+ - `LLM_ROUTER_FALLBACK_CIRCUIT_FAILURES` (default `2`)
188
+ - `LLM_ROUTER_FALLBACK_CIRCUIT_COOLDOWN_MS` (default `30000`)
189
+ - `LLM_ROUTER_MAX_REQUEST_BODY_BYTES` (default `1048576`, min `4096`, max `20971520`)
190
+ - `LLM_ROUTER_UPSTREAM_TIMEOUT_MS` (default `60000`, min `1000`, max `300000`)
191
+
192
+ Optional browser access (CORS):
193
+ - By default, cross-origin browser reads are denied unless explicitly allow-listed.
194
+ - `LLM_ROUTER_CORS_ALLOWED_ORIGINS` (comma-separated exact origins, e.g. `https://app.example.com`)
195
+ - `LLM_ROUTER_CORS_ALLOW_ALL=true` (allows any origin; not recommended for production)
196
+
197
+ Optional source IP allowlist (recommended for Worker deployments):
198
+ - `LLM_ROUTER_ALLOWED_IPS` (comma-separated client IPs; denies requests from all other IPs)
199
+ - `LLM_ROUTER_IP_ALLOWLIST` (alias of `LLM_ROUTER_ALLOWED_IPS`)
200
+
201
+ ## Default Config Path
202
+
203
+ `~/.llm-router.json`
204
+
205
+ Minimal shape:
206
+
207
+ ```json
208
+ {
209
+ "masterKey": "local_or_worker_key",
210
+ "defaultModel": "openrouter/gpt-4o",
211
+ "providers": [
212
+ {
213
+ "id": "openrouter",
214
+ "name": "OpenRouter",
215
+ "baseUrl": "https://openrouter.ai/api/v1",
216
+ "apiKey": "sk-or-v1-...",
217
+ "formats": ["openai"],
218
+ "models": [{ "id": "gpt-4o" }]
219
+ }
220
+ ]
221
+ }
222
+ ```
223
+
224
+ ## Smoke Test
225
+
226
+ ```bash
227
+ npm run test:provider-smoke
228
+ ```
229
+
230
+ Use `.env.test-suite.example` as template for provider-based smoke tests.
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@khanglvm/llm-router",
3
+ "version": "1.0.5",
4
+ "description": "Single gateway endpoint for multi-provider LLMs with unified OpenAI+Anthropic format and seamless fallback",
5
+ "type": "module",
6
+ "main": "src/index.js",
7
+ "bin": {
8
+ "llm-router": "./src/cli-entry.js",
9
+ "llm-router-route": "./src/cli-entry.js"
10
+ },
11
+ "scripts": {
12
+ "dev": "wrangler dev",
13
+ "deploy": "wrangler deploy",
14
+ "tail": "wrangler tail",
15
+ "start": "node ./src/cli-entry.js start",
16
+ "config": "node ./src/cli-entry.js config",
17
+ "deploy:worker": "node ./src/cli-entry.js deploy",
18
+ "test:provider-smoke": "node ./scripts/provider-smoke-suite.mjs"
19
+ },
20
+ "dependencies": {
21
+ "@levu/snap": "^0.3.8"
22
+ },
23
+ "devDependencies": {
24
+ "wrangler": "^4.68.1"
25
+ }
26
+ }