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