@tonyclaw/llm-inspector 1.14.1 → 1.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-BzK2SzIB.js → main-BElVT2p3.js} +3 -3
- package/.output/server/_ssr/{index-Cso39vJc.mjs → index-DmLit8Ad.mjs} +145 -112
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-B8X3GXM2.mjs → router-BoeSXWHG.mjs} +539 -286
- package/.output/server/{_tanstack-start-manifest_v-vO4aM6jK.mjs → _tanstack-start-manifest_v-B6idtbmL.mjs} +1 -1
- package/.output/server/index.mjs +21 -21
- package/package.json +1 -1
- package/src/components/providers/ProviderCard.tsx +111 -6
- package/src/components/providers/ProviderForm.tsx +70 -34
- package/src/components/providers/ProvidersPanel.tsx +3 -3
- package/src/lib/providerContract.ts +1 -0
- package/src/lib/providerTestContract.ts +8 -0
- package/src/proxy/providers.ts +119 -21
- package/src/routes/api/providers.$providerId.test.log.ts +293 -0
- package/src/routes/api/providers.$providerId.ts +2 -1
- package/src/routes/api/providers.ts +3 -2
- package/.output/public/assets/index-DEUddp_2.css +0 -1
- package/.output/public/assets/index-ax85pt2A.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, _ as _enum, 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,6 +1608,7 @@ 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(),
|
|
@@ -1675,6 +1676,62 @@ function migrateProviders() {
|
|
|
1675
1676
|
}
|
|
1676
1677
|
}
|
|
1677
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();
|
|
1678
1735
|
const providersJson = process.env["LLM_INSPECTOR_PROVIDERS_JSON"];
|
|
1679
1736
|
if (providersJson !== void 0) {
|
|
1680
1737
|
try {
|
|
@@ -1696,22 +1753,39 @@ function getProvider(id) {
|
|
|
1696
1753
|
function normalizeApiKey(apiKey) {
|
|
1697
1754
|
return apiKey.replace(/^Bearer\s+/i, "").trim();
|
|
1698
1755
|
}
|
|
1699
|
-
function addProvider(name, apiKey, format, baseUrl,
|
|
1756
|
+
function addProvider(name, apiKey, format, baseUrl, models, authHeader, apiDocsUrl, anthropicBaseUrl, openaiBaseUrl, source) {
|
|
1700
1757
|
const providers = getProviders();
|
|
1758
|
+
const normalizedKey = normalizeApiKey(apiKey);
|
|
1759
|
+
const resolvedAnthropicUrl = anthropicBaseUrl ?? "";
|
|
1760
|
+
const resolvedOpenaiUrl = openaiBaseUrl ?? "";
|
|
1701
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
|
+
}
|
|
1702
1776
|
const newProvider = {
|
|
1703
1777
|
id: randomUUID(),
|
|
1704
1778
|
name,
|
|
1705
|
-
apiKey:
|
|
1779
|
+
apiKey: normalizedKey,
|
|
1706
1780
|
format: format ?? (anthropicBaseUrl !== void 0 ? "anthropic" : openaiBaseUrl !== void 0 ? "openai" : void 0),
|
|
1707
1781
|
baseUrl,
|
|
1708
|
-
|
|
1782
|
+
models: models ?? [],
|
|
1709
1783
|
authHeader: authHeader ?? "bearer",
|
|
1710
1784
|
apiDocsUrl,
|
|
1711
1785
|
createdAt: now,
|
|
1712
1786
|
updatedAt: now,
|
|
1713
|
-
anthropicBaseUrl:
|
|
1714
|
-
openaiBaseUrl:
|
|
1787
|
+
anthropicBaseUrl: resolvedAnthropicUrl,
|
|
1788
|
+
openaiBaseUrl: resolvedOpenaiUrl,
|
|
1715
1789
|
source
|
|
1716
1790
|
};
|
|
1717
1791
|
providers.push(newProvider);
|
|
@@ -1726,7 +1800,7 @@ function updateProvider(id, updates) {
|
|
|
1726
1800
|
id: existing.id,
|
|
1727
1801
|
name: updates.name ?? existing.name,
|
|
1728
1802
|
apiKey: updates.apiKey !== void 0 ? normalizeApiKey(updates.apiKey) : existing.apiKey,
|
|
1729
|
-
|
|
1803
|
+
models: updates.models !== void 0 ? updates.models : existing.models,
|
|
1730
1804
|
format: updates.format ?? existing.format,
|
|
1731
1805
|
baseUrl: updates.baseUrl !== void 0 ? updates.baseUrl : existing.baseUrl,
|
|
1732
1806
|
authHeader: updates.authHeader ?? existing.authHeader,
|
|
@@ -1836,16 +1910,21 @@ function findProviderByModel(model) {
|
|
|
1836
1910
|
if (modelLower.startsWith(providerPrefix)) {
|
|
1837
1911
|
return provider;
|
|
1838
1912
|
}
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
if (provider.model !== void 0 && provider.model !== "") {
|
|
1843
|
-
const modelPart = modelNormalized.replace(normalizeModelName(provider.name), "");
|
|
1844
|
-
const concatenated = normalizeModelName(provider.name) + modelPart;
|
|
1845
|
-
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)) {
|
|
1846
1916
|
return provider;
|
|
1847
1917
|
}
|
|
1848
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
|
+
}
|
|
1849
1928
|
}
|
|
1850
1929
|
return null;
|
|
1851
1930
|
}
|
|
@@ -2475,7 +2554,7 @@ async function handleProxy(req) {
|
|
|
2475
2554
|
}
|
|
2476
2555
|
return handleStreamingResponse(upstreamRes, req, startTime, formatHandler, upstreamUrl, log);
|
|
2477
2556
|
}
|
|
2478
|
-
const Route$
|
|
2557
|
+
const Route$h = createFileRoute("/proxy/$")({
|
|
2479
2558
|
server: {
|
|
2480
2559
|
handlers: {
|
|
2481
2560
|
GET: ({ request }) => handleProxy(request),
|
|
@@ -2487,7 +2566,7 @@ const Route$g = createFileRoute("/proxy/$")({
|
|
|
2487
2566
|
}
|
|
2488
2567
|
}
|
|
2489
2568
|
});
|
|
2490
|
-
const Route$
|
|
2569
|
+
const Route$g = createFileRoute("/api/sessions")({
|
|
2491
2570
|
server: {
|
|
2492
2571
|
handlers: {
|
|
2493
2572
|
GET: () => Response.json(getSessions())
|
|
@@ -2500,12 +2579,13 @@ const ProviderInputSchema = object({
|
|
|
2500
2579
|
format: _enum(["anthropic", "openai"]).optional(),
|
|
2501
2580
|
anthropicBaseUrl: string().optional(),
|
|
2502
2581
|
openaiBaseUrl: string().optional(),
|
|
2503
|
-
|
|
2582
|
+
models: array(string()).min(1, "At least one model is required"),
|
|
2583
|
+
model: string().optional(),
|
|
2504
2584
|
authHeader: _enum(["bearer", "x-api-key"]).optional().default("bearer"),
|
|
2505
2585
|
apiDocsUrl: string().optional(),
|
|
2506
2586
|
source: _enum(["company", "personal"]).optional()
|
|
2507
2587
|
});
|
|
2508
|
-
const Route$
|
|
2588
|
+
const Route$f = createFileRoute("/api/providers")({
|
|
2509
2589
|
server: {
|
|
2510
2590
|
handlers: {
|
|
2511
2591
|
GET: () => {
|
|
@@ -2522,7 +2602,7 @@ const Route$e = createFileRoute("/api/providers")({
|
|
|
2522
2602
|
parsed.data.format,
|
|
2523
2603
|
void 0,
|
|
2524
2604
|
// baseUrl (legacy) — use format-specific URLs instead
|
|
2525
|
-
parsed.data.
|
|
2605
|
+
parsed.data.models,
|
|
2526
2606
|
parsed.data.authHeader,
|
|
2527
2607
|
parsed.data.apiDocsUrl,
|
|
2528
2608
|
parsed.data.anthropicBaseUrl,
|
|
@@ -2534,7 +2614,7 @@ const Route$e = createFileRoute("/api/providers")({
|
|
|
2534
2614
|
}
|
|
2535
2615
|
}
|
|
2536
2616
|
});
|
|
2537
|
-
const Route$
|
|
2617
|
+
const Route$e = createFileRoute("/api/models")({
|
|
2538
2618
|
server: {
|
|
2539
2619
|
handlers: {
|
|
2540
2620
|
GET: () => Response.json(getModels())
|
|
@@ -3044,7 +3124,7 @@ PATCH-style update: only the fields you supply are changed. Returns the updated
|
|
|
3044
3124
|
({ id }) => safeCall(() => testProviderImpl(callApi, id))
|
|
3045
3125
|
);
|
|
3046
3126
|
}
|
|
3047
|
-
const Route$
|
|
3127
|
+
const Route$d = createFileRoute("/api/mcp")({
|
|
3048
3128
|
server: {
|
|
3049
3129
|
handlers: {
|
|
3050
3130
|
// The SDK may issue either POST, GET, or DELETE. TanStack Start only
|
|
@@ -3056,7 +3136,7 @@ const Route$c = createFileRoute("/api/mcp")({
|
|
|
3056
3136
|
}
|
|
3057
3137
|
}
|
|
3058
3138
|
});
|
|
3059
|
-
const Route$
|
|
3139
|
+
const Route$c = createFileRoute("/api/logs")({
|
|
3060
3140
|
server: {
|
|
3061
3141
|
handlers: {
|
|
3062
3142
|
GET: ({ request }) => {
|
|
@@ -3082,7 +3162,7 @@ const Route$b = createFileRoute("/api/logs")({
|
|
|
3082
3162
|
}
|
|
3083
3163
|
});
|
|
3084
3164
|
logger.debug("Health endpoint loaded");
|
|
3085
|
-
const Route$
|
|
3165
|
+
const Route$b = createFileRoute("/api/health")({
|
|
3086
3166
|
server: {
|
|
3087
3167
|
handlers: {
|
|
3088
3168
|
GET: () => {
|
|
@@ -3096,7 +3176,7 @@ const RuntimeConfigPatchSchema = object({
|
|
|
3096
3176
|
}).strict().refine((v) => Object.keys(v).length > 0, {
|
|
3097
3177
|
message: "At least one field must be provided"
|
|
3098
3178
|
});
|
|
3099
|
-
const Route$
|
|
3179
|
+
const Route$a = createFileRoute("/api/config")({
|
|
3100
3180
|
server: {
|
|
3101
3181
|
handlers: {
|
|
3102
3182
|
GET: () => {
|
|
@@ -3126,7 +3206,7 @@ const Route$9 = createFileRoute("/api/config")({
|
|
|
3126
3206
|
}
|
|
3127
3207
|
});
|
|
3128
3208
|
union([string(), object({ providers: unknown() })]);
|
|
3129
|
-
const Route$
|
|
3209
|
+
const Route$9 = createFileRoute("/api/providers/import")({
|
|
3130
3210
|
server: {
|
|
3131
3211
|
handlers: {
|
|
3132
3212
|
POST: async ({ request }) => {
|
|
@@ -3159,7 +3239,7 @@ const Route$8 = createFileRoute("/api/providers/import")({
|
|
|
3159
3239
|
}
|
|
3160
3240
|
}
|
|
3161
3241
|
});
|
|
3162
|
-
const Route$
|
|
3242
|
+
const Route$8 = createFileRoute("/api/providers/export")({
|
|
3163
3243
|
server: {
|
|
3164
3244
|
handlers: {
|
|
3165
3245
|
GET: ({ request }) => {
|
|
@@ -3182,14 +3262,15 @@ const ProviderUpdateSchema = object({
|
|
|
3182
3262
|
apiKey: string().min(1, "API key is required").optional(),
|
|
3183
3263
|
format: _enum(["anthropic", "openai"]).optional(),
|
|
3184
3264
|
baseUrl: string().min(1, "Base URL is required").optional(),
|
|
3185
|
-
model: string().
|
|
3265
|
+
model: string().optional(),
|
|
3266
|
+
models: array(string()).optional(),
|
|
3186
3267
|
authHeader: _enum(["bearer", "x-api-key"]).optional(),
|
|
3187
3268
|
anthropicBaseUrl: string().optional(),
|
|
3188
3269
|
openaiBaseUrl: string().optional(),
|
|
3189
3270
|
apiDocsUrl: string().optional(),
|
|
3190
3271
|
source: _enum(["company", "personal"]).optional()
|
|
3191
3272
|
});
|
|
3192
|
-
const Route$
|
|
3273
|
+
const Route$7 = createFileRoute("/api/providers/$providerId")({
|
|
3193
3274
|
server: {
|
|
3194
3275
|
handlers: {
|
|
3195
3276
|
GET: ({ params }) => {
|
|
@@ -3221,7 +3302,7 @@ const Route$6 = createFileRoute("/api/providers/$providerId")({
|
|
|
3221
3302
|
}
|
|
3222
3303
|
}
|
|
3223
3304
|
});
|
|
3224
|
-
const Route$
|
|
3305
|
+
const Route$6 = createFileRoute("/api/logs/stream")({
|
|
3225
3306
|
server: {
|
|
3226
3307
|
handlers: {
|
|
3227
3308
|
GET: ({ request }) => {
|
|
@@ -3275,7 +3356,7 @@ const Route$5 = createFileRoute("/api/logs/stream")({
|
|
|
3275
3356
|
}
|
|
3276
3357
|
}
|
|
3277
3358
|
});
|
|
3278
|
-
const Route$
|
|
3359
|
+
const Route$5 = createFileRoute("/api/logs/$id")({
|
|
3279
3360
|
server: {
|
|
3280
3361
|
handlers: {
|
|
3281
3362
|
GET: async ({ params }) => {
|
|
@@ -3292,7 +3373,7 @@ const Route$4 = createFileRoute("/api/logs/$id")({
|
|
|
3292
3373
|
}
|
|
3293
3374
|
}
|
|
3294
3375
|
});
|
|
3295
|
-
const Route$
|
|
3376
|
+
const Route$4 = createFileRoute("/api/config/paths")({
|
|
3296
3377
|
server: {
|
|
3297
3378
|
handlers: {
|
|
3298
3379
|
GET: () => {
|
|
@@ -3710,31 +3791,7 @@ async function testStreamingEndpoint(baseUrl, apiKey, path2, model, isOpenAI) {
|
|
|
3710
3791
|
return createErrorResult(err, Date.now() - startTime, true);
|
|
3711
3792
|
}
|
|
3712
3793
|
}
|
|
3713
|
-
|
|
3714
|
-
return {
|
|
3715
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3716
|
-
id: `test-${Date.now()}`,
|
|
3717
|
-
method: "POST",
|
|
3718
|
-
path: path2,
|
|
3719
|
-
model: isTest ? result.model : void 0,
|
|
3720
|
-
sessionId: null,
|
|
3721
|
-
rawRequestBody: body,
|
|
3722
|
-
responseStatus: result.success ? 200 : 500,
|
|
3723
|
-
responseText: result.rawResponse ?? JSON.stringify(result),
|
|
3724
|
-
inputTokens: result.inputTokens ?? null,
|
|
3725
|
-
outputTokens: result.outputTokens ?? null,
|
|
3726
|
-
elapsedMs: result.latencyMs ?? 0,
|
|
3727
|
-
streaming: result.streaming ?? false,
|
|
3728
|
-
userAgent: "provider-test",
|
|
3729
|
-
origin: null,
|
|
3730
|
-
upstreamUrl,
|
|
3731
|
-
error: result.success ? null : result.error?.message ?? String(result.error),
|
|
3732
|
-
isTest: true,
|
|
3733
|
-
providerName,
|
|
3734
|
-
headers: result.requestHeaders ?? {}
|
|
3735
|
-
};
|
|
3736
|
-
}
|
|
3737
|
-
const Route$2 = createFileRoute("/api/providers/$providerId/test")({
|
|
3794
|
+
const Route$3 = createFileRoute("/api/providers/$providerId/test")({
|
|
3738
3795
|
server: {
|
|
3739
3796
|
handlers: {
|
|
3740
3797
|
POST: async ({ params }) => {
|
|
@@ -3742,208 +3799,70 @@ const Route$2 = createFileRoute("/api/providers/$providerId/test")({
|
|
|
3742
3799
|
if (!provider) {
|
|
3743
3800
|
return Response.json({ error: "Provider not found" }, { status: 404 });
|
|
3744
3801
|
}
|
|
3745
|
-
|
|
3802
|
+
const p = provider;
|
|
3803
|
+
const modelsToTest = (provider.models ?? []).filter((m) => m.trim() !== "");
|
|
3804
|
+
if (modelsToTest.length === 0) {
|
|
3746
3805
|
return Response.json(
|
|
3747
|
-
{ error: "Please configure
|
|
3806
|
+
{ error: "Please configure at least one model in provider settings" },
|
|
3748
3807
|
{ status: 400 }
|
|
3749
3808
|
);
|
|
3750
3809
|
}
|
|
3751
|
-
const model = provider.model.trim();
|
|
3752
|
-
const usageModel = getModelUsageName(model, provider.name);
|
|
3753
3810
|
const results = {
|
|
3754
3811
|
anthropic: { nonStreaming: { notConfigured: true }, streaming: { notConfigured: true } },
|
|
3755
|
-
openai: { nonStreaming: { notConfigured: true }, streaming: { notConfigured: true } }
|
|
3812
|
+
openai: { nonStreaming: { notConfigured: true }, streaming: { notConfigured: true } },
|
|
3813
|
+
models: {}
|
|
3756
3814
|
};
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
const
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
upstreamUrl,
|
|
3800
|
-
nonStreamingResult,
|
|
3801
|
-
true
|
|
3802
|
-
)
|
|
3803
|
-
);
|
|
3804
|
-
const streamingResult = await testStreamingEndpoint(
|
|
3805
|
-
provider.anthropicBaseUrl,
|
|
3806
|
-
provider.apiKey,
|
|
3807
|
-
"/v1/messages",
|
|
3808
|
-
usageModel,
|
|
3809
|
-
false
|
|
3810
|
-
);
|
|
3811
|
-
results.anthropic.streaming = streamingResult;
|
|
3812
|
-
const streamingRequestBody = JSON.stringify({
|
|
3813
|
-
model: usageModel,
|
|
3814
|
-
messages: [{ role: "user", content: "say hello" }],
|
|
3815
|
-
max_tokens: 256,
|
|
3816
|
-
stream: true
|
|
3817
|
-
});
|
|
3818
|
-
await addTestLogEntry({
|
|
3819
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3820
|
-
method: "POST",
|
|
3821
|
-
path: "/v1/messages",
|
|
3822
|
-
model: streamingResult.model ?? model,
|
|
3823
|
-
sessionId: null,
|
|
3824
|
-
rawRequestBody: streamingRequestBody,
|
|
3825
|
-
responseStatus: streamingResult.success ? 200 : 500,
|
|
3826
|
-
responseText: streamingResult.rawResponse ?? JSON.stringify(streamingResult),
|
|
3827
|
-
inputTokens: streamingResult.inputTokens ?? null,
|
|
3828
|
-
outputTokens: streamingResult.outputTokens ?? null,
|
|
3829
|
-
cacheCreationInputTokens: streamingResult.cacheCreationInputTokens ?? null,
|
|
3830
|
-
cacheReadInputTokens: streamingResult.cacheReadInputTokens ?? null,
|
|
3831
|
-
elapsedMs: streamingResult.latencyMs ?? 0,
|
|
3832
|
-
streaming: true,
|
|
3833
|
-
streamingChunks: streamingResult.streamingChunks,
|
|
3834
|
-
userAgent: "provider-test",
|
|
3835
|
-
origin: null,
|
|
3836
|
-
apiFormat: "anthropic",
|
|
3837
|
-
isTest: true,
|
|
3838
|
-
providerName: provider.name,
|
|
3839
|
-
headers: streamingResult.requestHeaders ?? {}
|
|
3840
|
-
});
|
|
3841
|
-
appendLogEntry(
|
|
3842
|
-
createTestLogEntry(
|
|
3843
|
-
provider.name,
|
|
3844
|
-
"/v1/messages",
|
|
3845
|
-
streamingRequestBody,
|
|
3846
|
-
upstreamUrl,
|
|
3847
|
-
streamingResult,
|
|
3848
|
-
true
|
|
3849
|
-
)
|
|
3850
|
-
);
|
|
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;
|
|
3851
3857
|
}
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
true
|
|
3859
|
-
);
|
|
3860
|
-
results.openai.nonStreaming = nonStreamingResult;
|
|
3861
|
-
const requestBody = JSON.stringify({
|
|
3862
|
-
model: usageModel,
|
|
3863
|
-
messages: [{ role: "user", content: "say hello and briefly introduce yourself" }],
|
|
3864
|
-
max_tokens: 1024
|
|
3865
|
-
});
|
|
3866
|
-
const upstreamUrl = `${provider.openaiBaseUrl}/v1/chat/completions`;
|
|
3867
|
-
await addTestLogEntry({
|
|
3868
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3869
|
-
method: "POST",
|
|
3870
|
-
path: "/v1/chat/completions",
|
|
3871
|
-
model: nonStreamingResult.model ?? model,
|
|
3872
|
-
sessionId: null,
|
|
3873
|
-
rawRequestBody: requestBody,
|
|
3874
|
-
responseStatus: nonStreamingResult.success ? 200 : 500,
|
|
3875
|
-
responseText: nonStreamingResult.rawResponse ?? JSON.stringify(nonStreamingResult),
|
|
3876
|
-
inputTokens: nonStreamingResult.inputTokens ?? null,
|
|
3877
|
-
outputTokens: nonStreamingResult.outputTokens ?? null,
|
|
3878
|
-
cacheCreationInputTokens: null,
|
|
3879
|
-
cacheReadInputTokens: null,
|
|
3880
|
-
elapsedMs: nonStreamingResult.latencyMs ?? 0,
|
|
3881
|
-
streaming: false,
|
|
3882
|
-
userAgent: "provider-test",
|
|
3883
|
-
origin: null,
|
|
3884
|
-
apiFormat: "openai",
|
|
3885
|
-
isTest: true,
|
|
3886
|
-
providerName: provider.name,
|
|
3887
|
-
headers: nonStreamingResult.requestHeaders ?? {}
|
|
3888
|
-
});
|
|
3889
|
-
appendLogEntry(
|
|
3890
|
-
createTestLogEntry(
|
|
3891
|
-
provider.name,
|
|
3892
|
-
"/v1/chat/completions",
|
|
3893
|
-
requestBody,
|
|
3894
|
-
upstreamUrl,
|
|
3895
|
-
nonStreamingResult,
|
|
3896
|
-
true
|
|
3897
|
-
)
|
|
3898
|
-
);
|
|
3899
|
-
const streamingResult = await testStreamingEndpoint(
|
|
3900
|
-
provider.openaiBaseUrl,
|
|
3901
|
-
provider.apiKey,
|
|
3902
|
-
"/v1/chat/completions",
|
|
3903
|
-
usageModel,
|
|
3904
|
-
true
|
|
3905
|
-
);
|
|
3906
|
-
results.openai.streaming = streamingResult;
|
|
3907
|
-
const streamingRequestBody = JSON.stringify({
|
|
3908
|
-
model: usageModel,
|
|
3909
|
-
messages: [{ role: "user", content: "say hello" }],
|
|
3910
|
-
max_tokens: 256,
|
|
3911
|
-
stream: true
|
|
3912
|
-
});
|
|
3913
|
-
await addTestLogEntry({
|
|
3914
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3915
|
-
method: "POST",
|
|
3916
|
-
path: "/v1/chat/completions",
|
|
3917
|
-
model: streamingResult.model ?? model,
|
|
3918
|
-
sessionId: null,
|
|
3919
|
-
rawRequestBody: streamingRequestBody,
|
|
3920
|
-
responseStatus: streamingResult.success ? 200 : 500,
|
|
3921
|
-
responseText: streamingResult.rawResponse ?? JSON.stringify(streamingResult),
|
|
3922
|
-
inputTokens: streamingResult.inputTokens ?? null,
|
|
3923
|
-
outputTokens: streamingResult.outputTokens ?? null,
|
|
3924
|
-
cacheCreationInputTokens: null,
|
|
3925
|
-
cacheReadInputTokens: null,
|
|
3926
|
-
elapsedMs: streamingResult.latencyMs ?? 0,
|
|
3927
|
-
streaming: true,
|
|
3928
|
-
streamingChunks: streamingResult.streamingChunks,
|
|
3929
|
-
userAgent: "provider-test",
|
|
3930
|
-
origin: null,
|
|
3931
|
-
apiFormat: "openai",
|
|
3932
|
-
isTest: true,
|
|
3933
|
-
providerName: provider.name,
|
|
3934
|
-
headers: streamingResult.requestHeaders ?? {}
|
|
3935
|
-
});
|
|
3936
|
-
appendLogEntry(
|
|
3937
|
-
createTestLogEntry(
|
|
3938
|
-
provider.name,
|
|
3939
|
-
"/v1/chat/completions",
|
|
3940
|
-
streamingRequestBody,
|
|
3941
|
-
upstreamUrl,
|
|
3942
|
-
streamingResult,
|
|
3943
|
-
true
|
|
3944
|
-
)
|
|
3945
|
-
);
|
|
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;
|
|
3946
3864
|
}
|
|
3865
|
+
results.testedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3947
3866
|
return Response.json(results);
|
|
3948
3867
|
}
|
|
3949
3868
|
}
|
|
@@ -3952,7 +3871,7 @@ const Route$2 = createFileRoute("/api/providers/$providerId/test")({
|
|
|
3952
3871
|
const ReplayRequestSchema = object({
|
|
3953
3872
|
modifiedBody: string()
|
|
3954
3873
|
});
|
|
3955
|
-
const Route$
|
|
3874
|
+
const Route$2 = createFileRoute("/api/logs/$id/replay")({
|
|
3956
3875
|
server: {
|
|
3957
3876
|
handlers: {
|
|
3958
3877
|
POST: async ({ params, request }) => {
|
|
@@ -4070,7 +3989,7 @@ const Route$1 = createFileRoute("/api/logs/$id/replay")({
|
|
|
4070
3989
|
}
|
|
4071
3990
|
}
|
|
4072
3991
|
});
|
|
4073
|
-
const Route = createFileRoute("/api/logs/$id/chunks")({
|
|
3992
|
+
const Route$1 = createFileRoute("/api/logs/$id/chunks")({
|
|
4074
3993
|
server: {
|
|
4075
3994
|
handlers: {
|
|
4076
3995
|
GET: async ({ params }) => {
|
|
@@ -4096,96 +4015,422 @@ const Route = createFileRoute("/api/logs/$id/chunks")({
|
|
|
4096
4015
|
}
|
|
4097
4016
|
}
|
|
4098
4017
|
});
|
|
4099
|
-
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({
|
|
4100
4340
|
id: "/",
|
|
4101
4341
|
path: "/",
|
|
4102
|
-
getParentRoute: () => Route$
|
|
4342
|
+
getParentRoute: () => Route$j
|
|
4103
4343
|
});
|
|
4104
|
-
const ProxySplatRoute = Route$
|
|
4344
|
+
const ProxySplatRoute = Route$h.update({
|
|
4105
4345
|
id: "/proxy/$",
|
|
4106
4346
|
path: "/proxy/$",
|
|
4107
|
-
getParentRoute: () => Route$
|
|
4347
|
+
getParentRoute: () => Route$j
|
|
4108
4348
|
});
|
|
4109
|
-
const ApiSessionsRoute = Route$
|
|
4349
|
+
const ApiSessionsRoute = Route$g.update({
|
|
4110
4350
|
id: "/api/sessions",
|
|
4111
4351
|
path: "/api/sessions",
|
|
4112
|
-
getParentRoute: () => Route$
|
|
4352
|
+
getParentRoute: () => Route$j
|
|
4113
4353
|
});
|
|
4114
|
-
const ApiProvidersRoute = Route$
|
|
4354
|
+
const ApiProvidersRoute = Route$f.update({
|
|
4115
4355
|
id: "/api/providers",
|
|
4116
4356
|
path: "/api/providers",
|
|
4117
|
-
getParentRoute: () => Route$
|
|
4357
|
+
getParentRoute: () => Route$j
|
|
4118
4358
|
});
|
|
4119
|
-
const ApiModelsRoute = Route$
|
|
4359
|
+
const ApiModelsRoute = Route$e.update({
|
|
4120
4360
|
id: "/api/models",
|
|
4121
4361
|
path: "/api/models",
|
|
4122
|
-
getParentRoute: () => Route$
|
|
4362
|
+
getParentRoute: () => Route$j
|
|
4123
4363
|
});
|
|
4124
|
-
const ApiMcpRoute = Route$
|
|
4364
|
+
const ApiMcpRoute = Route$d.update({
|
|
4125
4365
|
id: "/api/mcp",
|
|
4126
4366
|
path: "/api/mcp",
|
|
4127
|
-
getParentRoute: () => Route$
|
|
4367
|
+
getParentRoute: () => Route$j
|
|
4128
4368
|
});
|
|
4129
|
-
const ApiLogsRoute = Route$
|
|
4369
|
+
const ApiLogsRoute = Route$c.update({
|
|
4130
4370
|
id: "/api/logs",
|
|
4131
4371
|
path: "/api/logs",
|
|
4132
|
-
getParentRoute: () => Route$
|
|
4372
|
+
getParentRoute: () => Route$j
|
|
4133
4373
|
});
|
|
4134
|
-
const ApiHealthRoute = Route$
|
|
4374
|
+
const ApiHealthRoute = Route$b.update({
|
|
4135
4375
|
id: "/api/health",
|
|
4136
4376
|
path: "/api/health",
|
|
4137
|
-
getParentRoute: () => Route$
|
|
4377
|
+
getParentRoute: () => Route$j
|
|
4138
4378
|
});
|
|
4139
|
-
const ApiConfigRoute = Route$
|
|
4379
|
+
const ApiConfigRoute = Route$a.update({
|
|
4140
4380
|
id: "/api/config",
|
|
4141
4381
|
path: "/api/config",
|
|
4142
|
-
getParentRoute: () => Route$
|
|
4382
|
+
getParentRoute: () => Route$j
|
|
4143
4383
|
});
|
|
4144
|
-
const ApiProvidersImportRoute = Route$
|
|
4384
|
+
const ApiProvidersImportRoute = Route$9.update({
|
|
4145
4385
|
id: "/import",
|
|
4146
4386
|
path: "/import",
|
|
4147
4387
|
getParentRoute: () => ApiProvidersRoute
|
|
4148
4388
|
});
|
|
4149
|
-
const ApiProvidersExportRoute = Route$
|
|
4389
|
+
const ApiProvidersExportRoute = Route$8.update({
|
|
4150
4390
|
id: "/export",
|
|
4151
4391
|
path: "/export",
|
|
4152
4392
|
getParentRoute: () => ApiProvidersRoute
|
|
4153
4393
|
});
|
|
4154
|
-
const ApiProvidersProviderIdRoute = Route$
|
|
4394
|
+
const ApiProvidersProviderIdRoute = Route$7.update({
|
|
4155
4395
|
id: "/$providerId",
|
|
4156
4396
|
path: "/$providerId",
|
|
4157
4397
|
getParentRoute: () => ApiProvidersRoute
|
|
4158
4398
|
});
|
|
4159
|
-
const ApiLogsStreamRoute = Route$
|
|
4399
|
+
const ApiLogsStreamRoute = Route$6.update({
|
|
4160
4400
|
id: "/stream",
|
|
4161
4401
|
path: "/stream",
|
|
4162
4402
|
getParentRoute: () => ApiLogsRoute
|
|
4163
4403
|
});
|
|
4164
|
-
const ApiLogsIdRoute = Route$
|
|
4404
|
+
const ApiLogsIdRoute = Route$5.update({
|
|
4165
4405
|
id: "/$id",
|
|
4166
4406
|
path: "/$id",
|
|
4167
4407
|
getParentRoute: () => ApiLogsRoute
|
|
4168
4408
|
});
|
|
4169
|
-
const ApiConfigPathsRoute = Route$
|
|
4409
|
+
const ApiConfigPathsRoute = Route$4.update({
|
|
4170
4410
|
id: "/paths",
|
|
4171
4411
|
path: "/paths",
|
|
4172
4412
|
getParentRoute: () => ApiConfigRoute
|
|
4173
4413
|
});
|
|
4174
|
-
const ApiProvidersProviderIdTestRoute = Route$
|
|
4414
|
+
const ApiProvidersProviderIdTestRoute = Route$3.update({
|
|
4175
4415
|
id: "/test",
|
|
4176
4416
|
path: "/test",
|
|
4177
4417
|
getParentRoute: () => ApiProvidersProviderIdRoute
|
|
4178
4418
|
});
|
|
4179
|
-
const ApiLogsIdReplayRoute = Route$
|
|
4419
|
+
const ApiLogsIdReplayRoute = Route$2.update({
|
|
4180
4420
|
id: "/replay",
|
|
4181
4421
|
path: "/replay",
|
|
4182
4422
|
getParentRoute: () => ApiLogsIdRoute
|
|
4183
4423
|
});
|
|
4184
|
-
const ApiLogsIdChunksRoute = Route.update({
|
|
4424
|
+
const ApiLogsIdChunksRoute = Route$1.update({
|
|
4185
4425
|
id: "/chunks",
|
|
4186
4426
|
path: "/chunks",
|
|
4187
4427
|
getParentRoute: () => ApiLogsIdRoute
|
|
4188
4428
|
});
|
|
4429
|
+
const ApiProvidersProviderIdTestLogRoute = Route.update({
|
|
4430
|
+
id: "/log",
|
|
4431
|
+
path: "/log",
|
|
4432
|
+
getParentRoute: () => ApiProvidersProviderIdTestRoute
|
|
4433
|
+
});
|
|
4189
4434
|
const ApiConfigRouteChildren = {
|
|
4190
4435
|
ApiConfigPathsRoute
|
|
4191
4436
|
};
|
|
@@ -4204,8 +4449,14 @@ const ApiLogsRouteChildren = {
|
|
|
4204
4449
|
ApiLogsStreamRoute
|
|
4205
4450
|
};
|
|
4206
4451
|
const ApiLogsRouteWithChildren = ApiLogsRoute._addFileChildren(ApiLogsRouteChildren);
|
|
4452
|
+
const ApiProvidersProviderIdTestRouteChildren = {
|
|
4453
|
+
ApiProvidersProviderIdTestLogRoute
|
|
4454
|
+
};
|
|
4455
|
+
const ApiProvidersProviderIdTestRouteWithChildren = ApiProvidersProviderIdTestRoute._addFileChildren(
|
|
4456
|
+
ApiProvidersProviderIdTestRouteChildren
|
|
4457
|
+
);
|
|
4207
4458
|
const ApiProvidersProviderIdRouteChildren = {
|
|
4208
|
-
ApiProvidersProviderIdTestRoute
|
|
4459
|
+
ApiProvidersProviderIdTestRoute: ApiProvidersProviderIdTestRouteWithChildren
|
|
4209
4460
|
};
|
|
4210
4461
|
const ApiProvidersProviderIdRouteWithChildren = ApiProvidersProviderIdRoute._addFileChildren(
|
|
4211
4462
|
ApiProvidersProviderIdRouteChildren
|
|
@@ -4229,7 +4480,7 @@ const rootRouteChildren = {
|
|
|
4229
4480
|
ApiSessionsRoute,
|
|
4230
4481
|
ProxySplatRoute
|
|
4231
4482
|
};
|
|
4232
|
-
const routeTree = Route$
|
|
4483
|
+
const routeTree = Route$j._addFileChildren(rootRouteChildren)._addFileTypes();
|
|
4233
4484
|
function getRouter() {
|
|
4234
4485
|
const router2 = createRouter({
|
|
4235
4486
|
routeTree,
|
|
@@ -4244,10 +4495,12 @@ const router = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProper
|
|
|
4244
4495
|
export {
|
|
4245
4496
|
CapturedLogSchema as C,
|
|
4246
4497
|
InspectorResponseSchema as I,
|
|
4247
|
-
|
|
4498
|
+
ProviderTestResultsSchema as P,
|
|
4248
4499
|
RuntimeConfigSchema as R,
|
|
4249
|
-
StreamingChunkSchema$1 as S,
|
|
4250
4500
|
parseRequest as a,
|
|
4501
|
+
createFailedProviderTestResults as b,
|
|
4502
|
+
createPendingProviderTestResults as c,
|
|
4503
|
+
ProviderConfigSchema as d,
|
|
4251
4504
|
parseOpenAIResponse as p,
|
|
4252
4505
|
router as r,
|
|
4253
4506
|
stripClaudeCodeBillingHeader as s
|