@tonyclaw/llm-inspector 1.7.8 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/nitro.json +1 -1
- package/.output/public/assets/index-BLVa7n9b.css +1 -0
- package/.output/public/assets/index-DH3FOgcK.js +97 -0
- package/.output/public/assets/main-Beo3LJDa.js +17 -0
- package/.output/server/_libs/dequal.mjs +27 -0
- package/.output/server/_libs/lucide-react.mjs +98 -91
- package/.output/server/_libs/swr.mjs +938 -0
- package/.output/server/_libs/use-sync-external-store.mjs +64 -1
- package/.output/server/_libs/zod.mjs +1 -0
- package/.output/server/_ssr/{index-hNquJMfH.mjs → index-HkueJ4Un.mjs} +218 -71
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-MmnX-LYh.mjs → router-DTswxb7l.mjs} +264 -52
- package/.output/server/_tanstack-start-manifest_v-DhUuivt-.mjs +4 -0
- package/.output/server/index.mjs +26 -26
- package/package.json +2 -1
- package/src/components/ProxyViewer.tsx +2 -0
- package/src/components/providers/ProviderCard.tsx +38 -33
- package/src/components/providers/ProviderLogo.tsx +6 -1
- package/src/components/providers/ProvidersPanel.tsx +144 -43
- package/src/components/providers/SettingsDialog.tsx +5 -3
- package/src/components/proxy-viewer/ConversationGroup.tsx +3 -3
- package/src/components/proxy-viewer/LogEntry.tsx +6 -3
- package/src/components/proxy-viewer/LogEntryHeader.tsx +3 -2
- package/src/lib/useProviders.ts +30 -0
- package/src/proxy/formats/anthropic/stream.ts +3 -2
- package/src/proxy/formats/openai/stream.ts +3 -2
- package/src/proxy/handler.ts +5 -0
- package/src/proxy/providers.ts +98 -0
- package/src/routes/__root.tsx +4 -1
- package/src/routes/api/providers.export.ts +26 -0
- package/src/routes/api/providers.import.ts +47 -0
- package/.output/public/assets/index-B3RwBPLW.css +0 -1
- package/.output/public/assets/index-C8o6bEv6.js +0 -97
- package/.output/public/assets/main-Bxc5pKCu.js +0 -17
- package/.output/server/_tanstack-start-manifest_v-CYKtU_9S.mjs +0 -4
|
@@ -1 +1,64 @@
|
|
|
1
|
-
|
|
1
|
+
import { b as requireReact } from "./react.mjs";
|
|
2
|
+
var shim = { exports: {} };
|
|
3
|
+
var useSyncExternalStoreShim_production = {};
|
|
4
|
+
var hasRequiredUseSyncExternalStoreShim_production;
|
|
5
|
+
function requireUseSyncExternalStoreShim_production() {
|
|
6
|
+
if (hasRequiredUseSyncExternalStoreShim_production) return useSyncExternalStoreShim_production;
|
|
7
|
+
hasRequiredUseSyncExternalStoreShim_production = 1;
|
|
8
|
+
var React = /* @__PURE__ */ requireReact();
|
|
9
|
+
function is(x, y) {
|
|
10
|
+
return x === y && (0 !== x || 1 / x === 1 / y) || x !== x && y !== y;
|
|
11
|
+
}
|
|
12
|
+
var objectIs = "function" === typeof Object.is ? Object.is : is, useState = React.useState, useEffect = React.useEffect, useLayoutEffect = React.useLayoutEffect, useDebugValue = React.useDebugValue;
|
|
13
|
+
function useSyncExternalStore$2(subscribe, getSnapshot) {
|
|
14
|
+
var value = getSnapshot(), _useState = useState({ inst: { value, getSnapshot } }), inst = _useState[0].inst, forceUpdate = _useState[1];
|
|
15
|
+
useLayoutEffect(
|
|
16
|
+
function() {
|
|
17
|
+
inst.value = value;
|
|
18
|
+
inst.getSnapshot = getSnapshot;
|
|
19
|
+
checkIfSnapshotChanged(inst) && forceUpdate({ inst });
|
|
20
|
+
},
|
|
21
|
+
[subscribe, value, getSnapshot]
|
|
22
|
+
);
|
|
23
|
+
useEffect(
|
|
24
|
+
function() {
|
|
25
|
+
checkIfSnapshotChanged(inst) && forceUpdate({ inst });
|
|
26
|
+
return subscribe(function() {
|
|
27
|
+
checkIfSnapshotChanged(inst) && forceUpdate({ inst });
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
[subscribe]
|
|
31
|
+
);
|
|
32
|
+
useDebugValue(value);
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
function checkIfSnapshotChanged(inst) {
|
|
36
|
+
var latestGetSnapshot = inst.getSnapshot;
|
|
37
|
+
inst = inst.value;
|
|
38
|
+
try {
|
|
39
|
+
var nextValue = latestGetSnapshot();
|
|
40
|
+
return !objectIs(inst, nextValue);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function useSyncExternalStore$1(subscribe, getSnapshot) {
|
|
46
|
+
return getSnapshot();
|
|
47
|
+
}
|
|
48
|
+
var shim2 = "undefined" === typeof window || "undefined" === typeof window.document || "undefined" === typeof window.document.createElement ? useSyncExternalStore$1 : useSyncExternalStore$2;
|
|
49
|
+
useSyncExternalStoreShim_production.useSyncExternalStore = void 0 !== React.useSyncExternalStore ? React.useSyncExternalStore : shim2;
|
|
50
|
+
return useSyncExternalStoreShim_production;
|
|
51
|
+
}
|
|
52
|
+
var hasRequiredShim;
|
|
53
|
+
function requireShim() {
|
|
54
|
+
if (hasRequiredShim) return shim.exports;
|
|
55
|
+
hasRequiredShim = 1;
|
|
56
|
+
{
|
|
57
|
+
shim.exports = /* @__PURE__ */ requireUseSyncExternalStoreShim_production();
|
|
58
|
+
}
|
|
59
|
+
return shim.exports;
|
|
60
|
+
}
|
|
61
|
+
var shimExports = /* @__PURE__ */ requireShim();
|
|
62
|
+
export {
|
|
63
|
+
shimExports as s
|
|
64
|
+
};
|
|
@@ -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-
|
|
2
|
+
import { C as CapturedLogSchema, a as parseRequest, p as parseOpenAIResponse, I as InspectorResponseSchema } from "./router-DTswxb7l.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,9 +7,10 @@ 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 {
|
|
10
|
+
import { u as useSWR } from "../_libs/swr.mjs";
|
|
11
|
+
import { D as Download, L as LayoutGrid, a as List, S as Settings, C as ChevronDown, b as Check, R as RotateCcw, X, 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, G as Globe, i as User, F as FileTerminal, j as Radio, E as ExternalLink, k as EyeOff, l as Eye, m as RotateCw, n as Pencil, T as Trash2, o as TriangleAlert, p as Minus, q as CircleCheckBig, r as CircleStop, s as CircleQuestionMark, t as Server, u as Gauge, v as Lock, w as Wifi, x as WifiOff, y as ChevronsUp, z as ChevronsDown, A as Terminal, B as Brain } from "../_libs/lucide-react.mjs";
|
|
11
12
|
import { M as Markdown } from "../_libs/react-markdown.mjs";
|
|
12
|
-
import { a as array, s as string, u as union, o as object, l as literal,
|
|
13
|
+
import { a as array, s as string, u as union, o as object, l as literal, n as number, b as boolean } from "../_libs/zod.mjs";
|
|
13
14
|
import { R as Root2$1, L as List$1, T as Trigger$2, C as Content$1 } from "../_libs/radix-ui__react-tabs.mjs";
|
|
14
15
|
import { S as Slot } from "../_libs/radix-ui__react-slot.mjs";
|
|
15
16
|
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";
|
|
@@ -57,6 +58,8 @@ import "../_libs/mimic-function.mjs";
|
|
|
57
58
|
import "../_libs/semver.mjs";
|
|
58
59
|
import "../_libs/uint8array-extras.mjs";
|
|
59
60
|
import "node:child_process";
|
|
61
|
+
import "../_libs/use-sync-external-store.mjs";
|
|
62
|
+
import "../_libs/dequal.mjs";
|
|
60
63
|
import "../_libs/tanstack__virtual-core.mjs";
|
|
61
64
|
import "../_libs/readable-stream.mjs";
|
|
62
65
|
import "../_libs/process-nextick-args.mjs";
|
|
@@ -196,6 +199,10 @@ async function exportLogsAsZip(logs) {
|
|
|
196
199
|
document.body.removeChild(anchor);
|
|
197
200
|
URL.revokeObjectURL(url);
|
|
198
201
|
}
|
|
202
|
+
const version = "1.8.0";
|
|
203
|
+
const packageJson = {
|
|
204
|
+
version
|
|
205
|
+
};
|
|
199
206
|
function cn(...inputs) {
|
|
200
207
|
return twMerge(clsx(inputs));
|
|
201
208
|
}
|
|
@@ -891,7 +898,15 @@ const AnthropicLogo = React.memo(
|
|
|
891
898
|
({ className }) => /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: AnthropicLogoSvg, alt: "Anthropic", className, style: sizeStyle })
|
|
892
899
|
);
|
|
893
900
|
const OpenAILogo = React.memo(
|
|
894
|
-
({ className }) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
901
|
+
({ className }) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
902
|
+
"img",
|
|
903
|
+
{
|
|
904
|
+
src: OpenAILogoSvg,
|
|
905
|
+
alt: "OpenAI",
|
|
906
|
+
className,
|
|
907
|
+
style: { ...sizeStyle, background: "white", borderRadius: "4px" }
|
|
908
|
+
}
|
|
909
|
+
)
|
|
895
910
|
);
|
|
896
911
|
const DeepSeekLogo = React.memo(
|
|
897
912
|
({ className }) => /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: DeepSeekLogoSvg, alt: "DeepSeek", className, style: sizeStyle })
|
|
@@ -946,7 +961,7 @@ const STATUS_BADGE_CLASSES = {
|
|
|
946
961
|
server_error: "",
|
|
947
962
|
pending: "bg-muted text-muted-foreground border-border"
|
|
948
963
|
};
|
|
949
|
-
|
|
964
|
+
const LogEntryHeader = reactExports.memo(function LogEntryHeader2({
|
|
950
965
|
log,
|
|
951
966
|
parsedRequest,
|
|
952
967
|
expanded,
|
|
@@ -1098,7 +1113,7 @@ function LogEntryHeader({
|
|
|
1098
1113
|
]
|
|
1099
1114
|
}
|
|
1100
1115
|
);
|
|
1101
|
-
}
|
|
1116
|
+
});
|
|
1102
1117
|
function Dialog({
|
|
1103
1118
|
...props
|
|
1104
1119
|
}) {
|
|
@@ -1832,7 +1847,10 @@ function CopyButton({
|
|
|
1832
1847
|
}
|
|
1833
1848
|
);
|
|
1834
1849
|
}
|
|
1835
|
-
|
|
1850
|
+
const LogEntry = reactExports.memo(function LogEntry2({
|
|
1851
|
+
log,
|
|
1852
|
+
viewMode = "simple"
|
|
1853
|
+
}) {
|
|
1836
1854
|
const [expanded, setExpanded] = reactExports.useState(false);
|
|
1837
1855
|
const [requestCopied, setRequestCopied] = reactExports.useState(false);
|
|
1838
1856
|
const [responseCopied, setResponseCopied] = reactExports.useState(false);
|
|
@@ -1953,7 +1971,7 @@ function LogEntry({ log, viewMode = "simple" }) {
|
|
|
1953
1971
|
] }),
|
|
1954
1972
|
/* @__PURE__ */ jsxRuntimeExports.jsx(ReplayDialog, { log, open: replayOpen, onOpenChange: setReplayOpen })
|
|
1955
1973
|
] });
|
|
1956
|
-
}
|
|
1974
|
+
});
|
|
1957
1975
|
function computeStats(logs) {
|
|
1958
1976
|
let totalInput = 0;
|
|
1959
1977
|
let totalOutput = 0;
|
|
@@ -1963,7 +1981,7 @@ function computeStats(logs) {
|
|
|
1963
1981
|
}
|
|
1964
1982
|
return { totalInputTokens: totalInput, totalOutputTokens: totalOutput };
|
|
1965
1983
|
}
|
|
1966
|
-
|
|
1984
|
+
const ConversationGroup = reactExports.memo(function ConversationGroup2({
|
|
1967
1985
|
group,
|
|
1968
1986
|
viewMode = "simple"
|
|
1969
1987
|
}) {
|
|
@@ -1988,7 +2006,7 @@ function ConversationGroup({
|
|
|
1988
2006
|
),
|
|
1989
2007
|
expanded && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pl-4 border-l-2 border-muted ml-3", children: group.logs.map((log) => /* @__PURE__ */ jsxRuntimeExports.jsx(LogEntry, { log, viewMode }, log.id)) })
|
|
1990
2008
|
] });
|
|
1991
|
-
}
|
|
2009
|
+
});
|
|
1992
2010
|
function Select({
|
|
1993
2011
|
...props
|
|
1994
2012
|
}) {
|
|
@@ -2117,6 +2135,9 @@ function maskApiKey(apiKey) {
|
|
|
2117
2135
|
function hasSuccessField(result) {
|
|
2118
2136
|
return Object.prototype.hasOwnProperty.call(result, "success");
|
|
2119
2137
|
}
|
|
2138
|
+
function isNotConfiguredState(result) {
|
|
2139
|
+
return Object.prototype.hasOwnProperty.call(result, "notConfigured");
|
|
2140
|
+
}
|
|
2120
2141
|
function getErrorIcon(type) {
|
|
2121
2142
|
const iconProps = { className: "size-3", strokeWidth: 2 };
|
|
2122
2143
|
switch (type) {
|
|
@@ -2140,18 +2161,21 @@ function getErrorIcon(type) {
|
|
|
2140
2161
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { ...iconProps });
|
|
2141
2162
|
}
|
|
2142
2163
|
}
|
|
2143
|
-
function TestStatus({
|
|
2144
|
-
result,
|
|
2145
|
-
isTesting
|
|
2146
|
-
}) {
|
|
2164
|
+
function TestStatus({ result }) {
|
|
2147
2165
|
if (!hasSuccessField(result)) {
|
|
2148
|
-
|
|
2149
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
2150
|
-
|
|
2166
|
+
if (isNotConfiguredState(result)) {
|
|
2167
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 text-xs text-muted-foreground shrink-0", children: [
|
|
2168
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Minus, { className: "size-3" }),
|
|
2169
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Not configured" })
|
|
2170
|
+
] });
|
|
2171
|
+
}
|
|
2172
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 text-xs text-muted-foreground shrink-0", children: [
|
|
2173
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(RotateCw, { className: "size-3 animate-spin" }),
|
|
2174
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Testing..." })
|
|
2151
2175
|
] });
|
|
2152
2176
|
}
|
|
2153
2177
|
if (result.success) {
|
|
2154
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 text-xs text-green-600", children: [
|
|
2178
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 text-xs text-green-600 shrink-0", children: [
|
|
2155
2179
|
/* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheckBig, { className: "size-3" }),
|
|
2156
2180
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Connected" })
|
|
2157
2181
|
] });
|
|
@@ -2160,20 +2184,18 @@ function TestStatus({
|
|
|
2160
2184
|
const errorMessage = error?.message ?? "Connection failed";
|
|
2161
2185
|
const errorHint = error?.hint;
|
|
2162
2186
|
const errorType = error?.type ?? "unknown";
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
errorHint !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-muted-foreground pl-4 truncate", title: errorHint, children: errorHint })
|
|
2176
|
-
] });
|
|
2187
|
+
const fullMessage = errorHint !== void 0 ? `${errorMessage} — ${errorHint}` : errorMessage;
|
|
2188
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2189
|
+
"div",
|
|
2190
|
+
{
|
|
2191
|
+
className: "flex items-center gap-1 text-xs text-red-600 shrink-0 max-w-[200px]",
|
|
2192
|
+
title: error?.details ?? fullMessage,
|
|
2193
|
+
children: [
|
|
2194
|
+
getErrorIcon(errorType),
|
|
2195
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: errorMessage })
|
|
2196
|
+
]
|
|
2197
|
+
}
|
|
2198
|
+
);
|
|
2177
2199
|
}
|
|
2178
2200
|
function ProviderCard({
|
|
2179
2201
|
provider,
|
|
@@ -2225,7 +2247,7 @@ function ProviderCard({
|
|
|
2225
2247
|
" ",
|
|
2226
2248
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: provider.anthropicBaseUrl })
|
|
2227
2249
|
] }),
|
|
2228
|
-
testResults && /* @__PURE__ */ jsxRuntimeExports.jsx(TestStatus, { result: testResults.anthropic.nonStreaming
|
|
2250
|
+
testResults && /* @__PURE__ */ jsxRuntimeExports.jsx(TestStatus, { result: testResults.anthropic.nonStreaming })
|
|
2229
2251
|
] }),
|
|
2230
2252
|
provider.openaiBaseUrl !== void 0 && provider.openaiBaseUrl !== "" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
2231
2253
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-muted-foreground min-w-0 flex-1", children: [
|
|
@@ -2233,7 +2255,7 @@ function ProviderCard({
|
|
|
2233
2255
|
" ",
|
|
2234
2256
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: provider.openaiBaseUrl })
|
|
2235
2257
|
] }),
|
|
2236
|
-
testResults && /* @__PURE__ */ jsxRuntimeExports.jsx(TestStatus, { result: testResults.openai.nonStreaming
|
|
2258
|
+
testResults && /* @__PURE__ */ jsxRuntimeExports.jsx(TestStatus, { result: testResults.openai.nonStreaming })
|
|
2237
2259
|
] }),
|
|
2238
2260
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 pt-1 border-t", children: [
|
|
2239
2261
|
onTest !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
@@ -2502,13 +2524,11 @@ function ProvidersPanel({
|
|
|
2502
2524
|
externalTestResults,
|
|
2503
2525
|
externalTestingProviders,
|
|
2504
2526
|
externalTestingTimeLeft,
|
|
2505
|
-
|
|
2527
|
+
onProvidersMutate,
|
|
2506
2528
|
onTestResultsChange,
|
|
2507
2529
|
onTestingProvidersChange,
|
|
2508
2530
|
onTestingTimeLeftChange
|
|
2509
2531
|
}) {
|
|
2510
|
-
const [internalProviders, setInternalProviders] = reactExports.useState([]);
|
|
2511
|
-
const [isLoading, setIsLoading] = reactExports.useState(true);
|
|
2512
2532
|
const [showForm, setShowForm] = reactExports.useState(false);
|
|
2513
2533
|
const [editingProvider, setEditingProvider] = reactExports.useState();
|
|
2514
2534
|
const [error, setError] = reactExports.useState(null);
|
|
@@ -2519,8 +2539,7 @@ function ProvidersPanel({
|
|
|
2519
2539
|
);
|
|
2520
2540
|
const [configPath, setConfigPath] = reactExports.useState(null);
|
|
2521
2541
|
const [configPathCopied, setConfigPathCopied] = reactExports.useState(false);
|
|
2522
|
-
const providers = externalProviders ??
|
|
2523
|
-
const setProviders = onProvidersChange ?? setInternalProviders;
|
|
2542
|
+
const providers = externalProviders ?? [];
|
|
2524
2543
|
const testResults = externalTestResults ?? internalTestResults;
|
|
2525
2544
|
const testingProviders = externalTestingProviders ?? internalTestingProviders;
|
|
2526
2545
|
const testingTimeLeft = externalTestingTimeLeft ?? internalTestingTimeLeft;
|
|
@@ -2535,19 +2554,7 @@ function ProvidersPanel({
|
|
|
2535
2554
|
setInternalTestingTimeLeft((prev) => ({ ...prev, [id]: seconds }));
|
|
2536
2555
|
}
|
|
2537
2556
|
};
|
|
2538
|
-
const fetchProviders = reactExports.useCallback(async () => {
|
|
2539
|
-
try {
|
|
2540
|
-
const providersRes = await fetch("/api/providers");
|
|
2541
|
-
const providersData = await providersRes.json();
|
|
2542
|
-
setProviders(providersData);
|
|
2543
|
-
} catch {
|
|
2544
|
-
setError("Failed to load providers");
|
|
2545
|
-
} finally {
|
|
2546
|
-
setIsLoading(false);
|
|
2547
|
-
}
|
|
2548
|
-
}, []);
|
|
2549
2557
|
reactExports.useEffect(() => {
|
|
2550
|
-
void fetchProviders();
|
|
2551
2558
|
void (async () => {
|
|
2552
2559
|
try {
|
|
2553
2560
|
const res = await fetch("/api/config/paths");
|
|
@@ -2558,10 +2565,19 @@ function ProvidersPanel({
|
|
|
2558
2565
|
} catch {
|
|
2559
2566
|
}
|
|
2560
2567
|
})();
|
|
2561
|
-
}, [
|
|
2568
|
+
}, []);
|
|
2562
2569
|
const TEST_TIMEOUT_SECONDS = 30;
|
|
2563
2570
|
const runTest = reactExports.useCallback(
|
|
2564
2571
|
async (providerId) => {
|
|
2572
|
+
const resetResults = {
|
|
2573
|
+
anthropic: { nonStreaming: { testing: true }, streaming: { testing: true } },
|
|
2574
|
+
openai: { nonStreaming: { testing: true }, streaming: { testing: true } }
|
|
2575
|
+
};
|
|
2576
|
+
if (onTestResultsChange) {
|
|
2577
|
+
onTestResultsChange(providerId, resetResults);
|
|
2578
|
+
} else {
|
|
2579
|
+
setInternalTestResults((prev) => ({ ...prev, [providerId]: resetResults }));
|
|
2580
|
+
}
|
|
2565
2581
|
if (onTestingProvidersChange) {
|
|
2566
2582
|
onTestingProvidersChange(providerId, true);
|
|
2567
2583
|
} else {
|
|
@@ -2614,7 +2630,8 @@ function ProvidersPanel({
|
|
|
2614
2630
|
}
|
|
2615
2631
|
}
|
|
2616
2632
|
} catch (err) {
|
|
2617
|
-
|
|
2633
|
+
const isAbort = err instanceof Error && err.name === "AbortError";
|
|
2634
|
+
if (isAbort) {
|
|
2618
2635
|
const timeoutResult = {
|
|
2619
2636
|
anthropic: {
|
|
2620
2637
|
nonStreaming: {
|
|
@@ -2640,14 +2657,17 @@ function ProvidersPanel({
|
|
|
2640
2657
|
} finally {
|
|
2641
2658
|
clearInterval(intervalId);
|
|
2642
2659
|
setTestingTimeLeft(providerId, void 0);
|
|
2643
|
-
|
|
2644
|
-
onTestingProvidersChange
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2660
|
+
try {
|
|
2661
|
+
if (onTestingProvidersChange) {
|
|
2662
|
+
onTestingProvidersChange(providerId, false);
|
|
2663
|
+
} else {
|
|
2664
|
+
setInternalTestingProviders((prev) => {
|
|
2665
|
+
const next = new Set(prev);
|
|
2666
|
+
next.delete(providerId);
|
|
2667
|
+
return next;
|
|
2668
|
+
});
|
|
2669
|
+
}
|
|
2670
|
+
} catch {
|
|
2651
2671
|
}
|
|
2652
2672
|
}
|
|
2653
2673
|
},
|
|
@@ -2674,7 +2694,7 @@ function ProvidersPanel({
|
|
|
2674
2694
|
return;
|
|
2675
2695
|
}
|
|
2676
2696
|
const newProvider = await res.json();
|
|
2677
|
-
|
|
2697
|
+
onProvidersMutate?.();
|
|
2678
2698
|
setShowForm(false);
|
|
2679
2699
|
await runTest(newProvider.id);
|
|
2680
2700
|
})();
|
|
@@ -2701,7 +2721,7 @@ function ProvidersPanel({
|
|
|
2701
2721
|
return;
|
|
2702
2722
|
}
|
|
2703
2723
|
const updated = await res.json();
|
|
2704
|
-
|
|
2724
|
+
onProvidersMutate?.();
|
|
2705
2725
|
setEditingProvider(void 0);
|
|
2706
2726
|
await runTest(updated.id);
|
|
2707
2727
|
})();
|
|
@@ -2717,10 +2737,69 @@ function ProvidersPanel({
|
|
|
2717
2737
|
setError(err.error ?? "Failed to delete provider");
|
|
2718
2738
|
return;
|
|
2719
2739
|
}
|
|
2720
|
-
|
|
2740
|
+
onProvidersMutate?.();
|
|
2721
2741
|
})();
|
|
2722
2742
|
}
|
|
2723
|
-
|
|
2743
|
+
const fileInputRef = reactExports.useRef(null);
|
|
2744
|
+
function handleExport(includeKeys) {
|
|
2745
|
+
const url = `/api/providers/export${""}`;
|
|
2746
|
+
void (async () => {
|
|
2747
|
+
try {
|
|
2748
|
+
const res = await fetch(url);
|
|
2749
|
+
if (!res.ok) {
|
|
2750
|
+
setError("Failed to export providers");
|
|
2751
|
+
return;
|
|
2752
|
+
}
|
|
2753
|
+
const blob = await res.blob();
|
|
2754
|
+
const downloadUrl = URL.createObjectURL(blob);
|
|
2755
|
+
const a = document.createElement("a");
|
|
2756
|
+
a.href = downloadUrl;
|
|
2757
|
+
a.download = res.headers.get("Content-Disposition")?.match(/filename="(.+)"/)?.[1] ?? "providers.json";
|
|
2758
|
+
document.body.appendChild(a);
|
|
2759
|
+
a.click();
|
|
2760
|
+
document.body.removeChild(a);
|
|
2761
|
+
URL.revokeObjectURL(downloadUrl);
|
|
2762
|
+
} catch {
|
|
2763
|
+
setError("Failed to export providers");
|
|
2764
|
+
}
|
|
2765
|
+
})();
|
|
2766
|
+
}
|
|
2767
|
+
function handleImportClick() {
|
|
2768
|
+
fileInputRef.current?.click();
|
|
2769
|
+
}
|
|
2770
|
+
function handleFileChange(e) {
|
|
2771
|
+
const file = e.target.files?.[0];
|
|
2772
|
+
if (!file) return;
|
|
2773
|
+
void (async () => {
|
|
2774
|
+
try {
|
|
2775
|
+
const text = await file.text();
|
|
2776
|
+
const res = await fetch("/api/providers/import", {
|
|
2777
|
+
method: "POST",
|
|
2778
|
+
headers: { "Content-Type": "application/json" },
|
|
2779
|
+
body: JSON.stringify(text)
|
|
2780
|
+
});
|
|
2781
|
+
const ImportResponseSchema = object({
|
|
2782
|
+
success: boolean().optional(),
|
|
2783
|
+
imported: number().optional(),
|
|
2784
|
+
message: string().optional(),
|
|
2785
|
+
errors: array(string()).optional()
|
|
2786
|
+
});
|
|
2787
|
+
const data = ImportResponseSchema.parse(await res.json());
|
|
2788
|
+
if (res.ok && data.imported !== void 0 && data.imported > 0) {
|
|
2789
|
+
onProvidersMutate?.();
|
|
2790
|
+
setError(null);
|
|
2791
|
+
} else if (data.errors && data.errors.length > 0) {
|
|
2792
|
+
setError(data.errors.join("; "));
|
|
2793
|
+
} else {
|
|
2794
|
+
setError(data.message ?? "Import failed");
|
|
2795
|
+
}
|
|
2796
|
+
} catch {
|
|
2797
|
+
setError("Failed to import providers");
|
|
2798
|
+
}
|
|
2799
|
+
e.target.value = "";
|
|
2800
|
+
})();
|
|
2801
|
+
}
|
|
2802
|
+
if (providers.length === 0) {
|
|
2724
2803
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-muted-foreground", children: "Loading providers..." }) });
|
|
2725
2804
|
}
|
|
2726
2805
|
if (showForm || editingProvider) {
|
|
@@ -2740,11 +2819,49 @@ function ProvidersPanel({
|
|
|
2740
2819
|
] });
|
|
2741
2820
|
}
|
|
2742
2821
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
|
|
2743
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2822
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between sticky top-0 z-10 bg-background pb-2", children: [
|
|
2744
2823
|
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-medium", children: "Providers" }),
|
|
2745
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2746
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
2747
|
-
|
|
2824
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2825
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2826
|
+
Button,
|
|
2827
|
+
{
|
|
2828
|
+
variant: "outline",
|
|
2829
|
+
size: "sm",
|
|
2830
|
+
onClick: () => handleExport(),
|
|
2831
|
+
className: "gap-1 hover:bg-muted",
|
|
2832
|
+
children: [
|
|
2833
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Download, { className: "size-3" }),
|
|
2834
|
+
"Export"
|
|
2835
|
+
]
|
|
2836
|
+
}
|
|
2837
|
+
),
|
|
2838
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
2839
|
+
Button,
|
|
2840
|
+
{
|
|
2841
|
+
variant: "outline",
|
|
2842
|
+
size: "sm",
|
|
2843
|
+
onClick: handleImportClick,
|
|
2844
|
+
className: "gap-1 hover:bg-muted",
|
|
2845
|
+
children: [
|
|
2846
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { className: "size-3" }),
|
|
2847
|
+
"Import"
|
|
2848
|
+
]
|
|
2849
|
+
}
|
|
2850
|
+
),
|
|
2851
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2852
|
+
"input",
|
|
2853
|
+
{
|
|
2854
|
+
type: "file",
|
|
2855
|
+
ref: fileInputRef,
|
|
2856
|
+
accept: ".json",
|
|
2857
|
+
onChange: handleFileChange,
|
|
2858
|
+
style: { display: "none" }
|
|
2859
|
+
}
|
|
2860
|
+
),
|
|
2861
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(Button, { onClick: () => setShowForm(true), size: "sm", className: "gap-1", children: [
|
|
2862
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { className: "size-4" }),
|
|
2863
|
+
"Add Provider"
|
|
2864
|
+
] })
|
|
2748
2865
|
] })
|
|
2749
2866
|
] }),
|
|
2750
2867
|
configPath !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground bg-muted/30 rounded-md px-3 py-2", children: [
|
|
@@ -2793,10 +2910,34 @@ function ProvidersPanel({
|
|
|
2793
2910
|
)) })
|
|
2794
2911
|
] });
|
|
2795
2912
|
}
|
|
2913
|
+
async function fetcher(url) {
|
|
2914
|
+
const response = await fetch(url);
|
|
2915
|
+
const data = await response.json();
|
|
2916
|
+
if (!Array.isArray(data)) {
|
|
2917
|
+
return [];
|
|
2918
|
+
}
|
|
2919
|
+
return data;
|
|
2920
|
+
}
|
|
2921
|
+
function useProviders() {
|
|
2922
|
+
const response = useSWR(
|
|
2923
|
+
"/api/providers",
|
|
2924
|
+
fetcher,
|
|
2925
|
+
{
|
|
2926
|
+
revalidateOnFocus: false,
|
|
2927
|
+
revalidateIfStale: false
|
|
2928
|
+
}
|
|
2929
|
+
);
|
|
2930
|
+
return {
|
|
2931
|
+
providers: response.data ?? [],
|
|
2932
|
+
isLoading: response.isLoading,
|
|
2933
|
+
isError: response.error,
|
|
2934
|
+
mutate: response.mutate
|
|
2935
|
+
};
|
|
2936
|
+
}
|
|
2796
2937
|
function SettingsDialog() {
|
|
2797
2938
|
const [open, setOpen] = reactExports.useState(false);
|
|
2798
2939
|
const [activeTab, setActiveTab] = reactExports.useState("providers");
|
|
2799
|
-
const
|
|
2940
|
+
const { providers, mutate } = useProviders();
|
|
2800
2941
|
const [testResults, setTestResults] = reactExports.useState({});
|
|
2801
2942
|
const [testingProviders, setTestingProviders] = reactExports.useState(/* @__PURE__ */ new Set());
|
|
2802
2943
|
const [testingTimeLeft, setTestingTimeLeft] = reactExports.useState({});
|
|
@@ -2846,7 +2987,9 @@ function SettingsDialog() {
|
|
|
2846
2987
|
externalTestResults: testResults,
|
|
2847
2988
|
externalTestingProviders: testingProviders,
|
|
2848
2989
|
externalTestingTimeLeft: testingTimeLeft,
|
|
2849
|
-
|
|
2990
|
+
onProvidersMutate: () => {
|
|
2991
|
+
void mutate();
|
|
2992
|
+
},
|
|
2850
2993
|
onTestResultsChange: handleTestResultsChange,
|
|
2851
2994
|
onTestingProvidersChange: handleTestingProvidersChange,
|
|
2852
2995
|
onTestingTimeLeftChange: handleTestingTimeLeftChange
|
|
@@ -2956,6 +3099,10 @@ function ProxyViewer({
|
|
|
2956
3099
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-[1200px] mx-auto flex flex-col h-screen", style: { maxHeight: "100vh" }, children: [
|
|
2957
3100
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4 mb-4 px-6 pt-6", children: [
|
|
2958
3101
|
/* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-lg font-bold flex-1", children: "LLM Proxy Inspector" }),
|
|
3102
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-muted-foreground text-xs font-mono", children: [
|
|
3103
|
+
"v",
|
|
3104
|
+
packageJson.version
|
|
3105
|
+
] }),
|
|
2959
3106
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center border border-border rounded-md overflow-hidden", children: [
|
|
2960
3107
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2961
3108
|
"button",
|
|
@@ -197,7 +197,7 @@ function getResponse() {
|
|
|
197
197
|
return event.res;
|
|
198
198
|
}
|
|
199
199
|
async function getStartManifest(matchedRoutes) {
|
|
200
|
-
const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-
|
|
200
|
+
const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-DhUuivt-.mjs");
|
|
201
201
|
const startManifest = tsrStartManifest();
|
|
202
202
|
const rootRoute = startManifest.routes[rootRouteId] = startManifest.routes[rootRouteId] || {};
|
|
203
203
|
rootRoute.assets = rootRoute.assets || [];
|
|
@@ -766,7 +766,7 @@ let entriesPromise;
|
|
|
766
766
|
let baseManifestPromise;
|
|
767
767
|
let cachedFinalManifestPromise;
|
|
768
768
|
async function loadEntries() {
|
|
769
|
-
const routerEntry = await import("./router-
|
|
769
|
+
const routerEntry = await import("./router-DTswxb7l.mjs").then((n) => n.r);
|
|
770
770
|
const startEntry = await import("./start-HYkvq4Ni.mjs");
|
|
771
771
|
return { startEntry, routerEntry };
|
|
772
772
|
}
|