@tonyclaw/llm-inspector 1.6.3 → 1.7.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.
@@ -1,5 +1,5 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports, a as React } from "../_libs/react.mjs";
2
- import { C as CapturedLogSchema, a as parseRequest, p as parseOpenAIResponse, I as InspectorResponseSchema } from "./router-Bq_mxeNz.mjs";
2
+ import { C as CapturedLogSchema, a as parseRequest, p as parseOpenAIResponse, I as InspectorResponseSchema } from "./router-D7g2K6y6.mjs";
3
3
  import { u as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
4
4
  import { J as JSZip } from "../_libs/jszip.mjs";
5
5
  import { c as clsx } from "../_libs/clsx.mjs";
@@ -7,7 +7,7 @@ import { t as twMerge } from "../_libs/tailwind-merge.mjs";
7
7
  import { c as cva } from "../_libs/class-variance-authority.mjs";
8
8
  import { R as Root, T as Trigger$1, C as Content, a as Close, b as Title, P as Portal$1, O as Overlay } from "../_libs/radix-ui__react-dialog.mjs";
9
9
  import { R as Root2, T as Trigger, I as Icon, V as Value, P as Portal, C as Content2, a as Viewport, b as Item, c as ItemIndicator, d as ItemText, S as ScrollUpButton, e as ScrollDownButton } from "../_libs/radix-ui__react-select.mjs";
10
- import { D as Download, L as LayoutGrid, a as List, S as Settings, C as ChevronDown, b as Check, R as RotateCcw, X, P as Plus, c as Copy, d as CircleAlert, e as ChevronUp, f as ChevronRight, g as Clock, M as MessageSquare, Z as Zap, h as LoaderCircle, W as Wrench, G as Globe, U as User, F as FileTerminal, i as Radio, E as ExternalLink, j as EyeOff, k as Eye, l as RotateCw, m as Pencil, T as Trash2, n as TriangleAlert, o as Minus, p as CircleCheckBig, q as CircleX, r as CircleStop, s as ChevronsUp, t as ChevronsDown, u as Terminal, B as Brain } from "../_libs/lucide-react.mjs";
10
+ import { D as Download, L as LayoutGrid, a as List, S as Settings, C as ChevronDown, b as Check, R as RotateCcw, X, P as Plus, c as Copy, d as CircleAlert, e as ChevronUp, f as ChevronRight, g as Clock, M as MessageSquare, Z as Zap, h as LoaderCircle, W as Wrench, G as Globe, U as User, F as FileTerminal, i as Radio, E as ExternalLink, j as EyeOff, k as Eye, l as RotateCw, m as Pencil, T as Trash2, n as TriangleAlert, o as Minus, p as CircleCheckBig, q as CircleStop, r as CircleQuestionMark, s as Server, t as Gauge, u as Lock, v as Wifi, w as WifiOff, x as ChevronsUp, y as ChevronsDown, z as Terminal, B as Brain } from "../_libs/lucide-react.mjs";
11
11
  import { M as Markdown } from "../_libs/react-markdown.mjs";
12
12
  import { a as array, s as string, u as union, o as object, l as literal, b as boolean, n as number } from "../_libs/zod.mjs";
13
13
  import { R as Root2$1, L as List$1, T as Trigger$2, C as Content$1 } from "../_libs/radix-ui__react-tabs.mjs";
@@ -27,6 +27,10 @@ import "../_libs/seroval-plugins.mjs";
27
27
  import "node:stream/web";
28
28
  import "node:stream";
29
29
  import "../_libs/react-dom.mjs";
30
+ import "util";
31
+ import "crypto";
32
+ import "async_hooks";
33
+ import "stream";
30
34
  import "../_libs/isbot.mjs";
31
35
  import "node:fs";
32
36
  import "node:path";
@@ -52,11 +56,9 @@ import "../_libs/debounce-fn.mjs";
52
56
  import "../_libs/mimic-function.mjs";
53
57
  import "../_libs/semver.mjs";
54
58
  import "../_libs/uint8array-extras.mjs";
55
- import "crypto";
56
59
  import "node:child_process";
57
60
  import "../_libs/tanstack__virtual-core.mjs";
58
61
  import "../_libs/readable-stream.mjs";
59
- import "stream";
60
62
  import "../_libs/process-nextick-args.mjs";
61
63
  import "../_libs/isarray.mjs";
62
64
  import "events";
@@ -64,7 +66,6 @@ import "../_libs/safe-buffer.mjs";
64
66
  import "buffer";
65
67
  import "../_libs/core-util-is.mjs";
66
68
  import "../_libs/inherits.mjs";
67
- import "util";
68
69
  import "../_libs/util-deprecate.mjs";
69
70
  import "node:string_decoder";
70
71
  import "../_libs/lie.mjs";
@@ -2115,7 +2116,33 @@ function maskApiKey(apiKey) {
2115
2116
  function hasSuccessField(result) {
2116
2117
  return Object.prototype.hasOwnProperty.call(result, "success");
2117
2118
  }
2118
- function TestStatus({ result }) {
2119
+ function getErrorIcon(type) {
2120
+ const iconProps = { className: "size-3", strokeWidth: 2 };
2121
+ switch (type) {
2122
+ case "timeout":
2123
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { ...iconProps });
2124
+ case "network_unreachable":
2125
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(WifiOff, { ...iconProps });
2126
+ case "connection_refused":
2127
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Wifi, { ...iconProps });
2128
+ case "auth_failed":
2129
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Lock, { ...iconProps });
2130
+ case "rate_limited":
2131
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Gauge, { ...iconProps });
2132
+ case "server_error":
2133
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Server, { ...iconProps });
2134
+ case "invalid_response":
2135
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(CircleQuestionMark, { ...iconProps });
2136
+ case "unknown":
2137
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { ...iconProps });
2138
+ default:
2139
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { ...iconProps });
2140
+ }
2141
+ }
2142
+ function TestStatus({
2143
+ result,
2144
+ isTesting
2145
+ }) {
2119
2146
  if (!hasSuccessField(result)) {
2120
2147
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
2121
2148
  /* @__PURE__ */ jsxRuntimeExports.jsx(Minus, { className: "size-3" }),
@@ -2128,9 +2155,23 @@ function TestStatus({ result }) {
2128
2155
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Connected" })
2129
2156
  ] });
2130
2157
  }
2131
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 text-xs text-red-600", title: result.error, children: [
2132
- /* @__PURE__ */ jsxRuntimeExports.jsx(CircleX, { className: "size-3" }),
2133
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: result.error })
2158
+ const error = result.error;
2159
+ const errorMessage = error?.message ?? "Connection failed";
2160
+ const errorHint = error?.hint;
2161
+ const errorType = error?.type ?? "unknown";
2162
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1 min-w-0", children: [
2163
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
2164
+ "div",
2165
+ {
2166
+ className: "flex items-center gap-1 text-xs text-red-600 min-w-0",
2167
+ title: error?.details ?? errorMessage,
2168
+ children: [
2169
+ getErrorIcon(errorType),
2170
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: errorMessage })
2171
+ ]
2172
+ }
2173
+ ),
2174
+ errorHint !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-muted-foreground pl-4 truncate", title: errorHint, children: errorHint })
2134
2175
  ] });
2135
2176
  }
2136
2177
  function ProviderCard({
@@ -2182,7 +2223,7 @@ function ProviderCard({
2182
2223
  " ",
2183
2224
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: provider.anthropicBaseUrl })
2184
2225
  ] }),
2185
- testResults && /* @__PURE__ */ jsxRuntimeExports.jsx(TestStatus, { result: testResults.anthropic.nonStreaming })
2226
+ testResults && /* @__PURE__ */ jsxRuntimeExports.jsx(TestStatus, { result: testResults.anthropic.nonStreaming, isTesting })
2186
2227
  ] }),
2187
2228
  provider.openaiBaseUrl !== void 0 && provider.openaiBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
2188
2229
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-muted-foreground min-w-0 flex-1", children: [
@@ -2190,7 +2231,7 @@ function ProviderCard({
2190
2231
  " ",
2191
2232
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: provider.openaiBaseUrl })
2192
2233
  ] }),
2193
- testResults && /* @__PURE__ */ jsxRuntimeExports.jsx(TestStatus, { result: testResults.openai.nonStreaming })
2234
+ testResults && /* @__PURE__ */ jsxRuntimeExports.jsx(TestStatus, { result: testResults.openai.nonStreaming, isTesting })
2194
2235
  ] }),
2195
2236
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 pt-1 border-t", children: [
2196
2237
  onTest !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
@@ -2506,10 +2547,18 @@ function ProvidersPanel() {
2506
2547
  }, []);
2507
2548
  function handleAddProvider(data) {
2508
2549
  void (async () => {
2550
+ const payload = {
2551
+ name: data.name,
2552
+ apiKey: data.apiKey,
2553
+ model: data.model,
2554
+ format: data.format,
2555
+ anthropicBaseUrl: data.format === "anthropic" ? data.baseUrl : void 0,
2556
+ openaiBaseUrl: data.format === "openai" ? data.baseUrl : void 0
2557
+ };
2509
2558
  const res = await fetch("/api/providers", {
2510
2559
  method: "POST",
2511
2560
  headers: { "Content-Type": "application/json" },
2512
- body: JSON.stringify(data)
2561
+ body: JSON.stringify(payload)
2513
2562
  });
2514
2563
  if (!res.ok) {
2515
2564
  const err = await res.json();
@@ -2525,10 +2574,18 @@ function ProvidersPanel() {
2525
2574
  function handleUpdateProvider(data) {
2526
2575
  if (!editingProvider) return;
2527
2576
  void (async () => {
2577
+ const payload = {
2578
+ name: data.name,
2579
+ apiKey: data.apiKey,
2580
+ model: data.model,
2581
+ format: data.format,
2582
+ anthropicBaseUrl: data.format === "anthropic" ? data.baseUrl : void 0,
2583
+ openaiBaseUrl: data.format === "openai" ? data.baseUrl : void 0
2584
+ };
2528
2585
  const res = await fetch(`/api/providers/${editingProvider.id}`, {
2529
2586
  method: "PUT",
2530
2587
  headers: { "Content-Type": "application/json" },
2531
- body: JSON.stringify(data)
2588
+ body: JSON.stringify(payload)
2532
2589
  });
2533
2590
  if (!res.ok) {
2534
2591
  const err = await res.json();
@@ -12,8 +12,15 @@ import "node:stream/web";
12
12
  import "node:stream";
13
13
  import "../_libs/rou3.mjs";
14
14
  import "../_libs/srvx.mjs";
15
+ import "node:http";
16
+ import "node:https";
17
+ import "node:http2";
15
18
  import "../_libs/tiny-warning.mjs";
16
19
  import "../_libs/react-dom.mjs";
20
+ import "util";
21
+ import "crypto";
22
+ import "async_hooks";
23
+ import "stream";
17
24
  import "../_libs/isbot.mjs";
18
25
  function StartServer(props) {
19
26
  return /* @__PURE__ */ jsxRuntimeExports.jsx(RouterProvider, { router: props.router });
@@ -190,7 +197,7 @@ function getResponse() {
190
197
  return event.res;
191
198
  }
192
199
  async function getStartManifest(matchedRoutes) {
193
- const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-C4E0e9my.mjs");
200
+ const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-b6u6g-Cr.mjs");
194
201
  const startManifest = tsrStartManifest();
195
202
  const rootRoute = startManifest.routes[rootRouteId] = startManifest.routes[rootRouteId] || {};
196
203
  rootRoute.assets = rootRoute.assets || [];
@@ -759,7 +766,7 @@ let entriesPromise;
759
766
  let baseManifestPromise;
760
767
  let cachedFinalManifestPromise;
761
768
  async function loadEntries() {
762
- const routerEntry = await import("./router-Bq_mxeNz.mjs").then((n) => n.r);
769
+ const routerEntry = await import("./router-D7g2K6y6.mjs").then((n) => n.r);
763
770
  const startEntry = await import("./start-HYkvq4Ni.mjs");
764
771
  return { startEntry, routerEntry };
765
772
  }
@@ -18,6 +18,9 @@ import "../_libs/seroval-plugins.mjs";
18
18
  import "node:stream/web";
19
19
  import "node:stream";
20
20
  import "../_libs/react-dom.mjs";
21
+ import "util";
22
+ import "async_hooks";
23
+ import "stream";
21
24
  import "../_libs/isbot.mjs";
22
25
  import "node:process";
23
26
  import "node:crypto";
@@ -62,7 +65,7 @@ function RootDocument({ children }) {
62
65
  ] })
63
66
  ] });
64
67
  }
65
- const $$splitComponentImporter = () => import("./index-ByCLZu7J.mjs");
68
+ const $$splitComponentImporter = () => import("./index-BZkxgx8f.mjs");
66
69
  const Route$d = createFileRoute("/")({
67
70
  component: lazyRouteComponent($$splitComponentImporter, "component")
68
71
  });
@@ -2071,6 +2074,77 @@ const Route$3 = createFileRoute("/api/config/paths")({
2071
2074
  }
2072
2075
  }
2073
2076
  });
2077
+ const ERROR_HINTS = {
2078
+ timeout: "The request took too long. Check your network connection or try again.",
2079
+ network_unreachable: "Cannot reach the server. Verify the base URL and check your firewall settings.",
2080
+ connection_refused: "Connection was refused. Make sure the provider server is running and the URL is correct.",
2081
+ auth_failed: "Authentication failed. Check your API key is correct and has not expired.",
2082
+ rate_limited: "Too many requests. Wait a moment and try again, or check your API quota.",
2083
+ server_error: "The provider server encountered an error. Check their status page and try again later.",
2084
+ invalid_response: "Received an unexpected response. The provider may be experiencing issues.",
2085
+ unknown: "An unexpected error occurred. Check the details and try again."
2086
+ };
2087
+ const MAX_ERROR_DETAILS_LENGTH = 200;
2088
+ function classifyError(error, responseStatus) {
2089
+ const errorStr = String(error);
2090
+ if (error instanceof Error && error.name === "AbortError") {
2091
+ return { type: "timeout", details: "Request was aborted due to timeout" };
2092
+ }
2093
+ if (errorStr.includes("timeout") || errorStr.includes("timed out") || errorStr.includes("Timeout")) {
2094
+ return { type: "timeout", details: truncateErrorDetails(errorStr) };
2095
+ }
2096
+ if (errorStr.includes("ECONNREFUSED") || errorStr.includes("connection refused")) {
2097
+ return { type: "connection_refused", details: truncateErrorDetails(errorStr) };
2098
+ }
2099
+ if (errorStr.includes("ENOTFOUND") || errorStr.includes("getaddrinfo") || errorStr.includes("DNS") || errorStr.includes("network") || errorStr.includes("fetch failed")) {
2100
+ return { type: "network_unreachable", details: truncateErrorDetails(errorStr) };
2101
+ }
2102
+ if (responseStatus !== void 0) {
2103
+ if (responseStatus === 401 || responseStatus === 403) {
2104
+ return { type: "auth_failed", details: `HTTP ${responseStatus}` };
2105
+ }
2106
+ if (responseStatus === 429) {
2107
+ return { type: "rate_limited", details: `HTTP ${responseStatus}` };
2108
+ }
2109
+ if (responseStatus >= 500 && responseStatus < 600) {
2110
+ return { type: "server_error", details: `HTTP ${responseStatus}` };
2111
+ }
2112
+ }
2113
+ return { type: "unknown", details: truncateErrorDetails(errorStr) };
2114
+ }
2115
+ function truncateErrorDetails(details) {
2116
+ if (details.length <= MAX_ERROR_DETAILS_LENGTH) {
2117
+ return details;
2118
+ }
2119
+ return details.slice(0, MAX_ERROR_DETAILS_LENGTH) + "...";
2120
+ }
2121
+ function createErrorResult(error, latencyMs, streaming, responseStatus) {
2122
+ const { type, details } = classifyError(error, responseStatus);
2123
+ return {
2124
+ success: false,
2125
+ error: {
2126
+ message: getErrorMessage(type),
2127
+ type,
2128
+ details,
2129
+ hint: ERROR_HINTS[type]
2130
+ },
2131
+ latencyMs,
2132
+ streaming
2133
+ };
2134
+ }
2135
+ function getErrorMessage(type) {
2136
+ const messages = {
2137
+ timeout: "Request timed out",
2138
+ network_unreachable: "Cannot reach host",
2139
+ connection_refused: "Connection refused",
2140
+ auth_failed: "Authentication failed",
2141
+ rate_limited: "Rate limited",
2142
+ server_error: "Provider server error",
2143
+ invalid_response: "Invalid response",
2144
+ unknown: "Unknown error"
2145
+ };
2146
+ return messages[type];
2147
+ }
2074
2148
  const AnthropicResponseSchema = object({
2075
2149
  id: string().optional(),
2076
2150
  type: string().optional(),
@@ -2103,6 +2177,7 @@ const OpenAIResponseSchema = object({
2103
2177
  })
2104
2178
  )
2105
2179
  });
2180
+ const TEST_TIMEOUT_MS = 3e4;
2106
2181
  async function testEndpoint(baseUrl, apiKey, path2, model, isOpenAI) {
2107
2182
  const startTime = Date.now();
2108
2183
  const body = JSON.stringify({
@@ -2110,6 +2185,8 @@ async function testEndpoint(baseUrl, apiKey, path2, model, isOpenAI) {
2110
2185
  messages: [{ role: "user", content: "say hello and briefly introduce yourself" }],
2111
2186
  max_tokens: 1024
2112
2187
  });
2188
+ const controller = new AbortController();
2189
+ const timeoutId = setTimeout(() => controller.abort(), TEST_TIMEOUT_MS);
2113
2190
  try {
2114
2191
  const url = `${baseUrl}${path2}`;
2115
2192
  const response = await fetch(url, {
@@ -2118,17 +2195,20 @@ async function testEndpoint(baseUrl, apiKey, path2, model, isOpenAI) {
2118
2195
  "Content-Type": "application/json",
2119
2196
  Authorization: `Bearer ${apiKey}`
2120
2197
  },
2121
- body
2198
+ body,
2199
+ signal: controller.signal
2122
2200
  });
2201
+ clearTimeout(timeoutId);
2123
2202
  const latencyMs = Date.now() - startTime;
2124
- const responseText = await response.text();
2125
2203
  if (!response.ok) {
2126
- return {
2127
- success: false,
2128
- error: `HTTP ${response.status}: ${responseText.slice(0, 200)}`,
2129
- latencyMs
2130
- };
2204
+ return createErrorResult(
2205
+ `HTTP ${response.status}: ${response.statusText}`,
2206
+ latencyMs,
2207
+ false,
2208
+ response.status
2209
+ );
2131
2210
  }
2211
+ const responseText = await response.text();
2132
2212
  try {
2133
2213
  if (isOpenAI) {
2134
2214
  const json = OpenAIResponseSchema.parse(JSON.parse(responseText));
@@ -2178,11 +2258,8 @@ async function testEndpoint(baseUrl, apiKey, path2, model, isOpenAI) {
2178
2258
  };
2179
2259
  }
2180
2260
  } catch (err) {
2181
- return {
2182
- success: false,
2183
- error: String(err),
2184
- latencyMs: Date.now() - startTime
2185
- };
2261
+ clearTimeout(timeoutId);
2262
+ return createErrorResult(err, Date.now() - startTime, false);
2186
2263
  }
2187
2264
  }
2188
2265
  async function testStreamingEndpoint(baseUrl, apiKey, path2, model, isOpenAI) {
@@ -2193,6 +2270,8 @@ async function testStreamingEndpoint(baseUrl, apiKey, path2, model, isOpenAI) {
2193
2270
  max_tokens: 256,
2194
2271
  stream: true
2195
2272
  });
2273
+ const controller = new AbortController();
2274
+ const timeoutId = setTimeout(() => controller.abort(), TEST_TIMEOUT_MS);
2196
2275
  try {
2197
2276
  const url = `${baseUrl}${path2}`;
2198
2277
  const response = await fetch(url, {
@@ -2201,24 +2280,29 @@ async function testStreamingEndpoint(baseUrl, apiKey, path2, model, isOpenAI) {
2201
2280
  "Content-Type": "application/json",
2202
2281
  Authorization: `Bearer ${apiKey}`
2203
2282
  },
2204
- body
2283
+ body,
2284
+ signal: controller.signal
2205
2285
  });
2286
+ clearTimeout(timeoutId);
2206
2287
  const latencyMs = Date.now() - startTime;
2207
2288
  if (!response.ok) {
2208
- const responseText = await response.text();
2209
- return {
2210
- success: false,
2211
- error: `HTTP ${response.status}: ${responseText.slice(0, 200)}`,
2289
+ return createErrorResult(
2290
+ `HTTP ${response.status}: ${response.statusText}`,
2212
2291
  latencyMs,
2213
- streaming: true
2214
- };
2292
+ true,
2293
+ response.status
2294
+ );
2215
2295
  }
2216
2296
  const chunks = [];
2217
2297
  const reader = response.body?.getReader();
2218
2298
  if (!reader) {
2219
2299
  return {
2220
2300
  success: false,
2221
- error: "No response body",
2301
+ error: {
2302
+ message: "No response body",
2303
+ type: "invalid_response",
2304
+ hint: ERROR_HINTS.invalid_response
2305
+ },
2222
2306
  latencyMs,
2223
2307
  streaming: true
2224
2308
  };
@@ -2231,12 +2315,7 @@ async function testStreamingEndpoint(baseUrl, apiKey, path2, model, isOpenAI) {
2231
2315
  chunks.push(decoder.decode(value, { stream: true }));
2232
2316
  }
2233
2317
  } catch (readErr) {
2234
- return {
2235
- success: false,
2236
- error: `Stream read error: ${readErr}`,
2237
- latencyMs,
2238
- streaming: true
2239
- };
2318
+ return createErrorResult(`Stream read error: ${readErr}`, latencyMs, true);
2240
2319
  }
2241
2320
  const fullResponse = chunks.join("");
2242
2321
  const mockLog = {
@@ -2317,12 +2396,8 @@ async function testStreamingEndpoint(baseUrl, apiKey, path2, model, isOpenAI) {
2317
2396
  };
2318
2397
  }
2319
2398
  } catch (err) {
2320
- return {
2321
- success: false,
2322
- error: String(err),
2323
- latencyMs: Date.now() - startTime,
2324
- streaming: true
2325
- };
2399
+ clearTimeout(timeoutId);
2400
+ return createErrorResult(err, Date.now() - startTime, true);
2326
2401
  }
2327
2402
  }
2328
2403
  function createTestLogEntry(providerName, path2, body, upstreamUrl, result, isTest) {
@@ -2343,7 +2418,7 @@ function createTestLogEntry(providerName, path2, body, upstreamUrl, result, isTe
2343
2418
  userAgent: "provider-test",
2344
2419
  origin: null,
2345
2420
  upstreamUrl,
2346
- error: result.success ? null : result.error,
2421
+ error: result.success ? null : result.error?.message ?? String(result.error),
2347
2422
  isTest: true,
2348
2423
  providerName
2349
2424
  };
@@ -1,4 +1,4 @@
1
- const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/__root.tsx", "children": ["/", "/api/health", "/api/logs", "/api/models", "/api/providers", "/api/sessions", "/proxy/$", "/api/config/paths"], "preloads": ["/assets/main-Cp8AM0Pa.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-s4lwsWvq.js"] }, "/api/health": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/health.ts" }, "/api/logs": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.ts", "children": ["/api/logs/$id", "/api/logs/stream"] }, "/api/models": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/models.ts" }, "/api/providers": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.ts", "children": ["/api/providers/$providerId"] }, "/api/sessions": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/sessions.ts" }, "/proxy/$": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/proxy/$.ts" }, "/api/config/paths": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/config.paths.ts" }, "/api/logs/$id": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.ts", "children": ["/api/logs/$id/chunks", "/api/logs/$id/replay"] }, "/api/logs/stream": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.stream.ts" }, "/api/providers/$providerId": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.ts", "children": ["/api/providers/$providerId/test"] }, "/api/logs/$id/chunks": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.chunks.ts" }, "/api/logs/$id/replay": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.replay.ts" }, "/api/providers/$providerId/test": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.test.ts" } }, "clientEntry": "/assets/main-Cp8AM0Pa.js" });
1
+ const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/__root.tsx", "children": ["/", "/api/health", "/api/logs", "/api/models", "/api/providers", "/api/sessions", "/proxy/$", "/api/config/paths"], "preloads": ["/assets/main-CpIX1ZHy.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-Bf_WGooQ.js"] }, "/api/health": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/health.ts" }, "/api/logs": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.ts", "children": ["/api/logs/$id", "/api/logs/stream"] }, "/api/models": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/models.ts" }, "/api/providers": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.ts", "children": ["/api/providers/$providerId"] }, "/api/sessions": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/sessions.ts" }, "/proxy/$": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/proxy/$.ts" }, "/api/config/paths": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/config.paths.ts" }, "/api/logs/$id": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.ts", "children": ["/api/logs/$id/chunks", "/api/logs/$id/replay"] }, "/api/logs/stream": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.stream.ts" }, "/api/providers/$providerId": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.ts", "children": ["/api/providers/$providerId/test"] }, "/api/logs/$id/chunks": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.chunks.ts" }, "/api/logs/$id/replay": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.replay.ts" }, "/api/providers/$providerId/test": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.test.ts" } }, "clientEntry": "/assets/main-CpIX1ZHy.js" });
2
2
  export {
3
3
  tsrStartManifest
4
4
  };
@@ -1,10 +1,14 @@
1
1
  globalThis.__nitro_main__ = import.meta.url;
2
- import { a as FastResponse, s as serve } from "./_libs/srvx.mjs";
2
+ import { N as NodeResponse, s as serve } from "./_libs/srvx.mjs";
3
3
  import { d as defineHandler, H as HTTPError, t as toEventHandler, a as defineLazyEventHandler, b as H3Core } from "./_libs/h3.mjs";
4
4
  import { d as decodePath, w as withLeadingSlash, a as withoutTrailingSlash, j as joinURL } from "./_libs/ufo.mjs";
5
5
  import { promises } from "node:fs";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { dirname, resolve } from "node:path";
8
+ import "node:http";
9
+ import "node:stream";
10
+ import "node:https";
11
+ import "node:http2";
8
12
  import "./_libs/rou3.mjs";
9
13
  function lazyService(loader) {
10
14
  let promise, mod;
@@ -26,7 +30,7 @@ const services = {
26
30
  globalThis.__nitro_vite_envs__ = services;
27
31
  const errorHandler$1 = (error, event) => {
28
32
  const res = defaultHandler(error, event);
29
- return new FastResponse(typeof res.body === "string" ? res.body : JSON.stringify(res.body, null, 2), res);
33
+ return new NodeResponse(typeof res.body === "string" ? res.body : JSON.stringify(res.body, null, 2), res);
30
34
  };
31
35
  function defaultHandler(error, event, opts) {
32
36
  const isSensitive = error.unhandled;
@@ -93,54 +97,54 @@ const headers = ((m) => function headersRouteRule(event) {
93
97
  }
94
98
  });
95
99
  const assets = {
100
+ "/assets/alibaba-TTwafVwX.svg": {
101
+ "type": "image/svg+xml",
102
+ "etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
103
+ "mtime": "2026-06-03T09:17:40.502Z",
104
+ "size": 5915,
105
+ "path": "../public/assets/alibaba-TTwafVwX.svg"
106
+ },
96
107
  "/assets/index-B3RwBPLW.css": {
97
108
  "type": "text/css; charset=utf-8",
98
109
  "etag": '"10c74-aXacU4DRFVsUwcC5jHnjoPRSlTA"',
99
- "mtime": "2026-06-03T08:06:11.052Z",
110
+ "mtime": "2026-06-03T09:17:40.504Z",
100
111
  "size": 68724,
101
112
  "path": "../public/assets/index-B3RwBPLW.css"
102
113
  },
103
- "/assets/alibaba-TTwafVwX.svg": {
104
- "type": "image/svg+xml",
105
- "etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
106
- "mtime": "2026-06-03T08:06:11.050Z",
107
- "size": 5915,
108
- "path": "../public/assets/alibaba-TTwafVwX.svg"
114
+ "/assets/main-CpIX1ZHy.js": {
115
+ "type": "text/javascript; charset=utf-8",
116
+ "etag": '"4db57-PIyiLXQGvlFJuizUFXRhGOYXJwY"',
117
+ "mtime": "2026-06-03T09:17:40.504Z",
118
+ "size": 318295,
119
+ "path": "../public/assets/main-CpIX1ZHy.js"
109
120
  },
110
121
  "/assets/minimax-BPMzvuL-.jpeg": {
111
122
  "type": "image/jpeg",
112
123
  "etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
113
- "mtime": "2026-06-03T08:06:11.050Z",
124
+ "mtime": "2026-06-03T09:17:40.501Z",
114
125
  "size": 6918,
115
126
  "path": "../public/assets/minimax-BPMzvuL-.jpeg"
116
127
  },
117
128
  "/assets/zhipuai-BPNAnxo-.svg": {
118
129
  "type": "image/svg+xml",
119
130
  "etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
120
- "mtime": "2026-06-03T08:06:11.050Z",
131
+ "mtime": "2026-06-03T09:17:40.502Z",
121
132
  "size": 11256,
122
133
  "path": "../public/assets/zhipuai-BPNAnxo-.svg"
123
134
  },
124
- "/assets/main-Cp8AM0Pa.js": {
125
- "type": "text/javascript; charset=utf-8",
126
- "etag": '"4db57-FpqlPRLq9OHoaAFCL2NIXtZbW5c"',
127
- "mtime": "2026-06-03T08:06:11.052Z",
128
- "size": 318295,
129
- "path": "../public/assets/main-Cp8AM0Pa.js"
130
- },
131
135
  "/assets/qwen-CONDcHqt.png": {
132
136
  "type": "image/png",
133
137
  "etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
134
- "mtime": "2026-06-03T08:06:11.052Z",
138
+ "mtime": "2026-06-03T09:17:40.502Z",
135
139
  "size": 357059,
136
140
  "path": "../public/assets/qwen-CONDcHqt.png"
137
141
  },
138
- "/assets/index-s4lwsWvq.js": {
142
+ "/assets/index-Bf_WGooQ.js": {
139
143
  "type": "text/javascript; charset=utf-8",
140
- "etag": '"828c8-LEW/XL92J2/5lU4VKALlH7aVpaA"',
141
- "mtime": "2026-06-03T08:06:11.052Z",
142
- "size": 534728,
143
- "path": "../public/assets/index-s4lwsWvq.js"
144
+ "etag": '"831df-gmdpd1CCnM4IdaxHIs9uyMgWFaY"',
145
+ "mtime": "2026-06-03T09:17:40.504Z",
146
+ "size": 537055,
147
+ "path": "../public/assets/index-Bf_WGooQ.js"
144
148
  }
145
149
  };
146
150
  function readAsset(id) {
@@ -375,7 +379,6 @@ const host = process.env.NITRO_HOST || process.env.HOST;
375
379
  const cert = process.env.NITRO_SSL_CERT;
376
380
  const key = process.env.NITRO_SSL_KEY;
377
381
  const nitroApp = useNitroApp();
378
- let _fetch = nitroApp.fetch;
379
382
  serve({
380
383
  port,
381
384
  hostname: host,
@@ -383,11 +386,10 @@ serve({
383
386
  cert,
384
387
  key
385
388
  } : void 0,
386
- fetch: _fetch,
387
- bun: { websocket: void 0 }
389
+ fetch: nitroApp.fetch
388
390
  });
389
391
  trapUnhandledErrors();
390
- const bun = {};
392
+ const nodeServer = {};
391
393
  export {
392
- bun as default
394
+ nodeServer as default
393
395
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tonyclaw/llm-inspector",
3
- "version": "1.6.3",
3
+ "version": "1.7.1",
4
4
  "type": "module",
5
5
  "description": "LLM API proxy inspector — captures and displays requests/responses from AI coding tools in a web UI",
6
6
  "license": "MIT",