@tonyclaw/llm-inspector 1.7.3 → 1.7.5
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/cli.js +22 -1
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{index-Bf_WGooQ.js → index-BkNsdDqV.js} +2 -2
- package/.output/public/assets/{main-CpIX1ZHy.js → main-CC-HN8LQ.js} +1 -1
- package/.output/server/_ssr/{index-D0iGQ1Zd.mjs → index-DosJndBx.mjs} +3 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-BWDeDWmr.mjs → router-4NfH7bm_.mjs} +91 -72
- package/.output/server/{_tanstack-start-manifest_v-b6u6g-Cr.mjs → _tanstack-start-manifest_v-CdS0WV2N.mjs} +1 -1
- package/.output/server/index.mjs +23 -23
- package/package.json +1 -1
- package/src/cli.ts +24 -1
- package/src/components/providers/ProviderLogo.tsx +2 -1
- package/src/proxy/providers.ts +74 -64
- package/src/routes/api/providers.$providerId.ts +2 -0
|
@@ -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-BkNsdDqV.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-4NfH7bm_.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";
|
|
@@ -878,8 +878,9 @@ const PROVIDER_MAP = {
|
|
|
878
878
|
};
|
|
879
879
|
function detectProvider(model) {
|
|
880
880
|
if (model === null) return "unknown";
|
|
881
|
+
const modelLower = model.toLowerCase();
|
|
881
882
|
for (const [prefix, provider] of Object.entries(PROVIDER_MAP)) {
|
|
882
|
-
if (
|
|
883
|
+
if (modelLower.startsWith(prefix.toLowerCase())) {
|
|
883
884
|
return provider;
|
|
884
885
|
}
|
|
885
886
|
}
|
|
@@ -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-CdS0WV2N.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-4NfH7bm_.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-DosJndBx.mjs");
|
|
69
69
|
const Route$d = createFileRoute("/")({
|
|
70
70
|
component: lazyRouteComponent($$splitComponentImporter, "component")
|
|
71
71
|
});
|
|
@@ -1396,68 +1396,68 @@ const ProviderConfigSchema = object({
|
|
|
1396
1396
|
object({
|
|
1397
1397
|
providers: array(ProviderConfigSchema)
|
|
1398
1398
|
});
|
|
1399
|
+
const configPath = process.env["LLM_INSPECTOR_CONFIG_PATH"];
|
|
1399
1400
|
const store = new Conf({
|
|
1400
1401
|
projectName: "llm-inspector",
|
|
1401
1402
|
defaults: {
|
|
1402
1403
|
providers: []
|
|
1404
|
+
},
|
|
1405
|
+
...configPath !== void 0 ? { path: configPath } : {}
|
|
1406
|
+
});
|
|
1407
|
+
function migrateProvider(p) {
|
|
1408
|
+
const currentAnthropicUrl = p.anthropicBaseUrl ?? "";
|
|
1409
|
+
const currentOpenaiUrl = p.openaiBaseUrl ?? "";
|
|
1410
|
+
if (currentAnthropicUrl !== "" || currentOpenaiUrl !== "") {
|
|
1411
|
+
return p;
|
|
1412
|
+
}
|
|
1413
|
+
let format;
|
|
1414
|
+
let baseUrl;
|
|
1415
|
+
if (currentAnthropicUrl !== "" && currentOpenaiUrl !== "") {
|
|
1416
|
+
format = p.format ?? "anthropic";
|
|
1417
|
+
baseUrl = p.baseUrl !== void 0 && p.baseUrl !== "" ? p.baseUrl : currentAnthropicUrl;
|
|
1418
|
+
} else if (currentOpenaiUrl !== "") {
|
|
1419
|
+
format = "openai";
|
|
1420
|
+
baseUrl = currentOpenaiUrl;
|
|
1421
|
+
} else if (currentAnthropicUrl !== "") {
|
|
1422
|
+
format = "anthropic";
|
|
1423
|
+
baseUrl = currentAnthropicUrl;
|
|
1424
|
+
} else if (p.format !== void 0 && p.baseUrl !== void 0 && p.baseUrl !== "") {
|
|
1425
|
+
format = p.format;
|
|
1426
|
+
baseUrl = p.baseUrl;
|
|
1427
|
+
if (format === "openai") {
|
|
1428
|
+
return { ...p, format, baseUrl, anthropicBaseUrl: "", openaiBaseUrl: p.baseUrl };
|
|
1429
|
+
} else {
|
|
1430
|
+
return { ...p, format, baseUrl, anthropicBaseUrl: p.baseUrl, openaiBaseUrl: "" };
|
|
1431
|
+
}
|
|
1403
1432
|
}
|
|
1404
|
-
|
|
1433
|
+
return {
|
|
1434
|
+
...p,
|
|
1435
|
+
format,
|
|
1436
|
+
baseUrl,
|
|
1437
|
+
anthropicBaseUrl: currentAnthropicUrl,
|
|
1438
|
+
openaiBaseUrl: currentOpenaiUrl
|
|
1439
|
+
};
|
|
1440
|
+
}
|
|
1405
1441
|
function migrateProviders() {
|
|
1406
1442
|
const providers = store.get("providers", []);
|
|
1407
|
-
|
|
1408
|
-
const
|
|
1409
|
-
function getOldUrl(obj, key) {
|
|
1410
|
-
if (obj !== null && typeof obj === "object") {
|
|
1411
|
-
const desc = Object.getOwnPropertyDescriptor(obj, key);
|
|
1412
|
-
if (desc !== void 0 && typeof desc.value === "string") {
|
|
1413
|
-
return desc.value;
|
|
1414
|
-
}
|
|
1415
|
-
}
|
|
1416
|
-
return "";
|
|
1417
|
-
}
|
|
1418
|
-
const oldAnthropicBaseUrl = getOldUrl(p, "anthropicBaseUrl");
|
|
1419
|
-
const oldOpenaiBaseUrl = getOldUrl(p, "openaiBaseUrl");
|
|
1420
|
-
const currentAnthropicUrl = p.anthropicBaseUrl ?? "";
|
|
1421
|
-
const currentOpenaiUrl = p.openaiBaseUrl ?? "";
|
|
1422
|
-
if (p.format !== void 0 && (currentAnthropicUrl !== "" || currentOpenaiUrl !== "")) {
|
|
1423
|
-
return p;
|
|
1424
|
-
}
|
|
1425
|
-
const newAnthropicUrl = oldAnthropicBaseUrl !== "" ? oldAnthropicBaseUrl : currentAnthropicUrl;
|
|
1426
|
-
const newOpenaiUrl = oldOpenaiBaseUrl !== "" ? oldOpenaiBaseUrl : currentOpenaiUrl;
|
|
1427
|
-
let format;
|
|
1428
|
-
let baseUrl;
|
|
1429
|
-
if (newAnthropicUrl !== "" && newOpenaiUrl !== "") {
|
|
1430
|
-
format = p.format ?? "anthropic";
|
|
1431
|
-
baseUrl = p.baseUrl !== void 0 && p.baseUrl !== "" ? p.baseUrl : newAnthropicUrl;
|
|
1432
|
-
} else if (newOpenaiUrl !== "") {
|
|
1433
|
-
format = "openai";
|
|
1434
|
-
baseUrl = newOpenaiUrl;
|
|
1435
|
-
} else if (newAnthropicUrl !== "") {
|
|
1436
|
-
format = "anthropic";
|
|
1437
|
-
baseUrl = newAnthropicUrl;
|
|
1438
|
-
} else if (p.format !== void 0 && p.baseUrl !== void 0 && p.baseUrl !== "") {
|
|
1439
|
-
format = p.format;
|
|
1440
|
-
baseUrl = p.baseUrl;
|
|
1441
|
-
if (format === "openai") {
|
|
1442
|
-
return { ...p, format, baseUrl, anthropicBaseUrl: "", openaiBaseUrl: p.baseUrl };
|
|
1443
|
-
} else {
|
|
1444
|
-
return { ...p, format, baseUrl, anthropicBaseUrl: p.baseUrl, openaiBaseUrl: "" };
|
|
1445
|
-
}
|
|
1446
|
-
}
|
|
1447
|
-
migrated = true;
|
|
1448
|
-
return {
|
|
1449
|
-
...p,
|
|
1450
|
-
format,
|
|
1451
|
-
baseUrl,
|
|
1452
|
-
anthropicBaseUrl: newAnthropicUrl,
|
|
1453
|
-
openaiBaseUrl: newOpenaiUrl
|
|
1454
|
-
};
|
|
1455
|
-
});
|
|
1443
|
+
const updated = providers.map(migrateProvider);
|
|
1444
|
+
const migrated = updated.some((p, i) => JSON.stringify(p) !== JSON.stringify(providers[i]));
|
|
1456
1445
|
if (migrated) {
|
|
1457
1446
|
store.set("providers", updated);
|
|
1458
1447
|
}
|
|
1459
1448
|
}
|
|
1460
1449
|
migrateProviders();
|
|
1450
|
+
const providersJson = process.env["LLM_INSPECTOR_PROVIDERS_JSON"];
|
|
1451
|
+
if (providersJson !== void 0) {
|
|
1452
|
+
try {
|
|
1453
|
+
const parsed = ProviderConfigSchema.array().safeParse(JSON.parse(providersJson));
|
|
1454
|
+
if (parsed.success) {
|
|
1455
|
+
const migrated = parsed.data.map(migrateProvider);
|
|
1456
|
+
store.set("providers", migrated);
|
|
1457
|
+
}
|
|
1458
|
+
} catch {
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
1461
|
function getProviders() {
|
|
1462
1462
|
return store.get("providers", []);
|
|
1463
1463
|
}
|
|
@@ -1480,7 +1480,9 @@ function addProvider(name, apiKey, format, baseUrl, model, authHeader) {
|
|
|
1480
1480
|
model,
|
|
1481
1481
|
authHeader: authHeader ?? "bearer",
|
|
1482
1482
|
createdAt: now,
|
|
1483
|
-
updatedAt: now
|
|
1483
|
+
updatedAt: now,
|
|
1484
|
+
anthropicBaseUrl: format === "anthropic" && baseUrl !== void 0 ? baseUrl : "",
|
|
1485
|
+
openaiBaseUrl: format === "openai" && baseUrl !== void 0 ? baseUrl : ""
|
|
1484
1486
|
};
|
|
1485
1487
|
providers.push(newProvider);
|
|
1486
1488
|
store.set("providers", providers);
|
|
@@ -1499,7 +1501,10 @@ function updateProvider(id, updates) {
|
|
|
1499
1501
|
baseUrl: updates.baseUrl !== void 0 ? updates.baseUrl : existing.baseUrl,
|
|
1500
1502
|
authHeader: updates.authHeader ?? existing.authHeader,
|
|
1501
1503
|
createdAt: existing.createdAt,
|
|
1502
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1504
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1505
|
+
// Handle format-specific URLs
|
|
1506
|
+
anthropicBaseUrl: updates.anthropicBaseUrl !== void 0 ? updates.anthropicBaseUrl : existing.anthropicBaseUrl,
|
|
1507
|
+
openaiBaseUrl: updates.openaiBaseUrl !== void 0 ? updates.openaiBaseUrl : existing.openaiBaseUrl
|
|
1503
1508
|
};
|
|
1504
1509
|
const index = providers.findIndex((p) => p.id === id);
|
|
1505
1510
|
providers[index] = updated;
|
|
@@ -1968,7 +1973,9 @@ const ProviderUpdateSchema = object({
|
|
|
1968
1973
|
format: _enum(["anthropic", "openai"]).optional(),
|
|
1969
1974
|
baseUrl: string().min(1, "Base URL is required").optional(),
|
|
1970
1975
|
model: string().min(1, "Model is required").optional(),
|
|
1971
|
-
authHeader: _enum(["bearer", "x-api-key"]).optional()
|
|
1976
|
+
authHeader: _enum(["bearer", "x-api-key"]).optional(),
|
|
1977
|
+
anthropicBaseUrl: string().optional(),
|
|
1978
|
+
openaiBaseUrl: string().optional()
|
|
1972
1979
|
});
|
|
1973
1980
|
const Route$6 = createFileRoute("/api/providers/$providerId")({
|
|
1974
1981
|
server: {
|
|
@@ -2195,16 +2202,17 @@ async function testEndpoint(baseUrl, apiKey, path2, model, isOpenAI) {
|
|
|
2195
2202
|
messages: [{ role: "user", content: "say hello and briefly introduce yourself" }],
|
|
2196
2203
|
max_tokens: 1024
|
|
2197
2204
|
});
|
|
2205
|
+
const requestHeaders = {
|
|
2206
|
+
"Content-Type": "application/json",
|
|
2207
|
+
Authorization: `Bearer ${apiKey}`
|
|
2208
|
+
};
|
|
2198
2209
|
const controller = new AbortController();
|
|
2199
2210
|
const timeoutId = setTimeout(() => controller.abort(), TEST_TIMEOUT_MS);
|
|
2200
2211
|
try {
|
|
2201
2212
|
const url = `${baseUrl}${path2}`;
|
|
2202
2213
|
const response = await fetch(url, {
|
|
2203
2214
|
method: "POST",
|
|
2204
|
-
headers:
|
|
2205
|
-
"Content-Type": "application/json",
|
|
2206
|
-
Authorization: `Bearer ${apiKey}`
|
|
2207
|
-
},
|
|
2215
|
+
headers: requestHeaders,
|
|
2208
2216
|
body,
|
|
2209
2217
|
signal: controller.signal
|
|
2210
2218
|
});
|
|
@@ -2233,7 +2241,8 @@ async function testEndpoint(baseUrl, apiKey, path2, model, isOpenAI) {
|
|
|
2233
2241
|
outputTokens,
|
|
2234
2242
|
latencyMs,
|
|
2235
2243
|
content: content !== null && content !== "" ? [{ type: "text", text: content }] : void 0,
|
|
2236
|
-
rawResponse: responseText
|
|
2244
|
+
rawResponse: responseText,
|
|
2245
|
+
requestHeaders
|
|
2237
2246
|
};
|
|
2238
2247
|
} else {
|
|
2239
2248
|
const json = AnthropicResponseSchema.parse(JSON.parse(responseText));
|
|
@@ -2255,7 +2264,8 @@ async function testEndpoint(baseUrl, apiKey, path2, model, isOpenAI) {
|
|
|
2255
2264
|
outputTokens,
|
|
2256
2265
|
latencyMs,
|
|
2257
2266
|
content: content.length > 0 ? content : void 0,
|
|
2258
|
-
rawResponse: responseText
|
|
2267
|
+
rawResponse: responseText,
|
|
2268
|
+
requestHeaders
|
|
2259
2269
|
};
|
|
2260
2270
|
}
|
|
2261
2271
|
} catch (parseErr) {
|
|
@@ -2264,7 +2274,8 @@ async function testEndpoint(baseUrl, apiKey, path2, model, isOpenAI) {
|
|
|
2264
2274
|
model,
|
|
2265
2275
|
latencyMs,
|
|
2266
2276
|
content: [{ type: "text", text: responseText.slice(0, 2e3) }],
|
|
2267
|
-
rawResponse: responseText
|
|
2277
|
+
rawResponse: responseText,
|
|
2278
|
+
requestHeaders
|
|
2268
2279
|
};
|
|
2269
2280
|
}
|
|
2270
2281
|
} catch (err) {
|
|
@@ -2280,16 +2291,17 @@ async function testStreamingEndpoint(baseUrl, apiKey, path2, model, isOpenAI) {
|
|
|
2280
2291
|
max_tokens: 256,
|
|
2281
2292
|
stream: true
|
|
2282
2293
|
});
|
|
2294
|
+
const requestHeaders = {
|
|
2295
|
+
"Content-Type": "application/json",
|
|
2296
|
+
Authorization: `Bearer ${apiKey}`
|
|
2297
|
+
};
|
|
2283
2298
|
const controller = new AbortController();
|
|
2284
2299
|
const timeoutId = setTimeout(() => controller.abort(), TEST_TIMEOUT_MS);
|
|
2285
2300
|
try {
|
|
2286
2301
|
const url = `${baseUrl}${path2}`;
|
|
2287
2302
|
const response = await fetch(url, {
|
|
2288
2303
|
method: "POST",
|
|
2289
|
-
headers:
|
|
2290
|
-
"Content-Type": "application/json",
|
|
2291
|
-
Authorization: `Bearer ${apiKey}`
|
|
2292
|
-
},
|
|
2304
|
+
headers: requestHeaders,
|
|
2293
2305
|
body,
|
|
2294
2306
|
signal: controller.signal
|
|
2295
2307
|
});
|
|
@@ -2392,7 +2404,8 @@ async function testStreamingEndpoint(baseUrl, apiKey, path2, model, isOpenAI) {
|
|
|
2392
2404
|
content: content.length > 0 ? content : void 0,
|
|
2393
2405
|
rawResponse: reconstructedJson,
|
|
2394
2406
|
streaming: true,
|
|
2395
|
-
streamingChunks
|
|
2407
|
+
streamingChunks,
|
|
2408
|
+
requestHeaders
|
|
2396
2409
|
};
|
|
2397
2410
|
} catch {
|
|
2398
2411
|
return {
|
|
@@ -2402,7 +2415,8 @@ async function testStreamingEndpoint(baseUrl, apiKey, path2, model, isOpenAI) {
|
|
|
2402
2415
|
content: [{ type: "text", text: reconstructedJson.slice(0, 2e3) }],
|
|
2403
2416
|
rawResponse: reconstructedJson,
|
|
2404
2417
|
streaming: true,
|
|
2405
|
-
streamingChunks
|
|
2418
|
+
streamingChunks,
|
|
2419
|
+
requestHeaders
|
|
2406
2420
|
};
|
|
2407
2421
|
}
|
|
2408
2422
|
} catch (err) {
|
|
@@ -2430,7 +2444,8 @@ function createTestLogEntry(providerName, path2, body, upstreamUrl, result, isTe
|
|
|
2430
2444
|
upstreamUrl,
|
|
2431
2445
|
error: result.success ? null : result.error?.message ?? String(result.error),
|
|
2432
2446
|
isTest: true,
|
|
2433
|
-
providerName
|
|
2447
|
+
providerName,
|
|
2448
|
+
headers: result.requestHeaders ?? {}
|
|
2434
2449
|
};
|
|
2435
2450
|
}
|
|
2436
2451
|
const Route$2 = createFileRoute("/api/providers/$providerId/test")({
|
|
@@ -2487,7 +2502,8 @@ const Route$2 = createFileRoute("/api/providers/$providerId/test")({
|
|
|
2487
2502
|
origin: null,
|
|
2488
2503
|
apiFormat: "anthropic",
|
|
2489
2504
|
isTest: true,
|
|
2490
|
-
providerName: provider.name
|
|
2505
|
+
providerName: provider.name,
|
|
2506
|
+
headers: nonStreamingResult.requestHeaders ?? {}
|
|
2491
2507
|
});
|
|
2492
2508
|
appendLogEntry(
|
|
2493
2509
|
createTestLogEntry(
|
|
@@ -2533,7 +2549,8 @@ const Route$2 = createFileRoute("/api/providers/$providerId/test")({
|
|
|
2533
2549
|
origin: null,
|
|
2534
2550
|
apiFormat: "anthropic",
|
|
2535
2551
|
isTest: true,
|
|
2536
|
-
providerName: provider.name
|
|
2552
|
+
providerName: provider.name,
|
|
2553
|
+
headers: streamingResult.requestHeaders ?? {}
|
|
2537
2554
|
});
|
|
2538
2555
|
appendLogEntry(
|
|
2539
2556
|
createTestLogEntry(
|
|
@@ -2580,7 +2597,8 @@ const Route$2 = createFileRoute("/api/providers/$providerId/test")({
|
|
|
2580
2597
|
origin: null,
|
|
2581
2598
|
apiFormat: "openai",
|
|
2582
2599
|
isTest: true,
|
|
2583
|
-
providerName: provider.name
|
|
2600
|
+
providerName: provider.name,
|
|
2601
|
+
headers: nonStreamingResult.requestHeaders ?? {}
|
|
2584
2602
|
});
|
|
2585
2603
|
appendLogEntry(
|
|
2586
2604
|
createTestLogEntry(
|
|
@@ -2626,7 +2644,8 @@ const Route$2 = createFileRoute("/api/providers/$providerId/test")({
|
|
|
2626
2644
|
origin: null,
|
|
2627
2645
|
apiFormat: "openai",
|
|
2628
2646
|
isTest: true,
|
|
2629
|
-
providerName: provider.name
|
|
2647
|
+
providerName: provider.name,
|
|
2648
|
+
headers: streamingResult.requestHeaders ?? {}
|
|
2630
2649
|
});
|
|
2631
2650
|
appendLogEntry(
|
|
2632
2651
|
createTestLogEntry(
|
|
@@ -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-CC-HN8LQ.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-BkNsdDqV.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-CC-HN8LQ.js" });
|
|
2
2
|
export {
|
|
3
3
|
tsrStartManifest
|
|
4
4
|
};
|
package/.output/server/index.mjs
CHANGED
|
@@ -100,51 +100,51 @@ const assets = {
|
|
|
100
100
|
"/assets/alibaba-TTwafVwX.svg": {
|
|
101
101
|
"type": "image/svg+xml",
|
|
102
102
|
"etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
|
|
103
|
-
"mtime": "2026-06-
|
|
103
|
+
"mtime": "2026-06-03T11:03:37.187Z",
|
|
104
104
|
"size": 5915,
|
|
105
105
|
"path": "../public/assets/alibaba-TTwafVwX.svg"
|
|
106
106
|
},
|
|
107
|
+
"/assets/zhipuai-BPNAnxo-.svg": {
|
|
108
|
+
"type": "image/svg+xml",
|
|
109
|
+
"etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
|
|
110
|
+
"mtime": "2026-06-03T11:03:37.189Z",
|
|
111
|
+
"size": 11256,
|
|
112
|
+
"path": "../public/assets/zhipuai-BPNAnxo-.svg"
|
|
113
|
+
},
|
|
107
114
|
"/assets/minimax-BPMzvuL-.jpeg": {
|
|
108
115
|
"type": "image/jpeg",
|
|
109
116
|
"etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
|
|
110
|
-
"mtime": "2026-06-
|
|
117
|
+
"mtime": "2026-06-03T11:03:37.187Z",
|
|
111
118
|
"size": 6918,
|
|
112
119
|
"path": "../public/assets/minimax-BPMzvuL-.jpeg"
|
|
113
120
|
},
|
|
121
|
+
"/assets/main-CC-HN8LQ.js": {
|
|
122
|
+
"type": "text/javascript; charset=utf-8",
|
|
123
|
+
"etag": '"4db57-dDRKN7pAYlQliYE7orCiiIlfW1M"',
|
|
124
|
+
"mtime": "2026-06-03T11:03:37.189Z",
|
|
125
|
+
"size": 318295,
|
|
126
|
+
"path": "../public/assets/main-CC-HN8LQ.js"
|
|
127
|
+
},
|
|
114
128
|
"/assets/index-B3RwBPLW.css": {
|
|
115
129
|
"type": "text/css; charset=utf-8",
|
|
116
130
|
"etag": '"10c74-aXacU4DRFVsUwcC5jHnjoPRSlTA"',
|
|
117
|
-
"mtime": "2026-06-
|
|
131
|
+
"mtime": "2026-06-03T11:03:37.189Z",
|
|
118
132
|
"size": 68724,
|
|
119
133
|
"path": "../public/assets/index-B3RwBPLW.css"
|
|
120
134
|
},
|
|
121
|
-
"/assets/zhipuai-BPNAnxo-.svg": {
|
|
122
|
-
"type": "image/svg+xml",
|
|
123
|
-
"etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
|
|
124
|
-
"mtime": "2026-06-03T09:45:53.063Z",
|
|
125
|
-
"size": 11256,
|
|
126
|
-
"path": "../public/assets/zhipuai-BPNAnxo-.svg"
|
|
127
|
-
},
|
|
128
135
|
"/assets/qwen-CONDcHqt.png": {
|
|
129
136
|
"type": "image/png",
|
|
130
137
|
"etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
|
|
131
|
-
"mtime": "2026-06-
|
|
138
|
+
"mtime": "2026-06-03T11:03:37.189Z",
|
|
132
139
|
"size": 357059,
|
|
133
140
|
"path": "../public/assets/qwen-CONDcHqt.png"
|
|
134
141
|
},
|
|
135
|
-
"/assets/
|
|
136
|
-
"type": "text/javascript; charset=utf-8",
|
|
137
|
-
"etag": '"4db57-PIyiLXQGvlFJuizUFXRhGOYXJwY"',
|
|
138
|
-
"mtime": "2026-06-03T09:45:53.065Z",
|
|
139
|
-
"size": 318295,
|
|
140
|
-
"path": "../public/assets/main-CpIX1ZHy.js"
|
|
141
|
-
},
|
|
142
|
-
"/assets/index-Bf_WGooQ.js": {
|
|
142
|
+
"/assets/index-BkNsdDqV.js": {
|
|
143
143
|
"type": "text/javascript; charset=utf-8",
|
|
144
|
-
"etag": '"
|
|
145
|
-
"mtime": "2026-06-
|
|
146
|
-
"size":
|
|
147
|
-
"path": "../public/assets/index-
|
|
144
|
+
"etag": '"83205-a3v/UM6yJRUCSO9lDIeVoj7vJXg"',
|
|
145
|
+
"mtime": "2026-06-03T11:03:37.189Z",
|
|
146
|
+
"size": 537093,
|
|
147
|
+
"path": "../public/assets/index-BkNsdDqV.js"
|
|
148
148
|
}
|
|
149
149
|
};
|
|
150
150
|
function readAsset(id) {
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -16,6 +16,8 @@ const portDefault = envPort !== undefined ? Number(envPort) : DEFAULT_PORT;
|
|
|
16
16
|
const args = process.argv.slice(2);
|
|
17
17
|
let port = portDefault;
|
|
18
18
|
let open = true;
|
|
19
|
+
let configDir: string | undefined;
|
|
20
|
+
let providersJson: string | undefined;
|
|
19
21
|
|
|
20
22
|
for (let i = 0; i < args.length; i++) {
|
|
21
23
|
const arg = args[i] ?? "";
|
|
@@ -31,6 +33,14 @@ for (let i = 0; i < args.length; i++) {
|
|
|
31
33
|
case "--open":
|
|
32
34
|
open = true;
|
|
33
35
|
break;
|
|
36
|
+
case "--config-dir":
|
|
37
|
+
configDir = args[i + 1];
|
|
38
|
+
i++;
|
|
39
|
+
break;
|
|
40
|
+
case "--providers":
|
|
41
|
+
providersJson = args[i + 1];
|
|
42
|
+
i++;
|
|
43
|
+
break;
|
|
34
44
|
default:
|
|
35
45
|
break;
|
|
36
46
|
}
|
|
@@ -157,10 +167,23 @@ const outputDir = __dirname;
|
|
|
157
167
|
const serverPath = join(outputDir, "../.output/server/index.mjs");
|
|
158
168
|
|
|
159
169
|
// Start server with node
|
|
170
|
+
const serverEnv = { ...process.env };
|
|
171
|
+
if (configDir !== undefined) {
|
|
172
|
+
// Convert MSYS/Git Bash path like /c/Users/... to Windows absolute path
|
|
173
|
+
let resolvedPath = join(configDir, "config.json");
|
|
174
|
+
// Convert /c/... to C:\... format
|
|
175
|
+
if (resolvedPath.startsWith("\\c\\")) {
|
|
176
|
+
resolvedPath = "C:" + resolvedPath;
|
|
177
|
+
}
|
|
178
|
+
serverEnv["LLM_INSPECTOR_CONFIG_PATH"] = resolvedPath;
|
|
179
|
+
}
|
|
180
|
+
if (providersJson !== undefined) {
|
|
181
|
+
serverEnv["LLM_INSPECTOR_PROVIDERS_JSON"] = providersJson;
|
|
182
|
+
}
|
|
160
183
|
const serverProcess = spawn(process.execPath, [serverPath], {
|
|
161
184
|
stdio: ["ignore", "inherit", "inherit"],
|
|
162
185
|
detached: true,
|
|
163
|
-
env:
|
|
186
|
+
env: serverEnv,
|
|
164
187
|
});
|
|
165
188
|
|
|
166
189
|
serverProcess.unref();
|
|
@@ -31,8 +31,9 @@ const PROVIDER_MAP: Record<string, Provider> = {
|
|
|
31
31
|
|
|
32
32
|
export function detectProvider(model: string | null): Provider {
|
|
33
33
|
if (model === null) return "unknown";
|
|
34
|
+
const modelLower = model.toLowerCase();
|
|
34
35
|
for (const [prefix, provider] of Object.entries(PROVIDER_MAP)) {
|
|
35
|
-
if (
|
|
36
|
+
if (modelLower.startsWith(prefix.toLowerCase())) {
|
|
36
37
|
return provider;
|
|
37
38
|
}
|
|
38
39
|
}
|