@tonyclaw/llm-inspector 1.7.6 → 1.7.7
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-Drusqil7.js +97 -0
- package/.output/public/assets/{main-B3Cmykkm.js → main-DYXtPYU8.js} +1 -1
- package/.output/server/_ssr/{index-DAvMem8_.mjs → index-DbpsE3Y4.mjs} +125 -22
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-tRLZo2WT.mjs → router-CZSteFqT.mjs} +1 -1
- package/.output/server/{_tanstack-start-manifest_v-_KPj4BcN.mjs → _tanstack-start-manifest_v-DgsS3z4y.mjs} +1 -1
- package/.output/server/index.mjs +28 -28
- package/package.json +1 -1
- package/src/components/providers/ProviderCard.tsx +7 -1
- package/src/components/providers/ProvidersPanel.tsx +104 -22
- package/src/components/providers/SettingsDialog.tsx +51 -2
- package/.output/public/assets/index-BKkFFKAM.js +0 -97
|
@@ -14,4 +14,4 @@ Error generating stack: `+l.message+`
|
|
|
14
14
|
`)}else{const p=o.indexOf(`
|
|
15
15
|
`);if(p>=0){const S=o.slice(0,p).trim();o=o.slice(p+1),S.length>0&&(m=JSON.parse(S),f=!0)}}}return(async()=>{try{for(;;){const{value:y,done:h}=await r.read();y&&(o+=y);const p=o.lastIndexOf(`
|
|
16
16
|
`);if(p>=0){const S=o.slice(0,p);o=o.slice(p+1);const b=S.split(`
|
|
17
|
-
`).filter(Boolean);for(const _ of b)try{u(JSON.parse(_))}catch(R){i?.(`Invalid JSON line: ${_}`,R)}}if(h)break}}catch(y){i?.("Stream processing error:",y)}})(),u(m)}async function _E({jsonStream:a,onMessage:u,onError:i}){const r=a.getReader(),{value:o,done:f}=await r.read();if(f||!o)throw new Error("Stream ended before first object");const m=JSON.parse(o);return(async()=>{try{for(;;){const{value:y,done:h}=await r.read();if(h)break;if(y)try{u(JSON.parse(y))}catch(p){i?.(`Invalid JSON: ${y}`,p)}}}catch(y){i?.("Stream processing error:",y)}})(),u(m)}function EE(a){const u="/_serverFn/"+a;return Object.assign((...o)=>{const f=Lp()?.serverFns?.fetch;return gE(u,o,f??fetch)},{url:u,serverFnMeta:{id:a},[Ao]:!0})}const RE={key:"$TSS/serverfn",test:a=>typeof a!="function"||!(Ao in a)?!1:!!a[Ao],toSerializable:({serverFnMeta:a})=>({functionId:a.id}),fromSerializable:({functionId:a})=>EE(a)},TE="/assets/index-B3RwBPLW.css",Hp=G_({head:()=>({meta:[{charSet:"utf-8"},{name:"viewport",content:"width=device-width, initial-scale=1"},{title:"llm-inspector"}],links:[{rel:"stylesheet",href:TE}]}),component:AE});function AE(){return k.jsx(OE,{children:k.jsx(Cp,{})})}function OE({children:a}){return k.jsxs("html",{lang:"en",className:"dark",children:[k.jsx("head",{children:k.jsx(aE,{})}),k.jsxs("body",{children:[a,k.jsx(lE,{})]})]})}const ME="modulepreload",zE=function(a){return"/"+a},zy={},xE=function(u,i,r){let o=Promise.resolve();if(i&&i.length>0){let h=function(p){return Promise.all(p.map(S=>Promise.resolve(S).then(b=>({status:"fulfilled",value:b}),b=>({status:"rejected",reason:b}))))};document.getElementsByTagName("link");const m=document.querySelector("meta[property=csp-nonce]"),y=m?.nonce||m?.getAttribute("nonce");o=h(i.map(p=>{if(p=zE(p),p in zy)return;zy[p]=!0;const S=p.endsWith(".css"),b=S?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${p}"]${b}`))return;const _=document.createElement("link");if(_.rel=S?"stylesheet":ME,S||(_.as="script"),_.crossOrigin="",_.href=p,y&&_.setAttribute("nonce",y),document.head.appendChild(_),S)return new Promise((R,D)=>{_.addEventListener("load",R),_.addEventListener("error",()=>D(new Error(`Unable to preload CSS for ${p}`)))})}))}function f(m){const y=new Event("vite:preloadError",{cancelable:!0});if(y.payload=m,window.dispatchEvent(y),!y.defaultPrevented)throw m}return o.then(m=>{for(const y of m||[])y.status==="rejected"&&f(y.reason);return u().catch(f)})},wE=()=>xE(()=>import("./index-
|
|
17
|
+
`).filter(Boolean);for(const _ of b)try{u(JSON.parse(_))}catch(R){i?.(`Invalid JSON line: ${_}`,R)}}if(h)break}}catch(y){i?.("Stream processing error:",y)}})(),u(m)}async function _E({jsonStream:a,onMessage:u,onError:i}){const r=a.getReader(),{value:o,done:f}=await r.read();if(f||!o)throw new Error("Stream ended before first object");const m=JSON.parse(o);return(async()=>{try{for(;;){const{value:y,done:h}=await r.read();if(h)break;if(y)try{u(JSON.parse(y))}catch(p){i?.(`Invalid JSON: ${y}`,p)}}}catch(y){i?.("Stream processing error:",y)}})(),u(m)}function EE(a){const u="/_serverFn/"+a;return Object.assign((...o)=>{const f=Lp()?.serverFns?.fetch;return gE(u,o,f??fetch)},{url:u,serverFnMeta:{id:a},[Ao]:!0})}const RE={key:"$TSS/serverfn",test:a=>typeof a!="function"||!(Ao in a)?!1:!!a[Ao],toSerializable:({serverFnMeta:a})=>({functionId:a.id}),fromSerializable:({functionId:a})=>EE(a)},TE="/assets/index-B3RwBPLW.css",Hp=G_({head:()=>({meta:[{charSet:"utf-8"},{name:"viewport",content:"width=device-width, initial-scale=1"},{title:"llm-inspector"}],links:[{rel:"stylesheet",href:TE}]}),component:AE});function AE(){return k.jsx(OE,{children:k.jsx(Cp,{})})}function OE({children:a}){return k.jsxs("html",{lang:"en",className:"dark",children:[k.jsx("head",{children:k.jsx(aE,{})}),k.jsxs("body",{children:[a,k.jsx(lE,{})]})]})}const ME="modulepreload",zE=function(a){return"/"+a},zy={},xE=function(u,i,r){let o=Promise.resolve();if(i&&i.length>0){let h=function(p){return Promise.all(p.map(S=>Promise.resolve(S).then(b=>({status:"fulfilled",value:b}),b=>({status:"rejected",reason:b}))))};document.getElementsByTagName("link");const m=document.querySelector("meta[property=csp-nonce]"),y=m?.nonce||m?.getAttribute("nonce");o=h(i.map(p=>{if(p=zE(p),p in zy)return;zy[p]=!0;const S=p.endsWith(".css"),b=S?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${p}"]${b}`))return;const _=document.createElement("link");if(_.rel=S?"stylesheet":ME,S||(_.as="script"),_.crossOrigin="",_.href=p,y&&_.setAttribute("nonce",y),document.head.appendChild(_),S)return new Promise((R,D)=>{_.addEventListener("load",R),_.addEventListener("error",()=>D(new Error(`Unable to preload CSS for ${p}`)))})}))}function f(m){const y=new Event("vite:preloadError",{cancelable:!0});if(y.payload=m,window.dispatchEvent(y),!y.defaultPrevented)throw m}return o.then(m=>{for(const y of m||[])y.status==="rejected"&&f(y.reason);return u().catch(f)})},wE=()=>xE(()=>import("./index-Drusqil7.js"),[]),CE=To("/")({component:V_(wE,"component")}),DE=CE.update({id:"/",path:"/",getParentRoute:()=>Hp}),UE={IndexRoute:DE},LE=Hp._addFileChildren(UE);function NE(){return P_({routeTree:LE,scrollRestoration:!1})}async function BE(){const a=await NE();let u;return u=[],window.__TSS_START_OPTIONS__={serializationAdapters:u},u.push(RE),a.options.serializationAdapters&&u.push(...a.options.serializationAdapters),a.update({basepath:"",serializationAdapters:u}),a.state.matches.length||await uE(a),a}async function jE(){const a=await BE();return window.$_TSR?.h(),a}let So;function HE(){return So||(So=jE()),k.jsx(p_,{promise:So,children:a=>k.jsx(I_,{router:a})})}nt.startTransition(()=>{h0.hydrateRoot(document,k.jsx(nt.StrictMode,{children:k.jsx(HE,{})}))});export{Ul as R,Mp as a,s0 as b,qE as c,XE as d,xy as g,k as j,nt as r};
|
|
@@ -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-CZSteFqT.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";
|
|
@@ -2179,6 +2179,7 @@ function ProviderCard({
|
|
|
2179
2179
|
provider,
|
|
2180
2180
|
testResults,
|
|
2181
2181
|
isTesting,
|
|
2182
|
+
testingTimeLeft,
|
|
2182
2183
|
onEdit,
|
|
2183
2184
|
onDelete,
|
|
2184
2185
|
onTest
|
|
@@ -2245,7 +2246,7 @@ function ProviderCard({
|
|
|
2245
2246
|
disabled: isTesting ?? false,
|
|
2246
2247
|
children: [
|
|
2247
2248
|
/* @__PURE__ */ jsxRuntimeExports.jsx(RotateCw, { className: `size-3 ${isTesting ?? false ? "animate-spin" : ""}` }),
|
|
2248
|
-
isTesting ?? false ? "Testing..." : "Test"
|
|
2249
|
+
isTesting ?? false ? testingTimeLeft !== void 0 ? `Testing (${testingTimeLeft}s)` : "Testing..." : "Test"
|
|
2249
2250
|
]
|
|
2250
2251
|
}
|
|
2251
2252
|
),
|
|
@@ -2496,16 +2497,44 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
|
|
|
2496
2497
|
] })
|
|
2497
2498
|
] });
|
|
2498
2499
|
}
|
|
2499
|
-
function ProvidersPanel(
|
|
2500
|
-
|
|
2500
|
+
function ProvidersPanel({
|
|
2501
|
+
externalProviders,
|
|
2502
|
+
externalTestResults,
|
|
2503
|
+
externalTestingProviders,
|
|
2504
|
+
externalTestingTimeLeft,
|
|
2505
|
+
onProvidersChange,
|
|
2506
|
+
onTestResultsChange,
|
|
2507
|
+
onTestingProvidersChange,
|
|
2508
|
+
onTestingTimeLeftChange
|
|
2509
|
+
}) {
|
|
2510
|
+
const [internalProviders, setInternalProviders] = reactExports.useState([]);
|
|
2501
2511
|
const [isLoading, setIsLoading] = reactExports.useState(true);
|
|
2502
2512
|
const [showForm, setShowForm] = reactExports.useState(false);
|
|
2503
2513
|
const [editingProvider, setEditingProvider] = reactExports.useState();
|
|
2504
2514
|
const [error, setError] = reactExports.useState(null);
|
|
2505
|
-
const [
|
|
2506
|
-
const [
|
|
2515
|
+
const [internalTestResults, setInternalTestResults] = reactExports.useState({});
|
|
2516
|
+
const [internalTestingProviders, setInternalTestingProviders] = reactExports.useState(/* @__PURE__ */ new Set());
|
|
2517
|
+
const [internalTestingTimeLeft, setInternalTestingTimeLeft] = reactExports.useState(
|
|
2518
|
+
{}
|
|
2519
|
+
);
|
|
2507
2520
|
const [configPath, setConfigPath] = reactExports.useState(null);
|
|
2508
2521
|
const [configPathCopied, setConfigPathCopied] = reactExports.useState(false);
|
|
2522
|
+
const providers = externalProviders ?? internalProviders;
|
|
2523
|
+
const setProviders = onProvidersChange ?? setInternalProviders;
|
|
2524
|
+
const testResults = externalTestResults ?? internalTestResults;
|
|
2525
|
+
const testingProviders = externalTestingProviders ?? internalTestingProviders;
|
|
2526
|
+
const testingTimeLeft = externalTestingTimeLeft ?? internalTestingTimeLeft;
|
|
2527
|
+
const setTestingTimeLeft = onTestingTimeLeftChange ? (id, seconds) => onTestingTimeLeftChange(id, seconds) : (id, seconds) => {
|
|
2528
|
+
if (seconds === void 0) {
|
|
2529
|
+
setInternalTestingTimeLeft((prev) => {
|
|
2530
|
+
const next = { ...prev };
|
|
2531
|
+
delete next[id];
|
|
2532
|
+
return next;
|
|
2533
|
+
});
|
|
2534
|
+
} else {
|
|
2535
|
+
setInternalTestingTimeLeft((prev) => ({ ...prev, [id]: seconds }));
|
|
2536
|
+
}
|
|
2537
|
+
};
|
|
2509
2538
|
const fetchProviders = reactExports.useCallback(async () => {
|
|
2510
2539
|
try {
|
|
2511
2540
|
const providersRes = await fetch("/api/providers");
|
|
@@ -2530,22 +2559,49 @@ function ProvidersPanel() {
|
|
|
2530
2559
|
}
|
|
2531
2560
|
})();
|
|
2532
2561
|
}, [fetchProviders]);
|
|
2533
|
-
const
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2562
|
+
const TEST_TIMEOUT_SECONDS = 30;
|
|
2563
|
+
const runTest = reactExports.useCallback(
|
|
2564
|
+
async (providerId) => {
|
|
2565
|
+
if (onTestingProvidersChange) {
|
|
2566
|
+
onTestingProvidersChange(providerId, true);
|
|
2567
|
+
} else {
|
|
2568
|
+
setInternalTestingProviders((prev) => new Set(prev).add(providerId));
|
|
2540
2569
|
}
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2570
|
+
let remaining = TEST_TIMEOUT_SECONDS;
|
|
2571
|
+
setTestingTimeLeft(providerId, remaining);
|
|
2572
|
+
const intervalId = setInterval(() => {
|
|
2573
|
+
remaining--;
|
|
2574
|
+
setTestingTimeLeft(providerId, remaining);
|
|
2575
|
+
if (remaining <= 0) {
|
|
2576
|
+
clearInterval(intervalId);
|
|
2577
|
+
}
|
|
2578
|
+
}, 1e3);
|
|
2579
|
+
try {
|
|
2580
|
+
const res = await fetch(`/api/providers/${providerId}/test`, { method: "POST" });
|
|
2581
|
+
if (res.ok) {
|
|
2582
|
+
const results = await res.json();
|
|
2583
|
+
if (onTestResultsChange) {
|
|
2584
|
+
onTestResultsChange(providerId, results);
|
|
2585
|
+
} else {
|
|
2586
|
+
setInternalTestResults((prev) => ({ ...prev, [providerId]: results }));
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
} finally {
|
|
2590
|
+
clearInterval(intervalId);
|
|
2591
|
+
setTestingTimeLeft(providerId, void 0);
|
|
2592
|
+
if (onTestingProvidersChange) {
|
|
2593
|
+
onTestingProvidersChange(providerId, false);
|
|
2594
|
+
} else {
|
|
2595
|
+
setInternalTestingProviders((prev) => {
|
|
2596
|
+
const next = new Set(prev);
|
|
2597
|
+
next.delete(providerId);
|
|
2598
|
+
return next;
|
|
2599
|
+
});
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
},
|
|
2603
|
+
[onTestingProvidersChange, onTestResultsChange, setTestingTimeLeft]
|
|
2604
|
+
);
|
|
2549
2605
|
function handleAddProvider(data) {
|
|
2550
2606
|
void (async () => {
|
|
2551
2607
|
const payload = {
|
|
@@ -2675,6 +2731,7 @@ function ProvidersPanel() {
|
|
|
2675
2731
|
provider,
|
|
2676
2732
|
testResults: testResults[provider.id],
|
|
2677
2733
|
isTesting: testingProviders.has(provider.id),
|
|
2734
|
+
testingTimeLeft: testingTimeLeft[provider.id],
|
|
2678
2735
|
onEdit: (p) => setEditingProvider(p),
|
|
2679
2736
|
onDelete: handleDeleteProvider,
|
|
2680
2737
|
onTest: (id) => {
|
|
@@ -2688,6 +2745,40 @@ function ProvidersPanel() {
|
|
|
2688
2745
|
function SettingsDialog() {
|
|
2689
2746
|
const [open, setOpen] = reactExports.useState(false);
|
|
2690
2747
|
const [activeTab, setActiveTab] = reactExports.useState("providers");
|
|
2748
|
+
const [providers, setProviders] = reactExports.useState([]);
|
|
2749
|
+
const [testResults, setTestResults] = reactExports.useState({});
|
|
2750
|
+
const [testingProviders, setTestingProviders] = reactExports.useState(/* @__PURE__ */ new Set());
|
|
2751
|
+
const [testingTimeLeft, setTestingTimeLeft] = reactExports.useState({});
|
|
2752
|
+
const handleTestResultsChange = reactExports.useCallback(
|
|
2753
|
+
(providerId, results) => {
|
|
2754
|
+
setTestResults((prev) => ({ ...prev, [providerId]: results }));
|
|
2755
|
+
},
|
|
2756
|
+
[]
|
|
2757
|
+
);
|
|
2758
|
+
const handleTestingProvidersChange = reactExports.useCallback((providerId, isTesting) => {
|
|
2759
|
+
setTestingProviders((prev) => {
|
|
2760
|
+
const next = new Set(prev);
|
|
2761
|
+
if (isTesting) {
|
|
2762
|
+
next.add(providerId);
|
|
2763
|
+
} else {
|
|
2764
|
+
next.delete(providerId);
|
|
2765
|
+
}
|
|
2766
|
+
return next;
|
|
2767
|
+
});
|
|
2768
|
+
}, []);
|
|
2769
|
+
const handleTestingTimeLeftChange = reactExports.useCallback(
|
|
2770
|
+
(providerId, seconds) => {
|
|
2771
|
+
setTestingTimeLeft((prev) => {
|
|
2772
|
+
if (seconds === void 0) {
|
|
2773
|
+
const next = { ...prev };
|
|
2774
|
+
delete next[providerId];
|
|
2775
|
+
return next;
|
|
2776
|
+
}
|
|
2777
|
+
return { ...prev, [providerId]: seconds };
|
|
2778
|
+
});
|
|
2779
|
+
},
|
|
2780
|
+
[]
|
|
2781
|
+
);
|
|
2691
2782
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(Dialog, { open, onOpenChange: setOpen, children: [
|
|
2692
2783
|
/* @__PURE__ */ jsxRuntimeExports.jsx(DialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Button, { variant: "ghost", size: "icon", className: "size-8", children: [
|
|
2693
2784
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Settings, { className: "size-4" }),
|
|
@@ -2697,7 +2788,19 @@ function SettingsDialog() {
|
|
|
2697
2788
|
/* @__PURE__ */ jsxRuntimeExports.jsx(DialogHeader, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(DialogTitle, { children: "Settings" }) }),
|
|
2698
2789
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(Tabs, { value: activeTab, onValueChange: setActiveTab, className: "flex-1 overflow-hidden", children: [
|
|
2699
2790
|
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsList, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "providers", children: "Providers" }) }),
|
|
2700
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-4 overflow-y-auto flex-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "providers", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2791
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-4 overflow-y-auto flex-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "providers", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
2792
|
+
ProvidersPanel,
|
|
2793
|
+
{
|
|
2794
|
+
externalProviders: providers,
|
|
2795
|
+
externalTestResults: testResults,
|
|
2796
|
+
externalTestingProviders: testingProviders,
|
|
2797
|
+
externalTestingTimeLeft: testingTimeLeft,
|
|
2798
|
+
onProvidersChange: setProviders,
|
|
2799
|
+
onTestResultsChange: handleTestResultsChange,
|
|
2800
|
+
onTestingProvidersChange: handleTestingProvidersChange,
|
|
2801
|
+
onTestingTimeLeftChange: handleTestingTimeLeftChange
|
|
2802
|
+
}
|
|
2803
|
+
) }) })
|
|
2701
2804
|
] })
|
|
2702
2805
|
] })
|
|
2703
2806
|
] });
|
|
@@ -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-DgsS3z4y.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-CZSteFqT.mjs").then((n) => n.r);
|
|
770
770
|
const startEntry = await import("./start-HYkvq4Ni.mjs");
|
|
771
771
|
return { startEntry, routerEntry };
|
|
772
772
|
}
|
|
@@ -65,7 +65,7 @@ function RootDocument({ children }) {
|
|
|
65
65
|
] })
|
|
66
66
|
] });
|
|
67
67
|
}
|
|
68
|
-
const $$splitComponentImporter = () => import("./index-
|
|
68
|
+
const $$splitComponentImporter = () => import("./index-DbpsE3Y4.mjs");
|
|
69
69
|
const Route$d = createFileRoute("/")({
|
|
70
70
|
component: lazyRouteComponent($$splitComponentImporter, "component")
|
|
71
71
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/__root.tsx", "children": ["/", "/api/health", "/api/logs", "/api/models", "/api/providers", "/api/sessions", "/proxy/$", "/api/config/paths"], "preloads": ["/assets/main-
|
|
1
|
+
const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/__root.tsx", "children": ["/", "/api/health", "/api/logs", "/api/models", "/api/providers", "/api/sessions", "/proxy/$", "/api/config/paths"], "preloads": ["/assets/main-DYXtPYU8.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-Drusqil7.js"] }, "/api/health": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/health.ts" }, "/api/logs": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.ts", "children": ["/api/logs/$id", "/api/logs/stream"] }, "/api/models": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/models.ts" }, "/api/providers": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.ts", "children": ["/api/providers/$providerId"] }, "/api/sessions": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/sessions.ts" }, "/proxy/$": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/proxy/$.ts" }, "/api/config/paths": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/config.paths.ts" }, "/api/logs/$id": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.ts", "children": ["/api/logs/$id/chunks", "/api/logs/$id/replay"] }, "/api/logs/stream": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.stream.ts" }, "/api/providers/$providerId": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.ts", "children": ["/api/providers/$providerId/test"] }, "/api/logs/$id/chunks": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.chunks.ts" }, "/api/logs/$id/replay": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.replay.ts" }, "/api/providers/$providerId/test": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.test.ts" } }, "clientEntry": "/assets/main-DYXtPYU8.js" });
|
|
2
2
|
export {
|
|
3
3
|
tsrStartManifest
|
|
4
4
|
};
|
package/.output/server/index.mjs
CHANGED
|
@@ -97,54 +97,54 @@ const headers = ((m) => function headersRouteRule(event) {
|
|
|
97
97
|
}
|
|
98
98
|
});
|
|
99
99
|
const assets = {
|
|
100
|
+
"/assets/index-B3RwBPLW.css": {
|
|
101
|
+
"type": "text/css; charset=utf-8",
|
|
102
|
+
"etag": '"10c74-aXacU4DRFVsUwcC5jHnjoPRSlTA"',
|
|
103
|
+
"mtime": "2026-06-03T12:05:46.053Z",
|
|
104
|
+
"size": 68724,
|
|
105
|
+
"path": "../public/assets/index-B3RwBPLW.css"
|
|
106
|
+
},
|
|
100
107
|
"/assets/alibaba-TTwafVwX.svg": {
|
|
101
108
|
"type": "image/svg+xml",
|
|
102
109
|
"etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
|
|
103
|
-
"mtime": "2026-06-
|
|
110
|
+
"mtime": "2026-06-03T12:05:46.051Z",
|
|
104
111
|
"size": 5915,
|
|
105
112
|
"path": "../public/assets/alibaba-TTwafVwX.svg"
|
|
106
113
|
},
|
|
107
|
-
"/assets/
|
|
108
|
-
"type": "text/
|
|
109
|
-
"etag": '"
|
|
110
|
-
"mtime": "2026-06-
|
|
111
|
-
"size":
|
|
112
|
-
"path": "../public/assets/
|
|
114
|
+
"/assets/main-DYXtPYU8.js": {
|
|
115
|
+
"type": "text/javascript; charset=utf-8",
|
|
116
|
+
"etag": '"4db57-3IoaJ0zzvDUU7WQZuVFYW7QEzGQ"',
|
|
117
|
+
"mtime": "2026-06-03T12:05:46.053Z",
|
|
118
|
+
"size": 318295,
|
|
119
|
+
"path": "../public/assets/main-DYXtPYU8.js"
|
|
120
|
+
},
|
|
121
|
+
"/assets/qwen-CONDcHqt.png": {
|
|
122
|
+
"type": "image/png",
|
|
123
|
+
"etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
|
|
124
|
+
"mtime": "2026-06-03T12:05:46.053Z",
|
|
125
|
+
"size": 357059,
|
|
126
|
+
"path": "../public/assets/qwen-CONDcHqt.png"
|
|
113
127
|
},
|
|
114
128
|
"/assets/minimax-BPMzvuL-.jpeg": {
|
|
115
129
|
"type": "image/jpeg",
|
|
116
130
|
"etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
|
|
117
|
-
"mtime": "2026-06-
|
|
131
|
+
"mtime": "2026-06-03T12:05:46.053Z",
|
|
118
132
|
"size": 6918,
|
|
119
133
|
"path": "../public/assets/minimax-BPMzvuL-.jpeg"
|
|
120
134
|
},
|
|
121
|
-
"/assets/main-B3Cmykkm.js": {
|
|
122
|
-
"type": "text/javascript; charset=utf-8",
|
|
123
|
-
"etag": '"4db57-BoW6SyNc1bhvI2SIfQuoPlQ7pjU"',
|
|
124
|
-
"mtime": "2026-06-03T11:15:10.950Z",
|
|
125
|
-
"size": 318295,
|
|
126
|
-
"path": "../public/assets/main-B3Cmykkm.js"
|
|
127
|
-
},
|
|
128
135
|
"/assets/zhipuai-BPNAnxo-.svg": {
|
|
129
136
|
"type": "image/svg+xml",
|
|
130
137
|
"etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
|
|
131
|
-
"mtime": "2026-06-
|
|
138
|
+
"mtime": "2026-06-03T12:05:46.053Z",
|
|
132
139
|
"size": 11256,
|
|
133
140
|
"path": "../public/assets/zhipuai-BPNAnxo-.svg"
|
|
134
141
|
},
|
|
135
|
-
"/assets/
|
|
136
|
-
"type": "image/png",
|
|
137
|
-
"etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
|
|
138
|
-
"mtime": "2026-06-03T11:15:10.950Z",
|
|
139
|
-
"size": 357059,
|
|
140
|
-
"path": "../public/assets/qwen-CONDcHqt.png"
|
|
141
|
-
},
|
|
142
|
-
"/assets/index-BKkFFKAM.js": {
|
|
142
|
+
"/assets/index-Drusqil7.js": {
|
|
143
143
|
"type": "text/javascript; charset=utf-8",
|
|
144
|
-
"etag": '"
|
|
145
|
-
"mtime": "2026-06-
|
|
146
|
-
"size":
|
|
147
|
-
"path": "../public/assets/index-
|
|
144
|
+
"etag": '"8368b-K/ZW3jyne5SeFVJGXXNOEllhQyM"',
|
|
145
|
+
"mtime": "2026-06-03T12:05:46.054Z",
|
|
146
|
+
"size": 538251,
|
|
147
|
+
"path": "../public/assets/index-Drusqil7.js"
|
|
148
148
|
}
|
|
149
149
|
};
|
|
150
150
|
function readAsset(id) {
|
package/package.json
CHANGED
|
@@ -63,6 +63,7 @@ type ProviderCardProps = {
|
|
|
63
63
|
provider: ProviderConfig;
|
|
64
64
|
testResults?: TestResults;
|
|
65
65
|
isTesting?: boolean;
|
|
66
|
+
testingTimeLeft?: number;
|
|
66
67
|
onEdit: (provider: ProviderConfig) => void;
|
|
67
68
|
onDelete: (providerId: string) => void;
|
|
68
69
|
onTest?: (providerId: string) => void;
|
|
@@ -152,6 +153,7 @@ export function ProviderCard({
|
|
|
152
153
|
provider,
|
|
153
154
|
testResults,
|
|
154
155
|
isTesting,
|
|
156
|
+
testingTimeLeft,
|
|
155
157
|
onEdit,
|
|
156
158
|
onDelete,
|
|
157
159
|
onTest,
|
|
@@ -233,7 +235,11 @@ export function ProviderCard({
|
|
|
233
235
|
disabled={isTesting ?? false}
|
|
234
236
|
>
|
|
235
237
|
<RotateCw className={`size-3 ${(isTesting ?? false) ? "animate-spin" : ""}`} />
|
|
236
|
-
{(isTesting ?? false)
|
|
238
|
+
{(isTesting ?? false)
|
|
239
|
+
? testingTimeLeft !== undefined
|
|
240
|
+
? `Testing (${testingTimeLeft}s)`
|
|
241
|
+
: "Testing..."
|
|
242
|
+
: "Test"}
|
|
237
243
|
</Button>
|
|
238
244
|
)}
|
|
239
245
|
<Button
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type JSX, useState, useEffect, useCallback } from "react";
|
|
1
|
+
import { type JSX, useState, useEffect, useCallback, useRef } from "react";
|
|
2
2
|
import { Button } from "../ui/button";
|
|
3
3
|
import { Plus, AlertCircle, Copy, Check } from "lucide-react";
|
|
4
4
|
import { ProviderCard } from "./ProviderCard";
|
|
@@ -36,22 +36,71 @@ type StreamingTestResults = {
|
|
|
36
36
|
streaming: TestResult | NotConfigured;
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
type TestResults = {
|
|
39
|
+
export type TestResults = {
|
|
40
40
|
anthropic: StreamingTestResults;
|
|
41
41
|
openai: StreamingTestResults;
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
type ProvidersPanelProps = {
|
|
45
|
+
externalProviders?: ProviderConfig[];
|
|
46
|
+
externalTestResults?: Record<string, TestResults>;
|
|
47
|
+
externalTestingProviders?: Set<string>;
|
|
48
|
+
externalTestingTimeLeft?: Record<string, number>;
|
|
49
|
+
onProvidersChange?: (providers: ProviderConfig[]) => void;
|
|
50
|
+
onTestResultsChange?: (providerId: string, results: TestResults) => void;
|
|
51
|
+
onTestingProvidersChange?: (providerId: string, isTesting: boolean) => void;
|
|
52
|
+
onTestingTimeLeftChange?: (providerId: string, seconds: number | undefined) => void;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export function ProvidersPanel({
|
|
56
|
+
externalProviders,
|
|
57
|
+
externalTestResults,
|
|
58
|
+
externalTestingProviders,
|
|
59
|
+
externalTestingTimeLeft,
|
|
60
|
+
onProvidersChange,
|
|
61
|
+
onTestResultsChange,
|
|
62
|
+
onTestingProvidersChange,
|
|
63
|
+
onTestingTimeLeftChange,
|
|
64
|
+
}: ProvidersPanelProps): JSX.Element {
|
|
65
|
+
const [internalProviders, setInternalProviders] = useState<ProviderConfig[]>([]);
|
|
46
66
|
const [isLoading, setIsLoading] = useState(true);
|
|
47
67
|
const [showForm, setShowForm] = useState(false);
|
|
48
68
|
const [editingProvider, setEditingProvider] = useState<ProviderConfig | undefined>();
|
|
49
69
|
const [error, setError] = useState<string | null>(null);
|
|
50
|
-
const [
|
|
51
|
-
const [
|
|
70
|
+
const [internalTestResults, setInternalTestResults] = useState<Record<string, TestResults>>({});
|
|
71
|
+
const [internalTestingProviders, setInternalTestingProviders] = useState<Set<string>>(new Set());
|
|
72
|
+
const [internalTestingTimeLeft, setInternalTestingTimeLeft] = useState<Record<string, number>>(
|
|
73
|
+
{},
|
|
74
|
+
);
|
|
52
75
|
const [configPath, setConfigPath] = useState<string | null>(null);
|
|
53
76
|
const [configPathCopied, setConfigPathCopied] = useState(false);
|
|
54
77
|
|
|
78
|
+
// Use external state if provided, otherwise use internal state
|
|
79
|
+
const providers = externalProviders ?? internalProviders;
|
|
80
|
+
const setProviders = onProvidersChange ?? setInternalProviders;
|
|
81
|
+
const testResults = externalTestResults ?? internalTestResults;
|
|
82
|
+
const setTestResults = onTestResultsChange
|
|
83
|
+
? (id: string, results: TestResults) => onTestResultsChange(id, results)
|
|
84
|
+
: setInternalTestResults;
|
|
85
|
+
const testingProviders = externalTestingProviders ?? internalTestingProviders;
|
|
86
|
+
const setTestingProviders = onTestingProvidersChange
|
|
87
|
+
? (id: string, isTesting: boolean) => onTestingProvidersChange(id, isTesting)
|
|
88
|
+
: setInternalTestingProviders;
|
|
89
|
+
const testingTimeLeft = externalTestingTimeLeft ?? internalTestingTimeLeft;
|
|
90
|
+
const setTestingTimeLeft = onTestingTimeLeftChange
|
|
91
|
+
? (id: string, seconds: number | undefined) => onTestingTimeLeftChange(id, seconds)
|
|
92
|
+
: (id: string, seconds: number | undefined) => {
|
|
93
|
+
if (seconds === undefined) {
|
|
94
|
+
setInternalTestingTimeLeft((prev) => {
|
|
95
|
+
const next = { ...prev };
|
|
96
|
+
delete next[id];
|
|
97
|
+
return next;
|
|
98
|
+
});
|
|
99
|
+
} else {
|
|
100
|
+
setInternalTestingTimeLeft((prev) => ({ ...prev, [id]: seconds }));
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
55
104
|
const fetchProviders = useCallback(async (): Promise<void> => {
|
|
56
105
|
try {
|
|
57
106
|
const providersRes = await fetch("/api/providers");
|
|
@@ -81,23 +130,55 @@ export function ProvidersPanel(): JSX.Element {
|
|
|
81
130
|
})();
|
|
82
131
|
}, [fetchProviders]);
|
|
83
132
|
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
133
|
+
const TEST_TIMEOUT_SECONDS = 30;
|
|
134
|
+
|
|
135
|
+
const runTest = useCallback(
|
|
136
|
+
async (providerId: string): Promise<void> => {
|
|
137
|
+
// Use callback form if available, otherwise direct set
|
|
138
|
+
if (onTestingProvidersChange) {
|
|
139
|
+
onTestingProvidersChange(providerId, true);
|
|
140
|
+
} else {
|
|
141
|
+
setInternalTestingProviders((prev) => new Set(prev).add(providerId));
|
|
92
142
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
143
|
+
|
|
144
|
+
// Start countdown
|
|
145
|
+
let remaining = TEST_TIMEOUT_SECONDS;
|
|
146
|
+
setTestingTimeLeft(providerId, remaining);
|
|
147
|
+
const intervalId = setInterval(() => {
|
|
148
|
+
remaining--;
|
|
149
|
+
setTestingTimeLeft(providerId, remaining);
|
|
150
|
+
if (remaining <= 0) {
|
|
151
|
+
clearInterval(intervalId);
|
|
152
|
+
}
|
|
153
|
+
}, 1000);
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
const res = await fetch(`/api/providers/${providerId}/test`, { method: "POST" });
|
|
157
|
+
if (res.ok) {
|
|
158
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
159
|
+
const results = (await res.json()) as TestResults;
|
|
160
|
+
if (onTestResultsChange) {
|
|
161
|
+
onTestResultsChange(providerId, results);
|
|
162
|
+
} else {
|
|
163
|
+
setInternalTestResults((prev) => ({ ...prev, [providerId]: results }));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
} finally {
|
|
167
|
+
clearInterval(intervalId);
|
|
168
|
+
setTestingTimeLeft(providerId, undefined);
|
|
169
|
+
if (onTestingProvidersChange) {
|
|
170
|
+
onTestingProvidersChange(providerId, false);
|
|
171
|
+
} else {
|
|
172
|
+
setInternalTestingProviders((prev) => {
|
|
173
|
+
const next = new Set(prev);
|
|
174
|
+
next.delete(providerId);
|
|
175
|
+
return next;
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
[onTestingProvidersChange, onTestResultsChange, setTestingTimeLeft],
|
|
181
|
+
);
|
|
101
182
|
|
|
102
183
|
function handleAddProvider(data: {
|
|
103
184
|
name: string;
|
|
@@ -279,6 +360,7 @@ export function ProvidersPanel(): JSX.Element {
|
|
|
279
360
|
provider={provider}
|
|
280
361
|
testResults={testResults[provider.id]}
|
|
281
362
|
isTesting={testingProviders.has(provider.id)}
|
|
363
|
+
testingTimeLeft={testingTimeLeft[provider.id]}
|
|
282
364
|
onEdit={(p) => setEditingProvider(p)}
|
|
283
365
|
onDelete={handleDeleteProvider}
|
|
284
366
|
onTest={(id: string) => {
|
|
@@ -1,13 +1,53 @@
|
|
|
1
|
-
import { type JSX, useState } from "react";
|
|
1
|
+
import { type JSX, useState, useCallback } from "react";
|
|
2
2
|
import { Settings } from "lucide-react";
|
|
3
3
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "../ui/dialog";
|
|
4
4
|
import { Tabs, TabsList, TabsTrigger, TabsContent } from "../ui/tabs";
|
|
5
5
|
import { Button } from "../ui/button";
|
|
6
6
|
import { ProvidersPanel } from "./ProvidersPanel";
|
|
7
|
+
import type { ProviderConfig } from "../../proxy/providers";
|
|
7
8
|
|
|
8
9
|
export function SettingsDialog(): JSX.Element {
|
|
9
10
|
const [open, setOpen] = useState(false);
|
|
10
11
|
const [activeTab, setActiveTab] = useState("providers");
|
|
12
|
+
const [providers, setProviders] = useState<ProviderConfig[]>([]);
|
|
13
|
+
const [testResults, setTestResults] = useState<
|
|
14
|
+
Record<string, import("./ProvidersPanel").TestResults>
|
|
15
|
+
>({});
|
|
16
|
+
const [testingProviders, setTestingProviders] = useState<Set<string>>(new Set());
|
|
17
|
+
const [testingTimeLeft, setTestingTimeLeft] = useState<Record<string, number>>({});
|
|
18
|
+
|
|
19
|
+
const handleTestResultsChange = useCallback(
|
|
20
|
+
(providerId: string, results: import("./ProvidersPanel").TestResults) => {
|
|
21
|
+
setTestResults((prev) => ({ ...prev, [providerId]: results }));
|
|
22
|
+
},
|
|
23
|
+
[],
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const handleTestingProvidersChange = useCallback((providerId: string, isTesting: boolean) => {
|
|
27
|
+
setTestingProviders((prev) => {
|
|
28
|
+
const next = new Set(prev);
|
|
29
|
+
if (isTesting) {
|
|
30
|
+
next.add(providerId);
|
|
31
|
+
} else {
|
|
32
|
+
next.delete(providerId);
|
|
33
|
+
}
|
|
34
|
+
return next;
|
|
35
|
+
});
|
|
36
|
+
}, []);
|
|
37
|
+
|
|
38
|
+
const handleTestingTimeLeftChange = useCallback(
|
|
39
|
+
(providerId: string, seconds: number | undefined) => {
|
|
40
|
+
setTestingTimeLeft((prev) => {
|
|
41
|
+
if (seconds === undefined) {
|
|
42
|
+
const next = { ...prev };
|
|
43
|
+
delete next[providerId];
|
|
44
|
+
return next;
|
|
45
|
+
}
|
|
46
|
+
return { ...prev, [providerId]: seconds };
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
[],
|
|
50
|
+
);
|
|
11
51
|
|
|
12
52
|
return (
|
|
13
53
|
<Dialog open={open} onOpenChange={setOpen}>
|
|
@@ -29,7 +69,16 @@ export function SettingsDialog(): JSX.Element {
|
|
|
29
69
|
|
|
30
70
|
<div className="mt-4 overflow-y-auto flex-1">
|
|
31
71
|
<TabsContent value="providers">
|
|
32
|
-
<ProvidersPanel
|
|
72
|
+
<ProvidersPanel
|
|
73
|
+
externalProviders={providers}
|
|
74
|
+
externalTestResults={testResults}
|
|
75
|
+
externalTestingProviders={testingProviders}
|
|
76
|
+
externalTestingTimeLeft={testingTimeLeft}
|
|
77
|
+
onProvidersChange={setProviders}
|
|
78
|
+
onTestResultsChange={handleTestResultsChange}
|
|
79
|
+
onTestingProvidersChange={handleTestingProvidersChange}
|
|
80
|
+
onTestingTimeLeftChange={handleTestingTimeLeftChange}
|
|
81
|
+
/>
|
|
33
82
|
</TabsContent>
|
|
34
83
|
</div>
|
|
35
84
|
</Tabs>
|