@tonyclaw/llm-inspector 1.14.0 → 1.14.2

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.
@@ -9,7 +9,7 @@ import { randomUUID } from "crypto";
9
9
  import { exec } from "node:child_process";
10
10
  import { promisify } from "node:util";
11
11
  import { M as McpServer, W as WebStandardStreamableHTTPServerTransport } from "../_libs/modelcontextprotocol__server.mjs";
12
- import { d as object, b as string, _ as _enum, u as union, a as array, c as boolean, n as number, g as discriminatedUnion, l as literal, r as record, h as _null, k as lazy, e as unknown } from "../_libs/zod.mjs";
12
+ import { d as object, _ as _enum, b as string, a as array, u as union, c as boolean, r as record, n as number, g as discriminatedUnion, l as literal, h as _null, k as lazy, e as unknown } from "../_libs/zod.mjs";
13
13
  import "../_libs/tiny-warning.mjs";
14
14
  import "../_libs/tanstack__router-core.mjs";
15
15
  import "../_libs/cookie-es.mjs";
@@ -45,8 +45,8 @@ import "../_libs/debounce-fn.mjs";
45
45
  import "../_libs/mimic-function.mjs";
46
46
  import "../_libs/semver.mjs";
47
47
  import "../_libs/uint8array-extras.mjs";
48
- const appCss = "/assets/index-B5q3Llgm.css";
49
- const Route$i = createRootRoute({
48
+ const appCss = "/assets/index-DOG5AdQ9.css";
49
+ const Route$j = createRootRoute({
50
50
  head: () => ({
51
51
  meta: [
52
52
  { charSet: "utf-8" },
@@ -69,8 +69,8 @@ function RootDocument({ children }) {
69
69
  ] })
70
70
  ] });
71
71
  }
72
- const $$splitComponentImporter = () => import("./index-AxruZp16.mjs");
73
- const Route$h = createFileRoute("/")({
72
+ const $$splitComponentImporter = () => import("./index-DmLit8Ad.mjs");
73
+ const Route$i = createFileRoute("/")({
74
74
  component: lazyRouteComponent($$splitComponentImporter, "component")
75
75
  });
76
76
  const LOG_DIR_ENV = process.env["LOG_DIR"];
@@ -1608,12 +1608,14 @@ const ProviderConfigSchema = object({
1608
1608
  name: string(),
1609
1609
  apiKey: string(),
1610
1610
  model: string().optional(),
1611
+ models: array(string()).min(1),
1611
1612
  format: _enum(["anthropic", "openai"]).optional(),
1612
1613
  baseUrl: string().optional(),
1613
1614
  anthropicBaseUrl: string().optional(),
1614
1615
  openaiBaseUrl: string().optional(),
1615
1616
  authHeader: _enum(["bearer", "x-api-key"]).optional().default("bearer"),
1616
1617
  apiDocsUrl: string().optional(),
1618
+ source: _enum(["company", "personal"]).optional(),
1617
1619
  createdAt: string(),
1618
1620
  updatedAt: string()
1619
1621
  });
@@ -1674,6 +1676,62 @@ function migrateProviders() {
1674
1676
  }
1675
1677
  }
1676
1678
  migrateProviders();
1679
+ function migrateMultiModel() {
1680
+ const providers = store.get("providers", []);
1681
+ if (providers.length === 0) return;
1682
+ let changed = false;
1683
+ const promoted = providers.map((p) => {
1684
+ if (p.models !== void 0 && p.models.length > 0) return p;
1685
+ const models = p.model !== void 0 && p.model !== "" ? [p.model] : [];
1686
+ changed = true;
1687
+ return { ...p, models };
1688
+ });
1689
+ const groups = /* @__PURE__ */ new Map();
1690
+ for (const p of promoted) {
1691
+ const key = `${p.apiKey}::${p.anthropicBaseUrl ?? ""}::${p.openaiBaseUrl ?? ""}`;
1692
+ const group = groups.get(key);
1693
+ if (group !== void 0) {
1694
+ group.push(p);
1695
+ } else {
1696
+ groups.set(key, [p]);
1697
+ }
1698
+ }
1699
+ const merged = [];
1700
+ for (const group of groups.values()) {
1701
+ const first = group[0];
1702
+ if (group.length === 1 && first !== void 0) {
1703
+ merged.push(first);
1704
+ continue;
1705
+ }
1706
+ changed = true;
1707
+ const sorted = group.toSorted(
1708
+ (a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
1709
+ );
1710
+ const earliest = sorted[0];
1711
+ if (earliest === void 0) continue;
1712
+ const allModels = /* @__PURE__ */ new Set();
1713
+ for (const p of sorted) {
1714
+ for (const m of p.models ?? []) {
1715
+ if (m !== "") allModels.add(m);
1716
+ }
1717
+ }
1718
+ const mergedSource = sorted.find((p) => p.source !== void 0)?.source;
1719
+ merged.push({
1720
+ ...earliest,
1721
+ models: [...allModels],
1722
+ source: mergedSource,
1723
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1724
+ });
1725
+ }
1726
+ if (changed && merged.length > 0) {
1727
+ try {
1728
+ writeFileSync(`${store.path}.bak`, readFileSync(store.path, "utf-8"));
1729
+ } catch {
1730
+ }
1731
+ store.set("providers", merged);
1732
+ }
1733
+ }
1734
+ migrateMultiModel();
1677
1735
  const providersJson = process.env["LLM_INSPECTOR_PROVIDERS_JSON"];
1678
1736
  if (providersJson !== void 0) {
1679
1737
  try {
@@ -1695,22 +1753,40 @@ function getProvider(id) {
1695
1753
  function normalizeApiKey(apiKey) {
1696
1754
  return apiKey.replace(/^Bearer\s+/i, "").trim();
1697
1755
  }
1698
- function addProvider(name, apiKey, format, baseUrl, model, authHeader, apiDocsUrl) {
1756
+ function addProvider(name, apiKey, format, baseUrl, models, authHeader, apiDocsUrl, anthropicBaseUrl, openaiBaseUrl, source) {
1699
1757
  const providers = getProviders();
1758
+ const normalizedKey = normalizeApiKey(apiKey);
1759
+ const resolvedAnthropicUrl = anthropicBaseUrl ?? "";
1760
+ const resolvedOpenaiUrl = openaiBaseUrl ?? "";
1700
1761
  const now = (/* @__PURE__ */ new Date()).toISOString();
1762
+ const existing = providers.find(
1763
+ (p) => p.apiKey === normalizedKey && (p.anthropicBaseUrl ?? "") === (resolvedAnthropicUrl ?? "") && (p.openaiBaseUrl ?? "") === (resolvedOpenaiUrl ?? "")
1764
+ );
1765
+ if (existing) {
1766
+ const newModels = (models ?? []).filter((m) => m !== "");
1767
+ if (newModels.length > 0) {
1768
+ const mergedModels = new Set(existing.models ?? []);
1769
+ for (const m of newModels) mergedModels.add(m);
1770
+ existing.models = [...mergedModels];
1771
+ existing.updatedAt = now;
1772
+ store.set("providers", providers);
1773
+ }
1774
+ return existing;
1775
+ }
1701
1776
  const newProvider = {
1702
1777
  id: randomUUID(),
1703
1778
  name,
1704
- apiKey: normalizeApiKey(apiKey),
1705
- format,
1779
+ apiKey: normalizedKey,
1780
+ format: format ?? (anthropicBaseUrl !== void 0 ? "anthropic" : openaiBaseUrl !== void 0 ? "openai" : void 0),
1706
1781
  baseUrl,
1707
- model,
1782
+ models: models ?? [],
1708
1783
  authHeader: authHeader ?? "bearer",
1709
1784
  apiDocsUrl,
1710
1785
  createdAt: now,
1711
1786
  updatedAt: now,
1712
- anthropicBaseUrl: format === "anthropic" && baseUrl !== void 0 ? baseUrl : "",
1713
- openaiBaseUrl: format === "openai" && baseUrl !== void 0 ? baseUrl : ""
1787
+ anthropicBaseUrl: resolvedAnthropicUrl,
1788
+ openaiBaseUrl: resolvedOpenaiUrl,
1789
+ source
1714
1790
  };
1715
1791
  providers.push(newProvider);
1716
1792
  store.set("providers", providers);
@@ -1724,7 +1800,7 @@ function updateProvider(id, updates) {
1724
1800
  id: existing.id,
1725
1801
  name: updates.name ?? existing.name,
1726
1802
  apiKey: updates.apiKey !== void 0 ? normalizeApiKey(updates.apiKey) : existing.apiKey,
1727
- model: updates.model !== void 0 ? updates.model : existing.model,
1803
+ models: updates.models !== void 0 ? updates.models : existing.models,
1728
1804
  format: updates.format ?? existing.format,
1729
1805
  baseUrl: updates.baseUrl !== void 0 ? updates.baseUrl : existing.baseUrl,
1730
1806
  authHeader: updates.authHeader ?? existing.authHeader,
@@ -1733,7 +1809,8 @@ function updateProvider(id, updates) {
1733
1809
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
1734
1810
  // Handle format-specific URLs
1735
1811
  anthropicBaseUrl: updates.anthropicBaseUrl !== void 0 ? updates.anthropicBaseUrl : existing.anthropicBaseUrl,
1736
- openaiBaseUrl: updates.openaiBaseUrl !== void 0 ? updates.openaiBaseUrl : existing.openaiBaseUrl
1812
+ openaiBaseUrl: updates.openaiBaseUrl !== void 0 ? updates.openaiBaseUrl : existing.openaiBaseUrl,
1813
+ source: updates.source !== void 0 ? updates.source : existing.source
1737
1814
  };
1738
1815
  const index = providers.findIndex((p) => p.id === id);
1739
1816
  providers[index] = updated;
@@ -1833,16 +1910,21 @@ function findProviderByModel(model) {
1833
1910
  if (modelLower.startsWith(providerPrefix)) {
1834
1911
  return provider;
1835
1912
  }
1836
- if (provider.model !== void 0 && provider.model !== "" && modelNormalized === normalizeModelName(provider.model)) {
1837
- return provider;
1838
- }
1839
- if (provider.model !== void 0 && provider.model !== "") {
1840
- const modelPart = modelNormalized.replace(normalizeModelName(provider.name), "");
1841
- const concatenated = normalizeModelName(provider.name) + modelPart;
1842
- if (modelNormalized === concatenated) {
1913
+ const modelList = provider.models ?? (provider.model !== void 0 ? [provider.model] : []);
1914
+ for (const m of modelList) {
1915
+ if (m !== "" && modelNormalized === normalizeModelName(m)) {
1843
1916
  return provider;
1844
1917
  }
1845
1918
  }
1919
+ for (const m of modelList) {
1920
+ if (m !== "") {
1921
+ const modelPart = modelNormalized.replace(normalizeModelName(provider.name), "");
1922
+ const concatenated = normalizeModelName(provider.name) + modelPart;
1923
+ if (modelNormalized === concatenated) {
1924
+ return provider;
1925
+ }
1926
+ }
1927
+ }
1846
1928
  }
1847
1929
  return null;
1848
1930
  }
@@ -2472,7 +2554,7 @@ async function handleProxy(req) {
2472
2554
  }
2473
2555
  return handleStreamingResponse(upstreamRes, req, startTime, formatHandler, upstreamUrl, log);
2474
2556
  }
2475
- const Route$g = createFileRoute("/proxy/$")({
2557
+ const Route$h = createFileRoute("/proxy/$")({
2476
2558
  server: {
2477
2559
  handlers: {
2478
2560
  GET: ({ request }) => handleProxy(request),
@@ -2484,7 +2566,7 @@ const Route$g = createFileRoute("/proxy/$")({
2484
2566
  }
2485
2567
  }
2486
2568
  });
2487
- const Route$f = createFileRoute("/api/sessions")({
2569
+ const Route$g = createFileRoute("/api/sessions")({
2488
2570
  server: {
2489
2571
  handlers: {
2490
2572
  GET: () => Response.json(getSessions())
@@ -2494,14 +2576,16 @@ const Route$f = createFileRoute("/api/sessions")({
2494
2576
  const ProviderInputSchema = object({
2495
2577
  name: string().min(1, "Name is required"),
2496
2578
  apiKey: string().min(1, "API key is required"),
2497
- format: _enum(["anthropic", "openai"]),
2579
+ format: _enum(["anthropic", "openai"]).optional(),
2498
2580
  anthropicBaseUrl: string().optional(),
2499
2581
  openaiBaseUrl: string().optional(),
2500
- model: string().min(1, "Model is required"),
2582
+ models: array(string()).min(1, "At least one model is required"),
2583
+ model: string().optional(),
2501
2584
  authHeader: _enum(["bearer", "x-api-key"]).optional().default("bearer"),
2502
- apiDocsUrl: string().optional()
2585
+ apiDocsUrl: string().optional(),
2586
+ source: _enum(["company", "personal"]).optional()
2503
2587
  });
2504
- const Route$e = createFileRoute("/api/providers")({
2588
+ const Route$f = createFileRoute("/api/providers")({
2505
2589
  server: {
2506
2590
  handlers: {
2507
2591
  GET: () => {
@@ -2516,17 +2600,21 @@ const Route$e = createFileRoute("/api/providers")({
2516
2600
  parsed.data.name,
2517
2601
  parsed.data.apiKey,
2518
2602
  parsed.data.format,
2519
- parsed.data.format === "anthropic" ? parsed.data.anthropicBaseUrl : parsed.data.openaiBaseUrl,
2520
- parsed.data.model,
2603
+ void 0,
2604
+ // baseUrl (legacy) — use format-specific URLs instead
2605
+ parsed.data.models,
2521
2606
  parsed.data.authHeader,
2522
- parsed.data.apiDocsUrl
2607
+ parsed.data.apiDocsUrl,
2608
+ parsed.data.anthropicBaseUrl,
2609
+ parsed.data.openaiBaseUrl,
2610
+ parsed.data.source
2523
2611
  );
2524
2612
  return Response.json(newProvider, { status: 201 });
2525
2613
  }
2526
2614
  }
2527
2615
  }
2528
2616
  });
2529
- const Route$d = createFileRoute("/api/models")({
2617
+ const Route$e = createFileRoute("/api/models")({
2530
2618
  server: {
2531
2619
  handlers: {
2532
2620
  GET: () => Response.json(getModels())
@@ -3036,7 +3124,7 @@ PATCH-style update: only the fields you supply are changed. Returns the updated
3036
3124
  ({ id }) => safeCall(() => testProviderImpl(callApi, id))
3037
3125
  );
3038
3126
  }
3039
- const Route$c = createFileRoute("/api/mcp")({
3127
+ const Route$d = createFileRoute("/api/mcp")({
3040
3128
  server: {
3041
3129
  handlers: {
3042
3130
  // The SDK may issue either POST, GET, or DELETE. TanStack Start only
@@ -3048,7 +3136,7 @@ const Route$c = createFileRoute("/api/mcp")({
3048
3136
  }
3049
3137
  }
3050
3138
  });
3051
- const Route$b = createFileRoute("/api/logs")({
3139
+ const Route$c = createFileRoute("/api/logs")({
3052
3140
  server: {
3053
3141
  handlers: {
3054
3142
  GET: ({ request }) => {
@@ -3074,7 +3162,7 @@ const Route$b = createFileRoute("/api/logs")({
3074
3162
  }
3075
3163
  });
3076
3164
  logger.debug("Health endpoint loaded");
3077
- const Route$a = createFileRoute("/api/health")({
3165
+ const Route$b = createFileRoute("/api/health")({
3078
3166
  server: {
3079
3167
  handlers: {
3080
3168
  GET: () => {
@@ -3088,7 +3176,7 @@ const RuntimeConfigPatchSchema = object({
3088
3176
  }).strict().refine((v) => Object.keys(v).length > 0, {
3089
3177
  message: "At least one field must be provided"
3090
3178
  });
3091
- const Route$9 = createFileRoute("/api/config")({
3179
+ const Route$a = createFileRoute("/api/config")({
3092
3180
  server: {
3093
3181
  handlers: {
3094
3182
  GET: () => {
@@ -3118,7 +3206,7 @@ const Route$9 = createFileRoute("/api/config")({
3118
3206
  }
3119
3207
  });
3120
3208
  union([string(), object({ providers: unknown() })]);
3121
- const Route$8 = createFileRoute("/api/providers/import")({
3209
+ const Route$9 = createFileRoute("/api/providers/import")({
3122
3210
  server: {
3123
3211
  handlers: {
3124
3212
  POST: async ({ request }) => {
@@ -3151,7 +3239,7 @@ const Route$8 = createFileRoute("/api/providers/import")({
3151
3239
  }
3152
3240
  }
3153
3241
  });
3154
- const Route$7 = createFileRoute("/api/providers/export")({
3242
+ const Route$8 = createFileRoute("/api/providers/export")({
3155
3243
  server: {
3156
3244
  handlers: {
3157
3245
  GET: ({ request }) => {
@@ -3174,13 +3262,15 @@ const ProviderUpdateSchema = object({
3174
3262
  apiKey: string().min(1, "API key is required").optional(),
3175
3263
  format: _enum(["anthropic", "openai"]).optional(),
3176
3264
  baseUrl: string().min(1, "Base URL is required").optional(),
3177
- model: string().min(1, "Model is required").optional(),
3265
+ model: string().optional(),
3266
+ models: array(string()).optional(),
3178
3267
  authHeader: _enum(["bearer", "x-api-key"]).optional(),
3179
3268
  anthropicBaseUrl: string().optional(),
3180
3269
  openaiBaseUrl: string().optional(),
3181
- apiDocsUrl: string().optional()
3270
+ apiDocsUrl: string().optional(),
3271
+ source: _enum(["company", "personal"]).optional()
3182
3272
  });
3183
- const Route$6 = createFileRoute("/api/providers/$providerId")({
3273
+ const Route$7 = createFileRoute("/api/providers/$providerId")({
3184
3274
  server: {
3185
3275
  handlers: {
3186
3276
  GET: ({ params }) => {
@@ -3212,7 +3302,7 @@ const Route$6 = createFileRoute("/api/providers/$providerId")({
3212
3302
  }
3213
3303
  }
3214
3304
  });
3215
- const Route$5 = createFileRoute("/api/logs/stream")({
3305
+ const Route$6 = createFileRoute("/api/logs/stream")({
3216
3306
  server: {
3217
3307
  handlers: {
3218
3308
  GET: ({ request }) => {
@@ -3266,7 +3356,7 @@ const Route$5 = createFileRoute("/api/logs/stream")({
3266
3356
  }
3267
3357
  }
3268
3358
  });
3269
- const Route$4 = createFileRoute("/api/logs/$id")({
3359
+ const Route$5 = createFileRoute("/api/logs/$id")({
3270
3360
  server: {
3271
3361
  handlers: {
3272
3362
  GET: async ({ params }) => {
@@ -3283,7 +3373,7 @@ const Route$4 = createFileRoute("/api/logs/$id")({
3283
3373
  }
3284
3374
  }
3285
3375
  });
3286
- const Route$3 = createFileRoute("/api/config/paths")({
3376
+ const Route$4 = createFileRoute("/api/config/paths")({
3287
3377
  server: {
3288
3378
  handlers: {
3289
3379
  GET: () => {
@@ -3701,31 +3791,7 @@ async function testStreamingEndpoint(baseUrl, apiKey, path2, model, isOpenAI) {
3701
3791
  return createErrorResult(err, Date.now() - startTime, true);
3702
3792
  }
3703
3793
  }
3704
- function createTestLogEntry(providerName, path2, body, upstreamUrl, result, isTest) {
3705
- return {
3706
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3707
- id: `test-${Date.now()}`,
3708
- method: "POST",
3709
- path: path2,
3710
- model: isTest ? result.model : void 0,
3711
- sessionId: null,
3712
- rawRequestBody: body,
3713
- responseStatus: result.success ? 200 : 500,
3714
- responseText: result.rawResponse ?? JSON.stringify(result),
3715
- inputTokens: result.inputTokens ?? null,
3716
- outputTokens: result.outputTokens ?? null,
3717
- elapsedMs: result.latencyMs ?? 0,
3718
- streaming: result.streaming ?? false,
3719
- userAgent: "provider-test",
3720
- origin: null,
3721
- upstreamUrl,
3722
- error: result.success ? null : result.error?.message ?? String(result.error),
3723
- isTest: true,
3724
- providerName,
3725
- headers: result.requestHeaders ?? {}
3726
- };
3727
- }
3728
- const Route$2 = createFileRoute("/api/providers/$providerId/test")({
3794
+ const Route$3 = createFileRoute("/api/providers/$providerId/test")({
3729
3795
  server: {
3730
3796
  handlers: {
3731
3797
  POST: async ({ params }) => {
@@ -3733,208 +3799,70 @@ const Route$2 = createFileRoute("/api/providers/$providerId/test")({
3733
3799
  if (!provider) {
3734
3800
  return Response.json({ error: "Provider not found" }, { status: 404 });
3735
3801
  }
3736
- if (provider.model === void 0 || provider.model.trim().length === 0) {
3802
+ const p = provider;
3803
+ const modelsToTest = (provider.models ?? []).filter((m) => m.trim() !== "");
3804
+ if (modelsToTest.length === 0) {
3737
3805
  return Response.json(
3738
- { error: "Please configure a model name in provider settings" },
3806
+ { error: "Please configure at least one model in provider settings" },
3739
3807
  { status: 400 }
3740
3808
  );
3741
3809
  }
3742
- const model = provider.model.trim();
3743
- const usageModel = getModelUsageName(model, provider.name);
3744
3810
  const results = {
3745
3811
  anthropic: { nonStreaming: { notConfigured: true }, streaming: { notConfigured: true } },
3746
- openai: { nonStreaming: { notConfigured: true }, streaming: { notConfigured: true } }
3812
+ openai: { nonStreaming: { notConfigured: true }, streaming: { notConfigured: true } },
3813
+ models: {}
3747
3814
  };
3748
- if (provider.anthropicBaseUrl !== void 0 && provider.anthropicBaseUrl.length > 0) {
3749
- const nonStreamingResult = await testEndpoint(
3750
- provider.anthropicBaseUrl,
3751
- provider.apiKey,
3752
- "/v1/messages",
3753
- usageModel,
3754
- false
3755
- );
3756
- results.anthropic.nonStreaming = nonStreamingResult;
3757
- const requestBody = JSON.stringify({
3758
- model: usageModel,
3759
- messages: [{ role: "user", content: "say hello and briefly introduce yourself" }],
3760
- max_tokens: 1024
3761
- });
3762
- const upstreamUrl = `${provider.anthropicBaseUrl}/v1/messages`;
3763
- await addTestLogEntry({
3764
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3765
- method: "POST",
3766
- path: "/v1/messages",
3767
- model: nonStreamingResult.model ?? model,
3768
- sessionId: null,
3769
- rawRequestBody: requestBody,
3770
- responseStatus: nonStreamingResult.success ? 200 : 500,
3771
- responseText: nonStreamingResult.rawResponse ?? JSON.stringify(nonStreamingResult),
3772
- inputTokens: nonStreamingResult.inputTokens ?? null,
3773
- outputTokens: nonStreamingResult.outputTokens ?? null,
3774
- cacheCreationInputTokens: nonStreamingResult.cacheCreationInputTokens ?? null,
3775
- cacheReadInputTokens: nonStreamingResult.cacheReadInputTokens ?? null,
3776
- elapsedMs: nonStreamingResult.latencyMs ?? 0,
3777
- streaming: false,
3778
- userAgent: "provider-test",
3779
- origin: null,
3780
- apiFormat: "anthropic",
3781
- isTest: true,
3782
- providerName: provider.name,
3783
- headers: nonStreamingResult.requestHeaders ?? {}
3784
- });
3785
- appendLogEntry(
3786
- createTestLogEntry(
3787
- provider.name,
3788
- "/v1/messages",
3789
- requestBody,
3790
- upstreamUrl,
3791
- nonStreamingResult,
3792
- true
3793
- )
3794
- );
3795
- const streamingResult = await testStreamingEndpoint(
3796
- provider.anthropicBaseUrl,
3797
- provider.apiKey,
3798
- "/v1/messages",
3799
- usageModel,
3800
- false
3801
- );
3802
- results.anthropic.streaming = streamingResult;
3803
- const streamingRequestBody = JSON.stringify({
3804
- model: usageModel,
3805
- messages: [{ role: "user", content: "say hello" }],
3806
- max_tokens: 256,
3807
- stream: true
3808
- });
3809
- await addTestLogEntry({
3810
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3811
- method: "POST",
3812
- path: "/v1/messages",
3813
- model: streamingResult.model ?? model,
3814
- sessionId: null,
3815
- rawRequestBody: streamingRequestBody,
3816
- responseStatus: streamingResult.success ? 200 : 500,
3817
- responseText: streamingResult.rawResponse ?? JSON.stringify(streamingResult),
3818
- inputTokens: streamingResult.inputTokens ?? null,
3819
- outputTokens: streamingResult.outputTokens ?? null,
3820
- cacheCreationInputTokens: streamingResult.cacheCreationInputTokens ?? null,
3821
- cacheReadInputTokens: streamingResult.cacheReadInputTokens ?? null,
3822
- elapsedMs: streamingResult.latencyMs ?? 0,
3823
- streaming: true,
3824
- streamingChunks: streamingResult.streamingChunks,
3825
- userAgent: "provider-test",
3826
- origin: null,
3827
- apiFormat: "anthropic",
3828
- isTest: true,
3829
- providerName: provider.name,
3830
- headers: streamingResult.requestHeaders ?? {}
3831
- });
3832
- appendLogEntry(
3833
- createTestLogEntry(
3834
- provider.name,
3835
- "/v1/messages",
3836
- streamingRequestBody,
3837
- upstreamUrl,
3838
- streamingResult,
3839
- true
3840
- )
3841
- );
3815
+ const anthropicUrl = provider.anthropicBaseUrl !== void 0 && provider.anthropicBaseUrl.length > 0 ? provider.anthropicBaseUrl : void 0;
3816
+ const openaiUrl = provider.openaiBaseUrl !== void 0 && provider.openaiBaseUrl.length > 0 ? provider.openaiBaseUrl : void 0;
3817
+ async function testOneModel(displayName) {
3818
+ const usageModel = getModelUsageName(displayName, p.name);
3819
+ const notConfigured = { notConfigured: true };
3820
+ const modelResults = {
3821
+ anthropic: { nonStreaming: notConfigured, streaming: notConfigured },
3822
+ openai: { nonStreaming: notConfigured, streaming: notConfigured }
3823
+ };
3824
+ const tasks = [];
3825
+ if (anthropicUrl !== void 0) {
3826
+ tasks.push(
3827
+ testEndpoint(anthropicUrl, p.apiKey, "/v1/messages", usageModel, false).then((r) => {
3828
+ modelResults.anthropic.nonStreaming = r;
3829
+ }),
3830
+ testStreamingEndpoint(anthropicUrl, p.apiKey, "/v1/messages", usageModel, false).then(
3831
+ (r) => {
3832
+ modelResults.anthropic.streaming = r;
3833
+ }
3834
+ )
3835
+ );
3836
+ }
3837
+ if (openaiUrl !== void 0) {
3838
+ tasks.push(
3839
+ testEndpoint(openaiUrl, p.apiKey, "/v1/chat/completions", usageModel, true).then(
3840
+ (r) => {
3841
+ modelResults.openai.nonStreaming = r;
3842
+ }
3843
+ ),
3844
+ testStreamingEndpoint(
3845
+ openaiUrl,
3846
+ p.apiKey,
3847
+ "/v1/chat/completions",
3848
+ usageModel,
3849
+ true
3850
+ ).then((r) => {
3851
+ modelResults.openai.streaming = r;
3852
+ })
3853
+ );
3854
+ }
3855
+ await Promise.all(tasks);
3856
+ results.models[displayName] = modelResults;
3842
3857
  }
3843
- if (provider.openaiBaseUrl !== void 0 && provider.openaiBaseUrl.length > 0) {
3844
- const nonStreamingResult = await testEndpoint(
3845
- provider.openaiBaseUrl,
3846
- provider.apiKey,
3847
- "/v1/chat/completions",
3848
- usageModel,
3849
- true
3850
- );
3851
- results.openai.nonStreaming = nonStreamingResult;
3852
- const requestBody = JSON.stringify({
3853
- model: usageModel,
3854
- messages: [{ role: "user", content: "say hello and briefly introduce yourself" }],
3855
- max_tokens: 1024
3856
- });
3857
- const upstreamUrl = `${provider.openaiBaseUrl}/v1/chat/completions`;
3858
- await addTestLogEntry({
3859
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3860
- method: "POST",
3861
- path: "/v1/chat/completions",
3862
- model: nonStreamingResult.model ?? model,
3863
- sessionId: null,
3864
- rawRequestBody: requestBody,
3865
- responseStatus: nonStreamingResult.success ? 200 : 500,
3866
- responseText: nonStreamingResult.rawResponse ?? JSON.stringify(nonStreamingResult),
3867
- inputTokens: nonStreamingResult.inputTokens ?? null,
3868
- outputTokens: nonStreamingResult.outputTokens ?? null,
3869
- cacheCreationInputTokens: null,
3870
- cacheReadInputTokens: null,
3871
- elapsedMs: nonStreamingResult.latencyMs ?? 0,
3872
- streaming: false,
3873
- userAgent: "provider-test",
3874
- origin: null,
3875
- apiFormat: "openai",
3876
- isTest: true,
3877
- providerName: provider.name,
3878
- headers: nonStreamingResult.requestHeaders ?? {}
3879
- });
3880
- appendLogEntry(
3881
- createTestLogEntry(
3882
- provider.name,
3883
- "/v1/chat/completions",
3884
- requestBody,
3885
- upstreamUrl,
3886
- nonStreamingResult,
3887
- true
3888
- )
3889
- );
3890
- const streamingResult = await testStreamingEndpoint(
3891
- provider.openaiBaseUrl,
3892
- provider.apiKey,
3893
- "/v1/chat/completions",
3894
- usageModel,
3895
- true
3896
- );
3897
- results.openai.streaming = streamingResult;
3898
- const streamingRequestBody = JSON.stringify({
3899
- model: usageModel,
3900
- messages: [{ role: "user", content: "say hello" }],
3901
- max_tokens: 256,
3902
- stream: true
3903
- });
3904
- await addTestLogEntry({
3905
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3906
- method: "POST",
3907
- path: "/v1/chat/completions",
3908
- model: streamingResult.model ?? model,
3909
- sessionId: null,
3910
- rawRequestBody: streamingRequestBody,
3911
- responseStatus: streamingResult.success ? 200 : 500,
3912
- responseText: streamingResult.rawResponse ?? JSON.stringify(streamingResult),
3913
- inputTokens: streamingResult.inputTokens ?? null,
3914
- outputTokens: streamingResult.outputTokens ?? null,
3915
- cacheCreationInputTokens: null,
3916
- cacheReadInputTokens: null,
3917
- elapsedMs: streamingResult.latencyMs ?? 0,
3918
- streaming: true,
3919
- streamingChunks: streamingResult.streamingChunks,
3920
- userAgent: "provider-test",
3921
- origin: null,
3922
- apiFormat: "openai",
3923
- isTest: true,
3924
- providerName: provider.name,
3925
- headers: streamingResult.requestHeaders ?? {}
3926
- });
3927
- appendLogEntry(
3928
- createTestLogEntry(
3929
- provider.name,
3930
- "/v1/chat/completions",
3931
- streamingRequestBody,
3932
- upstreamUrl,
3933
- streamingResult,
3934
- true
3935
- )
3936
- );
3858
+ await Promise.all(modelsToTest.map((displayName) => testOneModel(displayName)));
3859
+ const firstModelName = modelsToTest[0];
3860
+ const firstResults = results.models[firstModelName];
3861
+ if (firstResults !== void 0) {
3862
+ results.anthropic = firstResults.anthropic;
3863
+ results.openai = firstResults.openai;
3937
3864
  }
3865
+ results.testedAt = (/* @__PURE__ */ new Date()).toISOString();
3938
3866
  return Response.json(results);
3939
3867
  }
3940
3868
  }
@@ -3943,7 +3871,7 @@ const Route$2 = createFileRoute("/api/providers/$providerId/test")({
3943
3871
  const ReplayRequestSchema = object({
3944
3872
  modifiedBody: string()
3945
3873
  });
3946
- const Route$1 = createFileRoute("/api/logs/$id/replay")({
3874
+ const Route$2 = createFileRoute("/api/logs/$id/replay")({
3947
3875
  server: {
3948
3876
  handlers: {
3949
3877
  POST: async ({ params, request }) => {
@@ -4061,7 +3989,7 @@ const Route$1 = createFileRoute("/api/logs/$id/replay")({
4061
3989
  }
4062
3990
  }
4063
3991
  });
4064
- const Route = createFileRoute("/api/logs/$id/chunks")({
3992
+ const Route$1 = createFileRoute("/api/logs/$id/chunks")({
4065
3993
  server: {
4066
3994
  handlers: {
4067
3995
  GET: async ({ params }) => {
@@ -4087,96 +4015,422 @@ const Route = createFileRoute("/api/logs/$id/chunks")({
4087
4015
  }
4088
4016
  }
4089
4017
  });
4090
- const IndexRoute = Route$h.update({
4018
+ const ProviderTestErrorTypeSchema = _enum([
4019
+ "timeout",
4020
+ "network_unreachable",
4021
+ "connection_refused",
4022
+ "auth_failed",
4023
+ "rate_limited",
4024
+ "server_error",
4025
+ "invalid_response",
4026
+ "unknown"
4027
+ ]);
4028
+ const ProviderTestErrorSchema = object({
4029
+ message: string(),
4030
+ type: ProviderTestErrorTypeSchema,
4031
+ details: string().optional(),
4032
+ hint: string().optional()
4033
+ });
4034
+ const ProviderTestContentSchema = object({
4035
+ type: _enum(["text", "thinking"]),
4036
+ text: string().optional(),
4037
+ thinking: string().optional()
4038
+ });
4039
+ const ProviderTestResultSchema = object({
4040
+ success: boolean(),
4041
+ error: ProviderTestErrorSchema.optional(),
4042
+ model: string().optional(),
4043
+ inputTokens: number().optional(),
4044
+ outputTokens: number().optional(),
4045
+ cacheCreationInputTokens: number().optional(),
4046
+ cacheReadInputTokens: number().optional(),
4047
+ latencyMs: number().optional(),
4048
+ content: array(ProviderTestContentSchema).optional(),
4049
+ rawResponse: string().optional(),
4050
+ streaming: boolean().optional(),
4051
+ streamingChunks: object({
4052
+ chunks: array(StreamingChunkSchema$1),
4053
+ truncated: boolean().default(false)
4054
+ }).optional(),
4055
+ requestHeaders: record(string(), string()).optional()
4056
+ });
4057
+ const ProviderTestStateSchema = union([
4058
+ ProviderTestResultSchema,
4059
+ object({ notConfigured: literal(true) }),
4060
+ object({ testing: literal(true) })
4061
+ ]);
4062
+ const ProviderFormatTestResultsSchema = object({
4063
+ nonStreaming: ProviderTestStateSchema,
4064
+ streaming: ProviderTestStateSchema
4065
+ });
4066
+ const ModelTestResultsSchema = object({
4067
+ anthropic: ProviderFormatTestResultsSchema,
4068
+ openai: ProviderFormatTestResultsSchema
4069
+ });
4070
+ const ProviderTestResultsSchema = object({
4071
+ anthropic: ProviderFormatTestResultsSchema,
4072
+ openai: ProviderFormatTestResultsSchema,
4073
+ models: record(string(), ModelTestResultsSchema).optional(),
4074
+ testedAt: string().optional()
4075
+ });
4076
+ function createPendingProviderTestResults() {
4077
+ return {
4078
+ anthropic: {
4079
+ nonStreaming: { testing: true },
4080
+ streaming: { testing: true }
4081
+ },
4082
+ openai: {
4083
+ nonStreaming: { testing: true },
4084
+ streaming: { testing: true }
4085
+ }
4086
+ };
4087
+ }
4088
+ function createFailedProviderTestResults(message, type) {
4089
+ const createFormatResult = () => ({
4090
+ nonStreaming: {
4091
+ success: false,
4092
+ error: { message, type }
4093
+ },
4094
+ streaming: { notConfigured: true }
4095
+ });
4096
+ return {
4097
+ anthropic: createFormatResult(),
4098
+ openai: createFormatResult()
4099
+ };
4100
+ }
4101
+ function hasSuccessField(result) {
4102
+ return Object.prototype.hasOwnProperty.call(result, "success");
4103
+ }
4104
+ function createTestLogEntry(providerName, path2, body, upstreamUrl, result, isTest) {
4105
+ return {
4106
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4107
+ id: `test-${Date.now()}`,
4108
+ method: "POST",
4109
+ path: path2,
4110
+ model: isTest ? result.model : void 0,
4111
+ sessionId: null,
4112
+ rawRequestBody: body,
4113
+ responseStatus: result.success ? 200 : 500,
4114
+ responseText: result.rawResponse ?? JSON.stringify(result),
4115
+ inputTokens: result.inputTokens ?? null,
4116
+ outputTokens: result.outputTokens ?? null,
4117
+ elapsedMs: result.latencyMs ?? 0,
4118
+ streaming: result.streaming ?? false,
4119
+ userAgent: "provider-test",
4120
+ origin: null,
4121
+ upstreamUrl,
4122
+ error: result.success ? null : result.error?.message ?? String(result.error),
4123
+ isTest: true,
4124
+ providerName,
4125
+ headers: result.requestHeaders ?? {}
4126
+ };
4127
+ }
4128
+ async function logModelResults(displayName, providerName, anthropicUrl, openaiUrl, modelResults) {
4129
+ const usageModel = getModelUsageName(displayName, providerName);
4130
+ if (anthropicUrl !== void 0) {
4131
+ const nsResult = modelResults.anthropic.nonStreaming;
4132
+ const sResult = modelResults.anthropic.streaming;
4133
+ if (hasSuccessField(nsResult) && hasSuccessField(sResult)) {
4134
+ const nonStreamingResult = nsResult;
4135
+ const streamingResult = sResult;
4136
+ const requestBody = JSON.stringify({
4137
+ model: usageModel,
4138
+ messages: [{ role: "user", content: "say hello and briefly introduce yourself" }],
4139
+ max_tokens: 1024
4140
+ });
4141
+ const upstreamUrl = `${anthropicUrl}/v1/messages`;
4142
+ await addTestLogEntry({
4143
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4144
+ method: "POST",
4145
+ path: "/v1/messages",
4146
+ model: nonStreamingResult.model ?? displayName,
4147
+ sessionId: null,
4148
+ rawRequestBody: requestBody,
4149
+ responseStatus: nonStreamingResult.success ? 200 : 500,
4150
+ responseText: nonStreamingResult.rawResponse ?? JSON.stringify(nonStreamingResult),
4151
+ inputTokens: nonStreamingResult.inputTokens ?? null,
4152
+ outputTokens: nonStreamingResult.outputTokens ?? null,
4153
+ cacheCreationInputTokens: nonStreamingResult.cacheCreationInputTokens ?? null,
4154
+ cacheReadInputTokens: nonStreamingResult.cacheReadInputTokens ?? null,
4155
+ elapsedMs: nonStreamingResult.latencyMs ?? 0,
4156
+ streaming: false,
4157
+ userAgent: "provider-test",
4158
+ origin: null,
4159
+ apiFormat: "anthropic",
4160
+ isTest: true,
4161
+ providerName,
4162
+ headers: nonStreamingResult.requestHeaders ?? {}
4163
+ });
4164
+ appendLogEntry(
4165
+ createTestLogEntry(
4166
+ providerName,
4167
+ "/v1/messages",
4168
+ requestBody,
4169
+ upstreamUrl,
4170
+ nonStreamingResult,
4171
+ true
4172
+ )
4173
+ );
4174
+ const streamingRequestBody = JSON.stringify({
4175
+ model: usageModel,
4176
+ messages: [{ role: "user", content: "say hello" }],
4177
+ max_tokens: 256,
4178
+ stream: true
4179
+ });
4180
+ await addTestLogEntry({
4181
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4182
+ method: "POST",
4183
+ path: "/v1/messages",
4184
+ model: streamingResult.model ?? displayName,
4185
+ sessionId: null,
4186
+ rawRequestBody: streamingRequestBody,
4187
+ responseStatus: streamingResult.success ? 200 : 500,
4188
+ responseText: streamingResult.rawResponse ?? JSON.stringify(streamingResult),
4189
+ inputTokens: streamingResult.inputTokens ?? null,
4190
+ outputTokens: streamingResult.outputTokens ?? null,
4191
+ cacheCreationInputTokens: streamingResult.cacheCreationInputTokens ?? null,
4192
+ cacheReadInputTokens: streamingResult.cacheReadInputTokens ?? null,
4193
+ elapsedMs: streamingResult.latencyMs ?? 0,
4194
+ streaming: true,
4195
+ streamingChunks: streamingResult.streamingChunks,
4196
+ userAgent: "provider-test",
4197
+ origin: null,
4198
+ apiFormat: "anthropic",
4199
+ isTest: true,
4200
+ providerName,
4201
+ headers: streamingResult.requestHeaders ?? {}
4202
+ });
4203
+ appendLogEntry(
4204
+ createTestLogEntry(
4205
+ providerName,
4206
+ "/v1/messages",
4207
+ streamingRequestBody,
4208
+ upstreamUrl,
4209
+ streamingResult,
4210
+ true
4211
+ )
4212
+ );
4213
+ }
4214
+ }
4215
+ if (openaiUrl !== void 0) {
4216
+ const nsResult = modelResults.openai.nonStreaming;
4217
+ const sResult = modelResults.openai.streaming;
4218
+ if (hasSuccessField(nsResult) && hasSuccessField(sResult)) {
4219
+ const nonStreamingResult = nsResult;
4220
+ const streamingResult = sResult;
4221
+ const requestBody = JSON.stringify({
4222
+ model: usageModel,
4223
+ messages: [{ role: "user", content: "say hello and briefly introduce yourself" }],
4224
+ max_tokens: 1024
4225
+ });
4226
+ const upstreamUrl = `${openaiUrl}/v1/chat/completions`;
4227
+ await addTestLogEntry({
4228
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4229
+ method: "POST",
4230
+ path: "/v1/chat/completions",
4231
+ model: nonStreamingResult.model ?? displayName,
4232
+ sessionId: null,
4233
+ rawRequestBody: requestBody,
4234
+ responseStatus: nonStreamingResult.success ? 200 : 500,
4235
+ responseText: nonStreamingResult.rawResponse ?? JSON.stringify(nonStreamingResult),
4236
+ inputTokens: nonStreamingResult.inputTokens ?? null,
4237
+ outputTokens: nonStreamingResult.outputTokens ?? null,
4238
+ cacheCreationInputTokens: null,
4239
+ cacheReadInputTokens: null,
4240
+ elapsedMs: nonStreamingResult.latencyMs ?? 0,
4241
+ streaming: false,
4242
+ userAgent: "provider-test",
4243
+ origin: null,
4244
+ apiFormat: "openai",
4245
+ isTest: true,
4246
+ providerName,
4247
+ headers: nonStreamingResult.requestHeaders ?? {}
4248
+ });
4249
+ appendLogEntry(
4250
+ createTestLogEntry(
4251
+ providerName,
4252
+ "/v1/chat/completions",
4253
+ requestBody,
4254
+ upstreamUrl,
4255
+ nonStreamingResult,
4256
+ true
4257
+ )
4258
+ );
4259
+ const streamingRequestBody = JSON.stringify({
4260
+ model: usageModel,
4261
+ messages: [{ role: "user", content: "say hello" }],
4262
+ max_tokens: 256,
4263
+ stream: true
4264
+ });
4265
+ await addTestLogEntry({
4266
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4267
+ method: "POST",
4268
+ path: "/v1/chat/completions",
4269
+ model: streamingResult.model ?? displayName,
4270
+ sessionId: null,
4271
+ rawRequestBody: streamingRequestBody,
4272
+ responseStatus: streamingResult.success ? 200 : 500,
4273
+ responseText: streamingResult.rawResponse ?? JSON.stringify(streamingResult),
4274
+ inputTokens: streamingResult.inputTokens ?? null,
4275
+ outputTokens: streamingResult.outputTokens ?? null,
4276
+ cacheCreationInputTokens: null,
4277
+ cacheReadInputTokens: null,
4278
+ elapsedMs: streamingResult.latencyMs ?? 0,
4279
+ streaming: true,
4280
+ streamingChunks: streamingResult.streamingChunks,
4281
+ userAgent: "provider-test",
4282
+ origin: null,
4283
+ apiFormat: "openai",
4284
+ isTest: true,
4285
+ providerName,
4286
+ headers: streamingResult.requestHeaders ?? {}
4287
+ });
4288
+ appendLogEntry(
4289
+ createTestLogEntry(
4290
+ providerName,
4291
+ "/v1/chat/completions",
4292
+ streamingRequestBody,
4293
+ upstreamUrl,
4294
+ streamingResult,
4295
+ true
4296
+ )
4297
+ );
4298
+ }
4299
+ }
4300
+ }
4301
+ const Route = createFileRoute("/api/providers/$providerId/test/log")({
4302
+ server: {
4303
+ handlers: {
4304
+ POST: async ({ params, request }) => {
4305
+ const provider = getProvider(params.providerId);
4306
+ if (!provider) {
4307
+ return Response.json({ error: "Provider not found" }, { status: 404 });
4308
+ }
4309
+ let body;
4310
+ try {
4311
+ body = await request.json();
4312
+ } catch {
4313
+ return Response.json({ error: "Invalid JSON body" }, { status: 400 });
4314
+ }
4315
+ const parsed = ProviderTestResultsSchema.safeParse(body);
4316
+ if (!parsed.success) {
4317
+ return Response.json(
4318
+ { error: `Invalid test results: ${parsed.error.message}` },
4319
+ { status: 400 }
4320
+ );
4321
+ }
4322
+ const results = parsed.data;
4323
+ const anthropicUrl = provider.anthropicBaseUrl !== void 0 && provider.anthropicBaseUrl.length > 0 ? provider.anthropicBaseUrl : void 0;
4324
+ const openaiUrl = provider.openaiBaseUrl !== void 0 && provider.openaiBaseUrl.length > 0 ? provider.openaiBaseUrl : void 0;
4325
+ const entries = [];
4326
+ if (results.models !== void 0) {
4327
+ for (const [modelName, modelResult] of Object.entries(results.models)) {
4328
+ entries.push(
4329
+ logModelResults(modelName, provider.name, anthropicUrl, openaiUrl, modelResult)
4330
+ );
4331
+ }
4332
+ }
4333
+ await Promise.all(entries);
4334
+ return Response.json({ logged: entries.length });
4335
+ }
4336
+ }
4337
+ }
4338
+ });
4339
+ const IndexRoute = Route$i.update({
4091
4340
  id: "/",
4092
4341
  path: "/",
4093
- getParentRoute: () => Route$i
4342
+ getParentRoute: () => Route$j
4094
4343
  });
4095
- const ProxySplatRoute = Route$g.update({
4344
+ const ProxySplatRoute = Route$h.update({
4096
4345
  id: "/proxy/$",
4097
4346
  path: "/proxy/$",
4098
- getParentRoute: () => Route$i
4347
+ getParentRoute: () => Route$j
4099
4348
  });
4100
- const ApiSessionsRoute = Route$f.update({
4349
+ const ApiSessionsRoute = Route$g.update({
4101
4350
  id: "/api/sessions",
4102
4351
  path: "/api/sessions",
4103
- getParentRoute: () => Route$i
4352
+ getParentRoute: () => Route$j
4104
4353
  });
4105
- const ApiProvidersRoute = Route$e.update({
4354
+ const ApiProvidersRoute = Route$f.update({
4106
4355
  id: "/api/providers",
4107
4356
  path: "/api/providers",
4108
- getParentRoute: () => Route$i
4357
+ getParentRoute: () => Route$j
4109
4358
  });
4110
- const ApiModelsRoute = Route$d.update({
4359
+ const ApiModelsRoute = Route$e.update({
4111
4360
  id: "/api/models",
4112
4361
  path: "/api/models",
4113
- getParentRoute: () => Route$i
4362
+ getParentRoute: () => Route$j
4114
4363
  });
4115
- const ApiMcpRoute = Route$c.update({
4364
+ const ApiMcpRoute = Route$d.update({
4116
4365
  id: "/api/mcp",
4117
4366
  path: "/api/mcp",
4118
- getParentRoute: () => Route$i
4367
+ getParentRoute: () => Route$j
4119
4368
  });
4120
- const ApiLogsRoute = Route$b.update({
4369
+ const ApiLogsRoute = Route$c.update({
4121
4370
  id: "/api/logs",
4122
4371
  path: "/api/logs",
4123
- getParentRoute: () => Route$i
4372
+ getParentRoute: () => Route$j
4124
4373
  });
4125
- const ApiHealthRoute = Route$a.update({
4374
+ const ApiHealthRoute = Route$b.update({
4126
4375
  id: "/api/health",
4127
4376
  path: "/api/health",
4128
- getParentRoute: () => Route$i
4377
+ getParentRoute: () => Route$j
4129
4378
  });
4130
- const ApiConfigRoute = Route$9.update({
4379
+ const ApiConfigRoute = Route$a.update({
4131
4380
  id: "/api/config",
4132
4381
  path: "/api/config",
4133
- getParentRoute: () => Route$i
4382
+ getParentRoute: () => Route$j
4134
4383
  });
4135
- const ApiProvidersImportRoute = Route$8.update({
4384
+ const ApiProvidersImportRoute = Route$9.update({
4136
4385
  id: "/import",
4137
4386
  path: "/import",
4138
4387
  getParentRoute: () => ApiProvidersRoute
4139
4388
  });
4140
- const ApiProvidersExportRoute = Route$7.update({
4389
+ const ApiProvidersExportRoute = Route$8.update({
4141
4390
  id: "/export",
4142
4391
  path: "/export",
4143
4392
  getParentRoute: () => ApiProvidersRoute
4144
4393
  });
4145
- const ApiProvidersProviderIdRoute = Route$6.update({
4394
+ const ApiProvidersProviderIdRoute = Route$7.update({
4146
4395
  id: "/$providerId",
4147
4396
  path: "/$providerId",
4148
4397
  getParentRoute: () => ApiProvidersRoute
4149
4398
  });
4150
- const ApiLogsStreamRoute = Route$5.update({
4399
+ const ApiLogsStreamRoute = Route$6.update({
4151
4400
  id: "/stream",
4152
4401
  path: "/stream",
4153
4402
  getParentRoute: () => ApiLogsRoute
4154
4403
  });
4155
- const ApiLogsIdRoute = Route$4.update({
4404
+ const ApiLogsIdRoute = Route$5.update({
4156
4405
  id: "/$id",
4157
4406
  path: "/$id",
4158
4407
  getParentRoute: () => ApiLogsRoute
4159
4408
  });
4160
- const ApiConfigPathsRoute = Route$3.update({
4409
+ const ApiConfigPathsRoute = Route$4.update({
4161
4410
  id: "/paths",
4162
4411
  path: "/paths",
4163
4412
  getParentRoute: () => ApiConfigRoute
4164
4413
  });
4165
- const ApiProvidersProviderIdTestRoute = Route$2.update({
4414
+ const ApiProvidersProviderIdTestRoute = Route$3.update({
4166
4415
  id: "/test",
4167
4416
  path: "/test",
4168
4417
  getParentRoute: () => ApiProvidersProviderIdRoute
4169
4418
  });
4170
- const ApiLogsIdReplayRoute = Route$1.update({
4419
+ const ApiLogsIdReplayRoute = Route$2.update({
4171
4420
  id: "/replay",
4172
4421
  path: "/replay",
4173
4422
  getParentRoute: () => ApiLogsIdRoute
4174
4423
  });
4175
- const ApiLogsIdChunksRoute = Route.update({
4424
+ const ApiLogsIdChunksRoute = Route$1.update({
4176
4425
  id: "/chunks",
4177
4426
  path: "/chunks",
4178
4427
  getParentRoute: () => ApiLogsIdRoute
4179
4428
  });
4429
+ const ApiProvidersProviderIdTestLogRoute = Route.update({
4430
+ id: "/log",
4431
+ path: "/log",
4432
+ getParentRoute: () => ApiProvidersProviderIdTestRoute
4433
+ });
4180
4434
  const ApiConfigRouteChildren = {
4181
4435
  ApiConfigPathsRoute
4182
4436
  };
@@ -4195,8 +4449,14 @@ const ApiLogsRouteChildren = {
4195
4449
  ApiLogsStreamRoute
4196
4450
  };
4197
4451
  const ApiLogsRouteWithChildren = ApiLogsRoute._addFileChildren(ApiLogsRouteChildren);
4452
+ const ApiProvidersProviderIdTestRouteChildren = {
4453
+ ApiProvidersProviderIdTestLogRoute
4454
+ };
4455
+ const ApiProvidersProviderIdTestRouteWithChildren = ApiProvidersProviderIdTestRoute._addFileChildren(
4456
+ ApiProvidersProviderIdTestRouteChildren
4457
+ );
4198
4458
  const ApiProvidersProviderIdRouteChildren = {
4199
- ApiProvidersProviderIdTestRoute
4459
+ ApiProvidersProviderIdTestRoute: ApiProvidersProviderIdTestRouteWithChildren
4200
4460
  };
4201
4461
  const ApiProvidersProviderIdRouteWithChildren = ApiProvidersProviderIdRoute._addFileChildren(
4202
4462
  ApiProvidersProviderIdRouteChildren
@@ -4220,7 +4480,7 @@ const rootRouteChildren = {
4220
4480
  ApiSessionsRoute,
4221
4481
  ProxySplatRoute
4222
4482
  };
4223
- const routeTree = Route$i._addFileChildren(rootRouteChildren)._addFileTypes();
4483
+ const routeTree = Route$j._addFileChildren(rootRouteChildren)._addFileTypes();
4224
4484
  function getRouter() {
4225
4485
  const router2 = createRouter({
4226
4486
  routeTree,
@@ -4235,10 +4495,12 @@ const router = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProper
4235
4495
  export {
4236
4496
  CapturedLogSchema as C,
4237
4497
  InspectorResponseSchema as I,
4238
- ProviderConfigSchema as P,
4498
+ ProviderTestResultsSchema as P,
4239
4499
  RuntimeConfigSchema as R,
4240
- StreamingChunkSchema$1 as S,
4241
4500
  parseRequest as a,
4501
+ createFailedProviderTestResults as b,
4502
+ createPendingProviderTestResults as c,
4503
+ ProviderConfigSchema as d,
4242
4504
  parseOpenAIResponse as p,
4243
4505
  router as r,
4244
4506
  stripClaudeCodeBillingHeader as s