@khanglvm/llm-router 1.3.1 → 2.0.0-beta.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +337 -41
  3. package/package.json +19 -3
  4. package/src/cli/router-module.js +7331 -3805
  5. package/src/cli/wrangler-toml.js +1 -1
  6. package/src/cli-entry.js +162 -24
  7. package/src/node/amp-client-config.js +426 -0
  8. package/src/node/coding-tool-config.js +763 -0
  9. package/src/node/config-store.js +49 -18
  10. package/src/node/instance-state.js +213 -12
  11. package/src/node/listen-port.js +5 -37
  12. package/src/node/local-server-settings.js +122 -0
  13. package/src/node/local-server.js +3 -2
  14. package/src/node/provider-probe.js +13 -0
  15. package/src/node/start-command.js +282 -40
  16. package/src/node/startup-manager.js +64 -29
  17. package/src/node/web-command.js +106 -0
  18. package/src/node/web-console-assets.js +26 -0
  19. package/src/node/web-console-client.js +56 -0
  20. package/src/node/web-console-dev-assets.js +258 -0
  21. package/src/node/web-console-server.js +3146 -0
  22. package/src/node/web-console-styles.generated.js +1 -0
  23. package/src/node/web-console-ui/config-editor-utils.js +616 -0
  24. package/src/node/web-console-ui/lib/utils.js +6 -0
  25. package/src/node/web-console-ui/rate-limit-utils.js +144 -0
  26. package/src/node/web-console-ui/select-search-utils.js +36 -0
  27. package/src/runtime/codex-request-transformer.js +46 -5
  28. package/src/runtime/codex-response-transformer.js +268 -35
  29. package/src/runtime/config.js +1394 -35
  30. package/src/runtime/handler/amp-gemini.js +913 -0
  31. package/src/runtime/handler/amp-response.js +308 -0
  32. package/src/runtime/handler/amp.js +290 -0
  33. package/src/runtime/handler/auth.js +17 -2
  34. package/src/runtime/handler/provider-call.js +168 -50
  35. package/src/runtime/handler/provider-translation.js +937 -26
  36. package/src/runtime/handler/request.js +149 -6
  37. package/src/runtime/handler/route-debug.js +22 -1
  38. package/src/runtime/handler.js +449 -9
  39. package/src/runtime/subscription-auth.js +1 -6
  40. package/src/shared/local-router-defaults.js +62 -0
  41. package/src/translator/index.js +3 -1
  42. package/src/translator/request/openai-to-claude.js +217 -6
  43. package/src/translator/response/openai-to-claude.js +206 -58
@@ -0,0 +1,106 @@
1
+ import { spawn } from "node:child_process";
2
+ import { getDefaultConfigPath } from "./config-store.js";
3
+ import { FIXED_LOCAL_ROUTER_HOST, FIXED_LOCAL_ROUTER_PORT } from "./local-server-settings.js";
4
+ import { startWebConsoleServer } from "./web-console-server.js";
5
+
6
+ function toBoolean(value, fallback) {
7
+ if (value === undefined || value === null || value === "") return fallback;
8
+ if (typeof value === "boolean") return value;
9
+ const normalized = String(value).trim().toLowerCase();
10
+ if (["1", "true", "yes", "y", "on"].includes(normalized)) return true;
11
+ if (["0", "false", "no", "n", "off"].includes(normalized)) return false;
12
+ return fallback;
13
+ }
14
+
15
+ function toPort(value, fallback) {
16
+ if (value === undefined || value === null || value === "") return fallback;
17
+ const parsed = Number.parseInt(String(value), 10);
18
+ if (!Number.isInteger(parsed) || parsed < 0 || parsed > 65535) return fallback;
19
+ return parsed;
20
+ }
21
+
22
+ export function resolveWebListenPort({ explicitPort, env = process.env, defaultPort = 8788 } = {}) {
23
+ return toPort(explicitPort, toPort(env.LLM_ROUTER_WEB_PORT, toPort(env.PORT, defaultPort)));
24
+ }
25
+
26
+ export function openBrowser(url) {
27
+ const platform = process.platform;
28
+ if (platform === "darwin") {
29
+ const child = spawn("open", [url], { detached: true, stdio: "ignore" });
30
+ child.unref();
31
+ return;
32
+ }
33
+
34
+ if (platform === "win32") {
35
+ const child = spawn("cmd", ["/c", "start", "", url], { detached: true, stdio: "ignore" });
36
+ child.unref();
37
+ return;
38
+ }
39
+
40
+ const child = spawn("xdg-open", [url], { detached: true, stdio: "ignore" });
41
+ child.unref();
42
+ }
43
+
44
+ export async function runWebCommand(options = {}) {
45
+ const host = String(options.host || "127.0.0.1").trim() || "127.0.0.1";
46
+ const port = resolveWebListenPort({ explicitPort: options.port, env: options.env });
47
+ const configPath = String(options.configPath || options.config || getDefaultConfigPath()).trim() || getDefaultConfigPath();
48
+ const shouldOpen = toBoolean(options.open ?? options.openBrowser, true);
49
+ const line = typeof options.onLine === "function" ? options.onLine : console.log;
50
+ const error = typeof options.onError === "function" ? options.onError : console.error;
51
+
52
+ let server;
53
+ try {
54
+ server = await startWebConsoleServer({
55
+ host,
56
+ port,
57
+ configPath,
58
+ routerHost: FIXED_LOCAL_ROUTER_HOST,
59
+ routerPort: FIXED_LOCAL_ROUTER_PORT,
60
+ routerWatchConfig: toBoolean(options.routerWatchConfig ?? options["router-watch-config"], true),
61
+ routerWatchBinary: toBoolean(options.routerWatchBinary ?? options["router-watch-binary"], true),
62
+ routerRequireAuth: toBoolean(options.routerRequireAuth ?? options["router-require-auth"], false),
63
+ allowRemoteClients: toBoolean(options.allowRemoteClients ?? options["allow-remote-clients"], false),
64
+ cliPathForRouter: String(options.cliPathForRouter || process.env.LLM_ROUTER_CLI_PATH || process.argv[1] || "").trim()
65
+ });
66
+ } catch (startError) {
67
+ return {
68
+ ok: false,
69
+ exitCode: 1,
70
+ errorMessage: `Failed to start llm-router web console: ${startError instanceof Error ? startError.message : String(startError)}`
71
+ };
72
+ }
73
+
74
+ line(`LLM Router web console started on ${server.url}`);
75
+ line(`Config file: ${configPath}`);
76
+ line("Use the in-app Exit Web button or Ctrl+C to stop the web console.");
77
+ line("Closing the web console leaves the router service running.");
78
+
79
+ if (shouldOpen) {
80
+ try {
81
+ openBrowser(server.url);
82
+ line("Opening your default browser...");
83
+ } catch (openError) {
84
+ error(`Could not open browser automatically: ${openError instanceof Error ? openError.message : String(openError)}`);
85
+ line(`Open this URL manually: ${server.url}`);
86
+ }
87
+ }
88
+
89
+ const handleSignal = (signal) => {
90
+ line(`Received ${signal}. Closing web console (router stays running)...`);
91
+ void server.close(signal.toLowerCase());
92
+ };
93
+ process.once("SIGINT", handleSignal);
94
+ process.once("SIGTERM", handleSignal);
95
+
96
+ await server.done;
97
+
98
+ process.removeListener("SIGINT", handleSignal);
99
+ process.removeListener("SIGTERM", handleSignal);
100
+
101
+ return {
102
+ ok: true,
103
+ exitCode: 0,
104
+ data: "Web console stopped. Router service keeps running."
105
+ };
106
+ }
@@ -0,0 +1,26 @@
1
+ import { WEB_CONSOLE_CSS } from "./web-console-styles.generated.js";
2
+
3
+ export { WEB_CONSOLE_CSS };
4
+
5
+ export function renderWebConsoleHtml({
6
+ title = "LLM Router Web",
7
+ headHtml = "",
8
+ bodyHtml = ""
9
+ } = {}) {
10
+ return String.raw`<!doctype html>
11
+ <html lang="en">
12
+ <head>
13
+ <meta charset="utf-8">
14
+ <meta name="viewport" content="width=device-width, initial-scale=1">
15
+ <meta name="color-scheme" content="light">
16
+ <title>${title}</title>
17
+ ${headHtml}
18
+ <link rel="stylesheet" href="/styles.css">
19
+ <script src="/app.js" defer></script>
20
+ </head>
21
+ <body>
22
+ <div id="app"></div>
23
+ ${bodyHtml}
24
+ </body>
25
+ </html>`;
26
+ }