@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 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
  ![Claude Code Routing](./assets/screenshots/web-ui-claude-code.png)
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.7",
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(options, {
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,
@@ -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
- } else if (!activeRuntimeState) {
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);