@tonyclaw/llm-inspector 1.14.1 → 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.
@@ -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, s as stripClaudeCodeBillingHeader, R as RuntimeConfigSchema, P as ProviderConfigSchema, p as parseOpenAIResponse, I as InspectorResponseSchema, S as StreamingChunkSchema$1 } from "./router-B8X3GXM2.mjs";
2
+ import { C as CapturedLogSchema, a as parseRequest, s as stripClaudeCodeBillingHeader, R as RuntimeConfigSchema, c as createPendingProviderTestResults, P as ProviderTestResultsSchema, b as createFailedProviderTestResults, d as ProviderConfigSchema, p as parseOpenAIResponse, I as InspectorResponseSchema } from "./router-BoeSXWHG.mjs";
3
3
  import { u as useSWR, a as useSWRConfig } from "../_libs/swr.mjs";
4
4
  import { u as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
5
5
  import { J as JSZip } from "../_libs/jszip.mjs";
@@ -12,7 +12,7 @@ import { R as Root2, T as Trigger, I as Icon, V as Value, P as Portal, C as Cont
12
12
  import "../_libs/modelcontextprotocol__server.mjs";
13
13
  import { D as Download, L as LayoutGrid, a as List, G as GitCompareArrows, X, S as Settings, C as ChevronDown, b as Check, R as RotateCcw, U as Upload, 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, i as Globe, j as User, F as FileTerminal, k as Radio, l as Rows3, m as Columns2, n as Minus, o as Pencil, E as Equal, p as EyeOff, q as Eye, r as ExternalLink, s as RotateCw, T as Trash2, A as ArrowUp, t as ArrowDown, u as TriangleAlert, v as CircleCheckBig, w as CircleStop, x as CircleQuestionMark, y as Server, z as Gauge, B as Lock, H as Wifi, I as WifiOff, J as ChevronsUp, K as ChevronsDown, N as Brain, O as Terminal } from "../_libs/lucide-react.mjs";
14
14
  import { M as Markdown } from "../_libs/react-markdown.mjs";
15
- import { a as array, b as string, u as union, d as object, l as literal, n as number, c as boolean, r as record, _ as _enum } from "../_libs/zod.mjs";
15
+ import { a as array, b as string, u as union, d as object, l as literal, n as number, c as boolean } from "../_libs/zod.mjs";
16
16
  import { R as Root2$1, L as List$1, T as Trigger$2, C as Content$1 } from "../_libs/radix-ui__react-tabs.mjs";
17
17
  import { S as Slot } from "../_libs/radix-ui__react-slot.mjs";
18
18
  import { P as Provider, R as Root3, T as Trigger$3, a as Portal$2, C as Content2$1, A as Arrow2 } from "../_libs/radix-ui__react-tooltip.mjs";
@@ -276,7 +276,7 @@ async function exportLogsAsZip(logs) {
276
276
  document.body.removeChild(anchor);
277
277
  URL.revokeObjectURL(url);
278
278
  }
279
- const version = "1.14.1";
279
+ const version = "1.14.2";
280
280
  const packageJson = {
281
281
  version
282
282
  };
@@ -2984,6 +2984,19 @@ function TestStatus({ result }) {
2984
2984
  ] })
2985
2985
  ] });
2986
2986
  }
2987
+ function formatTimeAgo(isoString) {
2988
+ const now = Date.now();
2989
+ const then = new Date(isoString).getTime();
2990
+ const diffMs = now - then;
2991
+ const diffSec = Math.floor(diffMs / 1e3);
2992
+ if (diffSec < 60) return "just now";
2993
+ const diffMin = Math.floor(diffSec / 60);
2994
+ if (diffMin < 60) return `${diffMin}m ago`;
2995
+ const diffHr = Math.floor(diffMin / 60);
2996
+ if (diffHr < 24) return `${diffHr}h ago`;
2997
+ const diffDay = Math.floor(diffHr / 24);
2998
+ return `${diffDay}d ago`;
2999
+ }
2987
3000
  function ProviderCard({
2988
3001
  provider,
2989
3002
  testResults,
@@ -2996,6 +3009,27 @@ function ProviderCard({
2996
3009
  }) {
2997
3010
  const [showApiKey, setShowApiKey] = reactExports.useState(false);
2998
3011
  const [copied, setCopied] = reactExports.useState(false);
3012
+ const [showModelResults, setShowModelResults] = reactExports.useState(false);
3013
+ const hasLoggedRef = reactExports.useRef(null);
3014
+ const lastTestedAtRef = reactExports.useRef(void 0);
3015
+ if (testResults?.testedAt !== void 0 && testResults.testedAt !== lastTestedAtRef.current) {
3016
+ lastTestedAtRef.current = testResults.testedAt;
3017
+ hasLoggedRef.current = null;
3018
+ }
3019
+ const handleToggleModelResults = reactExports.useCallback(() => {
3020
+ setShowModelResults((v) => {
3021
+ const next = !v;
3022
+ if (next && hasLoggedRef.current === null && testResults?.models !== void 0) {
3023
+ hasLoggedRef.current = testResults.testedAt ?? "";
3024
+ void fetch(`/api/providers/${provider.id}/test/log`, {
3025
+ method: "POST",
3026
+ headers: { "Content-Type": "application/json" },
3027
+ body: JSON.stringify(testResults)
3028
+ });
3029
+ }
3030
+ return next;
3031
+ });
3032
+ }, [provider.id, testResults]);
2999
3033
  function handleCopy() {
3000
3034
  navigator.clipboard.writeText(provider.apiKey).catch(() => {
3001
3035
  });
@@ -3012,7 +3046,7 @@ function ProviderCard({
3012
3046
  children: [
3013
3047
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start justify-between gap-2", children: [
3014
3048
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
3015
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium truncate", children: provider.model !== void 0 && provider.model !== "" ? `${provider.model} (${provider.name})` : provider.name }),
3049
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium truncate", children: provider.name }),
3016
3050
  provider.source === "company" && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs px-1.5 py-0.5 rounded bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400 shrink-0", children: "公司" }),
3017
3051
  provider.source === "personal" && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs px-1.5 py-0.5 rounded bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400 shrink-0", children: "个人" })
3018
3052
  ] }),
@@ -3031,6 +3065,7 @@ function ProviderCard({
3031
3065
  }
3032
3066
  )
3033
3067
  ] }),
3068
+ provider.models !== void 0 && provider.models.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-wrap gap-1", children: provider.models.map((m) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs px-1.5 py-0.5 rounded bg-muted text-muted-foreground", children: m }, m)) }),
3034
3069
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
3035
3070
  /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-xs text-muted-foreground bg-muted px-2 py-1 rounded flex-1 truncate", children: showApiKey ? provider.apiKey : maskApiKey(provider.apiKey) }),
3036
3071
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -3070,6 +3105,41 @@ function ProviderCard({
3070
3105
  ] }),
3071
3106
  testResults && /* @__PURE__ */ jsxRuntimeExports.jsx(TestStatus, { result: testResults.openai.nonStreaming })
3072
3107
  ] }),
3108
+ testResults?.testedAt !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-muted-foreground flex items-center gap-1", children: [
3109
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
3110
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
3111
+ "Tested ",
3112
+ formatTimeAgo(testResults.testedAt)
3113
+ ] })
3114
+ ] }),
3115
+ testResults?.models !== void 0 && Object.keys(testResults.models).length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t pt-2", children: [
3116
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
3117
+ "button",
3118
+ {
3119
+ type: "button",
3120
+ onClick: handleToggleModelResults,
3121
+ className: "text-xs text-muted-foreground hover:text-foreground transition-colors flex items-center gap-1",
3122
+ children: [
3123
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono", children: showModelResults ? "▾" : "▸" }),
3124
+ "Model Test Results (",
3125
+ Object.keys(testResults.models).length,
3126
+ ")"
3127
+ ]
3128
+ }
3129
+ ),
3130
+ showModelResults && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2 overflow-x-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("table", { className: "w-full text-xs border-collapse", children: [
3131
+ /* @__PURE__ */ jsxRuntimeExports.jsx("thead", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "border-b border-border", children: [
3132
+ /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-left py-1 px-2 font-medium text-muted-foreground", children: "Model" }),
3133
+ provider.anthropicBaseUrl !== void 0 && provider.anthropicBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-left py-1 px-2 font-medium text-muted-foreground", children: "Anthropic" }),
3134
+ provider.openaiBaseUrl !== void 0 && provider.openaiBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx("th", { className: "text-left py-1 px-2 font-medium text-muted-foreground", children: "OpenAI" })
3135
+ ] }) }),
3136
+ /* @__PURE__ */ jsxRuntimeExports.jsx("tbody", { children: Object.entries(testResults.models).map(([modelName, modelResult]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "border-b border-border/50 last:border-0", children: [
3137
+ /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "py-1 px-2 font-medium", children: modelName }),
3138
+ provider.anthropicBaseUrl !== void 0 && provider.anthropicBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "py-1 px-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(TestStatus, { result: modelResult.anthropic.nonStreaming }) }),
3139
+ provider.openaiBaseUrl !== void 0 && provider.openaiBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "py-1 px-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(TestStatus, { result: modelResult.openai.nonStreaming }) })
3140
+ ] }, modelName)) })
3141
+ ] }) })
3142
+ ] }),
3073
3143
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 pt-1 border-t", children: [
3074
3144
  onTest !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
3075
3145
  Button,
@@ -3147,7 +3217,10 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
3147
3217
  const [apiKey, setApiKey] = reactExports.useState(provider?.apiKey ?? "");
3148
3218
  const [showApiKey, setShowApiKey] = reactExports.useState(false);
3149
3219
  const [copied, setCopied] = reactExports.useState(false);
3150
- const [model, setModel] = reactExports.useState(provider?.model ?? "");
3220
+ const initialModels = provider?.models;
3221
+ const [models, setModels] = reactExports.useState(
3222
+ initialModels !== void 0 && initialModels.length > 0 ? initialModels : [""]
3223
+ );
3151
3224
  const [activeTab, setActiveTab] = reactExports.useState("anthropic");
3152
3225
  const [anthropicBaseUrl, setAnthropicBaseUrl] = reactExports.useState(provider?.anthropicBaseUrl ?? "");
3153
3226
  const [openaiBaseUrl, setOpenaiBaseUrl] = reactExports.useState(provider?.openaiBaseUrl ?? "");
@@ -3169,7 +3242,7 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
3169
3242
  if (provider) {
3170
3243
  setName(provider.name);
3171
3244
  setApiKey(provider.apiKey);
3172
- setModel(provider.model ?? "");
3245
+ setModels((provider.models?.length ?? 0) > 0 ? provider.models : [""]);
3173
3246
  setAnthropicBaseUrl(provider.anthropicBaseUrl ?? "");
3174
3247
  setOpenaiBaseUrl(provider.openaiBaseUrl ?? "");
3175
3248
  setApiDocsUrl(provider.apiDocsUrl ?? "");
@@ -3190,11 +3263,11 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
3190
3263
  if (preset.apiDocsUrl !== void 0 && !apiDocsUrl) {
3191
3264
  setApiDocsUrl(preset.apiDocsUrl);
3192
3265
  }
3193
- if (keyword === "minimax" && !model) {
3194
- setModel(MINIMAX_MODELS[0] ?? "");
3266
+ if (keyword === "minimax" && models.length === 1 && models[0] === "") {
3267
+ setModels([MINIMAX_MODELS[0] ?? ""]);
3195
3268
  }
3196
- if (keyword === "alibaba" && !model) {
3197
- setModel(ALIBABA_MODELS[0] ?? "");
3269
+ if (keyword === "alibaba" && models.length === 1 && models[0] === "") {
3270
+ setModels([ALIBABA_MODELS[0] ?? ""]);
3198
3271
  }
3199
3272
  break;
3200
3273
  }
@@ -3208,8 +3281,8 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
3208
3281
  if (!apiKey.trim()) {
3209
3282
  newErrors.apiKey = "API key is required";
3210
3283
  }
3211
- if (!model.trim()) {
3212
- newErrors.model = "Model is required";
3284
+ if (models.length === 0 || models.every((m) => !m.trim())) {
3285
+ newErrors.models = "At least one model is required";
3213
3286
  }
3214
3287
  if (anthropicBaseUrl.trim() && !isValidUrl(anthropicBaseUrl.trim())) {
3215
3288
  newErrors.anthropicBaseUrl = "Invalid URL format";
@@ -3239,7 +3312,7 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
3239
3312
  onSubmit({
3240
3313
  name: name.trim(),
3241
3314
  apiKey: apiKey.trim(),
3242
- model: model.trim() || void 0,
3315
+ models: models.map((m) => m.trim()).filter((m) => m !== ""),
3243
3316
  anthropicBaseUrl: anthropicBaseUrl.trim() || void 0,
3244
3317
  openaiBaseUrl: openaiBaseUrl.trim() || void 0,
3245
3318
  apiDocsUrl: apiDocsUrl.trim() || void 0,
@@ -3333,31 +3406,68 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
3333
3406
  errors.apiKey !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-destructive", children: errors.apiKey })
3334
3407
  ] }),
3335
3408
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
3336
- /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { htmlFor: "provider-model", className: "text-sm font-medium", children: [
3337
- "Model ",
3409
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-sm font-medium", children: [
3410
+ "Models ",
3338
3411
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-destructive", children: "*" })
3339
3412
  ] }),
3340
- isMiniMax || isAlibaba ? /* @__PURE__ */ jsxRuntimeExports.jsx(
3341
- "select",
3342
- {
3343
- id: "provider-model",
3344
- value: model,
3345
- onChange: (e) => setModel(e.target.value),
3346
- className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:border-ring focus-visible:outline-ring focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
3347
- children: (isMiniMax ? MINIMAX_MODELS : ALIBABA_MODELS).map((m) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: m, children: m }, m))
3348
- }
3349
- ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
3350
- "input",
3413
+ (isMiniMax || isAlibaba) && /* @__PURE__ */ jsxRuntimeExports.jsx("datalist", { id: "model-suggestions", children: (isMiniMax ? MINIMAX_MODELS : ALIBABA_MODELS).map((opt) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: opt }, opt)) }),
3414
+ models.map((m, i) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
3415
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
3416
+ "input",
3417
+ {
3418
+ type: "text",
3419
+ value: m,
3420
+ onChange: (e) => {
3421
+ setModels((prev) => {
3422
+ const next = [...prev];
3423
+ next[i] = e.target.value;
3424
+ return next;
3425
+ });
3426
+ },
3427
+ placeholder: isMiniMax || isAlibaba ? "Type or select a model..." : "Model name",
3428
+ list: isMiniMax || isAlibaba ? "model-suggestions" : void 0,
3429
+ className: "flex-1 rounded-md border border-input bg-background px-4 py-3 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-ring focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50"
3430
+ }
3431
+ ),
3432
+ models.length > 1 && /* @__PURE__ */ jsxRuntimeExports.jsx(
3433
+ "button",
3434
+ {
3435
+ type: "button",
3436
+ onClick: () => setModels((prev) => prev.filter((_, idx) => idx !== i)),
3437
+ className: "text-muted-foreground hover:text-destructive transition-colors p-1 shrink-0",
3438
+ "aria-label": "Remove model",
3439
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
3440
+ "svg",
3441
+ {
3442
+ xmlns: "http://www.w3.org/2000/svg",
3443
+ width: "16",
3444
+ height: "16",
3445
+ viewBox: "0 0 24 24",
3446
+ fill: "none",
3447
+ stroke: "currentColor",
3448
+ strokeWidth: "2",
3449
+ strokeLinecap: "round",
3450
+ strokeLinejoin: "round",
3451
+ children: [
3452
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M3 6h18" }),
3453
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }),
3454
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" })
3455
+ ]
3456
+ }
3457
+ )
3458
+ }
3459
+ )
3460
+ ] }, i)),
3461
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
3462
+ "button",
3351
3463
  {
3352
- id: "provider-model",
3353
- type: "text",
3354
- value: model,
3355
- onChange: (e) => setModel(e.target.value),
3356
- placeholder: "",
3357
- className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:border-ring focus-visible:outline-ring focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50"
3464
+ type: "button",
3465
+ onClick: () => setModels((prev) => [...prev, ""]),
3466
+ className: "text-xs text-primary hover:underline flex items-center gap-1",
3467
+ children: "+ Add Model"
3358
3468
  }
3359
3469
  ),
3360
- errors.model !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-destructive", children: errors.model })
3470
+ errors.models !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-destructive", children: errors.models })
3361
3471
  ] }),
3362
3472
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
3363
3473
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-1 border-b border-border", children: [
@@ -3441,83 +3551,6 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
3441
3551
  ] })
3442
3552
  ] });
3443
3553
  }
3444
- const ProviderTestErrorTypeSchema = _enum([
3445
- "timeout",
3446
- "network_unreachable",
3447
- "connection_refused",
3448
- "auth_failed",
3449
- "rate_limited",
3450
- "server_error",
3451
- "invalid_response",
3452
- "unknown"
3453
- ]);
3454
- const ProviderTestErrorSchema = object({
3455
- message: string(),
3456
- type: ProviderTestErrorTypeSchema,
3457
- details: string().optional(),
3458
- hint: string().optional()
3459
- });
3460
- const ProviderTestContentSchema = object({
3461
- type: _enum(["text", "thinking"]),
3462
- text: string().optional(),
3463
- thinking: string().optional()
3464
- });
3465
- const ProviderTestResultSchema = object({
3466
- success: boolean(),
3467
- error: ProviderTestErrorSchema.optional(),
3468
- model: string().optional(),
3469
- inputTokens: number().optional(),
3470
- outputTokens: number().optional(),
3471
- cacheCreationInputTokens: number().optional(),
3472
- cacheReadInputTokens: number().optional(),
3473
- latencyMs: number().optional(),
3474
- content: array(ProviderTestContentSchema).optional(),
3475
- rawResponse: string().optional(),
3476
- streaming: boolean().optional(),
3477
- streamingChunks: object({
3478
- chunks: array(StreamingChunkSchema$1),
3479
- truncated: boolean().default(false)
3480
- }).optional(),
3481
- requestHeaders: record(string(), string()).optional()
3482
- });
3483
- const ProviderTestStateSchema = union([
3484
- ProviderTestResultSchema,
3485
- object({ notConfigured: literal(true) }),
3486
- object({ testing: literal(true) })
3487
- ]);
3488
- const ProviderFormatTestResultsSchema = object({
3489
- nonStreaming: ProviderTestStateSchema,
3490
- streaming: ProviderTestStateSchema
3491
- });
3492
- const ProviderTestResultsSchema = object({
3493
- anthropic: ProviderFormatTestResultsSchema,
3494
- openai: ProviderFormatTestResultsSchema
3495
- });
3496
- function createPendingProviderTestResults() {
3497
- return {
3498
- anthropic: {
3499
- nonStreaming: { testing: true },
3500
- streaming: { testing: true }
3501
- },
3502
- openai: {
3503
- nonStreaming: { testing: true },
3504
- streaming: { testing: true }
3505
- }
3506
- };
3507
- }
3508
- function createFailedProviderTestResults(message, type) {
3509
- const createFormatResult = () => ({
3510
- nonStreaming: {
3511
- success: false,
3512
- error: { message, type }
3513
- },
3514
- streaming: { notConfigured: true }
3515
- });
3516
- return {
3517
- anthropic: createFormatResult(),
3518
- openai: createFormatResult()
3519
- };
3520
- }
3521
3554
  const ConfigPathsResponseSchema = object({
3522
3555
  providerConfig: string()
3523
3556
  });
@@ -3533,7 +3566,7 @@ function createProviderPayload(data) {
3533
3566
  return {
3534
3567
  name: data.name,
3535
3568
  apiKey: data.apiKey,
3536
- model: data.model,
3569
+ models: data.models,
3537
3570
  anthropicBaseUrl: (data.anthropicBaseUrl?.length ?? 0) > 0 ? data.anthropicBaseUrl : void 0,
3538
3571
  openaiBaseUrl: (data.openaiBaseUrl?.length ?? 0) > 0 ? data.openaiBaseUrl : void 0,
3539
3572
  apiDocsUrl: (data.apiDocsUrl?.length ?? 0) > 0 ? data.apiDocsUrl : void 0,
@@ -3731,7 +3764,7 @@ function ProvidersPanel({
3731
3764
  setEditingProvider(void 0);
3732
3765
  triggerHighlight(updated.id);
3733
3766
  refreshProviders();
3734
- const criticalFieldsChanged = (data.apiKey ?? "") !== (editingProvider.apiKey ?? "") || (data.model ?? "") !== (editingProvider.model ?? "") || (data.anthropicBaseUrl ?? "") !== (editingProvider.anthropicBaseUrl ?? "") || (data.openaiBaseUrl ?? "") !== (editingProvider.openaiBaseUrl ?? "");
3767
+ const criticalFieldsChanged = (data.apiKey ?? "") !== (editingProvider.apiKey ?? "") || JSON.stringify(data.models) !== JSON.stringify(editingProvider.models) || (data.anthropicBaseUrl ?? "") !== (editingProvider.anthropicBaseUrl ?? "") || (data.openaiBaseUrl ?? "") !== (editingProvider.openaiBaseUrl ?? "");
3735
3768
  if (criticalFieldsChanged) {
3736
3769
  await runTest(updated.id);
3737
3770
  }
@@ -198,7 +198,7 @@ function getResponse() {
198
198
  return event.res;
199
199
  }
200
200
  async function getStartManifest(matchedRoutes) {
201
- const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-vO4aM6jK.mjs");
201
+ const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-B6idtbmL.mjs");
202
202
  const startManifest = tsrStartManifest();
203
203
  const rootRoute = startManifest.routes[rootRouteId] = startManifest.routes[rootRouteId] || {};
204
204
  rootRoute.assets = rootRoute.assets || [];
@@ -767,7 +767,7 @@ let entriesPromise;
767
767
  let baseManifestPromise;
768
768
  let cachedFinalManifestPromise;
769
769
  async function loadEntries() {
770
- const routerEntry = await import("./router-B8X3GXM2.mjs").then((n) => n.r);
770
+ const routerEntry = await import("./router-BoeSXWHG.mjs").then((n) => n.r);
771
771
  const startEntry = await import("./start-HYkvq4Ni.mjs");
772
772
  return { startEntry, routerEntry };
773
773
  }