@tonyclaw/agent-inspector 2.0.28 → 2.0.30
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/{CompareDrawer-CicCP3Hb.js → CompareDrawer-BDzfRSt1.js} +1 -1
- package/.output/public/assets/ProxyViewerContainer-NtOD8Ex_.js +115 -0
- package/.output/public/assets/{ReplayDialog-Bc8q3ujm.js → ReplayDialog-p-5TKg75.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-Coyy3zcH.js → RequestAnatomy-G0dV8-D_.js} +1 -1
- package/.output/public/assets/{ResponseView-BWJzgh0c.js → ResponseView-D2wE6lD-.js} +1 -1
- package/.output/public/assets/{StreamingChunkSequence-BSC3uuE5.js → StreamingChunkSequence-D8JRK-j_.js} +1 -1
- package/.output/public/assets/_sessionId-zimzVrJE.js +1 -0
- package/.output/public/assets/index-Cv5vPgpr.js +1 -0
- package/.output/public/assets/{index-DsiKfWCp.css → index-CwlHPmgL.css} +1 -1
- package/.output/public/assets/{main-Brj0Gn91.js → main-XHHZsOBK.js} +2 -2
- package/.output/server/_libs/lucide-react.mjs +13 -13
- package/.output/server/{_sessionId-DDdyKVG-.mjs → _sessionId-CK9QEhkB.mjs} +3 -3
- package/.output/server/_ssr/{CompareDrawer-XSExe2ml.mjs → CompareDrawer-BJVPFMIx.mjs} +2 -2
- package/.output/server/_ssr/{ProxyViewerContainer-B5pIiBZN.mjs → ProxyViewerContainer-DhbmJ2zj.mjs} +83 -20
- package/.output/server/_ssr/{ReplayDialog-BOAu0ric.mjs → ReplayDialog-DXRj95Gj.mjs} +4 -4
- package/.output/server/_ssr/{RequestAnatomy-C8Q5lozD.mjs → RequestAnatomy-CrYJTXdJ.mjs} +2 -2
- package/.output/server/_ssr/{ResponseView-a_iJfPUF.mjs → ResponseView-4ESqSITr.mjs} +2 -2
- package/.output/server/_ssr/{StreamingChunkSequence-YMKC0j8U.mjs → StreamingChunkSequence-Czdko5n_.mjs} +2 -2
- package/.output/server/_ssr/{index-CkDwBPzI.mjs → index-bei0I7qL.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-DXOXdFFM.mjs → router-sQh4Gk8J.mjs} +1338 -137
- package/.output/server/_tanstack-start-manifest_v-C0fdSWnA.mjs +4 -0
- package/.output/server/index.mjs +64 -64
- package/README.md +24 -1
- package/package.json +1 -1
- package/src/components/ProxyViewer.tsx +3 -0
- package/src/components/providers/ProviderCard.tsx +32 -0
- package/src/components/proxy-viewer/LogEntryHeader.tsx +38 -1
- package/src/lib/groupContract.ts +139 -0
- package/src/lib/providerTestContract.ts +3 -0
- package/src/lib/sessionInfoContract.ts +3 -0
- package/src/mcp/server.ts +278 -0
- package/src/mcp/toolHandlers.ts +126 -0
- package/src/proxy/evidenceAnalysis.ts +5 -0
- package/src/proxy/evidenceExporter.ts +8 -3
- package/src/proxy/groupEvidenceExporter.ts +341 -0
- package/src/proxy/groupStore.ts +259 -0
- package/src/proxy/handler.ts +8 -1
- package/src/proxy/logFinalizer.ts +36 -0
- package/src/proxy/schemas.ts +3 -0
- package/src/proxy/sessionInfo.ts +3 -0
- package/src/proxy/store.ts +3 -0
- package/src/proxy/streamTiming.ts +31 -0
- package/src/routes/api/groups.$groupId.evidence.ts +62 -0
- package/src/routes/api/groups.$groupId.sessions.ts +50 -0
- package/src/routes/api/groups.$groupId.ts +50 -0
- package/src/routes/api/groups.ts +39 -0
- package/src/routes/api/logs.$id.replay.ts +25 -2
- package/src/routes/api/providers.$providerId.test.log.ts +34 -2
- package/.output/public/assets/ProxyViewerContainer-BccuA6p5.js +0 -115
- package/.output/public/assets/_sessionId-9rEF0uSE.js +0 -1
- package/.output/public/assets/index-B9_VaAWl.js +0 -1
- package/.output/server/_tanstack-start-manifest_v-DPf3uJys.mjs +0 -4
|
@@ -50,8 +50,8 @@ import "../_libs/mimic-function.mjs";
|
|
|
50
50
|
import "../_libs/semver.mjs";
|
|
51
51
|
import "../_libs/uint8array-extras.mjs";
|
|
52
52
|
const faviconSvg = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2064%2064'%20role='img'%20aria-label='Agent%20Inspector'%3e%3crect%20width='64'%20height='64'%20rx='14'%20fill='%23111827'%20/%3e%3cg%20fill='none'%20stroke='%23f59e0b'%20stroke-width='4.2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20fill='%23f59e0b'%20d='M15%2036c0-11%207-18%2017-18s17%207%2017%2018c0%208-7%2013-17%2013s-17-5-17-13z'%20/%3e%3cpath%20d='M16%2031c-6-5-12-3-12%204%200%205%206%206%2011%202'%20/%3e%3cpath%20d='M48%2031c6-5%2012-3%2012%204%200%205-6%206-11%202'%20/%3e%3cpath%20d='M27%2019l-3-7'%20/%3e%3cpath%20d='M37%2019l3-7'%20/%3e%3cpath%20d='M19%2045l-6%209'%20/%3e%3cpath%20d='M27%2048l-3%209'%20/%3e%3cpath%20d='M37%2048l3%209'%20/%3e%3cpath%20d='M45%2045l6%209'%20/%3e%3c/g%3e%3cpath%20d='M14%2047l9-8%208%209c-5%203.5-12%203-17-1z'%20fill='%232f6b3f'%20opacity='.95'%20/%3e%3cpath%20d='M18%2046l5-5%205%206c-3%201.6-7%201.4-10-1z'%20fill='%236fb36f'%20opacity='.95'%20/%3e%3cpath%20d='M23%2041v10'%20fill='none'%20stroke='%23d6b45f'%20stroke-width='1.6'%20stroke-linecap='round'%20/%3e%3ccircle%20cx='31'%20cy='48'%20r='1.8'%20fill='%23c2412d'%20/%3e%3cpath%20d='M24%2044l13-11%2014%2013c-8%205.8-18%205.3-27-2z'%20fill='%232f6b3f'%20opacity='.97'%20/%3e%3cpath%20d='M30%2043l7-7%209%209c-5%202.7-11%202.5-16-2z'%20fill='%236fb36f'%20opacity='.95'%20/%3e%3cpath%20d='M37%2036v14'%20fill='none'%20stroke='%23d6b45f'%20stroke-width='2'%20stroke-linecap='round'%20/%3e%3cpath%20d='M30%2043c5-2%2011-1.5%2016%202'%20fill='none'%20stroke='%239fca78'%20stroke-width='1.8'%20stroke-linecap='round'%20/%3e%3ccircle%20cx='51'%20cy='46'%20r='2'%20fill='%23c2412d'%20/%3e%3cpath%20d='M40%2050l8-8%207%208c-4.2%203.2-10%203-15%200z'%20fill='%232f6b3f'%20opacity='.95'%20/%3e%3cpath%20d='M43%2049l5-5%204.5%205.5c-3%201.5-6%201.2-9.5-.5z'%20fill='%236fb36f'%20opacity='.95'%20/%3e%3cpath%20d='M48%2044v9'%20fill='none'%20stroke='%23d6b45f'%20stroke-width='1.5'%20stroke-linecap='round'%20/%3e%3ccircle%20cx='55'%20cy='50'%20r='1.7'%20fill='%23c2412d'%20/%3e%3ccircle%20cx='24'%20cy='11'%20r='3.2'%20fill='%23f59e0b'%20/%3e%3ccircle%20cx='40'%20cy='11'%20r='3.2'%20fill='%23f59e0b'%20/%3e%3ccircle%20cx='25'%20cy='34'%20r='2.1'%20fill='%23111827'%20/%3e%3ccircle%20cx='39'%20cy='34'%20r='2.1'%20fill='%23111827'%20/%3e%3c/svg%3e";
|
|
53
|
-
const appCss = "/assets/index-
|
|
54
|
-
const Route$
|
|
53
|
+
const appCss = "/assets/index-CwlHPmgL.css";
|
|
54
|
+
const Route$z = createRootRoute({
|
|
55
55
|
head: () => ({
|
|
56
56
|
meta: [
|
|
57
57
|
{ charSet: "utf-8" },
|
|
@@ -93,8 +93,8 @@ function RootDocument({ children }) {
|
|
|
93
93
|
] })
|
|
94
94
|
] });
|
|
95
95
|
}
|
|
96
|
-
const $$splitComponentImporter$1 = () => import("./index-
|
|
97
|
-
const Route$
|
|
96
|
+
const $$splitComponentImporter$1 = () => import("./index-bei0I7qL.mjs");
|
|
97
|
+
const Route$y = createFileRoute("/")({
|
|
98
98
|
component: lazyRouteComponent($$splitComponentImporter$1, "component")
|
|
99
99
|
});
|
|
100
100
|
const B64URL_RE = /^[A-Za-z0-9_-]+$/;
|
|
@@ -136,8 +136,8 @@ function decodeSessionIdFromPath(encoded) {
|
|
|
136
136
|
function getSessionPath(sessionId) {
|
|
137
137
|
return `/session/${encodeSessionIdForPath(sessionId)}`;
|
|
138
138
|
}
|
|
139
|
-
const $$splitComponentImporter = () => import("../_sessionId-
|
|
140
|
-
const Route$
|
|
139
|
+
const $$splitComponentImporter = () => import("../_sessionId-CK9QEhkB.mjs");
|
|
140
|
+
const Route$x = createFileRoute("/session/$sessionId")({
|
|
141
141
|
component: lazyRouteComponent($$splitComponentImporter, "component"),
|
|
142
142
|
parseParams: (params) => ({
|
|
143
143
|
sessionId: decodeSessionIdFromPath(params.sessionId)
|
|
@@ -713,6 +713,9 @@ const CapturedLogSchema = object({
|
|
|
713
713
|
cacheCreationInputTokens: number().nullable(),
|
|
714
714
|
cacheReadInputTokens: number().nullable(),
|
|
715
715
|
elapsedMs: number().nullable(),
|
|
716
|
+
firstChunkMs: number().nullable().optional(),
|
|
717
|
+
totalStreamMs: number().nullable().optional(),
|
|
718
|
+
tokensPerSecond: number().nullable().optional(),
|
|
716
719
|
streaming: boolean(),
|
|
717
720
|
userAgent: string().nullable(),
|
|
718
721
|
origin: string().nullable(),
|
|
@@ -1066,6 +1069,9 @@ function buildSessionLogSummary(log) {
|
|
|
1066
1069
|
hasError: hasLogError(log),
|
|
1067
1070
|
error: truncateError(log.error),
|
|
1068
1071
|
latencyMs: log.elapsedMs,
|
|
1072
|
+
firstChunkMs: log.firstChunkMs ?? null,
|
|
1073
|
+
totalStreamMs: log.totalStreamMs ?? null,
|
|
1074
|
+
tokensPerSecond: log.tokensPerSecond ?? null,
|
|
1069
1075
|
tokens: {
|
|
1070
1076
|
input: log.inputTokens,
|
|
1071
1077
|
output: log.outputTokens,
|
|
@@ -1079,7 +1085,7 @@ function nonNegativeInteger(value) {
|
|
|
1079
1085
|
if (value === null || !Number.isFinite(value) || value < 0) return 0;
|
|
1080
1086
|
return Math.floor(value);
|
|
1081
1087
|
}
|
|
1082
|
-
function addTokenUsage(total, summary) {
|
|
1088
|
+
function addTokenUsage$1(total, summary) {
|
|
1083
1089
|
const input = nonNegativeInteger(summary.tokens.input);
|
|
1084
1090
|
const output = nonNegativeInteger(summary.tokens.output);
|
|
1085
1091
|
const cacheCreate = nonNegativeInteger(summary.tokens.cacheCreate);
|
|
@@ -1109,7 +1115,7 @@ function buildApiPath(sessionId) {
|
|
|
1109
1115
|
function buildCompactLogsPath(sessionId) {
|
|
1110
1116
|
return buildRelativePath("/api/logs", new URLSearchParams({ compact: "1", sessionId }));
|
|
1111
1117
|
}
|
|
1112
|
-
function collectSortedValues(values) {
|
|
1118
|
+
function collectSortedValues$1(values) {
|
|
1113
1119
|
const set = /* @__PURE__ */ new Set();
|
|
1114
1120
|
for (const value of values) {
|
|
1115
1121
|
if (value !== null && value.length > 0) {
|
|
@@ -1153,7 +1159,7 @@ function buildSessionInfo(input) {
|
|
|
1153
1159
|
const errorCount = Math.max(countErrorLogs(summaries), input.snapshot?.failedRequests ?? 0);
|
|
1154
1160
|
const completedLogCount = countCompletedLogs(summaries);
|
|
1155
1161
|
const tokenUsage = summaries.reduce(
|
|
1156
|
-
(total, summary) => addTokenUsage(total, summary),
|
|
1162
|
+
(total, summary) => addTokenUsage$1(total, summary),
|
|
1157
1163
|
{ input: 0, output: 0, cacheCreate: 0, cacheRead: 0, total: 0 }
|
|
1158
1164
|
);
|
|
1159
1165
|
const requestCount = Math.max(input.snapshot?.requestCount ?? 0, logCount);
|
|
@@ -1191,8 +1197,8 @@ function buildSessionInfo(input) {
|
|
|
1191
1197
|
lastTaskError,
|
|
1192
1198
|
logCount,
|
|
1193
1199
|
errorCount,
|
|
1194
|
-
models: collectSortedValues(summaries.map((summary) => summary.model)),
|
|
1195
|
-
providers: collectSortedValues(summaries.map((summary) => summary.provider)),
|
|
1200
|
+
models: collectSortedValues$1(summaries.map((summary) => summary.model)),
|
|
1201
|
+
providers: collectSortedValues$1(summaries.map((summary) => summary.provider)),
|
|
1196
1202
|
tokenUsage,
|
|
1197
1203
|
lastLogId: input.snapshot?.lastLogId ?? latestLog?.id ?? null,
|
|
1198
1204
|
lastModel: normalizeString(input.snapshot?.lastModel) ?? latestLog?.model ?? null,
|
|
@@ -1602,6 +1608,9 @@ async function createLog(method, path2, requestBody, headers, clientInfo, rawHea
|
|
|
1602
1608
|
cacheCreationInputTokens: null,
|
|
1603
1609
|
cacheReadInputTokens: null,
|
|
1604
1610
|
elapsedMs: null,
|
|
1611
|
+
firstChunkMs: null,
|
|
1612
|
+
totalStreamMs: null,
|
|
1613
|
+
tokensPerSecond: null,
|
|
1605
1614
|
streaming: false,
|
|
1606
1615
|
userAgent,
|
|
1607
1616
|
origin,
|
|
@@ -4145,6 +4154,23 @@ function stripOpenAIOrphanToolMessages(rawBody) {
|
|
|
4145
4154
|
parsed.messages = kept;
|
|
4146
4155
|
return { body: JSON.stringify(parsed), removed: indices.length, orphanIds };
|
|
4147
4156
|
}
|
|
4157
|
+
function computeTokensPerSecond({
|
|
4158
|
+
outputTokens,
|
|
4159
|
+
firstChunkMs,
|
|
4160
|
+
totalStreamMs
|
|
4161
|
+
}) {
|
|
4162
|
+
if (outputTokens === null || outputTokens === void 0 || outputTokens <= 0) return null;
|
|
4163
|
+
if (totalStreamMs === null || totalStreamMs === void 0 || totalStreamMs <= 0) return null;
|
|
4164
|
+
const generationMs = firstChunkMs === null || firstChunkMs === void 0 ? totalStreamMs : totalStreamMs - firstChunkMs;
|
|
4165
|
+
if (!Number.isFinite(generationMs) || generationMs <= 0) return null;
|
|
4166
|
+
return Number((outputTokens / (generationMs / 1e3)).toFixed(2));
|
|
4167
|
+
}
|
|
4168
|
+
function firstChunkMsFromChunks(chunks) {
|
|
4169
|
+
const first = chunks?.[0];
|
|
4170
|
+
if (first === void 0) return null;
|
|
4171
|
+
if (!Number.isFinite(first.timestamp) || first.timestamp < 0) return null;
|
|
4172
|
+
return Math.floor(first.timestamp);
|
|
4173
|
+
}
|
|
4148
4174
|
const DEFAULT_MAX_FINALIZE_STREAM_BYTES = 20 * 1024 * 1024;
|
|
4149
4175
|
function resolveMaxFinalizeStreamBytes() {
|
|
4150
4176
|
const raw = process.env["AGENT_INSPECTOR_MAX_FINALIZE_STREAM_BYTES"];
|
|
@@ -4169,6 +4195,9 @@ function buildFileLogEntry(log, upstreamUrl) {
|
|
|
4169
4195
|
cacheCreationInputTokens: log.cacheCreationInputTokens,
|
|
4170
4196
|
cacheReadInputTokens: log.cacheReadInputTokens,
|
|
4171
4197
|
elapsedMs: log.elapsedMs,
|
|
4198
|
+
firstChunkMs: log.firstChunkMs,
|
|
4199
|
+
totalStreamMs: log.totalStreamMs,
|
|
4200
|
+
tokensPerSecond: log.tokensPerSecond,
|
|
4172
4201
|
streaming: log.streaming,
|
|
4173
4202
|
userAgent: log.userAgent,
|
|
4174
4203
|
origin: log.origin,
|
|
@@ -4204,9 +4233,29 @@ function finalizeWithError(job, log, fallbackStatus, fallbackResponseText, err,
|
|
|
4204
4233
|
log.responseStatus = log.responseStatus ?? fallbackStatus;
|
|
4205
4234
|
log.responseText = log.responseText ?? fallbackResponseText;
|
|
4206
4235
|
log.elapsedMs = job.elapsedMs;
|
|
4236
|
+
applyOptionalStreamingTiming(log, job);
|
|
4207
4237
|
log.error = message;
|
|
4208
4238
|
return { log, upstreamUrl: job.upstreamUrl, error: message, cleanupRawStreamPath };
|
|
4209
4239
|
}
|
|
4240
|
+
function applyOptionalStreamingTiming(log, job) {
|
|
4241
|
+
switch (job.type) {
|
|
4242
|
+
case "non-streaming":
|
|
4243
|
+
log.firstChunkMs = null;
|
|
4244
|
+
log.totalStreamMs = null;
|
|
4245
|
+
log.tokensPerSecond = null;
|
|
4246
|
+
return;
|
|
4247
|
+
case "streaming":
|
|
4248
|
+
case "stream-abort":
|
|
4249
|
+
log.firstChunkMs = job.firstChunkMs;
|
|
4250
|
+
log.totalStreamMs = job.totalStreamMs;
|
|
4251
|
+
log.tokensPerSecond = computeTokensPerSecond({
|
|
4252
|
+
outputTokens: log.outputTokens,
|
|
4253
|
+
firstChunkMs: job.firstChunkMs,
|
|
4254
|
+
totalStreamMs: job.totalStreamMs
|
|
4255
|
+
});
|
|
4256
|
+
return;
|
|
4257
|
+
}
|
|
4258
|
+
}
|
|
4210
4259
|
function finalizeNonStreaming(job, log) {
|
|
4211
4260
|
const formatHandler = formatForPath(log.path);
|
|
4212
4261
|
if (formatHandler === null) {
|
|
@@ -4215,6 +4264,9 @@ function finalizeNonStreaming(job, log) {
|
|
|
4215
4264
|
try {
|
|
4216
4265
|
const tokens = formatHandler.extractTokens(job.responseBody);
|
|
4217
4266
|
log.elapsedMs = job.elapsedMs;
|
|
4267
|
+
log.firstChunkMs = null;
|
|
4268
|
+
log.totalStreamMs = null;
|
|
4269
|
+
log.tokensPerSecond = null;
|
|
4218
4270
|
log.responseStatus = job.responseStatus;
|
|
4219
4271
|
log.responseText = job.responseBody;
|
|
4220
4272
|
log.inputTokens = tokens.inputTokens;
|
|
@@ -4295,6 +4347,7 @@ function finalizeStreaming(job, log) {
|
|
|
4295
4347
|
const oversized = getOversizedRawStream(job.rawStream);
|
|
4296
4348
|
if (oversized !== null) {
|
|
4297
4349
|
log.elapsedMs = job.elapsedMs;
|
|
4350
|
+
applyOptionalStreamingTiming(log, job);
|
|
4298
4351
|
log.responseStatus = job.responseStatus;
|
|
4299
4352
|
log.responseText = oversizedRawStreamText(oversized);
|
|
4300
4353
|
return {
|
|
@@ -4318,6 +4371,7 @@ function finalizeStreaming(job, log) {
|
|
|
4318
4371
|
log.model ?? void 0,
|
|
4319
4372
|
job.collectStreamingChunks
|
|
4320
4373
|
);
|
|
4374
|
+
applyOptionalStreamingTiming(log, job);
|
|
4321
4375
|
persistStreamingChunks(log);
|
|
4322
4376
|
return { log, upstreamUrl: job.upstreamUrl, error: null, cleanupRawStreamPath };
|
|
4323
4377
|
} catch (err) {
|
|
@@ -4347,6 +4401,7 @@ function finalizeStreamAbort(job, log) {
|
|
|
4347
4401
|
let cleanupRawStreamPath = null;
|
|
4348
4402
|
try {
|
|
4349
4403
|
log.elapsedMs = job.elapsedMs;
|
|
4404
|
+
applyOptionalStreamingTiming(log, job);
|
|
4350
4405
|
if (job.hasChunks && formatHandler !== null) {
|
|
4351
4406
|
const oversized = getOversizedRawStream(job.rawStream);
|
|
4352
4407
|
if (oversized !== null) {
|
|
@@ -4367,6 +4422,7 @@ function finalizeStreamAbort(job, log) {
|
|
|
4367
4422
|
log.model ?? void 0,
|
|
4368
4423
|
job.collectStreamingChunks
|
|
4369
4424
|
);
|
|
4425
|
+
applyOptionalStreamingTiming(log, job);
|
|
4370
4426
|
persistStreamingChunks(log);
|
|
4371
4427
|
} else {
|
|
4372
4428
|
log.responseText = "Client aborted";
|
|
@@ -4713,10 +4769,12 @@ function handleStreamingResponse(upstreamRes, req, startTime, upstreamUrl, log,
|
|
|
4713
4769
|
const capture = new RawStreamCapture();
|
|
4714
4770
|
const decoder = new TextDecoder();
|
|
4715
4771
|
let finalizationScheduled = false;
|
|
4772
|
+
let firstChunkMs = null;
|
|
4716
4773
|
const scheduleStreamingFinalization = (type) => {
|
|
4717
4774
|
if (finalizationScheduled) return;
|
|
4718
4775
|
finalizationScheduled = true;
|
|
4719
|
-
const
|
|
4776
|
+
const totalStreamMs = Date.now() - startTime;
|
|
4777
|
+
const elapsedMs = totalStreamMs;
|
|
4720
4778
|
const rawStream = capture.snapshot();
|
|
4721
4779
|
switch (type) {
|
|
4722
4780
|
case "streaming":
|
|
@@ -4727,7 +4785,9 @@ function handleStreamingResponse(upstreamRes, req, startTime, upstreamUrl, log,
|
|
|
4727
4785
|
elapsedMs,
|
|
4728
4786
|
responseStatus: upstreamRes.status,
|
|
4729
4787
|
rawStream,
|
|
4730
|
-
collectStreamingChunks
|
|
4788
|
+
collectStreamingChunks,
|
|
4789
|
+
firstChunkMs,
|
|
4790
|
+
totalStreamMs
|
|
4731
4791
|
});
|
|
4732
4792
|
return;
|
|
4733
4793
|
case "stream-abort":
|
|
@@ -4738,13 +4798,16 @@ function handleStreamingResponse(upstreamRes, req, startTime, upstreamUrl, log,
|
|
|
4738
4798
|
elapsedMs,
|
|
4739
4799
|
rawStream,
|
|
4740
4800
|
hasChunks: capture.hasChunks,
|
|
4741
|
-
collectStreamingChunks
|
|
4801
|
+
collectStreamingChunks,
|
|
4802
|
+
firstChunkMs,
|
|
4803
|
+
totalStreamMs
|
|
4742
4804
|
});
|
|
4743
4805
|
return;
|
|
4744
4806
|
}
|
|
4745
4807
|
};
|
|
4746
4808
|
const transform = new TransformStream({
|
|
4747
4809
|
async transform(chunk, controller) {
|
|
4810
|
+
if (firstChunkMs === null) firstChunkMs = Date.now() - startTime;
|
|
4748
4811
|
controller.enqueue(chunk);
|
|
4749
4812
|
await capture.append(decoder.decode(chunk, { stream: true }));
|
|
4750
4813
|
},
|
|
@@ -4872,7 +4935,7 @@ async function handleProxy(req) {
|
|
|
4872
4935
|
}
|
|
4873
4936
|
return handleStreamingResponse(upstreamRes, req, startTime, upstreamUrl, log, captureFullDetails);
|
|
4874
4937
|
}
|
|
4875
|
-
const Route$
|
|
4938
|
+
const Route$w = createFileRoute("/proxy/$")({
|
|
4876
4939
|
server: {
|
|
4877
4940
|
handlers: {
|
|
4878
4941
|
GET: ({ request }) => handleProxy(request),
|
|
@@ -4893,7 +4956,7 @@ function parsePositiveInt$2(value) {
|
|
|
4893
4956
|
function parseBooleanFlag(value) {
|
|
4894
4957
|
return value === "1" || value === "true";
|
|
4895
4958
|
}
|
|
4896
|
-
const Route$
|
|
4959
|
+
const Route$v = createFileRoute("/api/sessions")({
|
|
4897
4960
|
server: {
|
|
4898
4961
|
handlers: {
|
|
4899
4962
|
GET: async ({ request }) => {
|
|
@@ -4942,6 +5005,9 @@ const SessionLogSummarySchema = object({
|
|
|
4942
5005
|
hasError: boolean(),
|
|
4943
5006
|
error: string().nullable(),
|
|
4944
5007
|
latencyMs: number().nullable(),
|
|
5008
|
+
firstChunkMs: number().nullable().optional(),
|
|
5009
|
+
totalStreamMs: number().nullable().optional(),
|
|
5010
|
+
tokensPerSecond: number().nullable().optional(),
|
|
4945
5011
|
tokens: object({
|
|
4946
5012
|
input: number().nullable(),
|
|
4947
5013
|
output: number().nullable(),
|
|
@@ -5113,10 +5179,10 @@ const RunsFileSchema = object({
|
|
|
5113
5179
|
function runsFilePath() {
|
|
5114
5180
|
return join(getDataDir(), "runs.json");
|
|
5115
5181
|
}
|
|
5116
|
-
function nowIso() {
|
|
5182
|
+
function nowIso$1() {
|
|
5117
5183
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
5118
5184
|
}
|
|
5119
|
-
function stableId(input) {
|
|
5185
|
+
function stableId$1(input) {
|
|
5120
5186
|
return input.trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
5121
5187
|
}
|
|
5122
5188
|
function createRunId() {
|
|
@@ -5124,7 +5190,7 @@ function createRunId() {
|
|
|
5124
5190
|
}
|
|
5125
5191
|
function normalizeRunId(input) {
|
|
5126
5192
|
if (input === void 0) return createRunId();
|
|
5127
|
-
const normalized = stableId(input);
|
|
5193
|
+
const normalized = stableId$1(input);
|
|
5128
5194
|
return normalized.length > 0 ? normalized : createRunId();
|
|
5129
5195
|
}
|
|
5130
5196
|
function normalizeSessionId(input, runId) {
|
|
@@ -5159,7 +5225,7 @@ function createRun(input) {
|
|
|
5159
5225
|
const runId = normalizeRunId(parsed?.runId);
|
|
5160
5226
|
const existing = getRun(runId);
|
|
5161
5227
|
if (existing !== null) return existing;
|
|
5162
|
-
const timestamp = nowIso();
|
|
5228
|
+
const timestamp = nowIso$1();
|
|
5163
5229
|
const sessionId = normalizeSessionId(parsed?.sessionId, runId);
|
|
5164
5230
|
const run = {
|
|
5165
5231
|
id: runId,
|
|
@@ -5198,7 +5264,7 @@ function updateRun(runId, input) {
|
|
|
5198
5264
|
const parsed = UpdateInspectorRunInputSchema.parse(input);
|
|
5199
5265
|
const runs = readRuns();
|
|
5200
5266
|
let updatedRun = null;
|
|
5201
|
-
const updatedAt = nowIso();
|
|
5267
|
+
const updatedAt = nowIso$1();
|
|
5202
5268
|
const updatedRuns = runs.map((run) => {
|
|
5203
5269
|
if (run.id !== runId) return run;
|
|
5204
5270
|
updatedRun = {
|
|
@@ -5285,7 +5351,7 @@ function listRecentFailures(limit) {
|
|
|
5285
5351
|
limit: clampedLimit
|
|
5286
5352
|
};
|
|
5287
5353
|
}
|
|
5288
|
-
async function readJsonBody$
|
|
5354
|
+
async function readJsonBody$6(request) {
|
|
5289
5355
|
try {
|
|
5290
5356
|
const raw = await request.text();
|
|
5291
5357
|
if (raw.trim().length === 0) return { ok: true, value: void 0 };
|
|
@@ -5300,7 +5366,7 @@ function parsePositiveInt$1(value, fallback) {
|
|
|
5300
5366
|
if (!Number.isInteger(parsed) || parsed < 1) return fallback;
|
|
5301
5367
|
return parsed;
|
|
5302
5368
|
}
|
|
5303
|
-
const Route$
|
|
5369
|
+
const Route$u = createFileRoute("/api/runs")({
|
|
5304
5370
|
server: {
|
|
5305
5371
|
handlers: {
|
|
5306
5372
|
GET: ({ request }) => {
|
|
@@ -5315,7 +5381,7 @@ const Route$q = createFileRoute("/api/runs")({
|
|
|
5315
5381
|
return Response.json({ runs: listRuns() });
|
|
5316
5382
|
},
|
|
5317
5383
|
POST: async ({ request }) => {
|
|
5318
|
-
const body = await readJsonBody$
|
|
5384
|
+
const body = await readJsonBody$6(request);
|
|
5319
5385
|
if (!body.ok) {
|
|
5320
5386
|
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
5321
5387
|
}
|
|
@@ -5345,7 +5411,7 @@ const ProviderInputSchema = object({
|
|
|
5345
5411
|
modelMetadata: array(ProviderModelMetadataSchema).optional(),
|
|
5346
5412
|
source: _enum(["company", "personal"]).optional()
|
|
5347
5413
|
});
|
|
5348
|
-
const Route$
|
|
5414
|
+
const Route$t = createFileRoute("/api/providers")({
|
|
5349
5415
|
server: {
|
|
5350
5416
|
handlers: {
|
|
5351
5417
|
GET: ({ request }) => {
|
|
@@ -5379,13 +5445,117 @@ const Route$p = createFileRoute("/api/providers")({
|
|
|
5379
5445
|
}
|
|
5380
5446
|
}
|
|
5381
5447
|
});
|
|
5382
|
-
const Route$
|
|
5448
|
+
const Route$s = createFileRoute("/api/models")({
|
|
5383
5449
|
server: {
|
|
5384
5450
|
handlers: {
|
|
5385
5451
|
GET: () => Response.json(getModels())
|
|
5386
5452
|
}
|
|
5387
5453
|
}
|
|
5388
5454
|
});
|
|
5455
|
+
const InspectorGroupStatusSchema = _enum([
|
|
5456
|
+
"created",
|
|
5457
|
+
"running",
|
|
5458
|
+
"completed",
|
|
5459
|
+
"failed",
|
|
5460
|
+
"cancelled"
|
|
5461
|
+
]);
|
|
5462
|
+
const InspectorGroupKindSchema = _enum(["evaluation", "batch", "manual"]);
|
|
5463
|
+
const InspectorGroupEvidenceSchema = object({
|
|
5464
|
+
jsonPath: string(),
|
|
5465
|
+
markdownPath: string(),
|
|
5466
|
+
htmlPath: string(),
|
|
5467
|
+
exportedAt: string()
|
|
5468
|
+
});
|
|
5469
|
+
const InspectorGroupMemberSchema = object({
|
|
5470
|
+
id: string(),
|
|
5471
|
+
groupId: string(),
|
|
5472
|
+
sessionId: string(),
|
|
5473
|
+
runId: string().nullable(),
|
|
5474
|
+
label: string().nullable(),
|
|
5475
|
+
agent: string().nullable(),
|
|
5476
|
+
provider: string().nullable(),
|
|
5477
|
+
model: string().nullable(),
|
|
5478
|
+
status: InspectorRunStatusSchema.nullable(),
|
|
5479
|
+
metadata: record(string(), JsonValueSchema),
|
|
5480
|
+
addedAt: string(),
|
|
5481
|
+
updatedAt: string()
|
|
5482
|
+
});
|
|
5483
|
+
const InspectorGroupSchema = object({
|
|
5484
|
+
id: string(),
|
|
5485
|
+
title: string(),
|
|
5486
|
+
kind: InspectorGroupKindSchema,
|
|
5487
|
+
task: string().nullable(),
|
|
5488
|
+
project: string().nullable(),
|
|
5489
|
+
status: InspectorGroupStatusSchema,
|
|
5490
|
+
tags: array(string()),
|
|
5491
|
+
metadata: record(string(), JsonValueSchema),
|
|
5492
|
+
evidence: InspectorGroupEvidenceSchema.nullable(),
|
|
5493
|
+
members: array(InspectorGroupMemberSchema),
|
|
5494
|
+
createdAt: string(),
|
|
5495
|
+
updatedAt: string()
|
|
5496
|
+
});
|
|
5497
|
+
const CreateInspectorGroupInputSchema = object({
|
|
5498
|
+
groupId: string().min(1).optional(),
|
|
5499
|
+
title: string().min(1).optional(),
|
|
5500
|
+
kind: InspectorGroupKindSchema.optional(),
|
|
5501
|
+
task: string().nullable().optional(),
|
|
5502
|
+
project: string().nullable().optional(),
|
|
5503
|
+
status: InspectorGroupStatusSchema.optional(),
|
|
5504
|
+
tags: array(string()).optional(),
|
|
5505
|
+
metadata: record(string(), JsonValueSchema).optional()
|
|
5506
|
+
}).optional();
|
|
5507
|
+
const UpdateInspectorGroupInputSchema = object({
|
|
5508
|
+
title: string().min(1).optional(),
|
|
5509
|
+
kind: InspectorGroupKindSchema.optional(),
|
|
5510
|
+
task: string().nullable().optional(),
|
|
5511
|
+
project: string().nullable().optional(),
|
|
5512
|
+
status: InspectorGroupStatusSchema.optional(),
|
|
5513
|
+
tags: array(string()).optional(),
|
|
5514
|
+
metadata: record(string(), JsonValueSchema).optional()
|
|
5515
|
+
});
|
|
5516
|
+
const AddInspectorGroupSessionInputSchema = object({
|
|
5517
|
+
memberId: string().min(1).optional(),
|
|
5518
|
+
sessionId: string().min(1),
|
|
5519
|
+
runId: string().min(1).nullable().optional(),
|
|
5520
|
+
label: string().min(1).nullable().optional(),
|
|
5521
|
+
agent: string().min(1).nullable().optional(),
|
|
5522
|
+
provider: string().min(1).nullable().optional(),
|
|
5523
|
+
model: string().min(1).nullable().optional(),
|
|
5524
|
+
status: InspectorRunStatusSchema.nullable().optional(),
|
|
5525
|
+
metadata: record(string(), JsonValueSchema).optional()
|
|
5526
|
+
});
|
|
5527
|
+
const GroupEvidenceExportOptionsSchema = object({
|
|
5528
|
+
includeHistory: boolean().optional(),
|
|
5529
|
+
latestLogLimit: number().int().positive().max(50).optional()
|
|
5530
|
+
}).optional();
|
|
5531
|
+
const InspectorGroupExportMemberSchema = object({
|
|
5532
|
+
member: InspectorGroupMemberSchema,
|
|
5533
|
+
run: InspectorRunSchema.nullable(),
|
|
5534
|
+
session: SessionInfoSchema.nullable()
|
|
5535
|
+
});
|
|
5536
|
+
const InspectorGroupEvidenceSummarySchema = object({
|
|
5537
|
+
memberCount: number().int().nonnegative(),
|
|
5538
|
+
sessionsWithData: number().int().nonnegative(),
|
|
5539
|
+
missingSessions: number().int().nonnegative(),
|
|
5540
|
+
requestCount: number().int().nonnegative(),
|
|
5541
|
+
errorCount: number().int().nonnegative(),
|
|
5542
|
+
tokenUsage: SessionTokenUsageSchema,
|
|
5543
|
+
models: array(string()),
|
|
5544
|
+
providers: array(string()),
|
|
5545
|
+
completedMembers: number().int().nonnegative(),
|
|
5546
|
+
failedMembers: number().int().nonnegative(),
|
|
5547
|
+
runningMembers: number().int().nonnegative()
|
|
5548
|
+
});
|
|
5549
|
+
const GroupEvidenceExportResultSchema = object({
|
|
5550
|
+
group: InspectorGroupSchema,
|
|
5551
|
+
evidence: InspectorGroupEvidenceSchema,
|
|
5552
|
+
members: array(InspectorGroupExportMemberSchema),
|
|
5553
|
+
summary: InspectorGroupEvidenceSummarySchema,
|
|
5554
|
+
jenkinsReport: JenkinsReportSchema
|
|
5555
|
+
});
|
|
5556
|
+
const InspectorGroupsListResponseSchema = object({
|
|
5557
|
+
groups: array(InspectorGroupSchema)
|
|
5558
|
+
});
|
|
5389
5559
|
let overridePort = null;
|
|
5390
5560
|
function setCurrentPort(port) {
|
|
5391
5561
|
if (!Number.isInteger(port) || port <= 0 || port > 65535) {
|
|
@@ -5616,6 +5786,9 @@ function buildLogSummary(log) {
|
|
|
5616
5786
|
isStreaming: log.streaming,
|
|
5617
5787
|
hasError,
|
|
5618
5788
|
latencyMs: log.elapsedMs,
|
|
5789
|
+
firstChunkMs: log.firstChunkMs ?? null,
|
|
5790
|
+
totalStreamMs: log.totalStreamMs ?? null,
|
|
5791
|
+
tokensPerSecond: log.tokensPerSecond ?? null,
|
|
5619
5792
|
tokens: {
|
|
5620
5793
|
input: log.inputTokens,
|
|
5621
5794
|
output: log.outputTokens,
|
|
@@ -5782,6 +5955,85 @@ async function exportEvidenceImpl(callApi2, args) {
|
|
|
5782
5955
|
}
|
|
5783
5956
|
return textJson(parsed.data);
|
|
5784
5957
|
}
|
|
5958
|
+
async function listGroupsImpl(callApi2) {
|
|
5959
|
+
const res = await callApi2("/api/groups");
|
|
5960
|
+
if (!res.ok) return toolError(`GET /api/groups returned ${res.status}`);
|
|
5961
|
+
const rawBody = await res.json();
|
|
5962
|
+
const parsed = InspectorGroupsListResponseSchema.safeParse(rawBody);
|
|
5963
|
+
if (!parsed.success) return toolError("GET /api/groups returned an unparseable group list");
|
|
5964
|
+
return textJson(parsed.data);
|
|
5965
|
+
}
|
|
5966
|
+
async function createGroupImpl(callApi2, args) {
|
|
5967
|
+
const res = await callApi2("/api/groups", {
|
|
5968
|
+
method: "POST",
|
|
5969
|
+
headers: { "content-type": "application/json" },
|
|
5970
|
+
body: JSON.stringify(args ?? {})
|
|
5971
|
+
});
|
|
5972
|
+
if (!res.ok) return toolError(`POST /api/groups returned ${res.status}`);
|
|
5973
|
+
const rawBody = await res.json();
|
|
5974
|
+
const parsed = InspectorGroupSchema.safeParse(rawBody);
|
|
5975
|
+
if (!parsed.success) return toolError("POST /api/groups returned an unparseable group");
|
|
5976
|
+
return textJson(parsed.data);
|
|
5977
|
+
}
|
|
5978
|
+
async function getGroupImpl(callApi2, args) {
|
|
5979
|
+
const path2 = `/api/groups/${encodeURIComponent(args.groupId)}`;
|
|
5980
|
+
const res = await callApi2(path2);
|
|
5981
|
+
if (!res.ok) return toolError(`GET ${path2} returned ${res.status}`);
|
|
5982
|
+
const rawBody = await res.json();
|
|
5983
|
+
const parsed = InspectorGroupSchema.safeParse(rawBody);
|
|
5984
|
+
if (!parsed.success) return toolError("GET /api/groups/{groupId} returned an unparseable group");
|
|
5985
|
+
return textJson(parsed.data);
|
|
5986
|
+
}
|
|
5987
|
+
async function updateGroupImpl(callApi2, args) {
|
|
5988
|
+
const { groupId, ...patch } = args;
|
|
5989
|
+
const path2 = `/api/groups/${encodeURIComponent(groupId)}`;
|
|
5990
|
+
const res = await callApi2(path2, {
|
|
5991
|
+
method: "PATCH",
|
|
5992
|
+
headers: { "content-type": "application/json" },
|
|
5993
|
+
body: JSON.stringify(patch)
|
|
5994
|
+
});
|
|
5995
|
+
if (!res.ok) return toolError(`PATCH ${path2} returned ${res.status}`);
|
|
5996
|
+
const rawBody = await res.json();
|
|
5997
|
+
const parsed = InspectorGroupSchema.safeParse(rawBody);
|
|
5998
|
+
if (!parsed.success) {
|
|
5999
|
+
return toolError("PATCH /api/groups/{groupId} returned an unparseable group");
|
|
6000
|
+
}
|
|
6001
|
+
return textJson(parsed.data);
|
|
6002
|
+
}
|
|
6003
|
+
async function addGroupSessionImpl(callApi2, args) {
|
|
6004
|
+
const { groupId, ...session } = args;
|
|
6005
|
+
const path2 = `/api/groups/${encodeURIComponent(groupId)}/sessions`;
|
|
6006
|
+
const res = await callApi2(path2, {
|
|
6007
|
+
method: "POST",
|
|
6008
|
+
headers: { "content-type": "application/json" },
|
|
6009
|
+
body: JSON.stringify(session)
|
|
6010
|
+
});
|
|
6011
|
+
if (!res.ok) return toolError(`POST ${path2} returned ${res.status}`);
|
|
6012
|
+
const rawBody = await res.json();
|
|
6013
|
+
const parsed = InspectorGroupSchema.safeParse(rawBody);
|
|
6014
|
+
if (!parsed.success) {
|
|
6015
|
+
return toolError("POST /api/groups/{groupId}/sessions returned an unparseable group");
|
|
6016
|
+
}
|
|
6017
|
+
return textJson(parsed.data);
|
|
6018
|
+
}
|
|
6019
|
+
async function exportGroupEvidenceImpl(callApi2, args) {
|
|
6020
|
+
const path2 = `/api/groups/${encodeURIComponent(args.groupId)}/evidence`;
|
|
6021
|
+
const res = await callApi2(path2, {
|
|
6022
|
+
method: "POST",
|
|
6023
|
+
headers: { "content-type": "application/json" },
|
|
6024
|
+
body: JSON.stringify({
|
|
6025
|
+
includeHistory: args.includeHistory,
|
|
6026
|
+
latestLogLimit: args.latestLogLimit
|
|
6027
|
+
})
|
|
6028
|
+
});
|
|
6029
|
+
if (!res.ok) return toolError(`POST ${path2} returned ${res.status}`);
|
|
6030
|
+
const rawBody = await res.json();
|
|
6031
|
+
const parsed = GroupEvidenceExportResultSchema.safeParse(rawBody);
|
|
6032
|
+
if (!parsed.success) {
|
|
6033
|
+
return toolError("POST /api/groups/{groupId}/evidence returned an unparseable evidence result");
|
|
6034
|
+
}
|
|
6035
|
+
return textJson(parsed.data);
|
|
6036
|
+
}
|
|
5785
6037
|
async function listModelsImpl(callApi2) {
|
|
5786
6038
|
const res = await callApi2("/api/models");
|
|
5787
6039
|
if (!res.ok) return toolError(`GET /api/models returned ${res.status}`);
|
|
@@ -5973,6 +6225,9 @@ const LogResourceListResponseSchema = object({
|
|
|
5973
6225
|
const EvidenceReadResponseSchema = object({
|
|
5974
6226
|
markdown: string()
|
|
5975
6227
|
});
|
|
6228
|
+
const GroupEvidenceReadResponseSchema = object({
|
|
6229
|
+
markdown: string()
|
|
6230
|
+
});
|
|
5976
6231
|
function textResource(uri, mimeType, text) {
|
|
5977
6232
|
return {
|
|
5978
6233
|
contents: [{ uri: uri.href, mimeType, text }]
|
|
@@ -6055,6 +6310,61 @@ async function listRunResources() {
|
|
|
6055
6310
|
return listResult([]);
|
|
6056
6311
|
}
|
|
6057
6312
|
}
|
|
6313
|
+
async function listGroupResources() {
|
|
6314
|
+
try {
|
|
6315
|
+
const response = await callApi("/api/groups");
|
|
6316
|
+
if (!response.ok) return listResult([]);
|
|
6317
|
+
const parsed = InspectorGroupsListResponseSchema.safeParse(await response.json());
|
|
6318
|
+
if (!parsed.success) return listResult([]);
|
|
6319
|
+
return listResult(
|
|
6320
|
+
parsed.data.groups.map((group) => ({
|
|
6321
|
+
uri: `inspector://groups/${encodeURIComponent(group.id)}`,
|
|
6322
|
+
name: `group:${group.id}`,
|
|
6323
|
+
title: group.title,
|
|
6324
|
+
mimeType: "application/json"
|
|
6325
|
+
}))
|
|
6326
|
+
);
|
|
6327
|
+
} catch {
|
|
6328
|
+
return listResult([]);
|
|
6329
|
+
}
|
|
6330
|
+
}
|
|
6331
|
+
async function listGroupSessionResources() {
|
|
6332
|
+
try {
|
|
6333
|
+
const response = await callApi("/api/groups");
|
|
6334
|
+
if (!response.ok) return listResult([]);
|
|
6335
|
+
const parsed = InspectorGroupsListResponseSchema.safeParse(await response.json());
|
|
6336
|
+
if (!parsed.success) return listResult([]);
|
|
6337
|
+
return listResult(
|
|
6338
|
+
parsed.data.groups.map((group) => ({
|
|
6339
|
+
uri: `inspector://groups/${encodeURIComponent(group.id)}/sessions`,
|
|
6340
|
+
name: `group-sessions:${group.id}`,
|
|
6341
|
+
title: `${group.title} sessions`,
|
|
6342
|
+
mimeType: "application/json"
|
|
6343
|
+
}))
|
|
6344
|
+
);
|
|
6345
|
+
} catch {
|
|
6346
|
+
return listResult([]);
|
|
6347
|
+
}
|
|
6348
|
+
}
|
|
6349
|
+
async function listGroupEvidenceResources() {
|
|
6350
|
+
try {
|
|
6351
|
+
const response = await callApi("/api/groups");
|
|
6352
|
+
if (!response.ok) return listResult([]);
|
|
6353
|
+
const parsed = InspectorGroupsListResponseSchema.safeParse(await response.json());
|
|
6354
|
+
if (!parsed.success) return listResult([]);
|
|
6355
|
+
return listResult(
|
|
6356
|
+
parsed.data.groups.filter((group) => group.evidence !== null).map((group) => ({
|
|
6357
|
+
uri: `inspector://groups/${encodeURIComponent(group.id)}/evidence`,
|
|
6358
|
+
name: `group-evidence:${group.id}`,
|
|
6359
|
+
title: `${group.title} evidence pack`,
|
|
6360
|
+
mimeType: "text/markdown",
|
|
6361
|
+
description: group.evidence?.markdownPath
|
|
6362
|
+
}))
|
|
6363
|
+
);
|
|
6364
|
+
} catch {
|
|
6365
|
+
return listResult([]);
|
|
6366
|
+
}
|
|
6367
|
+
}
|
|
6058
6368
|
async function listEvidenceResources() {
|
|
6059
6369
|
try {
|
|
6060
6370
|
const response = await callApi("/api/runs");
|
|
@@ -6227,6 +6537,77 @@ function registerTools(server) {
|
|
|
6227
6537
|
},
|
|
6228
6538
|
(args) => safeCall(() => getRecentFailuresImpl(callApi, args))
|
|
6229
6539
|
);
|
|
6540
|
+
server.registerTool(
|
|
6541
|
+
"inspector_list_groups",
|
|
6542
|
+
{
|
|
6543
|
+
title: "List Inspector groups",
|
|
6544
|
+
description: "Lists declared Inspector groups. Groups aggregate multiple sessions/runs, commonly one evaluation matrix spanning several providers or models.",
|
|
6545
|
+
inputSchema: object({})
|
|
6546
|
+
},
|
|
6547
|
+
() => safeCall(() => listGroupsImpl(callApi))
|
|
6548
|
+
);
|
|
6549
|
+
server.registerTool(
|
|
6550
|
+
"inspector_create_group",
|
|
6551
|
+
{
|
|
6552
|
+
title: "Create or declare an Inspector group",
|
|
6553
|
+
description: "Creates an evaluation/batch group that external systems can use to aggregate multiple OpenCode/Codex sessions across models such as MiniMax, DeepSeek, or GLM.",
|
|
6554
|
+
inputSchema: object({
|
|
6555
|
+
groupId: string().min(1).optional().describe("Stable group id. Generated when omitted."),
|
|
6556
|
+
title: string().min(1).optional().describe("Human-readable group title."),
|
|
6557
|
+
kind: _enum(["evaluation", "batch", "manual"]).optional().describe("Group kind. Defaults to evaluation."),
|
|
6558
|
+
task: string().nullable().optional().describe("Task, benchmark, or evaluation goal."),
|
|
6559
|
+
project: string().nullable().optional().describe("Project or repository under test."),
|
|
6560
|
+
status: InspectorGroupStatusSchema.optional().describe("Initial group status."),
|
|
6561
|
+
tags: array(string()).optional().describe("Free-form group labels."),
|
|
6562
|
+
metadata: record(string(), JsonValueSchema).optional().describe("JSON metadata.")
|
|
6563
|
+
})
|
|
6564
|
+
},
|
|
6565
|
+
(args) => safeCall(() => createGroupImpl(callApi, args))
|
|
6566
|
+
);
|
|
6567
|
+
server.registerTool(
|
|
6568
|
+
"inspector_get_group",
|
|
6569
|
+
{
|
|
6570
|
+
title: "Get an Inspector group",
|
|
6571
|
+
description: "Returns one declared Inspector group with its attached session/run members and exported evidence paths when available.",
|
|
6572
|
+
inputSchema: object({
|
|
6573
|
+
groupId: string().min(1).describe("The Inspector group id.")
|
|
6574
|
+
})
|
|
6575
|
+
},
|
|
6576
|
+
(args) => safeCall(() => getGroupImpl(callApi, args))
|
|
6577
|
+
);
|
|
6578
|
+
server.registerTool(
|
|
6579
|
+
"inspector_update_group",
|
|
6580
|
+
{
|
|
6581
|
+
title: "Update an Inspector group",
|
|
6582
|
+
description: "PATCH-style update for a declared group. Use this to mark a whole evaluation running, failed, completed, or to merge CI metadata.",
|
|
6583
|
+
inputSchema: UpdateInspectorGroupInputSchema.extend({
|
|
6584
|
+
groupId: string().min(1).describe("The Inspector group id.")
|
|
6585
|
+
})
|
|
6586
|
+
},
|
|
6587
|
+
(args) => safeCall(() => updateGroupImpl(callApi, args))
|
|
6588
|
+
);
|
|
6589
|
+
server.registerTool(
|
|
6590
|
+
"inspector_add_group_session",
|
|
6591
|
+
{
|
|
6592
|
+
title: "Attach a session to an Inspector group",
|
|
6593
|
+
description: "Adds or updates one group member. Use it after each OpenCode process discovers its session id, or while an evaluation matrix is running to attach model/provider labels.",
|
|
6594
|
+
inputSchema: AddInspectorGroupSessionInputSchema.extend({
|
|
6595
|
+
groupId: string().min(1).describe("The Inspector group id.")
|
|
6596
|
+
})
|
|
6597
|
+
},
|
|
6598
|
+
(args) => safeCall(() => addGroupSessionImpl(callApi, args))
|
|
6599
|
+
);
|
|
6600
|
+
server.registerTool(
|
|
6601
|
+
"inspector_export_group_evidence",
|
|
6602
|
+
{
|
|
6603
|
+
title: "Export an Inspector group evidence pack",
|
|
6604
|
+
description: "Exports a whole group's evidence pack to local JSON, Markdown, and HTML files under <dataDir>/evidence/groups/<groupId>. The export contains a provider/model matrix and compact session summaries.",
|
|
6605
|
+
inputSchema: GroupEvidenceExportOptionsSchema.unwrap().extend({
|
|
6606
|
+
groupId: string().min(1).describe("The Inspector group id.")
|
|
6607
|
+
})
|
|
6608
|
+
},
|
|
6609
|
+
(args) => safeCall(() => exportGroupEvidenceImpl(callApi, args))
|
|
6610
|
+
);
|
|
6230
6611
|
server.registerTool(
|
|
6231
6612
|
"inspector_list_models",
|
|
6232
6613
|
{
|
|
@@ -6434,6 +6815,46 @@ function registerResources(server) {
|
|
|
6434
6815
|
},
|
|
6435
6816
|
(uri) => readApiJsonResource(uri, "/api/runs")
|
|
6436
6817
|
);
|
|
6818
|
+
server.registerResource(
|
|
6819
|
+
"inspector_groups",
|
|
6820
|
+
"inspector://groups",
|
|
6821
|
+
{
|
|
6822
|
+
title: "Inspector groups",
|
|
6823
|
+
description: "Declared Inspector groups aggregating multiple sessions or runs.",
|
|
6824
|
+
mimeType: "application/json"
|
|
6825
|
+
},
|
|
6826
|
+
(uri) => readApiJsonResource(uri, "/api/groups")
|
|
6827
|
+
);
|
|
6828
|
+
server.registerResource(
|
|
6829
|
+
"inspector_group",
|
|
6830
|
+
new ResourceTemplate("inspector://groups/{groupId}", { list: listGroupResources }),
|
|
6831
|
+
{
|
|
6832
|
+
title: "Inspector group",
|
|
6833
|
+
description: "One declared Inspector group with attached session/run members.",
|
|
6834
|
+
mimeType: "application/json"
|
|
6835
|
+
},
|
|
6836
|
+
(uri, variables) => {
|
|
6837
|
+
const groupId = variableString(variables, "groupId");
|
|
6838
|
+
if (groupId === null) return textResource(uri, "text/plain", "Missing groupId");
|
|
6839
|
+
return readApiJsonResource(uri, `/api/groups/${encodeURIComponent(groupId)}`);
|
|
6840
|
+
}
|
|
6841
|
+
);
|
|
6842
|
+
server.registerResource(
|
|
6843
|
+
"inspector_group_sessions",
|
|
6844
|
+
new ResourceTemplate("inspector://groups/{groupId}/sessions", {
|
|
6845
|
+
list: listGroupSessionResources
|
|
6846
|
+
}),
|
|
6847
|
+
{
|
|
6848
|
+
title: "Inspector group sessions",
|
|
6849
|
+
description: "Attached session/run members for one Inspector group.",
|
|
6850
|
+
mimeType: "application/json"
|
|
6851
|
+
},
|
|
6852
|
+
(uri, variables) => {
|
|
6853
|
+
const groupId = variableString(variables, "groupId");
|
|
6854
|
+
if (groupId === null) return textResource(uri, "text/plain", "Missing groupId");
|
|
6855
|
+
return readApiJsonResource(uri, `/api/groups/${encodeURIComponent(groupId)}/sessions`);
|
|
6856
|
+
}
|
|
6857
|
+
);
|
|
6437
6858
|
server.registerResource(
|
|
6438
6859
|
"inspector_recent_failures",
|
|
6439
6860
|
"inspector://failures/recent",
|
|
@@ -6486,6 +6907,36 @@ function registerResources(server) {
|
|
|
6486
6907
|
}
|
|
6487
6908
|
}
|
|
6488
6909
|
);
|
|
6910
|
+
server.registerResource(
|
|
6911
|
+
"inspector_group_evidence",
|
|
6912
|
+
new ResourceTemplate("inspector://groups/{groupId}/evidence", {
|
|
6913
|
+
list: listGroupEvidenceResources
|
|
6914
|
+
}),
|
|
6915
|
+
{
|
|
6916
|
+
title: "Inspector group evidence pack",
|
|
6917
|
+
description: "Markdown evidence pack for an Inspector group. Generate it first with inspector_export_group_evidence.",
|
|
6918
|
+
mimeType: "text/markdown"
|
|
6919
|
+
},
|
|
6920
|
+
async (uri, variables) => {
|
|
6921
|
+
const groupId = variableString(variables, "groupId");
|
|
6922
|
+
if (groupId === null) return textResource(uri, "text/plain", "Missing groupId");
|
|
6923
|
+
const path2 = `/api/groups/${encodeURIComponent(groupId)}/evidence`;
|
|
6924
|
+
try {
|
|
6925
|
+
const response = await callApi(path2);
|
|
6926
|
+
if (!response.ok) {
|
|
6927
|
+
return textResource(uri, "text/plain", `GET ${path2} returned ${response.status}`);
|
|
6928
|
+
}
|
|
6929
|
+
const parsed = GroupEvidenceReadResponseSchema.safeParse(await response.json());
|
|
6930
|
+
if (!parsed.success) {
|
|
6931
|
+
return textResource(uri, "text/plain", "Evidence endpoint returned an unparseable body");
|
|
6932
|
+
}
|
|
6933
|
+
return textResource(uri, "text/markdown", parsed.data.markdown);
|
|
6934
|
+
} catch (err) {
|
|
6935
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
6936
|
+
return textResource(uri, "text/plain", `Resource read failed: ${message}`);
|
|
6937
|
+
}
|
|
6938
|
+
}
|
|
6939
|
+
);
|
|
6489
6940
|
}
|
|
6490
6941
|
function registerPrompts(server) {
|
|
6491
6942
|
server.registerPrompt(
|
|
@@ -6558,6 +7009,31 @@ The report should include:
|
|
|
6558
7009
|
3. Models/providers used, token totals, request counts, and error counts
|
|
6559
7010
|
4. Failure analysis or success evidence
|
|
6560
7011
|
5. Reproducible next action for a developer`)
|
|
7012
|
+
);
|
|
7013
|
+
server.registerPrompt(
|
|
7014
|
+
"inspector_generate_group_report",
|
|
7015
|
+
{
|
|
7016
|
+
title: "Generate group report",
|
|
7017
|
+
description: "Generate a model/provider evaluation report from an Inspector group and group evidence pack.",
|
|
7018
|
+
argsSchema: object({
|
|
7019
|
+
groupId: string().min(1).describe("The Inspector group id.")
|
|
7020
|
+
})
|
|
7021
|
+
},
|
|
7022
|
+
({ groupId }) => userPrompt(`Generate a model/provider evaluation report for this Inspector group.
|
|
7023
|
+
|
|
7024
|
+
Evidence to read:
|
|
7025
|
+
- Group resource: inspector://groups/${encodeURIComponent(groupId)}
|
|
7026
|
+
- Group session members: inspector://groups/${encodeURIComponent(groupId)}/sessions
|
|
7027
|
+
- Group evidence pack: inspector://groups/${encodeURIComponent(groupId)}/evidence
|
|
7028
|
+
|
|
7029
|
+
If the evidence pack resource says it has not been exported, call inspector_export_group_evidence for this group first.
|
|
7030
|
+
|
|
7031
|
+
The report should include:
|
|
7032
|
+
1. Evaluation status summary
|
|
7033
|
+
2. Provider/model matrix with session links
|
|
7034
|
+
3. Request counts, token totals, streaming timing, and error counts
|
|
7035
|
+
4. Winner/loser observations when the evidence supports them
|
|
7036
|
+
5. Concrete next actions for failed or missing sessions`)
|
|
6561
7037
|
);
|
|
6562
7038
|
server.registerPrompt(
|
|
6563
7039
|
"inspector_extract_repro_steps",
|
|
@@ -6582,7 +7058,7 @@ Return:
|
|
|
6582
7058
|
5. Minimal verification command or UI check`)
|
|
6583
7059
|
);
|
|
6584
7060
|
}
|
|
6585
|
-
const Route$
|
|
7061
|
+
const Route$r = createFileRoute("/api/mcp")({
|
|
6586
7062
|
server: {
|
|
6587
7063
|
handlers: {
|
|
6588
7064
|
// The SDK may issue either POST, GET, or DELETE. TanStack Start only
|
|
@@ -6692,7 +7168,7 @@ function parsePositiveInt(value, fallback) {
|
|
|
6692
7168
|
if (!Number.isInteger(parsed) || parsed < 1) return fallback;
|
|
6693
7169
|
return parsed;
|
|
6694
7170
|
}
|
|
6695
|
-
const Route$
|
|
7171
|
+
const Route$q = createFileRoute("/api/logs")({
|
|
6696
7172
|
server: {
|
|
6697
7173
|
handlers: {
|
|
6698
7174
|
GET: async ({ request }) => {
|
|
@@ -6768,7 +7244,7 @@ const Route$m = createFileRoute("/api/logs")({
|
|
|
6768
7244
|
}
|
|
6769
7245
|
});
|
|
6770
7246
|
logger.debug("Health endpoint loaded");
|
|
6771
|
-
const Route$
|
|
7247
|
+
const Route$p = createFileRoute("/api/health")({
|
|
6772
7248
|
server: {
|
|
6773
7249
|
handlers: {
|
|
6774
7250
|
GET: () => {
|
|
@@ -6777,22 +7253,235 @@ const Route$l = createFileRoute("/api/health")({
|
|
|
6777
7253
|
}
|
|
6778
7254
|
}
|
|
6779
7255
|
});
|
|
6780
|
-
const
|
|
6781
|
-
|
|
6782
|
-
hasSeenOnboarding: boolean().optional(),
|
|
6783
|
-
slowResponseThresholdSeconds: number().int().min(0).max(MAX_SLOW_RESPONSE_THRESHOLD_SECONDS).optional(),
|
|
6784
|
-
providerTestTimeoutSeconds: number().int().min(1).max(MAX_PROVIDER_TEST_TIMEOUT_SECONDS).optional(),
|
|
6785
|
-
timeDisplayFormat: TimeDisplayFormatSchema.optional()
|
|
6786
|
-
}).strict().refine((v) => Object.keys(v).length > 0, {
|
|
6787
|
-
message: "At least one field must be provided"
|
|
7256
|
+
const GroupsFileSchema = object({
|
|
7257
|
+
groups: array(InspectorGroupSchema)
|
|
6788
7258
|
});
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
7259
|
+
function groupsFilePath() {
|
|
7260
|
+
return join(getDataDir(), "groups.json");
|
|
7261
|
+
}
|
|
7262
|
+
function nowIso() {
|
|
7263
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
7264
|
+
}
|
|
7265
|
+
function stableId(input) {
|
|
7266
|
+
return input.trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
7267
|
+
}
|
|
7268
|
+
function createGroupId() {
|
|
7269
|
+
return `grp_${Date.now().toString(36)}_${randomUUID$1().slice(0, 8)}`;
|
|
7270
|
+
}
|
|
7271
|
+
function createMemberId() {
|
|
7272
|
+
return `mem_${Date.now().toString(36)}_${randomUUID$1().slice(0, 8)}`;
|
|
7273
|
+
}
|
|
7274
|
+
function normalizeGroupId(input) {
|
|
7275
|
+
if (input === void 0) return createGroupId();
|
|
7276
|
+
const normalized = stableId(input);
|
|
7277
|
+
return normalized.length > 0 ? normalized : createGroupId();
|
|
7278
|
+
}
|
|
7279
|
+
function normalizeMemberId(input, sessionId) {
|
|
7280
|
+
if (input === void 0) {
|
|
7281
|
+
const normalizedSession = stableId(sessionId);
|
|
7282
|
+
return normalizedSession.length > 0 ? `mem_${normalizedSession}` : createMemberId();
|
|
7283
|
+
}
|
|
7284
|
+
const normalized = stableId(input);
|
|
7285
|
+
return normalized.length > 0 ? normalized : createMemberId();
|
|
7286
|
+
}
|
|
7287
|
+
function nullableText(value) {
|
|
7288
|
+
if (value === void 0 || value === null) return null;
|
|
7289
|
+
const trimmed = value.trim();
|
|
7290
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
7291
|
+
}
|
|
7292
|
+
function readGroups() {
|
|
7293
|
+
const filePath = groupsFilePath();
|
|
7294
|
+
if (!existsSync(filePath)) return [];
|
|
7295
|
+
try {
|
|
7296
|
+
const parsed = JSON.parse(readFileSync(filePath, "utf8"));
|
|
7297
|
+
const result = GroupsFileSchema.safeParse(parsed);
|
|
7298
|
+
return result.success ? result.data.groups : [];
|
|
7299
|
+
} catch {
|
|
7300
|
+
return [];
|
|
7301
|
+
}
|
|
7302
|
+
}
|
|
7303
|
+
function writeGroups(groups) {
|
|
7304
|
+
const filePath = groupsFilePath();
|
|
7305
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
7306
|
+
writeFileSync(filePath, `${JSON.stringify({ groups }, null, 2)}
|
|
7307
|
+
`, "utf8");
|
|
7308
|
+
}
|
|
7309
|
+
function sortedGroups(groups) {
|
|
7310
|
+
return [...groups].sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
7311
|
+
}
|
|
7312
|
+
function listGroups() {
|
|
7313
|
+
return sortedGroups(readGroups());
|
|
7314
|
+
}
|
|
7315
|
+
function getGroup(groupId) {
|
|
7316
|
+
return readGroups().find((group) => group.id === groupId) ?? null;
|
|
7317
|
+
}
|
|
7318
|
+
function createGroup(input) {
|
|
7319
|
+
const parsed = CreateInspectorGroupInputSchema.parse(input);
|
|
7320
|
+
const groupId = normalizeGroupId(parsed?.groupId);
|
|
7321
|
+
const existing = getGroup(groupId);
|
|
7322
|
+
if (existing !== null) return existing;
|
|
7323
|
+
const timestamp = nowIso();
|
|
7324
|
+
const group = {
|
|
7325
|
+
id: groupId,
|
|
7326
|
+
title: parsed?.title ?? `Inspector Group ${groupId}`,
|
|
7327
|
+
kind: parsed?.kind ?? "evaluation",
|
|
7328
|
+
task: parsed?.task ?? null,
|
|
7329
|
+
project: parsed?.project ?? null,
|
|
7330
|
+
status: parsed?.status ?? "created",
|
|
7331
|
+
tags: parsed?.tags ?? [],
|
|
7332
|
+
metadata: parsed?.metadata ?? {},
|
|
7333
|
+
evidence: null,
|
|
7334
|
+
members: [],
|
|
7335
|
+
createdAt: timestamp,
|
|
7336
|
+
updatedAt: timestamp
|
|
7337
|
+
};
|
|
7338
|
+
writeGroups([...readGroups(), group]);
|
|
7339
|
+
return group;
|
|
7340
|
+
}
|
|
7341
|
+
function updateGroup(groupId, input) {
|
|
7342
|
+
const parsed = UpdateInspectorGroupInputSchema.parse(input);
|
|
7343
|
+
const groups = readGroups();
|
|
7344
|
+
let updatedGroup = null;
|
|
7345
|
+
const updatedAt = nowIso();
|
|
7346
|
+
const updatedGroups = groups.map((group) => {
|
|
7347
|
+
if (group.id !== groupId) return group;
|
|
7348
|
+
updatedGroup = {
|
|
7349
|
+
...group,
|
|
7350
|
+
title: parsed.title ?? group.title,
|
|
7351
|
+
kind: parsed.kind ?? group.kind,
|
|
7352
|
+
task: parsed.task === void 0 ? group.task : parsed.task,
|
|
7353
|
+
project: parsed.project === void 0 ? group.project : parsed.project,
|
|
7354
|
+
status: parsed.status ?? group.status,
|
|
7355
|
+
tags: parsed.tags ?? group.tags,
|
|
7356
|
+
metadata: parsed.metadata === void 0 ? group.metadata : { ...group.metadata, ...parsed.metadata },
|
|
7357
|
+
updatedAt
|
|
7358
|
+
};
|
|
7359
|
+
return updatedGroup;
|
|
7360
|
+
});
|
|
7361
|
+
if (updatedGroup === null) return null;
|
|
7362
|
+
writeGroups(updatedGroups);
|
|
7363
|
+
return updatedGroup;
|
|
7364
|
+
}
|
|
7365
|
+
function matchesExistingMember(member, memberId, sessionId, runId) {
|
|
7366
|
+
if (member.id === memberId) return true;
|
|
7367
|
+
if (member.sessionId !== sessionId) return false;
|
|
7368
|
+
return member.runId === runId;
|
|
7369
|
+
}
|
|
7370
|
+
function upsertMember(group, input, updatedAt) {
|
|
7371
|
+
const parsed = AddInspectorGroupSessionInputSchema.parse(input);
|
|
7372
|
+
const sessionId = parsed.sessionId.trim();
|
|
7373
|
+
const runId = nullableText(parsed.runId);
|
|
7374
|
+
const memberId = normalizeMemberId(parsed.memberId, sessionId);
|
|
7375
|
+
let matched = false;
|
|
7376
|
+
const members = group.members.map((member) => {
|
|
7377
|
+
if (!matchesExistingMember(member, memberId, sessionId, runId)) return member;
|
|
7378
|
+
matched = true;
|
|
7379
|
+
return {
|
|
7380
|
+
...member,
|
|
7381
|
+
sessionId,
|
|
7382
|
+
runId,
|
|
7383
|
+
label: parsed.label === void 0 ? member.label : nullableText(parsed.label),
|
|
7384
|
+
agent: parsed.agent === void 0 ? member.agent : nullableText(parsed.agent),
|
|
7385
|
+
provider: parsed.provider === void 0 ? member.provider : nullableText(parsed.provider),
|
|
7386
|
+
model: parsed.model === void 0 ? member.model : nullableText(parsed.model),
|
|
7387
|
+
status: parsed.status === void 0 ? member.status : parsed.status,
|
|
7388
|
+
metadata: parsed.metadata === void 0 ? member.metadata : { ...member.metadata, ...parsed.metadata },
|
|
7389
|
+
updatedAt
|
|
7390
|
+
};
|
|
7391
|
+
});
|
|
7392
|
+
if (!matched) {
|
|
7393
|
+
members.push({
|
|
7394
|
+
id: memberId,
|
|
7395
|
+
groupId: group.id,
|
|
7396
|
+
sessionId,
|
|
7397
|
+
runId,
|
|
7398
|
+
label: nullableText(parsed.label),
|
|
7399
|
+
agent: nullableText(parsed.agent),
|
|
7400
|
+
provider: nullableText(parsed.provider),
|
|
7401
|
+
model: nullableText(parsed.model),
|
|
7402
|
+
status: parsed.status ?? null,
|
|
7403
|
+
metadata: parsed.metadata ?? {},
|
|
7404
|
+
addedAt: updatedAt,
|
|
7405
|
+
updatedAt
|
|
7406
|
+
});
|
|
7407
|
+
}
|
|
7408
|
+
return { ...group, members, updatedAt };
|
|
7409
|
+
}
|
|
7410
|
+
function addGroupSession(groupId, input) {
|
|
7411
|
+
const groups = readGroups();
|
|
7412
|
+
let updatedGroup = null;
|
|
7413
|
+
const updatedAt = nowIso();
|
|
7414
|
+
const updatedGroups = groups.map((group) => {
|
|
7415
|
+
if (group.id !== groupId) return group;
|
|
7416
|
+
updatedGroup = upsertMember(group, input, updatedAt);
|
|
7417
|
+
return updatedGroup;
|
|
7418
|
+
});
|
|
7419
|
+
if (updatedGroup === null) return null;
|
|
7420
|
+
writeGroups(updatedGroups);
|
|
7421
|
+
return updatedGroup;
|
|
7422
|
+
}
|
|
7423
|
+
function updateGroupEvidence(groupId, evidence) {
|
|
7424
|
+
const groups = readGroups();
|
|
7425
|
+
let updatedGroup = null;
|
|
7426
|
+
const updatedGroups = groups.map((group) => {
|
|
7427
|
+
if (group.id !== groupId) return group;
|
|
7428
|
+
updatedGroup = {
|
|
7429
|
+
...group,
|
|
7430
|
+
evidence,
|
|
7431
|
+
updatedAt: evidence.exportedAt
|
|
7432
|
+
};
|
|
7433
|
+
return updatedGroup;
|
|
7434
|
+
});
|
|
7435
|
+
if (updatedGroup === null) return null;
|
|
7436
|
+
writeGroups(updatedGroups);
|
|
7437
|
+
return updatedGroup;
|
|
7438
|
+
}
|
|
7439
|
+
async function readJsonBody$5(request) {
|
|
7440
|
+
try {
|
|
7441
|
+
const raw = await request.text();
|
|
7442
|
+
if (raw.trim().length === 0) return { ok: true, value: void 0 };
|
|
7443
|
+
return { ok: true, value: JSON.parse(raw) };
|
|
7444
|
+
} catch {
|
|
7445
|
+
return { ok: false };
|
|
7446
|
+
}
|
|
7447
|
+
}
|
|
7448
|
+
const Route$o = createFileRoute("/api/groups")({
|
|
7449
|
+
server: {
|
|
7450
|
+
handlers: {
|
|
7451
|
+
GET: () => Response.json({ groups: listGroups() }),
|
|
7452
|
+
POST: async ({ request }) => {
|
|
7453
|
+
const body = await readJsonBody$5(request);
|
|
7454
|
+
if (!body.ok) {
|
|
7455
|
+
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
7456
|
+
}
|
|
7457
|
+
const parsed = CreateInspectorGroupInputSchema.safeParse(body.value);
|
|
7458
|
+
if (!parsed.success) {
|
|
7459
|
+
return Response.json(
|
|
7460
|
+
{ error: "Invalid request body", details: parsed.error.format() },
|
|
7461
|
+
{ status: 400 }
|
|
7462
|
+
);
|
|
7463
|
+
}
|
|
7464
|
+
return Response.json(createGroup(parsed.data), { status: 201 });
|
|
7465
|
+
}
|
|
7466
|
+
}
|
|
7467
|
+
}
|
|
7468
|
+
});
|
|
7469
|
+
const RuntimeConfigPatchSchema = object({
|
|
7470
|
+
stripClaudeCodeBillingHeader: boolean().optional(),
|
|
7471
|
+
hasSeenOnboarding: boolean().optional(),
|
|
7472
|
+
slowResponseThresholdSeconds: number().int().min(0).max(MAX_SLOW_RESPONSE_THRESHOLD_SECONDS).optional(),
|
|
7473
|
+
providerTestTimeoutSeconds: number().int().min(1).max(MAX_PROVIDER_TEST_TIMEOUT_SECONDS).optional(),
|
|
7474
|
+
timeDisplayFormat: TimeDisplayFormatSchema.optional()
|
|
7475
|
+
}).strict().refine((v) => Object.keys(v).length > 0, {
|
|
7476
|
+
message: "At least one field must be provided"
|
|
7477
|
+
});
|
|
7478
|
+
const Route$n = createFileRoute("/api/config")({
|
|
7479
|
+
server: {
|
|
7480
|
+
handlers: {
|
|
7481
|
+
GET: () => {
|
|
7482
|
+
return Response.json(getConfig());
|
|
7483
|
+
},
|
|
7484
|
+
PATCH: async ({ request }) => {
|
|
6796
7485
|
let body;
|
|
6797
7486
|
try {
|
|
6798
7487
|
body = await request.json();
|
|
@@ -6815,7 +7504,7 @@ const Route$k = createFileRoute("/api/config")({
|
|
|
6815
7504
|
}
|
|
6816
7505
|
}
|
|
6817
7506
|
});
|
|
6818
|
-
async function readJsonBody$
|
|
7507
|
+
async function readJsonBody$4(request) {
|
|
6819
7508
|
try {
|
|
6820
7509
|
const raw = await request.text();
|
|
6821
7510
|
if (raw.trim().length === 0) return { ok: true, value: {} };
|
|
@@ -6824,7 +7513,7 @@ async function readJsonBody$1(request) {
|
|
|
6824
7513
|
return { ok: false };
|
|
6825
7514
|
}
|
|
6826
7515
|
}
|
|
6827
|
-
const Route$
|
|
7516
|
+
const Route$m = createFileRoute("/api/runs/$runId")({
|
|
6828
7517
|
server: {
|
|
6829
7518
|
handlers: {
|
|
6830
7519
|
GET: ({ params }) => {
|
|
@@ -6835,7 +7524,7 @@ const Route$j = createFileRoute("/api/runs/$runId")({
|
|
|
6835
7524
|
return Response.json(run);
|
|
6836
7525
|
},
|
|
6837
7526
|
PATCH: async ({ params, request }) => {
|
|
6838
|
-
const body = await readJsonBody$
|
|
7527
|
+
const body = await readJsonBody$4(request);
|
|
6839
7528
|
if (!body.ok) {
|
|
6840
7529
|
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
6841
7530
|
}
|
|
@@ -7281,7 +7970,7 @@ function scanExternalProviders() {
|
|
|
7281
7970
|
}
|
|
7282
7971
|
return { providers: filteredProviders, warnings };
|
|
7283
7972
|
}
|
|
7284
|
-
const Route$
|
|
7973
|
+
const Route$l = createFileRoute("/api/providers/scan")({
|
|
7285
7974
|
server: {
|
|
7286
7975
|
handlers: {
|
|
7287
7976
|
GET: () => {
|
|
@@ -7302,7 +7991,7 @@ const Route$i = createFileRoute("/api/providers/scan")({
|
|
|
7302
7991
|
}
|
|
7303
7992
|
});
|
|
7304
7993
|
union([string(), object({ providers: unknown() })]);
|
|
7305
|
-
const Route$
|
|
7994
|
+
const Route$k = createFileRoute("/api/providers/import")({
|
|
7306
7995
|
server: {
|
|
7307
7996
|
handlers: {
|
|
7308
7997
|
POST: async ({ request }) => {
|
|
@@ -7335,7 +8024,7 @@ const Route$h = createFileRoute("/api/providers/import")({
|
|
|
7335
8024
|
}
|
|
7336
8025
|
}
|
|
7337
8026
|
});
|
|
7338
|
-
const Route$
|
|
8027
|
+
const Route$j = createFileRoute("/api/providers/export")({
|
|
7339
8028
|
server: {
|
|
7340
8029
|
handlers: {
|
|
7341
8030
|
GET: ({ request }) => {
|
|
@@ -7368,7 +8057,7 @@ const ProviderUpdateSchema = object({
|
|
|
7368
8057
|
modelMetadata: array(ProviderModelMetadataSchema).optional(),
|
|
7369
8058
|
source: _enum(["company", "personal"]).optional()
|
|
7370
8059
|
});
|
|
7371
|
-
const Route$
|
|
8060
|
+
const Route$i = createFileRoute("/api/providers/$providerId")({
|
|
7372
8061
|
server: {
|
|
7373
8062
|
handlers: {
|
|
7374
8063
|
GET: ({ params, request }) => {
|
|
@@ -7403,7 +8092,7 @@ const Route$f = createFileRoute("/api/providers/$providerId")({
|
|
|
7403
8092
|
}
|
|
7404
8093
|
});
|
|
7405
8094
|
const INITIAL_STREAM_LOG_LIMIT = 100;
|
|
7406
|
-
const Route$
|
|
8095
|
+
const Route$h = createFileRoute("/api/logs/stream")({
|
|
7407
8096
|
server: {
|
|
7408
8097
|
handlers: {
|
|
7409
8098
|
GET: ({ request }) => {
|
|
@@ -7476,7 +8165,7 @@ const Route$e = createFileRoute("/api/logs/stream")({
|
|
|
7476
8165
|
}
|
|
7477
8166
|
}
|
|
7478
8167
|
});
|
|
7479
|
-
const Route$
|
|
8168
|
+
const Route$g = createFileRoute("/api/logs/$id")({
|
|
7480
8169
|
server: {
|
|
7481
8170
|
handlers: {
|
|
7482
8171
|
GET: async ({ params }) => {
|
|
@@ -8013,7 +8702,7 @@ const SearchBodySchema = object({
|
|
|
8013
8702
|
query: string().min(1),
|
|
8014
8703
|
project: string().optional()
|
|
8015
8704
|
});
|
|
8016
|
-
const Route$
|
|
8705
|
+
const Route$f = createFileRoute("/api/knowledge/search")({
|
|
8017
8706
|
server: {
|
|
8018
8707
|
handlers: {
|
|
8019
8708
|
GET: async ({ request }) => {
|
|
@@ -8035,7 +8724,7 @@ const Route$c = createFileRoute("/api/knowledge/search")({
|
|
|
8035
8724
|
}
|
|
8036
8725
|
}
|
|
8037
8726
|
});
|
|
8038
|
-
const Route$
|
|
8727
|
+
const Route$e = createFileRoute("/api/knowledge/project-context")({
|
|
8039
8728
|
server: {
|
|
8040
8729
|
handlers: {
|
|
8041
8730
|
GET: async ({ request }) => {
|
|
@@ -8117,14 +8806,54 @@ function updateCandidateDraft(id, updates) {
|
|
|
8117
8806
|
candidates.set(id, updated);
|
|
8118
8807
|
return updated;
|
|
8119
8808
|
}
|
|
8120
|
-
const Route$
|
|
8809
|
+
const Route$d = createFileRoute("/api/knowledge/candidates")({
|
|
8121
8810
|
server: {
|
|
8122
8811
|
handlers: {
|
|
8123
8812
|
GET: () => Response.json({ candidates: listCandidates() })
|
|
8124
8813
|
}
|
|
8125
8814
|
}
|
|
8126
8815
|
});
|
|
8127
|
-
|
|
8816
|
+
async function readJsonBody$3(request) {
|
|
8817
|
+
try {
|
|
8818
|
+
const raw = await request.text();
|
|
8819
|
+
if (raw.trim().length === 0) return { ok: true, value: {} };
|
|
8820
|
+
return { ok: true, value: JSON.parse(raw) };
|
|
8821
|
+
} catch {
|
|
8822
|
+
return { ok: false };
|
|
8823
|
+
}
|
|
8824
|
+
}
|
|
8825
|
+
const Route$c = createFileRoute("/api/groups/$groupId")({
|
|
8826
|
+
server: {
|
|
8827
|
+
handlers: {
|
|
8828
|
+
GET: ({ params }) => {
|
|
8829
|
+
const group = getGroup(params.groupId);
|
|
8830
|
+
if (group === null) {
|
|
8831
|
+
return Response.json({ error: "Group not found" }, { status: 404 });
|
|
8832
|
+
}
|
|
8833
|
+
return Response.json(group);
|
|
8834
|
+
},
|
|
8835
|
+
PATCH: async ({ params, request }) => {
|
|
8836
|
+
const body = await readJsonBody$3(request);
|
|
8837
|
+
if (!body.ok) {
|
|
8838
|
+
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
8839
|
+
}
|
|
8840
|
+
const parsed = UpdateInspectorGroupInputSchema.safeParse(body.value);
|
|
8841
|
+
if (!parsed.success) {
|
|
8842
|
+
return Response.json(
|
|
8843
|
+
{ error: "Invalid request body", details: parsed.error.format() },
|
|
8844
|
+
{ status: 400 }
|
|
8845
|
+
);
|
|
8846
|
+
}
|
|
8847
|
+
const updated = updateGroup(params.groupId, parsed.data);
|
|
8848
|
+
if (updated === null) {
|
|
8849
|
+
return Response.json({ error: "Group not found" }, { status: 404 });
|
|
8850
|
+
}
|
|
8851
|
+
return Response.json(updated);
|
|
8852
|
+
}
|
|
8853
|
+
}
|
|
8854
|
+
}
|
|
8855
|
+
});
|
|
8856
|
+
const Route$b = createFileRoute("/api/config/paths")({
|
|
8128
8857
|
server: {
|
|
8129
8858
|
handlers: {
|
|
8130
8859
|
GET: () => {
|
|
@@ -8391,6 +9120,11 @@ function logDetails(log) {
|
|
|
8391
9120
|
`streaming=${log.isStreaming ? "yes" : "no"}`,
|
|
8392
9121
|
`latencyMs=${formatNullable(log.latencyMs)}`
|
|
8393
9122
|
];
|
|
9123
|
+
if (log.isStreaming) {
|
|
9124
|
+
parts.push(`firstChunkMs=${formatNullable(log.firstChunkMs ?? null)}`);
|
|
9125
|
+
parts.push(`totalStreamMs=${formatNullable(log.totalStreamMs ?? null)}`);
|
|
9126
|
+
parts.push(`tokensPerSecond=${formatNullable(log.tokensPerSecond ?? null)}`);
|
|
9127
|
+
}
|
|
8394
9128
|
if (log.error !== null) {
|
|
8395
9129
|
parts.push(`error=${log.error}`);
|
|
8396
9130
|
}
|
|
@@ -8502,7 +9236,7 @@ function timelineMarkdown(timeline) {
|
|
|
8502
9236
|
})
|
|
8503
9237
|
];
|
|
8504
9238
|
}
|
|
8505
|
-
function buildJenkinsReport(input) {
|
|
9239
|
+
function buildJenkinsReport$1(input) {
|
|
8506
9240
|
const status = reportStatus(input.classification);
|
|
8507
9241
|
const session = input.session;
|
|
8508
9242
|
const summary = `[${status}] ${input.classification.summary}`;
|
|
@@ -8550,7 +9284,7 @@ function buildJenkinsReport(input) {
|
|
|
8550
9284
|
function analyzeEvidence(input) {
|
|
8551
9285
|
const classification = classifyRunFailure(input.run, input.session);
|
|
8552
9286
|
const timeline = buildRunTimeline(input.run, input.session, input.exportedAt);
|
|
8553
|
-
const jenkinsReport = buildJenkinsReport({
|
|
9287
|
+
const jenkinsReport = buildJenkinsReport$1({
|
|
8554
9288
|
run: input.run,
|
|
8555
9289
|
session: input.session,
|
|
8556
9290
|
timeline,
|
|
@@ -8562,22 +9296,22 @@ function analyzeEvidence(input) {
|
|
|
8562
9296
|
function evidenceDir(runId) {
|
|
8563
9297
|
return join(getDataDir(), "evidence", runId);
|
|
8564
9298
|
}
|
|
8565
|
-
function jsonPath(runId) {
|
|
9299
|
+
function jsonPath$1(runId) {
|
|
8566
9300
|
return join(evidenceDir(runId), "evidence.json");
|
|
8567
9301
|
}
|
|
8568
|
-
function markdownPath(runId) {
|
|
9302
|
+
function markdownPath$1(runId) {
|
|
8569
9303
|
return join(evidenceDir(runId), "evidence.md");
|
|
8570
9304
|
}
|
|
8571
|
-
function htmlPath(runId) {
|
|
9305
|
+
function htmlPath$1(runId) {
|
|
8572
9306
|
return join(evidenceDir(runId), "evidence.html");
|
|
8573
9307
|
}
|
|
8574
9308
|
function formatList(values) {
|
|
8575
9309
|
return values.length > 0 ? values.join(", ") : "n/a";
|
|
8576
9310
|
}
|
|
8577
|
-
function escapeHtml(value) {
|
|
9311
|
+
function escapeHtml$1(value) {
|
|
8578
9312
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
8579
9313
|
}
|
|
8580
|
-
function buildMarkdown(document) {
|
|
9314
|
+
function buildMarkdown$1(document) {
|
|
8581
9315
|
const session = document.session;
|
|
8582
9316
|
const lines = [
|
|
8583
9317
|
`# ${document.run.title}`,
|
|
@@ -8643,12 +9377,13 @@ function buildMarkdown(document) {
|
|
|
8643
9377
|
lines.push("No compact logs were available.", "");
|
|
8644
9378
|
} else {
|
|
8645
9379
|
lines.push(
|
|
8646
|
-
"| ID | Status | Model | Latency | Path | Error |",
|
|
8647
|
-
"| --- | --- | --- | --- | --- | --- |"
|
|
9380
|
+
"| ID | Status | Model | Latency | Stream | Path | Error |",
|
|
9381
|
+
"| --- | --- | --- | --- | --- | --- | --- |"
|
|
8648
9382
|
);
|
|
8649
9383
|
for (const log of session.latestLogs) {
|
|
9384
|
+
const streamTiming = log.isStreaming ? `first=${log.firstChunkMs ?? "n/a"}ms total=${log.totalStreamMs ?? "n/a"}ms tps=${log.tokensPerSecond ?? "n/a"}` : "n/a";
|
|
8650
9385
|
lines.push(
|
|
8651
|
-
`| ${log.id} | ${log.status ?? "n/a"} | ${log.model ?? "n/a"} | ${log.latencyMs ?? "n/a"} | ${log.path} | ${log.hasError ? "yes" : "no"} |`
|
|
9386
|
+
`| ${log.id} | ${log.status ?? "n/a"} | ${log.model ?? "n/a"} | ${log.latencyMs ?? "n/a"} | ${streamTiming} | ${log.path} | ${log.hasError ? "yes" : "no"} |`
|
|
8652
9387
|
);
|
|
8653
9388
|
}
|
|
8654
9389
|
lines.push("");
|
|
@@ -8658,19 +9393,19 @@ function buildMarkdown(document) {
|
|
|
8658
9393
|
return `${lines.join("\n")}
|
|
8659
9394
|
`;
|
|
8660
9395
|
}
|
|
8661
|
-
function buildHtml(markdown, title) {
|
|
9396
|
+
function buildHtml$1(markdown, title) {
|
|
8662
9397
|
return `<!doctype html>
|
|
8663
9398
|
<html lang="en">
|
|
8664
9399
|
<head>
|
|
8665
9400
|
<meta charset="utf-8">
|
|
8666
|
-
<title>${escapeHtml(title)}</title>
|
|
9401
|
+
<title>${escapeHtml$1(title)}</title>
|
|
8667
9402
|
<style>
|
|
8668
9403
|
body { font-family: system-ui, sans-serif; max-width: 960px; margin: 40px auto; line-height: 1.5; }
|
|
8669
9404
|
pre { white-space: pre-wrap; background: #f6f8fa; padding: 16px; border-radius: 8px; }
|
|
8670
9405
|
</style>
|
|
8671
9406
|
</head>
|
|
8672
9407
|
<body>
|
|
8673
|
-
<pre>${escapeHtml(markdown)}</pre>
|
|
9408
|
+
<pre>${escapeHtml$1(markdown)}</pre>
|
|
8674
9409
|
</body>
|
|
8675
9410
|
</html>
|
|
8676
9411
|
`;
|
|
@@ -8683,9 +9418,9 @@ async function exportRunEvidence(run, options, baseUrl) {
|
|
|
8683
9418
|
});
|
|
8684
9419
|
const exportedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8685
9420
|
const evidence = {
|
|
8686
|
-
jsonPath: jsonPath(run.id),
|
|
8687
|
-
markdownPath: markdownPath(run.id),
|
|
8688
|
-
htmlPath: htmlPath(run.id),
|
|
9421
|
+
jsonPath: jsonPath$1(run.id),
|
|
9422
|
+
markdownPath: markdownPath$1(run.id),
|
|
9423
|
+
htmlPath: htmlPath$1(run.id),
|
|
8689
9424
|
exportedAt
|
|
8690
9425
|
};
|
|
8691
9426
|
const documentRun = {
|
|
@@ -8711,7 +9446,7 @@ async function exportRunEvidence(run, options, baseUrl) {
|
|
|
8711
9446
|
classification: analysis.classification,
|
|
8712
9447
|
jenkinsReport: analysis.jenkinsReport
|
|
8713
9448
|
};
|
|
8714
|
-
const markdown = buildMarkdown(document);
|
|
9449
|
+
const markdown = buildMarkdown$1(document);
|
|
8715
9450
|
mkdirSync(evidenceDir(run.id), { recursive: true });
|
|
8716
9451
|
writeFileSync(
|
|
8717
9452
|
evidence.jsonPath,
|
|
@@ -8720,7 +9455,7 @@ async function exportRunEvidence(run, options, baseUrl) {
|
|
|
8720
9455
|
"utf8"
|
|
8721
9456
|
);
|
|
8722
9457
|
writeFileSync(evidence.markdownPath, markdown, "utf8");
|
|
8723
|
-
writeFileSync(evidence.htmlPath, buildHtml(markdown, run.title), "utf8");
|
|
9458
|
+
writeFileSync(evidence.htmlPath, buildHtml$1(markdown, run.title), "utf8");
|
|
8724
9459
|
const updatedRun = updateRunEvidence(run.id, evidence) ?? documentRun;
|
|
8725
9460
|
return { ...document, run: updatedRun };
|
|
8726
9461
|
}
|
|
@@ -8733,7 +9468,7 @@ function readEvidenceMarkdown(run) {
|
|
|
8733
9468
|
return null;
|
|
8734
9469
|
}
|
|
8735
9470
|
}
|
|
8736
|
-
async function readJsonBody(request) {
|
|
9471
|
+
async function readJsonBody$2(request) {
|
|
8737
9472
|
try {
|
|
8738
9473
|
const raw = await request.text();
|
|
8739
9474
|
if (raw.trim().length === 0) return { ok: true, value: void 0 };
|
|
@@ -8742,7 +9477,7 @@ async function readJsonBody(request) {
|
|
|
8742
9477
|
return { ok: false };
|
|
8743
9478
|
}
|
|
8744
9479
|
}
|
|
8745
|
-
const Route$
|
|
9480
|
+
const Route$a = createFileRoute("/api/runs/$runId/evidence")({
|
|
8746
9481
|
server: {
|
|
8747
9482
|
handlers: {
|
|
8748
9483
|
GET: ({ params }) => {
|
|
@@ -8764,7 +9499,7 @@ const Route$8 = createFileRoute("/api/runs/$runId/evidence")({
|
|
|
8764
9499
|
if (run === null) {
|
|
8765
9500
|
return Response.json({ error: "Run not found" }, { status: 404 });
|
|
8766
9501
|
}
|
|
8767
|
-
const body = await readJsonBody(request);
|
|
9502
|
+
const body = await readJsonBody$2(request);
|
|
8768
9503
|
if (!body.ok) {
|
|
8769
9504
|
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
8770
9505
|
}
|
|
@@ -8998,7 +9733,7 @@ async function readResponseText(response) {
|
|
|
8998
9733
|
return `Failed to read response body: ${String(err)}`;
|
|
8999
9734
|
}
|
|
9000
9735
|
}
|
|
9001
|
-
function createErrorResult(error, latencyMs, streaming, responseStatus, debug) {
|
|
9736
|
+
function createErrorResult(error, latencyMs, streaming, responseStatus, debug, streamTiming) {
|
|
9002
9737
|
const { type, details } = classifyError(error, responseStatus);
|
|
9003
9738
|
const result = {
|
|
9004
9739
|
success: false,
|
|
@@ -9011,6 +9746,11 @@ function createErrorResult(error, latencyMs, streaming, responseStatus, debug) {
|
|
|
9011
9746
|
latencyMs,
|
|
9012
9747
|
streaming
|
|
9013
9748
|
};
|
|
9749
|
+
if (streamTiming !== void 0) {
|
|
9750
|
+
result.firstChunkMs = streamTiming.firstChunkMs;
|
|
9751
|
+
result.totalStreamMs = streamTiming.totalStreamMs;
|
|
9752
|
+
result.tokensPerSecond = streamTiming.tokensPerSecond;
|
|
9753
|
+
}
|
|
9014
9754
|
if (debug !== void 0) {
|
|
9015
9755
|
result.debug = debug;
|
|
9016
9756
|
if (debug.requestHeaders !== void 0) {
|
|
@@ -9232,14 +9972,17 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
|
|
|
9232
9972
|
const decoder = new TextDecoder();
|
|
9233
9973
|
const MAX_CHUNKS_SIZE = 10 * 1024 * 1024;
|
|
9234
9974
|
let totalSize = 0;
|
|
9975
|
+
let firstChunkMs = null;
|
|
9235
9976
|
try {
|
|
9236
9977
|
while (true) {
|
|
9237
9978
|
const { done, value } = await reader.read();
|
|
9238
9979
|
if (done) break;
|
|
9980
|
+
if (firstChunkMs === null) firstChunkMs = Date.now() - startTime;
|
|
9239
9981
|
if (totalSize >= MAX_CHUNKS_SIZE) {
|
|
9982
|
+
const totalStreamMs2 = Date.now() - startTime;
|
|
9240
9983
|
return createErrorResult(
|
|
9241
9984
|
"Response too large (exceeded 10MB limit)",
|
|
9242
|
-
|
|
9985
|
+
totalStreamMs2,
|
|
9243
9986
|
true,
|
|
9244
9987
|
response.status,
|
|
9245
9988
|
createTestDebug({
|
|
@@ -9248,7 +9991,8 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
|
|
|
9248
9991
|
requestBody: body,
|
|
9249
9992
|
response,
|
|
9250
9993
|
responseBody: chunks.join("")
|
|
9251
|
-
})
|
|
9994
|
+
}),
|
|
9995
|
+
{ firstChunkMs, totalStreamMs: totalStreamMs2, tokensPerSecond: null }
|
|
9252
9996
|
);
|
|
9253
9997
|
}
|
|
9254
9998
|
const decoded = decoder.decode(value, { stream: true });
|
|
@@ -9260,6 +10004,7 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
|
|
|
9260
10004
|
chunks.push(finalChunk);
|
|
9261
10005
|
}
|
|
9262
10006
|
} catch (readErr) {
|
|
10007
|
+
const totalStreamMs2 = Date.now() - startTime;
|
|
9263
10008
|
const error = readErr instanceof Error && readErr.name === "AbortError" ? readErr : `Stream read error: ${String(readErr)}`;
|
|
9264
10009
|
return createErrorResult(
|
|
9265
10010
|
error,
|
|
@@ -9272,10 +10017,12 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
|
|
|
9272
10017
|
requestBody: body,
|
|
9273
10018
|
response,
|
|
9274
10019
|
responseBody: chunks.join("")
|
|
9275
|
-
})
|
|
10020
|
+
}),
|
|
10021
|
+
{ firstChunkMs, totalStreamMs: totalStreamMs2, tokensPerSecond: null }
|
|
9276
10022
|
);
|
|
9277
10023
|
}
|
|
9278
10024
|
const fullResponse = chunks.join("");
|
|
10025
|
+
const totalStreamMs = Date.now() - startTime;
|
|
9279
10026
|
const safeRequestHeaders = redactHeaders(requestHeaders);
|
|
9280
10027
|
const mockLog = {
|
|
9281
10028
|
id: 0,
|
|
@@ -9336,6 +10083,11 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
|
|
|
9336
10083
|
}
|
|
9337
10084
|
}
|
|
9338
10085
|
}
|
|
10086
|
+
const tokensPerSecond = computeTokensPerSecond({
|
|
10087
|
+
outputTokens,
|
|
10088
|
+
firstChunkMs,
|
|
10089
|
+
totalStreamMs
|
|
10090
|
+
});
|
|
9339
10091
|
return {
|
|
9340
10092
|
success: true,
|
|
9341
10093
|
model: responseModel ?? model,
|
|
@@ -9344,6 +10096,9 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
|
|
|
9344
10096
|
cacheCreationInputTokens,
|
|
9345
10097
|
cacheReadInputTokens,
|
|
9346
10098
|
latencyMs,
|
|
10099
|
+
firstChunkMs,
|
|
10100
|
+
totalStreamMs,
|
|
10101
|
+
tokensPerSecond,
|
|
9347
10102
|
content: content.length > 0 ? content : void 0,
|
|
9348
10103
|
rawResponse: reconstructedJson,
|
|
9349
10104
|
streaming: true,
|
|
@@ -9362,7 +10117,8 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
|
|
|
9362
10117
|
requestBody: body,
|
|
9363
10118
|
response,
|
|
9364
10119
|
responseBody: fullResponse
|
|
9365
|
-
})
|
|
10120
|
+
}),
|
|
10121
|
+
{ firstChunkMs, totalStreamMs, tokensPerSecond: null }
|
|
9366
10122
|
);
|
|
9367
10123
|
}
|
|
9368
10124
|
} catch (err) {
|
|
@@ -9377,7 +10133,7 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
|
|
|
9377
10133
|
clearTimeout(timeoutId);
|
|
9378
10134
|
}
|
|
9379
10135
|
}
|
|
9380
|
-
const Route$
|
|
10136
|
+
const Route$9 = createFileRoute("/api/providers/$providerId/test")({
|
|
9381
10137
|
server: {
|
|
9382
10138
|
handlers: {
|
|
9383
10139
|
POST: async ({ params }) => {
|
|
@@ -9471,7 +10227,7 @@ async function readRegistryJson(response) {
|
|
|
9471
10227
|
return null;
|
|
9472
10228
|
}
|
|
9473
10229
|
}
|
|
9474
|
-
const Route$
|
|
10230
|
+
const Route$8 = createFileRoute("/api/providers/$providerId/model-metadata")({
|
|
9475
10231
|
server: {
|
|
9476
10232
|
handlers: {
|
|
9477
10233
|
POST: async ({ params, request }) => {
|
|
@@ -9561,7 +10317,7 @@ const Route$6 = createFileRoute("/api/providers/$providerId/model-metadata")({
|
|
|
9561
10317
|
const ReplayRequestSchema = object({
|
|
9562
10318
|
modifiedBody: string()
|
|
9563
10319
|
});
|
|
9564
|
-
const Route$
|
|
10320
|
+
const Route$7 = createFileRoute("/api/logs/$id/replay")({
|
|
9565
10321
|
server: {
|
|
9566
10322
|
handlers: {
|
|
9567
10323
|
POST: async ({ params, request }) => {
|
|
@@ -9633,26 +10389,35 @@ const Route$5 = createFileRoute("/api/logs/$id/replay")({
|
|
|
9633
10389
|
error: String(err)
|
|
9634
10390
|
});
|
|
9635
10391
|
}
|
|
9636
|
-
const elapsedMs = Date.now() - startTime;
|
|
9637
10392
|
const isStream = upstreamRes.headers.get(HEADER_CONTENT_TYPE)?.includes(CONTENT_TYPE_EVENT_STREAM) ?? false;
|
|
9638
10393
|
if (isStream) {
|
|
9639
10394
|
const chunks = [];
|
|
9640
10395
|
const decoder = new TextDecoder();
|
|
9641
10396
|
const reader = upstreamRes.body?.getReader();
|
|
10397
|
+
let firstChunkMs = null;
|
|
9642
10398
|
if (reader) {
|
|
9643
10399
|
try {
|
|
9644
10400
|
while (true) {
|
|
9645
10401
|
const { done, value } = await reader.read();
|
|
9646
10402
|
if (done) break;
|
|
10403
|
+
if (firstChunkMs === null) firstChunkMs = Date.now() - startTime;
|
|
9647
10404
|
chunks.push(decoder.decode(value, { stream: true }));
|
|
9648
10405
|
}
|
|
9649
10406
|
} catch {
|
|
9650
10407
|
}
|
|
9651
10408
|
}
|
|
9652
10409
|
const fullResponse = chunks.join("");
|
|
10410
|
+
const elapsedMs = Date.now() - startTime;
|
|
10411
|
+
const totalStreamMs = elapsedMs;
|
|
9653
10412
|
const mockLog = { ...log };
|
|
9654
10413
|
const responseText = formatHandler.extractStream(fullResponse, mockLog, model, false);
|
|
9655
10414
|
const tokens = formatHandler.extractTokens(responseText);
|
|
10415
|
+
const outputTokens = tokens.outputTokens ?? null;
|
|
10416
|
+
const tokensPerSecond = computeTokensPerSecond({
|
|
10417
|
+
outputTokens,
|
|
10418
|
+
firstChunkMs,
|
|
10419
|
+
totalStreamMs
|
|
10420
|
+
});
|
|
9656
10421
|
const savedReplayLog = await addTestLogEntry({
|
|
9657
10422
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9658
10423
|
method: log.method,
|
|
@@ -9663,10 +10428,13 @@ const Route$5 = createFileRoute("/api/logs/$id/replay")({
|
|
|
9663
10428
|
responseStatus: upstreamRes.status,
|
|
9664
10429
|
responseText,
|
|
9665
10430
|
inputTokens: tokens.inputTokens ?? null,
|
|
9666
|
-
outputTokens
|
|
10431
|
+
outputTokens,
|
|
9667
10432
|
cacheCreationInputTokens: tokens.cacheCreationInputTokens ?? null,
|
|
9668
10433
|
cacheReadInputTokens: tokens.cacheReadInputTokens ?? null,
|
|
9669
10434
|
elapsedMs,
|
|
10435
|
+
firstChunkMs,
|
|
10436
|
+
totalStreamMs,
|
|
10437
|
+
tokensPerSecond,
|
|
9670
10438
|
streaming: true,
|
|
9671
10439
|
userAgent: log.userAgent,
|
|
9672
10440
|
origin: log.origin,
|
|
@@ -9691,11 +10459,15 @@ const Route$5 = createFileRoute("/api/logs/$id/replay")({
|
|
|
9691
10459
|
inputTokens: tokens.inputTokens ?? void 0,
|
|
9692
10460
|
outputTokens: tokens.outputTokens ?? void 0,
|
|
9693
10461
|
elapsedMs,
|
|
10462
|
+
firstChunkMs,
|
|
10463
|
+
totalStreamMs,
|
|
10464
|
+
tokensPerSecond,
|
|
9694
10465
|
streaming: true,
|
|
9695
10466
|
replayLogId: savedReplayLog.id
|
|
9696
10467
|
});
|
|
9697
10468
|
} else {
|
|
9698
10469
|
const responseText = await upstreamRes.text();
|
|
10470
|
+
const elapsedMs = Date.now() - startTime;
|
|
9699
10471
|
const tokens = formatHandler.extractTokens(responseText);
|
|
9700
10472
|
const savedReplayLog = await addTestLogEntry({
|
|
9701
10473
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -9711,6 +10483,9 @@ const Route$5 = createFileRoute("/api/logs/$id/replay")({
|
|
|
9711
10483
|
cacheCreationInputTokens: tokens.cacheCreationInputTokens ?? null,
|
|
9712
10484
|
cacheReadInputTokens: tokens.cacheReadInputTokens ?? null,
|
|
9713
10485
|
elapsedMs,
|
|
10486
|
+
firstChunkMs: null,
|
|
10487
|
+
totalStreamMs: null,
|
|
10488
|
+
tokensPerSecond: null,
|
|
9714
10489
|
streaming: false,
|
|
9715
10490
|
userAgent: log.userAgent,
|
|
9716
10491
|
origin: log.origin,
|
|
@@ -9743,7 +10518,7 @@ const Route$5 = createFileRoute("/api/logs/$id/replay")({
|
|
|
9743
10518
|
}
|
|
9744
10519
|
}
|
|
9745
10520
|
});
|
|
9746
|
-
const Route$
|
|
10521
|
+
const Route$6 = createFileRoute("/api/logs/$id/chunks")({
|
|
9747
10522
|
server: {
|
|
9748
10523
|
handlers: {
|
|
9749
10524
|
GET: async ({ params }) => {
|
|
@@ -9778,7 +10553,7 @@ const CandidateUpdateSchema = object({
|
|
|
9778
10553
|
object({
|
|
9779
10554
|
candidate: KnowledgeCandidateSchema
|
|
9780
10555
|
});
|
|
9781
|
-
const Route$
|
|
10556
|
+
const Route$5 = createFileRoute("/api/knowledge/candidates/$candidateId")({
|
|
9782
10557
|
server: {
|
|
9783
10558
|
handlers: {
|
|
9784
10559
|
PATCH: async ({ params, request }) => {
|
|
@@ -9806,6 +10581,372 @@ const Route$3 = createFileRoute("/api/knowledge/candidates/$candidateId")({
|
|
|
9806
10581
|
}
|
|
9807
10582
|
}
|
|
9808
10583
|
});
|
|
10584
|
+
async function readJsonBody$1(request) {
|
|
10585
|
+
try {
|
|
10586
|
+
const raw = await request.text();
|
|
10587
|
+
if (raw.trim().length === 0) return { ok: true, value: {} };
|
|
10588
|
+
return { ok: true, value: JSON.parse(raw) };
|
|
10589
|
+
} catch {
|
|
10590
|
+
return { ok: false };
|
|
10591
|
+
}
|
|
10592
|
+
}
|
|
10593
|
+
const Route$4 = createFileRoute("/api/groups/$groupId/sessions")({
|
|
10594
|
+
server: {
|
|
10595
|
+
handlers: {
|
|
10596
|
+
GET: ({ params }) => {
|
|
10597
|
+
const group = getGroup(params.groupId);
|
|
10598
|
+
if (group === null) {
|
|
10599
|
+
return Response.json({ error: "Group not found" }, { status: 404 });
|
|
10600
|
+
}
|
|
10601
|
+
return Response.json({ groupId: group.id, members: group.members });
|
|
10602
|
+
},
|
|
10603
|
+
POST: async ({ params, request }) => {
|
|
10604
|
+
const body = await readJsonBody$1(request);
|
|
10605
|
+
if (!body.ok) {
|
|
10606
|
+
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
10607
|
+
}
|
|
10608
|
+
const parsed = AddInspectorGroupSessionInputSchema.safeParse(body.value);
|
|
10609
|
+
if (!parsed.success) {
|
|
10610
|
+
return Response.json(
|
|
10611
|
+
{ error: "Invalid request body", details: parsed.error.format() },
|
|
10612
|
+
{ status: 400 }
|
|
10613
|
+
);
|
|
10614
|
+
}
|
|
10615
|
+
const updated = addGroupSession(params.groupId, parsed.data);
|
|
10616
|
+
if (updated === null) {
|
|
10617
|
+
return Response.json({ error: "Group not found" }, { status: 404 });
|
|
10618
|
+
}
|
|
10619
|
+
return Response.json(updated);
|
|
10620
|
+
}
|
|
10621
|
+
}
|
|
10622
|
+
}
|
|
10623
|
+
});
|
|
10624
|
+
function groupEvidenceDir(groupId) {
|
|
10625
|
+
return join(getDataDir(), "evidence", "groups", groupId);
|
|
10626
|
+
}
|
|
10627
|
+
function jsonPath(groupId) {
|
|
10628
|
+
return join(groupEvidenceDir(groupId), "evidence.json");
|
|
10629
|
+
}
|
|
10630
|
+
function markdownPath(groupId) {
|
|
10631
|
+
return join(groupEvidenceDir(groupId), "evidence.md");
|
|
10632
|
+
}
|
|
10633
|
+
function htmlPath(groupId) {
|
|
10634
|
+
return join(groupEvidenceDir(groupId), "evidence.html");
|
|
10635
|
+
}
|
|
10636
|
+
function escapeMarkdownCell(value) {
|
|
10637
|
+
return value.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
10638
|
+
}
|
|
10639
|
+
function escapeHtml(value) {
|
|
10640
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
10641
|
+
}
|
|
10642
|
+
function formatText(value) {
|
|
10643
|
+
if (value === null || value === void 0 || value.length === 0) return "n/a";
|
|
10644
|
+
return value;
|
|
10645
|
+
}
|
|
10646
|
+
function formatNumber(value) {
|
|
10647
|
+
if (value === null || value === void 0) return "n/a";
|
|
10648
|
+
return String(value);
|
|
10649
|
+
}
|
|
10650
|
+
function collectSortedValues(values) {
|
|
10651
|
+
const set = /* @__PURE__ */ new Set();
|
|
10652
|
+
for (const value of values) {
|
|
10653
|
+
if (value !== null && value !== void 0 && value.length > 0) {
|
|
10654
|
+
set.add(value);
|
|
10655
|
+
}
|
|
10656
|
+
}
|
|
10657
|
+
return [...set].sort();
|
|
10658
|
+
}
|
|
10659
|
+
function addTokenUsage(total, session) {
|
|
10660
|
+
if (session === null) return total;
|
|
10661
|
+
return {
|
|
10662
|
+
input: total.input + session.tokenUsage.input,
|
|
10663
|
+
output: total.output + session.tokenUsage.output,
|
|
10664
|
+
cacheCreate: total.cacheCreate + session.tokenUsage.cacheCreate,
|
|
10665
|
+
cacheRead: total.cacheRead + session.tokenUsage.cacheRead,
|
|
10666
|
+
total: total.total + session.tokenUsage.total
|
|
10667
|
+
};
|
|
10668
|
+
}
|
|
10669
|
+
function memberEffectiveStatus(member) {
|
|
10670
|
+
if (member.member.status !== null) return member.member.status;
|
|
10671
|
+
if (member.run !== null) return member.run.status;
|
|
10672
|
+
return member.session?.status ?? "unknown";
|
|
10673
|
+
}
|
|
10674
|
+
function isCompletedMember(member) {
|
|
10675
|
+
const status = memberEffectiveStatus(member);
|
|
10676
|
+
return status === "completed";
|
|
10677
|
+
}
|
|
10678
|
+
function isFailedMember(member) {
|
|
10679
|
+
const status = memberEffectiveStatus(member);
|
|
10680
|
+
return status === "failed" || status === "cancelled";
|
|
10681
|
+
}
|
|
10682
|
+
function isRunningMember(member) {
|
|
10683
|
+
const status = memberEffectiveStatus(member);
|
|
10684
|
+
return status === "running" || status === "active";
|
|
10685
|
+
}
|
|
10686
|
+
function latestLogMetric(session, field) {
|
|
10687
|
+
if (session === null) return null;
|
|
10688
|
+
for (const log of session.latestLogs) {
|
|
10689
|
+
const value = log[field];
|
|
10690
|
+
if (value !== void 0 && value !== null) return value;
|
|
10691
|
+
}
|
|
10692
|
+
return null;
|
|
10693
|
+
}
|
|
10694
|
+
function buildSummary(members) {
|
|
10695
|
+
const tokenUsage = members.reduce(
|
|
10696
|
+
(total, member) => addTokenUsage(total, member.session),
|
|
10697
|
+
{ input: 0, output: 0, cacheCreate: 0, cacheRead: 0, total: 0 }
|
|
10698
|
+
);
|
|
10699
|
+
const sessionsWithData = members.filter((member) => member.session !== null).length;
|
|
10700
|
+
const requestCount = members.reduce(
|
|
10701
|
+
(total, member) => total + (member.session?.requestCount ?? 0),
|
|
10702
|
+
0
|
|
10703
|
+
);
|
|
10704
|
+
const errorCount = members.reduce(
|
|
10705
|
+
(total, member) => total + (member.session?.errorCount ?? 0),
|
|
10706
|
+
0
|
|
10707
|
+
);
|
|
10708
|
+
return {
|
|
10709
|
+
memberCount: members.length,
|
|
10710
|
+
sessionsWithData,
|
|
10711
|
+
missingSessions: members.length - sessionsWithData,
|
|
10712
|
+
requestCount,
|
|
10713
|
+
errorCount,
|
|
10714
|
+
tokenUsage,
|
|
10715
|
+
models: collectSortedValues(
|
|
10716
|
+
members.flatMap((member) => [member.member.model, ...member.session?.models ?? []])
|
|
10717
|
+
),
|
|
10718
|
+
providers: collectSortedValues(
|
|
10719
|
+
members.flatMap((member) => [member.member.provider, ...member.session?.providers ?? []])
|
|
10720
|
+
),
|
|
10721
|
+
completedMembers: members.filter(isCompletedMember).length,
|
|
10722
|
+
failedMembers: members.filter(isFailedMember).length,
|
|
10723
|
+
runningMembers: members.filter(isRunningMember).length
|
|
10724
|
+
};
|
|
10725
|
+
}
|
|
10726
|
+
function buildJenkinsReport(group, summary) {
|
|
10727
|
+
if (summary.failedMembers > 0 || summary.errorCount > 0 || group.status === "failed") {
|
|
10728
|
+
return {
|
|
10729
|
+
status: "FAIL",
|
|
10730
|
+
summary: `[FAIL] ${summary.failedMembers} failed members, ${summary.errorCount} captured errors.`,
|
|
10731
|
+
markdown: `# Jenkins Report: ${group.title}
|
|
10732
|
+
|
|
10733
|
+
Status: FAIL
|
|
10734
|
+
|
|
10735
|
+
${summary.failedMembers} failed members and ${summary.errorCount} captured errors need triage.`
|
|
10736
|
+
};
|
|
10737
|
+
}
|
|
10738
|
+
if (summary.runningMembers > 0 || group.status === "running") {
|
|
10739
|
+
return {
|
|
10740
|
+
status: "RUNNING",
|
|
10741
|
+
summary: `[RUNNING] ${summary.runningMembers} group members are still active.`,
|
|
10742
|
+
markdown: `# Jenkins Report: ${group.title}
|
|
10743
|
+
|
|
10744
|
+
Status: RUNNING
|
|
10745
|
+
|
|
10746
|
+
${summary.runningMembers} group members are still active.`
|
|
10747
|
+
};
|
|
10748
|
+
}
|
|
10749
|
+
if (summary.memberCount > 0 && summary.sessionsWithData > 0 && summary.errorCount === 0 && group.status === "completed") {
|
|
10750
|
+
return {
|
|
10751
|
+
status: "PASS",
|
|
10752
|
+
summary: `[PASS] ${summary.memberCount} group members completed with no captured errors.`,
|
|
10753
|
+
markdown: `# Jenkins Report: ${group.title}
|
|
10754
|
+
|
|
10755
|
+
Status: PASS
|
|
10756
|
+
|
|
10757
|
+
${summary.memberCount} group members completed with no captured errors.`
|
|
10758
|
+
};
|
|
10759
|
+
}
|
|
10760
|
+
return {
|
|
10761
|
+
status: "UNKNOWN",
|
|
10762
|
+
summary: `[UNKNOWN] Group has ${summary.memberCount} members and ${summary.missingSessions} missing sessions.`,
|
|
10763
|
+
markdown: `# Jenkins Report: ${group.title}
|
|
10764
|
+
|
|
10765
|
+
Status: UNKNOWN
|
|
10766
|
+
|
|
10767
|
+
Exported group evidence, but the outcome is not conclusive yet.`
|
|
10768
|
+
};
|
|
10769
|
+
}
|
|
10770
|
+
function buildMemberRows(members) {
|
|
10771
|
+
if (members.length === 0) return ["No sessions have been attached to this group.", ""];
|
|
10772
|
+
const rows = [
|
|
10773
|
+
"| Label | Provider | Model | Session | Run | Status | Requests | Errors | Tokens | First Chunk | Stream Total | TPS | Inspector |",
|
|
10774
|
+
"| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |"
|
|
10775
|
+
];
|
|
10776
|
+
for (const member of members) {
|
|
10777
|
+
const session = member.session;
|
|
10778
|
+
rows.push(
|
|
10779
|
+
[
|
|
10780
|
+
formatText(member.member.label),
|
|
10781
|
+
formatText(member.member.provider ?? session?.providers[0]),
|
|
10782
|
+
formatText(member.member.model ?? session?.lastModel),
|
|
10783
|
+
member.member.sessionId,
|
|
10784
|
+
formatText(member.member.runId),
|
|
10785
|
+
memberEffectiveStatus(member),
|
|
10786
|
+
formatNumber(session?.requestCount),
|
|
10787
|
+
formatNumber(session?.errorCount),
|
|
10788
|
+
formatNumber(session?.tokenUsage.total),
|
|
10789
|
+
formatNumber(latestLogMetric(session, "firstChunkMs")),
|
|
10790
|
+
formatNumber(latestLogMetric(session, "totalStreamMs")),
|
|
10791
|
+
formatNumber(latestLogMetric(session, "tokensPerSecond")),
|
|
10792
|
+
formatText(session?.inspectorUrl)
|
|
10793
|
+
].map(escapeMarkdownCell).join(" | ").replace(/^/, "| ").replace(/$/, " |")
|
|
10794
|
+
);
|
|
10795
|
+
}
|
|
10796
|
+
rows.push("");
|
|
10797
|
+
return rows;
|
|
10798
|
+
}
|
|
10799
|
+
function buildMarkdown(document) {
|
|
10800
|
+
const group = document.group;
|
|
10801
|
+
const summary = document.summary;
|
|
10802
|
+
const lines = [
|
|
10803
|
+
`# ${group.title}`,
|
|
10804
|
+
"",
|
|
10805
|
+
`- Group ID: ${group.id}`,
|
|
10806
|
+
`- Kind: ${group.kind}`,
|
|
10807
|
+
`- Status: ${group.status}`,
|
|
10808
|
+
`- Project: ${group.project ?? "n/a"}`,
|
|
10809
|
+
`- Created: ${group.createdAt}`,
|
|
10810
|
+
`- Members: ${summary.memberCount}`,
|
|
10811
|
+
`- Sessions With Data: ${summary.sessionsWithData}`,
|
|
10812
|
+
`- Missing Sessions: ${summary.missingSessions}`,
|
|
10813
|
+
`- Requests: ${summary.requestCount}`,
|
|
10814
|
+
`- Errors: ${summary.errorCount}`,
|
|
10815
|
+
`- Tokens: ${summary.tokenUsage.total}`,
|
|
10816
|
+
`- Models: ${summary.models.length > 0 ? summary.models.join(", ") : "n/a"}`,
|
|
10817
|
+
`- Providers: ${summary.providers.length > 0 ? summary.providers.join(", ") : "n/a"}`,
|
|
10818
|
+
`- Evidence JSON: ${document.evidence.jsonPath}`,
|
|
10819
|
+
`- Evidence HTML: ${document.evidence.htmlPath}`,
|
|
10820
|
+
""
|
|
10821
|
+
];
|
|
10822
|
+
if (group.task !== null) {
|
|
10823
|
+
lines.push("## Task", "", group.task, "");
|
|
10824
|
+
}
|
|
10825
|
+
lines.push("## Evaluation Matrix", "", ...buildMemberRows(document.members));
|
|
10826
|
+
lines.push("## Jenkins Report", "", document.jenkinsReport.markdown, "");
|
|
10827
|
+
return `${lines.join("\n")}
|
|
10828
|
+
`;
|
|
10829
|
+
}
|
|
10830
|
+
function buildHtml(markdown, title) {
|
|
10831
|
+
return `<!doctype html>
|
|
10832
|
+
<html lang="en">
|
|
10833
|
+
<head>
|
|
10834
|
+
<meta charset="utf-8">
|
|
10835
|
+
<title>${escapeHtml(title)}</title>
|
|
10836
|
+
<style>
|
|
10837
|
+
body { font-family: system-ui, sans-serif; max-width: 1120px; margin: 40px auto; line-height: 1.5; }
|
|
10838
|
+
pre { white-space: pre-wrap; background: #f6f8fa; padding: 16px; border-radius: 8px; }
|
|
10839
|
+
</style>
|
|
10840
|
+
</head>
|
|
10841
|
+
<body>
|
|
10842
|
+
<pre>${escapeHtml(markdown)}</pre>
|
|
10843
|
+
</body>
|
|
10844
|
+
</html>
|
|
10845
|
+
`;
|
|
10846
|
+
}
|
|
10847
|
+
async function buildExportMembers(group, options, baseUrl) {
|
|
10848
|
+
const members = [];
|
|
10849
|
+
for (const member of group.members) {
|
|
10850
|
+
const run = member.runId === null ? null : getRun(member.runId);
|
|
10851
|
+
const session = await getSessionInfo(member.sessionId, {
|
|
10852
|
+
baseUrl,
|
|
10853
|
+
includeHistory: options?.includeHistory,
|
|
10854
|
+
latestLogLimit: options?.latestLogLimit
|
|
10855
|
+
});
|
|
10856
|
+
members.push({ member, run, session });
|
|
10857
|
+
}
|
|
10858
|
+
return members;
|
|
10859
|
+
}
|
|
10860
|
+
async function exportGroupEvidence(group, options, baseUrl) {
|
|
10861
|
+
const members = await buildExportMembers(group, options, baseUrl);
|
|
10862
|
+
const exportedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10863
|
+
const evidence = {
|
|
10864
|
+
jsonPath: jsonPath(group.id),
|
|
10865
|
+
markdownPath: markdownPath(group.id),
|
|
10866
|
+
htmlPath: htmlPath(group.id),
|
|
10867
|
+
exportedAt
|
|
10868
|
+
};
|
|
10869
|
+
const documentGroup = {
|
|
10870
|
+
...group,
|
|
10871
|
+
evidence,
|
|
10872
|
+
updatedAt: exportedAt
|
|
10873
|
+
};
|
|
10874
|
+
const summary = buildSummary(members);
|
|
10875
|
+
const jenkinsReport = buildJenkinsReport(documentGroup, summary);
|
|
10876
|
+
const document = {
|
|
10877
|
+
group: documentGroup,
|
|
10878
|
+
evidence,
|
|
10879
|
+
members,
|
|
10880
|
+
summary,
|
|
10881
|
+
jenkinsReport
|
|
10882
|
+
};
|
|
10883
|
+
const markdown = buildMarkdown(document);
|
|
10884
|
+
mkdirSync(groupEvidenceDir(group.id), { recursive: true });
|
|
10885
|
+
writeFileSync(evidence.jsonPath, `${JSON.stringify(document, null, 2)}
|
|
10886
|
+
`, "utf8");
|
|
10887
|
+
writeFileSync(evidence.markdownPath, markdown, "utf8");
|
|
10888
|
+
writeFileSync(evidence.htmlPath, buildHtml(markdown, group.title), "utf8");
|
|
10889
|
+
const updatedGroup = updateGroupEvidence(group.id, evidence) ?? documentGroup;
|
|
10890
|
+
return { ...document, group: updatedGroup };
|
|
10891
|
+
}
|
|
10892
|
+
function readGroupEvidenceMarkdown(group) {
|
|
10893
|
+
const path2 = group.evidence?.markdownPath;
|
|
10894
|
+
if (path2 === void 0 || !existsSync(path2)) return null;
|
|
10895
|
+
try {
|
|
10896
|
+
return readFileSync(path2, "utf8");
|
|
10897
|
+
} catch {
|
|
10898
|
+
return null;
|
|
10899
|
+
}
|
|
10900
|
+
}
|
|
10901
|
+
async function readJsonBody(request) {
|
|
10902
|
+
try {
|
|
10903
|
+
const raw = await request.text();
|
|
10904
|
+
if (raw.trim().length === 0) return { ok: true, value: void 0 };
|
|
10905
|
+
return { ok: true, value: JSON.parse(raw) };
|
|
10906
|
+
} catch {
|
|
10907
|
+
return { ok: false };
|
|
10908
|
+
}
|
|
10909
|
+
}
|
|
10910
|
+
const Route$3 = createFileRoute("/api/groups/$groupId/evidence")({
|
|
10911
|
+
server: {
|
|
10912
|
+
handlers: {
|
|
10913
|
+
GET: ({ params }) => {
|
|
10914
|
+
const group = getGroup(params.groupId);
|
|
10915
|
+
if (group === null) {
|
|
10916
|
+
return Response.json({ error: "Group not found" }, { status: 404 });
|
|
10917
|
+
}
|
|
10918
|
+
const markdown = readGroupEvidenceMarkdown(group);
|
|
10919
|
+
if (group.evidence === null || markdown === null) {
|
|
10920
|
+
return Response.json(
|
|
10921
|
+
{ error: "Evidence has not been exported for this group" },
|
|
10922
|
+
{ status: 404 }
|
|
10923
|
+
);
|
|
10924
|
+
}
|
|
10925
|
+
return Response.json({ group, evidence: group.evidence, markdown });
|
|
10926
|
+
},
|
|
10927
|
+
POST: async ({ params, request }) => {
|
|
10928
|
+
const group = getGroup(params.groupId);
|
|
10929
|
+
if (group === null) {
|
|
10930
|
+
return Response.json({ error: "Group not found" }, { status: 404 });
|
|
10931
|
+
}
|
|
10932
|
+
const body = await readJsonBody(request);
|
|
10933
|
+
if (!body.ok) {
|
|
10934
|
+
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
10935
|
+
}
|
|
10936
|
+
const parsed = GroupEvidenceExportOptionsSchema.safeParse(body.value);
|
|
10937
|
+
if (!parsed.success) {
|
|
10938
|
+
return Response.json(
|
|
10939
|
+
{ error: "Invalid request body", details: parsed.error.format() },
|
|
10940
|
+
{ status: 400 }
|
|
10941
|
+
);
|
|
10942
|
+
}
|
|
10943
|
+
return Response.json(
|
|
10944
|
+
await exportGroupEvidence(group, parsed.data, new URL(request.url).origin)
|
|
10945
|
+
);
|
|
10946
|
+
}
|
|
10947
|
+
}
|
|
10948
|
+
}
|
|
10949
|
+
});
|
|
9809
10950
|
const ProviderTestErrorTypeSchema = _enum([
|
|
9810
10951
|
"timeout",
|
|
9811
10952
|
"network_unreachable",
|
|
@@ -9846,6 +10987,9 @@ const ProviderTestResultSchema = object({
|
|
|
9846
10987
|
cacheCreationInputTokens: number().optional(),
|
|
9847
10988
|
cacheReadInputTokens: number().optional(),
|
|
9848
10989
|
latencyMs: number().optional(),
|
|
10990
|
+
firstChunkMs: number().nullable().optional(),
|
|
10991
|
+
totalStreamMs: number().nullable().optional(),
|
|
10992
|
+
tokensPerSecond: number().nullable().optional(),
|
|
9849
10993
|
content: array(ProviderTestContentSchema).optional(),
|
|
9850
10994
|
rawResponse: string().optional(),
|
|
9851
10995
|
streaming: boolean().optional(),
|
|
@@ -9915,6 +11059,19 @@ function getResultResponseText(result) {
|
|
|
9915
11059
|
function getResultHeaders(result) {
|
|
9916
11060
|
return result.requestHeaders ?? result.debug?.requestHeaders ?? {};
|
|
9917
11061
|
}
|
|
11062
|
+
function getResultTotalStreamMs(result) {
|
|
11063
|
+
return result.totalStreamMs ?? (result.streaming === true ? result.latencyMs ?? null : null);
|
|
11064
|
+
}
|
|
11065
|
+
function getResultFirstChunkMs(result) {
|
|
11066
|
+
return result.firstChunkMs ?? firstChunkMsFromChunks(result.streamingChunks?.chunks);
|
|
11067
|
+
}
|
|
11068
|
+
function getResultTokensPerSecond(result) {
|
|
11069
|
+
return result.tokensPerSecond ?? computeTokensPerSecond({
|
|
11070
|
+
outputTokens: result.outputTokens,
|
|
11071
|
+
firstChunkMs: getResultFirstChunkMs(result),
|
|
11072
|
+
totalStreamMs: getResultTotalStreamMs(result)
|
|
11073
|
+
});
|
|
11074
|
+
}
|
|
9918
11075
|
async function logModelResults(displayName, providerName, anthropicUrl, openaiUrl, modelResults, captureFullDetails) {
|
|
9919
11076
|
const usageModel = getModelUsageName(displayName, providerName);
|
|
9920
11077
|
if (anthropicUrl !== void 0) {
|
|
@@ -9938,6 +11095,9 @@ async function logModelResults(displayName, providerName, anthropicUrl, openaiUr
|
|
|
9938
11095
|
cacheCreationInputTokens: nonStreamingResult.cacheCreationInputTokens ?? null,
|
|
9939
11096
|
cacheReadInputTokens: nonStreamingResult.cacheReadInputTokens ?? null,
|
|
9940
11097
|
elapsedMs: nonStreamingResult.latencyMs ?? 0,
|
|
11098
|
+
firstChunkMs: null,
|
|
11099
|
+
totalStreamMs: null,
|
|
11100
|
+
tokensPerSecond: null,
|
|
9941
11101
|
streaming: false,
|
|
9942
11102
|
userAgent: "provider-test",
|
|
9943
11103
|
origin: null,
|
|
@@ -9962,7 +11122,10 @@ async function logModelResults(displayName, providerName, anthropicUrl, openaiUr
|
|
|
9962
11122
|
outputTokens: streamingResult.outputTokens ?? null,
|
|
9963
11123
|
cacheCreationInputTokens: streamingResult.cacheCreationInputTokens ?? null,
|
|
9964
11124
|
cacheReadInputTokens: streamingResult.cacheReadInputTokens ?? null,
|
|
9965
|
-
elapsedMs: streamingResult
|
|
11125
|
+
elapsedMs: getResultTotalStreamMs(streamingResult) ?? 0,
|
|
11126
|
+
firstChunkMs: getResultFirstChunkMs(streamingResult),
|
|
11127
|
+
totalStreamMs: getResultTotalStreamMs(streamingResult),
|
|
11128
|
+
tokensPerSecond: getResultTokensPerSecond(streamingResult),
|
|
9966
11129
|
streaming: true,
|
|
9967
11130
|
streamingChunks: captureFullDetails ? streamingResult.streamingChunks : void 0,
|
|
9968
11131
|
userAgent: "provider-test",
|
|
@@ -9995,6 +11158,9 @@ async function logModelResults(displayName, providerName, anthropicUrl, openaiUr
|
|
|
9995
11158
|
cacheCreationInputTokens: null,
|
|
9996
11159
|
cacheReadInputTokens: null,
|
|
9997
11160
|
elapsedMs: nonStreamingResult.latencyMs ?? 0,
|
|
11161
|
+
firstChunkMs: null,
|
|
11162
|
+
totalStreamMs: null,
|
|
11163
|
+
tokensPerSecond: null,
|
|
9998
11164
|
streaming: false,
|
|
9999
11165
|
userAgent: "provider-test",
|
|
10000
11166
|
origin: null,
|
|
@@ -10019,7 +11185,10 @@ async function logModelResults(displayName, providerName, anthropicUrl, openaiUr
|
|
|
10019
11185
|
outputTokens: streamingResult.outputTokens ?? null,
|
|
10020
11186
|
cacheCreationInputTokens: null,
|
|
10021
11187
|
cacheReadInputTokens: null,
|
|
10022
|
-
elapsedMs: streamingResult
|
|
11188
|
+
elapsedMs: getResultTotalStreamMs(streamingResult) ?? 0,
|
|
11189
|
+
firstChunkMs: getResultFirstChunkMs(streamingResult),
|
|
11190
|
+
totalStreamMs: getResultTotalStreamMs(streamingResult),
|
|
11191
|
+
tokensPerSecond: getResultTokensPerSecond(streamingResult),
|
|
10023
11192
|
streaming: true,
|
|
10024
11193
|
streamingChunks: captureFullDetails ? streamingResult.streamingChunks : void 0,
|
|
10025
11194
|
userAgent: "provider-test",
|
|
@@ -10201,146 +11370,166 @@ const Route = createFileRoute("/api/knowledge/candidates/$candidateId/promote")(
|
|
|
10201
11370
|
}
|
|
10202
11371
|
}
|
|
10203
11372
|
});
|
|
10204
|
-
const IndexRoute = Route$
|
|
11373
|
+
const IndexRoute = Route$y.update({
|
|
10205
11374
|
id: "/",
|
|
10206
11375
|
path: "/",
|
|
10207
|
-
getParentRoute: () => Route$
|
|
11376
|
+
getParentRoute: () => Route$z
|
|
10208
11377
|
});
|
|
10209
|
-
const SessionSessionIdRoute = Route$
|
|
11378
|
+
const SessionSessionIdRoute = Route$x.update({
|
|
10210
11379
|
id: "/session/$sessionId",
|
|
10211
11380
|
path: "/session/$sessionId",
|
|
10212
|
-
getParentRoute: () => Route$
|
|
11381
|
+
getParentRoute: () => Route$z
|
|
10213
11382
|
});
|
|
10214
|
-
const ProxySplatRoute = Route$
|
|
11383
|
+
const ProxySplatRoute = Route$w.update({
|
|
10215
11384
|
id: "/proxy/$",
|
|
10216
11385
|
path: "/proxy/$",
|
|
10217
|
-
getParentRoute: () => Route$
|
|
11386
|
+
getParentRoute: () => Route$z
|
|
10218
11387
|
});
|
|
10219
|
-
const ApiSessionsRoute = Route$
|
|
11388
|
+
const ApiSessionsRoute = Route$v.update({
|
|
10220
11389
|
id: "/api/sessions",
|
|
10221
11390
|
path: "/api/sessions",
|
|
10222
|
-
getParentRoute: () => Route$
|
|
11391
|
+
getParentRoute: () => Route$z
|
|
10223
11392
|
});
|
|
10224
|
-
const ApiRunsRoute = Route$
|
|
11393
|
+
const ApiRunsRoute = Route$u.update({
|
|
10225
11394
|
id: "/api/runs",
|
|
10226
11395
|
path: "/api/runs",
|
|
10227
|
-
getParentRoute: () => Route$
|
|
11396
|
+
getParentRoute: () => Route$z
|
|
10228
11397
|
});
|
|
10229
|
-
const ApiProvidersRoute = Route$
|
|
11398
|
+
const ApiProvidersRoute = Route$t.update({
|
|
10230
11399
|
id: "/api/providers",
|
|
10231
11400
|
path: "/api/providers",
|
|
10232
|
-
getParentRoute: () => Route$
|
|
11401
|
+
getParentRoute: () => Route$z
|
|
10233
11402
|
});
|
|
10234
|
-
const ApiModelsRoute = Route$
|
|
11403
|
+
const ApiModelsRoute = Route$s.update({
|
|
10235
11404
|
id: "/api/models",
|
|
10236
11405
|
path: "/api/models",
|
|
10237
|
-
getParentRoute: () => Route$
|
|
11406
|
+
getParentRoute: () => Route$z
|
|
10238
11407
|
});
|
|
10239
|
-
const ApiMcpRoute = Route$
|
|
11408
|
+
const ApiMcpRoute = Route$r.update({
|
|
10240
11409
|
id: "/api/mcp",
|
|
10241
11410
|
path: "/api/mcp",
|
|
10242
|
-
getParentRoute: () => Route$
|
|
11411
|
+
getParentRoute: () => Route$z
|
|
10243
11412
|
});
|
|
10244
|
-
const ApiLogsRoute = Route$
|
|
11413
|
+
const ApiLogsRoute = Route$q.update({
|
|
10245
11414
|
id: "/api/logs",
|
|
10246
11415
|
path: "/api/logs",
|
|
10247
|
-
getParentRoute: () => Route$
|
|
11416
|
+
getParentRoute: () => Route$z
|
|
10248
11417
|
});
|
|
10249
|
-
const ApiHealthRoute = Route$
|
|
11418
|
+
const ApiHealthRoute = Route$p.update({
|
|
10250
11419
|
id: "/api/health",
|
|
10251
11420
|
path: "/api/health",
|
|
10252
|
-
getParentRoute: () => Route$
|
|
11421
|
+
getParentRoute: () => Route$z
|
|
11422
|
+
});
|
|
11423
|
+
const ApiGroupsRoute = Route$o.update({
|
|
11424
|
+
id: "/api/groups",
|
|
11425
|
+
path: "/api/groups",
|
|
11426
|
+
getParentRoute: () => Route$z
|
|
10253
11427
|
});
|
|
10254
|
-
const ApiConfigRoute = Route$
|
|
11428
|
+
const ApiConfigRoute = Route$n.update({
|
|
10255
11429
|
id: "/api/config",
|
|
10256
11430
|
path: "/api/config",
|
|
10257
|
-
getParentRoute: () => Route$
|
|
11431
|
+
getParentRoute: () => Route$z
|
|
10258
11432
|
});
|
|
10259
|
-
const ApiRunsRunIdRoute = Route$
|
|
11433
|
+
const ApiRunsRunIdRoute = Route$m.update({
|
|
10260
11434
|
id: "/$runId",
|
|
10261
11435
|
path: "/$runId",
|
|
10262
11436
|
getParentRoute: () => ApiRunsRoute
|
|
10263
11437
|
});
|
|
10264
|
-
const ApiProvidersScanRoute = Route$
|
|
11438
|
+
const ApiProvidersScanRoute = Route$l.update({
|
|
10265
11439
|
id: "/scan",
|
|
10266
11440
|
path: "/scan",
|
|
10267
11441
|
getParentRoute: () => ApiProvidersRoute
|
|
10268
11442
|
});
|
|
10269
|
-
const ApiProvidersImportRoute = Route$
|
|
11443
|
+
const ApiProvidersImportRoute = Route$k.update({
|
|
10270
11444
|
id: "/import",
|
|
10271
11445
|
path: "/import",
|
|
10272
11446
|
getParentRoute: () => ApiProvidersRoute
|
|
10273
11447
|
});
|
|
10274
|
-
const ApiProvidersExportRoute = Route$
|
|
11448
|
+
const ApiProvidersExportRoute = Route$j.update({
|
|
10275
11449
|
id: "/export",
|
|
10276
11450
|
path: "/export",
|
|
10277
11451
|
getParentRoute: () => ApiProvidersRoute
|
|
10278
11452
|
});
|
|
10279
|
-
const ApiProvidersProviderIdRoute = Route$
|
|
11453
|
+
const ApiProvidersProviderIdRoute = Route$i.update({
|
|
10280
11454
|
id: "/$providerId",
|
|
10281
11455
|
path: "/$providerId",
|
|
10282
11456
|
getParentRoute: () => ApiProvidersRoute
|
|
10283
11457
|
});
|
|
10284
|
-
const ApiLogsStreamRoute = Route$
|
|
11458
|
+
const ApiLogsStreamRoute = Route$h.update({
|
|
10285
11459
|
id: "/stream",
|
|
10286
11460
|
path: "/stream",
|
|
10287
11461
|
getParentRoute: () => ApiLogsRoute
|
|
10288
11462
|
});
|
|
10289
|
-
const ApiLogsIdRoute = Route$
|
|
11463
|
+
const ApiLogsIdRoute = Route$g.update({
|
|
10290
11464
|
id: "/$id",
|
|
10291
11465
|
path: "/$id",
|
|
10292
11466
|
getParentRoute: () => ApiLogsRoute
|
|
10293
11467
|
});
|
|
10294
|
-
const ApiKnowledgeSearchRoute = Route$
|
|
11468
|
+
const ApiKnowledgeSearchRoute = Route$f.update({
|
|
10295
11469
|
id: "/api/knowledge/search",
|
|
10296
11470
|
path: "/api/knowledge/search",
|
|
10297
|
-
getParentRoute: () => Route$
|
|
11471
|
+
getParentRoute: () => Route$z
|
|
10298
11472
|
});
|
|
10299
|
-
const ApiKnowledgeProjectContextRoute = Route$
|
|
11473
|
+
const ApiKnowledgeProjectContextRoute = Route$e.update({
|
|
10300
11474
|
id: "/api/knowledge/project-context",
|
|
10301
11475
|
path: "/api/knowledge/project-context",
|
|
10302
|
-
getParentRoute: () => Route$
|
|
11476
|
+
getParentRoute: () => Route$z
|
|
10303
11477
|
});
|
|
10304
|
-
const ApiKnowledgeCandidatesRoute = Route$
|
|
11478
|
+
const ApiKnowledgeCandidatesRoute = Route$d.update({
|
|
10305
11479
|
id: "/api/knowledge/candidates",
|
|
10306
11480
|
path: "/api/knowledge/candidates",
|
|
10307
|
-
getParentRoute: () => Route$
|
|
11481
|
+
getParentRoute: () => Route$z
|
|
11482
|
+
});
|
|
11483
|
+
const ApiGroupsGroupIdRoute = Route$c.update({
|
|
11484
|
+
id: "/$groupId",
|
|
11485
|
+
path: "/$groupId",
|
|
11486
|
+
getParentRoute: () => ApiGroupsRoute
|
|
10308
11487
|
});
|
|
10309
|
-
const ApiConfigPathsRoute = Route$
|
|
11488
|
+
const ApiConfigPathsRoute = Route$b.update({
|
|
10310
11489
|
id: "/paths",
|
|
10311
11490
|
path: "/paths",
|
|
10312
11491
|
getParentRoute: () => ApiConfigRoute
|
|
10313
11492
|
});
|
|
10314
|
-
const ApiRunsRunIdEvidenceRoute = Route$
|
|
11493
|
+
const ApiRunsRunIdEvidenceRoute = Route$a.update({
|
|
10315
11494
|
id: "/evidence",
|
|
10316
11495
|
path: "/evidence",
|
|
10317
11496
|
getParentRoute: () => ApiRunsRunIdRoute
|
|
10318
11497
|
});
|
|
10319
|
-
const ApiProvidersProviderIdTestRoute = Route$
|
|
11498
|
+
const ApiProvidersProviderIdTestRoute = Route$9.update({
|
|
10320
11499
|
id: "/test",
|
|
10321
11500
|
path: "/test",
|
|
10322
11501
|
getParentRoute: () => ApiProvidersProviderIdRoute
|
|
10323
11502
|
});
|
|
10324
|
-
const ApiProvidersProviderIdModelMetadataRoute = Route$
|
|
11503
|
+
const ApiProvidersProviderIdModelMetadataRoute = Route$8.update({
|
|
10325
11504
|
id: "/model-metadata",
|
|
10326
11505
|
path: "/model-metadata",
|
|
10327
11506
|
getParentRoute: () => ApiProvidersProviderIdRoute
|
|
10328
11507
|
});
|
|
10329
|
-
const ApiLogsIdReplayRoute = Route$
|
|
11508
|
+
const ApiLogsIdReplayRoute = Route$7.update({
|
|
10330
11509
|
id: "/replay",
|
|
10331
11510
|
path: "/replay",
|
|
10332
11511
|
getParentRoute: () => ApiLogsIdRoute
|
|
10333
11512
|
});
|
|
10334
|
-
const ApiLogsIdChunksRoute = Route$
|
|
11513
|
+
const ApiLogsIdChunksRoute = Route$6.update({
|
|
10335
11514
|
id: "/chunks",
|
|
10336
11515
|
path: "/chunks",
|
|
10337
11516
|
getParentRoute: () => ApiLogsIdRoute
|
|
10338
11517
|
});
|
|
10339
|
-
const ApiKnowledgeCandidatesCandidateIdRoute = Route$
|
|
11518
|
+
const ApiKnowledgeCandidatesCandidateIdRoute = Route$5.update({
|
|
10340
11519
|
id: "/$candidateId",
|
|
10341
11520
|
path: "/$candidateId",
|
|
10342
11521
|
getParentRoute: () => ApiKnowledgeCandidatesRoute
|
|
10343
11522
|
});
|
|
11523
|
+
const ApiGroupsGroupIdSessionsRoute = Route$4.update({
|
|
11524
|
+
id: "/sessions",
|
|
11525
|
+
path: "/sessions",
|
|
11526
|
+
getParentRoute: () => ApiGroupsGroupIdRoute
|
|
11527
|
+
});
|
|
11528
|
+
const ApiGroupsGroupIdEvidenceRoute = Route$3.update({
|
|
11529
|
+
id: "/evidence",
|
|
11530
|
+
path: "/evidence",
|
|
11531
|
+
getParentRoute: () => ApiGroupsGroupIdRoute
|
|
11532
|
+
});
|
|
10344
11533
|
const ApiProvidersProviderIdTestLogRoute = Route$2.update({
|
|
10345
11534
|
id: "/log",
|
|
10346
11535
|
path: "/log",
|
|
@@ -10349,7 +11538,7 @@ const ApiProvidersProviderIdTestLogRoute = Route$2.update({
|
|
|
10349
11538
|
const ApiKnowledgeSessionsSessionIdCandidatesRoute = Route$1.update({
|
|
10350
11539
|
id: "/api/knowledge/sessions/$sessionId/candidates",
|
|
10351
11540
|
path: "/api/knowledge/sessions/$sessionId/candidates",
|
|
10352
|
-
getParentRoute: () => Route$
|
|
11541
|
+
getParentRoute: () => Route$z
|
|
10353
11542
|
});
|
|
10354
11543
|
const ApiKnowledgeCandidatesCandidateIdPromoteRoute = Route.update({
|
|
10355
11544
|
id: "/promote",
|
|
@@ -10362,6 +11551,17 @@ const ApiConfigRouteChildren = {
|
|
|
10362
11551
|
const ApiConfigRouteWithChildren = ApiConfigRoute._addFileChildren(
|
|
10363
11552
|
ApiConfigRouteChildren
|
|
10364
11553
|
);
|
|
11554
|
+
const ApiGroupsGroupIdRouteChildren = {
|
|
11555
|
+
ApiGroupsGroupIdEvidenceRoute,
|
|
11556
|
+
ApiGroupsGroupIdSessionsRoute
|
|
11557
|
+
};
|
|
11558
|
+
const ApiGroupsGroupIdRouteWithChildren = ApiGroupsGroupIdRoute._addFileChildren(ApiGroupsGroupIdRouteChildren);
|
|
11559
|
+
const ApiGroupsRouteChildren = {
|
|
11560
|
+
ApiGroupsGroupIdRoute: ApiGroupsGroupIdRouteWithChildren
|
|
11561
|
+
};
|
|
11562
|
+
const ApiGroupsRouteWithChildren = ApiGroupsRoute._addFileChildren(
|
|
11563
|
+
ApiGroupsRouteChildren
|
|
11564
|
+
);
|
|
10365
11565
|
const ApiLogsIdRouteChildren = {
|
|
10366
11566
|
ApiLogsIdChunksRoute,
|
|
10367
11567
|
ApiLogsIdReplayRoute
|
|
@@ -10421,6 +11621,7 @@ const ApiKnowledgeCandidatesRouteWithChildren = ApiKnowledgeCandidatesRoute._add
|
|
|
10421
11621
|
const rootRouteChildren = {
|
|
10422
11622
|
IndexRoute,
|
|
10423
11623
|
ApiConfigRoute: ApiConfigRouteWithChildren,
|
|
11624
|
+
ApiGroupsRoute: ApiGroupsRouteWithChildren,
|
|
10424
11625
|
ApiHealthRoute,
|
|
10425
11626
|
ApiLogsRoute: ApiLogsRouteWithChildren,
|
|
10426
11627
|
ApiMcpRoute,
|
|
@@ -10435,7 +11636,7 @@ const rootRouteChildren = {
|
|
|
10435
11636
|
ApiKnowledgeSearchRoute,
|
|
10436
11637
|
ApiKnowledgeSessionsSessionIdCandidatesRoute
|
|
10437
11638
|
};
|
|
10438
|
-
const routeTree = Route$
|
|
11639
|
+
const routeTree = Route$z._addFileChildren(rootRouteChildren)._addFileTypes();
|
|
10439
11640
|
function getRouter() {
|
|
10440
11641
|
const router2 = createRouter({
|
|
10441
11642
|
routeTree,
|
|
@@ -10455,7 +11656,7 @@ export {
|
|
|
10455
11656
|
MAX_SLOW_RESPONSE_THRESHOLD_SECONDS as M,
|
|
10456
11657
|
OpenAIRequestSchema as O,
|
|
10457
11658
|
ProviderConfigSchema as P,
|
|
10458
|
-
Route$
|
|
11659
|
+
Route$x as R,
|
|
10459
11660
|
TimeDisplayFormatSchema as T,
|
|
10460
11661
|
DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS as a,
|
|
10461
11662
|
DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS as b,
|