@khanglvm/llm-router 2.3.7 → 2.4.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/CHANGELOG.md +17 -0
- package/README.md +12 -0
- package/package.json +2 -1
- package/src/node/instance-state.js +6 -2
- package/src/node/port-reclaim.js +4 -1
- package/src/node/web-console-client.js +26 -26
- package/src/node/web-console-server.js +175 -3
- package/src/node/web-console-styles.generated.js +1 -1
- package/src/node/web-console-ui/web-search-utils.js +42 -0
- package/src/runtime/config.js +53 -0
- package/src/runtime/handler/amp-web-search.js +75 -12
- package/src/runtime/handler/provider-call.js +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.4.1] - 2026-04-19
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- The published production web console bundle now rebuilds before packing so Claude Code shows the shared web-search provider selector added in `2.4.0` instead of serving a stale prebuilt client.
|
|
14
|
+
|
|
15
|
+
## [2.4.0] - 2026-04-18
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- Claude Code can now store a router-managed `claudeCode.webSearchProvider` selection, with validation plus Web UI controls for choosing either built-in web search providers or hosted search routes.
|
|
19
|
+
- Native Claude web search and page-fetch tool calls can now be intercepted locally for non-AMP clients, so Claude-compatible traffic can use the router-managed shared web search stack instead of falling back to upstream-native tools.
|
|
20
|
+
- `yarn dev` now exposes a one-click "Sync production config" action that clones the current production config into the dedicated dev config while preserving the dev router's local server settings.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
- `yarn dev` now launches the detached router backend with the runtime start path, so the dedicated dev router port is honored instead of conflicting with the fixed production port.
|
|
24
|
+
- Dev-mode router reclaim now leaves startup-managed production instances alone when reclaiming non-fixed dev ports.
|
|
25
|
+
- The dev terminal and web console now clearly mark when you are operating in the isolated development sandbox.
|
|
26
|
+
|
|
10
27
|
## [2.3.7] - 2026-04-18
|
|
11
28
|
|
|
12
29
|
### Fixed
|
package/README.md
CHANGED
|
@@ -29,6 +29,8 @@ llr ai-help # agent-oriented setup brief
|
|
|
29
29
|
- **Model aliases with routing** — group models into stable alias names with weighted round-robin, quota-aware balancing, and automatic fallback
|
|
30
30
|
- **Rate limiting** — set request caps per model or across all models over configurable time windows
|
|
31
31
|
- **Coding tool routing** — one-click routing config for Codex CLI, Claude Code, Factory Droid, and AMP
|
|
32
|
+
- **Dev sandbox** — `yarn dev` runs the console against a dedicated dev config/router port, highlights dev mode in terminal + UI, and can clone the production config into the sandbox for quick iteration
|
|
33
|
+
- **Claude native web tools** — local handling for Claude web search and page fetch requests, with selectable Claude Code web-search providers from the shared Web Search config
|
|
32
34
|
- **Seamless local updates** — `llr update` keeps the fixed local router endpoint online, drains in-flight requests, and automatically retries through backend restart windows
|
|
33
35
|
- **Web search** — built-in web search for AMP and other router-managed tools
|
|
34
36
|
- **Deployable** — run locally or deploy to Cloudflare Workers
|
|
@@ -40,6 +42,14 @@ llr ai-help # agent-oriented setup brief
|
|
|
40
42
|
|
|
41
43
|
That means `llr update` can install a new package version and gracefully swap the backend without breaking active CLI or tool requests. Requests that arrive during the short backend handoff are deferred and retried automatically instead of failing immediately. The Web UI may reconnect during that window, but router-managed API traffic keeps the same public local endpoint.
|
|
42
44
|
|
|
45
|
+
## Development Sandbox
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
yarn dev
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Development mode uses the dedicated `~/.llm-router-dev.json` config and its own local router port so it can run alongside a startup-managed or manually started production router. The terminal and Web UI both show a dev-mode indicator, and the dev Web UI includes a one-click sync action to copy the current production config into the sandbox without changing the dev router binding.
|
|
52
|
+
|
|
43
53
|
## Web UI
|
|
44
54
|
|
|
45
55
|
### Alias & Fallback
|
|
@@ -66,6 +76,8 @@ Route Claude Code through the gateway with per-tier model bindings.
|
|
|
66
76
|
|
|
67
77
|

|
|
68
78
|
|
|
79
|
+
Claude Code can also select a shared Web Search provider or hosted search route from the router config. When Claude-compatible traffic uses native web-search or page-fetch tools, LLM Router can satisfy those calls through the selected shared web-search provider instead of relying on upstream-native web tooling.
|
|
80
|
+
|
|
69
81
|
### Factory Droid
|
|
70
82
|
|
|
71
83
|
Route Factory Droid through the gateway via a managed custom model entry with reasoning effort control.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khanglvm/llm-router",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"description": "LLM Router: single gateway endpoint for multi-provider LLMs with unified OpenAI+Anthropic format and seamless fallback",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"llm-router",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"deploy": "wrangler deploy",
|
|
27
27
|
"tail": "wrangler tail",
|
|
28
28
|
"build:web-console": "node ./scripts/build-web-console.mjs",
|
|
29
|
+
"prepack": "npm run build:web-console",
|
|
29
30
|
"start": "node ./src/cli-entry.js start",
|
|
30
31
|
"config": "node ./src/cli-entry.js config",
|
|
31
32
|
"deploy:worker": "node ./src/cli-entry.js deploy",
|
|
@@ -239,6 +239,7 @@ export async function waitForRuntimeMatch(options = {}, deps = {}) {
|
|
|
239
239
|
|
|
240
240
|
export function spawnStartProcess({
|
|
241
241
|
cliPath,
|
|
242
|
+
startCommand = "start-runtime",
|
|
242
243
|
configPath,
|
|
243
244
|
host = FIXED_LOCAL_ROUTER_HOST,
|
|
244
245
|
port = FIXED_LOCAL_ROUTER_PORT,
|
|
@@ -256,7 +257,7 @@ export function spawnStartProcess({
|
|
|
256
257
|
|
|
257
258
|
const args = [
|
|
258
259
|
finalCliPath,
|
|
259
|
-
"start",
|
|
260
|
+
String(startCommand || "start-runtime").trim() || "start-runtime",
|
|
260
261
|
`--config=${configPath}`,
|
|
261
262
|
`--host=${host}`,
|
|
262
263
|
`--port=${port}`,
|
|
@@ -290,7 +291,10 @@ export async function startDetachedRouterService(options = {}, deps = {}) {
|
|
|
290
291
|
|
|
291
292
|
let child;
|
|
292
293
|
try {
|
|
293
|
-
child = spawnStartProcessFn(
|
|
294
|
+
child = spawnStartProcessFn({
|
|
295
|
+
...options,
|
|
296
|
+
startCommand: String(options?.startCommand || "start-runtime").trim() || "start-runtime"
|
|
297
|
+
}, {
|
|
294
298
|
detached: true,
|
|
295
299
|
stdio: ["ignore", "pipe", "pipe"],
|
|
296
300
|
unref: false,
|
package/src/node/port-reclaim.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
2
|
import { clearRuntimeState, getActiveRuntimeState } from "./instance-state.js";
|
|
3
|
+
import { FIXED_LOCAL_ROUTER_PORT } from "./local-server-settings.js";
|
|
3
4
|
import { startupStatus, stopStartup } from "./startup-manager.js";
|
|
4
5
|
|
|
5
6
|
export function parsePidList(text) {
|
|
@@ -119,7 +120,9 @@ export async function stopStartupManagedListener({ port, line, error }, deps = {
|
|
|
119
120
|
let shouldStopStartup = false;
|
|
120
121
|
if (activeRuntimeState?.managedByStartup) {
|
|
121
122
|
shouldStopStartup = Number(activeRuntimeState.port) === Number(port);
|
|
122
|
-
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (!shouldStopStartup && Number(port) === Number(FIXED_LOCAL_ROUTER_PORT)) {
|
|
123
126
|
try {
|
|
124
127
|
const status = await startupStatusFn();
|
|
125
128
|
shouldStopStartup = Boolean(status?.running);
|