@tonyclaw/agent-inspector 2.0.29 → 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-DcqxlgSQ.js → CompareDrawer-BDzfRSt1.js} +1 -1
- package/.output/public/assets/{ProxyViewerContainer-D650kQlv.js → ProxyViewerContainer-NtOD8Ex_.js} +4 -4
- package/.output/public/assets/{ReplayDialog-CBcnPgx1.js → ReplayDialog-p-5TKg75.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-DSgSqCYt.js → RequestAnatomy-G0dV8-D_.js} +1 -1
- package/.output/public/assets/{ResponseView-CjqzBSoF.js → ResponseView-D2wE6lD-.js} +1 -1
- package/.output/public/assets/{StreamingChunkSequence-DdBBKolI.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/{main-B6OLZCp9.js → main-XHHZsOBK.js} +2 -2
- package/.output/server/{_sessionId-CCfKJJ19.mjs → _sessionId-CK9QEhkB.mjs} +3 -3
- package/.output/server/_ssr/{CompareDrawer-uaPI5R6e.mjs → CompareDrawer-BJVPFMIx.mjs} +2 -2
- package/.output/server/_ssr/{ProxyViewerContainer-BV2nIxXy.mjs → ProxyViewerContainer-DhbmJ2zj.mjs} +7 -7
- package/.output/server/_ssr/{ReplayDialog-eE2Hy2Nl.mjs → ReplayDialog-DXRj95Gj.mjs} +3 -3
- package/.output/server/_ssr/{RequestAnatomy-B7vwWo57.mjs → RequestAnatomy-CrYJTXdJ.mjs} +2 -2
- package/.output/server/_ssr/{ResponseView-Bm6Qp8mo.mjs → ResponseView-4ESqSITr.mjs} +2 -2
- package/.output/server/_ssr/{StreamingChunkSequence-CbAJKJQx.mjs → StreamingChunkSequence-Czdko5n_.mjs} +2 -2
- package/.output/server/_ssr/{index-u14_Aj60.mjs → index-bei0I7qL.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-qgeGUp1k.mjs → router-sQh4Gk8J.mjs} +1189 -131
- package/.output/server/_tanstack-start-manifest_v-C0fdSWnA.mjs +4 -0
- package/.output/server/index.mjs +62 -62
- package/README.md +24 -1
- package/package.json +1 -1
- package/src/lib/groupContract.ts +139 -0
- package/src/mcp/server.ts +278 -0
- package/src/mcp/toolHandlers.ts +123 -0
- package/src/proxy/groupEvidenceExporter.ts +341 -0
- package/src/proxy/groupStore.ts +259 -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/.output/public/assets/_sessionId-wctOoGh_.js +0 -1
- package/.output/public/assets/index-BhQGSdhG.js +0 -1
- package/.output/server/_tanstack-start-manifest_v-BrfUXnre.mjs +0 -4
|
@@ -51,7 +51,7 @@ 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
53
|
const appCss = "/assets/index-CwlHPmgL.css";
|
|
54
|
-
const Route$
|
|
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)
|
|
@@ -1085,7 +1085,7 @@ function nonNegativeInteger(value) {
|
|
|
1085
1085
|
if (value === null || !Number.isFinite(value) || value < 0) return 0;
|
|
1086
1086
|
return Math.floor(value);
|
|
1087
1087
|
}
|
|
1088
|
-
function addTokenUsage(total, summary) {
|
|
1088
|
+
function addTokenUsage$1(total, summary) {
|
|
1089
1089
|
const input = nonNegativeInteger(summary.tokens.input);
|
|
1090
1090
|
const output = nonNegativeInteger(summary.tokens.output);
|
|
1091
1091
|
const cacheCreate = nonNegativeInteger(summary.tokens.cacheCreate);
|
|
@@ -1115,7 +1115,7 @@ function buildApiPath(sessionId) {
|
|
|
1115
1115
|
function buildCompactLogsPath(sessionId) {
|
|
1116
1116
|
return buildRelativePath("/api/logs", new URLSearchParams({ compact: "1", sessionId }));
|
|
1117
1117
|
}
|
|
1118
|
-
function collectSortedValues(values) {
|
|
1118
|
+
function collectSortedValues$1(values) {
|
|
1119
1119
|
const set = /* @__PURE__ */ new Set();
|
|
1120
1120
|
for (const value of values) {
|
|
1121
1121
|
if (value !== null && value.length > 0) {
|
|
@@ -1159,7 +1159,7 @@ function buildSessionInfo(input) {
|
|
|
1159
1159
|
const errorCount = Math.max(countErrorLogs(summaries), input.snapshot?.failedRequests ?? 0);
|
|
1160
1160
|
const completedLogCount = countCompletedLogs(summaries);
|
|
1161
1161
|
const tokenUsage = summaries.reduce(
|
|
1162
|
-
(total, summary) => addTokenUsage(total, summary),
|
|
1162
|
+
(total, summary) => addTokenUsage$1(total, summary),
|
|
1163
1163
|
{ input: 0, output: 0, cacheCreate: 0, cacheRead: 0, total: 0 }
|
|
1164
1164
|
);
|
|
1165
1165
|
const requestCount = Math.max(input.snapshot?.requestCount ?? 0, logCount);
|
|
@@ -1197,8 +1197,8 @@ function buildSessionInfo(input) {
|
|
|
1197
1197
|
lastTaskError,
|
|
1198
1198
|
logCount,
|
|
1199
1199
|
errorCount,
|
|
1200
|
-
models: collectSortedValues(summaries.map((summary) => summary.model)),
|
|
1201
|
-
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)),
|
|
1202
1202
|
tokenUsage,
|
|
1203
1203
|
lastLogId: input.snapshot?.lastLogId ?? latestLog?.id ?? null,
|
|
1204
1204
|
lastModel: normalizeString(input.snapshot?.lastModel) ?? latestLog?.model ?? null,
|
|
@@ -4935,7 +4935,7 @@ async function handleProxy(req) {
|
|
|
4935
4935
|
}
|
|
4936
4936
|
return handleStreamingResponse(upstreamRes, req, startTime, upstreamUrl, log, captureFullDetails);
|
|
4937
4937
|
}
|
|
4938
|
-
const Route$
|
|
4938
|
+
const Route$w = createFileRoute("/proxy/$")({
|
|
4939
4939
|
server: {
|
|
4940
4940
|
handlers: {
|
|
4941
4941
|
GET: ({ request }) => handleProxy(request),
|
|
@@ -4956,7 +4956,7 @@ function parsePositiveInt$2(value) {
|
|
|
4956
4956
|
function parseBooleanFlag(value) {
|
|
4957
4957
|
return value === "1" || value === "true";
|
|
4958
4958
|
}
|
|
4959
|
-
const Route$
|
|
4959
|
+
const Route$v = createFileRoute("/api/sessions")({
|
|
4960
4960
|
server: {
|
|
4961
4961
|
handlers: {
|
|
4962
4962
|
GET: async ({ request }) => {
|
|
@@ -5179,10 +5179,10 @@ const RunsFileSchema = object({
|
|
|
5179
5179
|
function runsFilePath() {
|
|
5180
5180
|
return join(getDataDir(), "runs.json");
|
|
5181
5181
|
}
|
|
5182
|
-
function nowIso() {
|
|
5182
|
+
function nowIso$1() {
|
|
5183
5183
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
5184
5184
|
}
|
|
5185
|
-
function stableId(input) {
|
|
5185
|
+
function stableId$1(input) {
|
|
5186
5186
|
return input.trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
5187
5187
|
}
|
|
5188
5188
|
function createRunId() {
|
|
@@ -5190,7 +5190,7 @@ function createRunId() {
|
|
|
5190
5190
|
}
|
|
5191
5191
|
function normalizeRunId(input) {
|
|
5192
5192
|
if (input === void 0) return createRunId();
|
|
5193
|
-
const normalized = stableId(input);
|
|
5193
|
+
const normalized = stableId$1(input);
|
|
5194
5194
|
return normalized.length > 0 ? normalized : createRunId();
|
|
5195
5195
|
}
|
|
5196
5196
|
function normalizeSessionId(input, runId) {
|
|
@@ -5225,7 +5225,7 @@ function createRun(input) {
|
|
|
5225
5225
|
const runId = normalizeRunId(parsed?.runId);
|
|
5226
5226
|
const existing = getRun(runId);
|
|
5227
5227
|
if (existing !== null) return existing;
|
|
5228
|
-
const timestamp = nowIso();
|
|
5228
|
+
const timestamp = nowIso$1();
|
|
5229
5229
|
const sessionId = normalizeSessionId(parsed?.sessionId, runId);
|
|
5230
5230
|
const run = {
|
|
5231
5231
|
id: runId,
|
|
@@ -5264,7 +5264,7 @@ function updateRun(runId, input) {
|
|
|
5264
5264
|
const parsed = UpdateInspectorRunInputSchema.parse(input);
|
|
5265
5265
|
const runs = readRuns();
|
|
5266
5266
|
let updatedRun = null;
|
|
5267
|
-
const updatedAt = nowIso();
|
|
5267
|
+
const updatedAt = nowIso$1();
|
|
5268
5268
|
const updatedRuns = runs.map((run) => {
|
|
5269
5269
|
if (run.id !== runId) return run;
|
|
5270
5270
|
updatedRun = {
|
|
@@ -5351,7 +5351,7 @@ function listRecentFailures(limit) {
|
|
|
5351
5351
|
limit: clampedLimit
|
|
5352
5352
|
};
|
|
5353
5353
|
}
|
|
5354
|
-
async function readJsonBody$
|
|
5354
|
+
async function readJsonBody$6(request) {
|
|
5355
5355
|
try {
|
|
5356
5356
|
const raw = await request.text();
|
|
5357
5357
|
if (raw.trim().length === 0) return { ok: true, value: void 0 };
|
|
@@ -5366,7 +5366,7 @@ function parsePositiveInt$1(value, fallback) {
|
|
|
5366
5366
|
if (!Number.isInteger(parsed) || parsed < 1) return fallback;
|
|
5367
5367
|
return parsed;
|
|
5368
5368
|
}
|
|
5369
|
-
const Route$
|
|
5369
|
+
const Route$u = createFileRoute("/api/runs")({
|
|
5370
5370
|
server: {
|
|
5371
5371
|
handlers: {
|
|
5372
5372
|
GET: ({ request }) => {
|
|
@@ -5381,7 +5381,7 @@ const Route$q = createFileRoute("/api/runs")({
|
|
|
5381
5381
|
return Response.json({ runs: listRuns() });
|
|
5382
5382
|
},
|
|
5383
5383
|
POST: async ({ request }) => {
|
|
5384
|
-
const body = await readJsonBody$
|
|
5384
|
+
const body = await readJsonBody$6(request);
|
|
5385
5385
|
if (!body.ok) {
|
|
5386
5386
|
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
5387
5387
|
}
|
|
@@ -5411,7 +5411,7 @@ const ProviderInputSchema = object({
|
|
|
5411
5411
|
modelMetadata: array(ProviderModelMetadataSchema).optional(),
|
|
5412
5412
|
source: _enum(["company", "personal"]).optional()
|
|
5413
5413
|
});
|
|
5414
|
-
const Route$
|
|
5414
|
+
const Route$t = createFileRoute("/api/providers")({
|
|
5415
5415
|
server: {
|
|
5416
5416
|
handlers: {
|
|
5417
5417
|
GET: ({ request }) => {
|
|
@@ -5445,13 +5445,117 @@ const Route$p = createFileRoute("/api/providers")({
|
|
|
5445
5445
|
}
|
|
5446
5446
|
}
|
|
5447
5447
|
});
|
|
5448
|
-
const Route$
|
|
5448
|
+
const Route$s = createFileRoute("/api/models")({
|
|
5449
5449
|
server: {
|
|
5450
5450
|
handlers: {
|
|
5451
5451
|
GET: () => Response.json(getModels())
|
|
5452
5452
|
}
|
|
5453
5453
|
}
|
|
5454
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
|
+
});
|
|
5455
5559
|
let overridePort = null;
|
|
5456
5560
|
function setCurrentPort(port) {
|
|
5457
5561
|
if (!Number.isInteger(port) || port <= 0 || port > 65535) {
|
|
@@ -5851,6 +5955,85 @@ async function exportEvidenceImpl(callApi2, args) {
|
|
|
5851
5955
|
}
|
|
5852
5956
|
return textJson(parsed.data);
|
|
5853
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
|
+
}
|
|
5854
6037
|
async function listModelsImpl(callApi2) {
|
|
5855
6038
|
const res = await callApi2("/api/models");
|
|
5856
6039
|
if (!res.ok) return toolError(`GET /api/models returned ${res.status}`);
|
|
@@ -6042,6 +6225,9 @@ const LogResourceListResponseSchema = object({
|
|
|
6042
6225
|
const EvidenceReadResponseSchema = object({
|
|
6043
6226
|
markdown: string()
|
|
6044
6227
|
});
|
|
6228
|
+
const GroupEvidenceReadResponseSchema = object({
|
|
6229
|
+
markdown: string()
|
|
6230
|
+
});
|
|
6045
6231
|
function textResource(uri, mimeType, text) {
|
|
6046
6232
|
return {
|
|
6047
6233
|
contents: [{ uri: uri.href, mimeType, text }]
|
|
@@ -6124,6 +6310,61 @@ async function listRunResources() {
|
|
|
6124
6310
|
return listResult([]);
|
|
6125
6311
|
}
|
|
6126
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
|
+
}
|
|
6127
6368
|
async function listEvidenceResources() {
|
|
6128
6369
|
try {
|
|
6129
6370
|
const response = await callApi("/api/runs");
|
|
@@ -6296,6 +6537,77 @@ function registerTools(server) {
|
|
|
6296
6537
|
},
|
|
6297
6538
|
(args) => safeCall(() => getRecentFailuresImpl(callApi, args))
|
|
6298
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
|
+
);
|
|
6299
6611
|
server.registerTool(
|
|
6300
6612
|
"inspector_list_models",
|
|
6301
6613
|
{
|
|
@@ -6503,6 +6815,46 @@ function registerResources(server) {
|
|
|
6503
6815
|
},
|
|
6504
6816
|
(uri) => readApiJsonResource(uri, "/api/runs")
|
|
6505
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
|
+
);
|
|
6506
6858
|
server.registerResource(
|
|
6507
6859
|
"inspector_recent_failures",
|
|
6508
6860
|
"inspector://failures/recent",
|
|
@@ -6555,6 +6907,36 @@ function registerResources(server) {
|
|
|
6555
6907
|
}
|
|
6556
6908
|
}
|
|
6557
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
|
+
);
|
|
6558
6940
|
}
|
|
6559
6941
|
function registerPrompts(server) {
|
|
6560
6942
|
server.registerPrompt(
|
|
@@ -6627,6 +7009,31 @@ The report should include:
|
|
|
6627
7009
|
3. Models/providers used, token totals, request counts, and error counts
|
|
6628
7010
|
4. Failure analysis or success evidence
|
|
6629
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`)
|
|
6630
7037
|
);
|
|
6631
7038
|
server.registerPrompt(
|
|
6632
7039
|
"inspector_extract_repro_steps",
|
|
@@ -6651,7 +7058,7 @@ Return:
|
|
|
6651
7058
|
5. Minimal verification command or UI check`)
|
|
6652
7059
|
);
|
|
6653
7060
|
}
|
|
6654
|
-
const Route$
|
|
7061
|
+
const Route$r = createFileRoute("/api/mcp")({
|
|
6655
7062
|
server: {
|
|
6656
7063
|
handlers: {
|
|
6657
7064
|
// The SDK may issue either POST, GET, or DELETE. TanStack Start only
|
|
@@ -6761,7 +7168,7 @@ function parsePositiveInt(value, fallback) {
|
|
|
6761
7168
|
if (!Number.isInteger(parsed) || parsed < 1) return fallback;
|
|
6762
7169
|
return parsed;
|
|
6763
7170
|
}
|
|
6764
|
-
const Route$
|
|
7171
|
+
const Route$q = createFileRoute("/api/logs")({
|
|
6765
7172
|
server: {
|
|
6766
7173
|
handlers: {
|
|
6767
7174
|
GET: async ({ request }) => {
|
|
@@ -6837,7 +7244,7 @@ const Route$m = createFileRoute("/api/logs")({
|
|
|
6837
7244
|
}
|
|
6838
7245
|
});
|
|
6839
7246
|
logger.debug("Health endpoint loaded");
|
|
6840
|
-
const Route$
|
|
7247
|
+
const Route$p = createFileRoute("/api/health")({
|
|
6841
7248
|
server: {
|
|
6842
7249
|
handlers: {
|
|
6843
7250
|
GET: () => {
|
|
@@ -6846,32 +7253,245 @@ const Route$l = createFileRoute("/api/health")({
|
|
|
6846
7253
|
}
|
|
6847
7254
|
}
|
|
6848
7255
|
});
|
|
6849
|
-
const
|
|
6850
|
-
|
|
6851
|
-
hasSeenOnboarding: boolean().optional(),
|
|
6852
|
-
slowResponseThresholdSeconds: number().int().min(0).max(MAX_SLOW_RESPONSE_THRESHOLD_SECONDS).optional(),
|
|
6853
|
-
providerTestTimeoutSeconds: number().int().min(1).max(MAX_PROVIDER_TEST_TIMEOUT_SECONDS).optional(),
|
|
6854
|
-
timeDisplayFormat: TimeDisplayFormatSchema.optional()
|
|
6855
|
-
}).strict().refine((v) => Object.keys(v).length > 0, {
|
|
6856
|
-
message: "At least one field must be provided"
|
|
7256
|
+
const GroupsFileSchema = object({
|
|
7257
|
+
groups: array(InspectorGroupSchema)
|
|
6857
7258
|
});
|
|
6858
|
-
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
|
|
6867
|
-
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
|
|
6871
|
-
|
|
6872
|
-
|
|
6873
|
-
|
|
6874
|
-
|
|
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 }) => {
|
|
7485
|
+
let body;
|
|
7486
|
+
try {
|
|
7487
|
+
body = await request.json();
|
|
7488
|
+
} catch {
|
|
7489
|
+
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
7490
|
+
}
|
|
7491
|
+
const result = RuntimeConfigPatchSchema.safeParse(body);
|
|
7492
|
+
if (!result.success) {
|
|
7493
|
+
return Response.json(
|
|
7494
|
+
{
|
|
6875
7495
|
error: "Invalid config payload",
|
|
6876
7496
|
issues: result.error.issues
|
|
6877
7497
|
},
|
|
@@ -6884,7 +7504,7 @@ const Route$k = createFileRoute("/api/config")({
|
|
|
6884
7504
|
}
|
|
6885
7505
|
}
|
|
6886
7506
|
});
|
|
6887
|
-
async function readJsonBody$
|
|
7507
|
+
async function readJsonBody$4(request) {
|
|
6888
7508
|
try {
|
|
6889
7509
|
const raw = await request.text();
|
|
6890
7510
|
if (raw.trim().length === 0) return { ok: true, value: {} };
|
|
@@ -6893,7 +7513,7 @@ async function readJsonBody$1(request) {
|
|
|
6893
7513
|
return { ok: false };
|
|
6894
7514
|
}
|
|
6895
7515
|
}
|
|
6896
|
-
const Route$
|
|
7516
|
+
const Route$m = createFileRoute("/api/runs/$runId")({
|
|
6897
7517
|
server: {
|
|
6898
7518
|
handlers: {
|
|
6899
7519
|
GET: ({ params }) => {
|
|
@@ -6904,7 +7524,7 @@ const Route$j = createFileRoute("/api/runs/$runId")({
|
|
|
6904
7524
|
return Response.json(run);
|
|
6905
7525
|
},
|
|
6906
7526
|
PATCH: async ({ params, request }) => {
|
|
6907
|
-
const body = await readJsonBody$
|
|
7527
|
+
const body = await readJsonBody$4(request);
|
|
6908
7528
|
if (!body.ok) {
|
|
6909
7529
|
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
6910
7530
|
}
|
|
@@ -7350,7 +7970,7 @@ function scanExternalProviders() {
|
|
|
7350
7970
|
}
|
|
7351
7971
|
return { providers: filteredProviders, warnings };
|
|
7352
7972
|
}
|
|
7353
|
-
const Route$
|
|
7973
|
+
const Route$l = createFileRoute("/api/providers/scan")({
|
|
7354
7974
|
server: {
|
|
7355
7975
|
handlers: {
|
|
7356
7976
|
GET: () => {
|
|
@@ -7371,7 +7991,7 @@ const Route$i = createFileRoute("/api/providers/scan")({
|
|
|
7371
7991
|
}
|
|
7372
7992
|
});
|
|
7373
7993
|
union([string(), object({ providers: unknown() })]);
|
|
7374
|
-
const Route$
|
|
7994
|
+
const Route$k = createFileRoute("/api/providers/import")({
|
|
7375
7995
|
server: {
|
|
7376
7996
|
handlers: {
|
|
7377
7997
|
POST: async ({ request }) => {
|
|
@@ -7404,7 +8024,7 @@ const Route$h = createFileRoute("/api/providers/import")({
|
|
|
7404
8024
|
}
|
|
7405
8025
|
}
|
|
7406
8026
|
});
|
|
7407
|
-
const Route$
|
|
8027
|
+
const Route$j = createFileRoute("/api/providers/export")({
|
|
7408
8028
|
server: {
|
|
7409
8029
|
handlers: {
|
|
7410
8030
|
GET: ({ request }) => {
|
|
@@ -7437,7 +8057,7 @@ const ProviderUpdateSchema = object({
|
|
|
7437
8057
|
modelMetadata: array(ProviderModelMetadataSchema).optional(),
|
|
7438
8058
|
source: _enum(["company", "personal"]).optional()
|
|
7439
8059
|
});
|
|
7440
|
-
const Route$
|
|
8060
|
+
const Route$i = createFileRoute("/api/providers/$providerId")({
|
|
7441
8061
|
server: {
|
|
7442
8062
|
handlers: {
|
|
7443
8063
|
GET: ({ params, request }) => {
|
|
@@ -7472,7 +8092,7 @@ const Route$f = createFileRoute("/api/providers/$providerId")({
|
|
|
7472
8092
|
}
|
|
7473
8093
|
});
|
|
7474
8094
|
const INITIAL_STREAM_LOG_LIMIT = 100;
|
|
7475
|
-
const Route$
|
|
8095
|
+
const Route$h = createFileRoute("/api/logs/stream")({
|
|
7476
8096
|
server: {
|
|
7477
8097
|
handlers: {
|
|
7478
8098
|
GET: ({ request }) => {
|
|
@@ -7545,7 +8165,7 @@ const Route$e = createFileRoute("/api/logs/stream")({
|
|
|
7545
8165
|
}
|
|
7546
8166
|
}
|
|
7547
8167
|
});
|
|
7548
|
-
const Route$
|
|
8168
|
+
const Route$g = createFileRoute("/api/logs/$id")({
|
|
7549
8169
|
server: {
|
|
7550
8170
|
handlers: {
|
|
7551
8171
|
GET: async ({ params }) => {
|
|
@@ -8082,7 +8702,7 @@ const SearchBodySchema = object({
|
|
|
8082
8702
|
query: string().min(1),
|
|
8083
8703
|
project: string().optional()
|
|
8084
8704
|
});
|
|
8085
|
-
const Route$
|
|
8705
|
+
const Route$f = createFileRoute("/api/knowledge/search")({
|
|
8086
8706
|
server: {
|
|
8087
8707
|
handlers: {
|
|
8088
8708
|
GET: async ({ request }) => {
|
|
@@ -8104,7 +8724,7 @@ const Route$c = createFileRoute("/api/knowledge/search")({
|
|
|
8104
8724
|
}
|
|
8105
8725
|
}
|
|
8106
8726
|
});
|
|
8107
|
-
const Route$
|
|
8727
|
+
const Route$e = createFileRoute("/api/knowledge/project-context")({
|
|
8108
8728
|
server: {
|
|
8109
8729
|
handlers: {
|
|
8110
8730
|
GET: async ({ request }) => {
|
|
@@ -8186,14 +8806,54 @@ function updateCandidateDraft(id, updates) {
|
|
|
8186
8806
|
candidates.set(id, updated);
|
|
8187
8807
|
return updated;
|
|
8188
8808
|
}
|
|
8189
|
-
const Route$
|
|
8809
|
+
const Route$d = createFileRoute("/api/knowledge/candidates")({
|
|
8190
8810
|
server: {
|
|
8191
8811
|
handlers: {
|
|
8192
8812
|
GET: () => Response.json({ candidates: listCandidates() })
|
|
8193
8813
|
}
|
|
8194
8814
|
}
|
|
8195
8815
|
});
|
|
8196
|
-
|
|
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")({
|
|
8197
8857
|
server: {
|
|
8198
8858
|
handlers: {
|
|
8199
8859
|
GET: () => {
|
|
@@ -8576,7 +9236,7 @@ function timelineMarkdown(timeline) {
|
|
|
8576
9236
|
})
|
|
8577
9237
|
];
|
|
8578
9238
|
}
|
|
8579
|
-
function buildJenkinsReport(input) {
|
|
9239
|
+
function buildJenkinsReport$1(input) {
|
|
8580
9240
|
const status = reportStatus(input.classification);
|
|
8581
9241
|
const session = input.session;
|
|
8582
9242
|
const summary = `[${status}] ${input.classification.summary}`;
|
|
@@ -8624,7 +9284,7 @@ function buildJenkinsReport(input) {
|
|
|
8624
9284
|
function analyzeEvidence(input) {
|
|
8625
9285
|
const classification = classifyRunFailure(input.run, input.session);
|
|
8626
9286
|
const timeline = buildRunTimeline(input.run, input.session, input.exportedAt);
|
|
8627
|
-
const jenkinsReport = buildJenkinsReport({
|
|
9287
|
+
const jenkinsReport = buildJenkinsReport$1({
|
|
8628
9288
|
run: input.run,
|
|
8629
9289
|
session: input.session,
|
|
8630
9290
|
timeline,
|
|
@@ -8636,22 +9296,22 @@ function analyzeEvidence(input) {
|
|
|
8636
9296
|
function evidenceDir(runId) {
|
|
8637
9297
|
return join(getDataDir(), "evidence", runId);
|
|
8638
9298
|
}
|
|
8639
|
-
function jsonPath(runId) {
|
|
9299
|
+
function jsonPath$1(runId) {
|
|
8640
9300
|
return join(evidenceDir(runId), "evidence.json");
|
|
8641
9301
|
}
|
|
8642
|
-
function markdownPath(runId) {
|
|
9302
|
+
function markdownPath$1(runId) {
|
|
8643
9303
|
return join(evidenceDir(runId), "evidence.md");
|
|
8644
9304
|
}
|
|
8645
|
-
function htmlPath(runId) {
|
|
9305
|
+
function htmlPath$1(runId) {
|
|
8646
9306
|
return join(evidenceDir(runId), "evidence.html");
|
|
8647
9307
|
}
|
|
8648
9308
|
function formatList(values) {
|
|
8649
9309
|
return values.length > 0 ? values.join(", ") : "n/a";
|
|
8650
9310
|
}
|
|
8651
|
-
function escapeHtml(value) {
|
|
9311
|
+
function escapeHtml$1(value) {
|
|
8652
9312
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
8653
9313
|
}
|
|
8654
|
-
function buildMarkdown(document) {
|
|
9314
|
+
function buildMarkdown$1(document) {
|
|
8655
9315
|
const session = document.session;
|
|
8656
9316
|
const lines = [
|
|
8657
9317
|
`# ${document.run.title}`,
|
|
@@ -8733,19 +9393,19 @@ function buildMarkdown(document) {
|
|
|
8733
9393
|
return `${lines.join("\n")}
|
|
8734
9394
|
`;
|
|
8735
9395
|
}
|
|
8736
|
-
function buildHtml(markdown, title) {
|
|
9396
|
+
function buildHtml$1(markdown, title) {
|
|
8737
9397
|
return `<!doctype html>
|
|
8738
9398
|
<html lang="en">
|
|
8739
9399
|
<head>
|
|
8740
9400
|
<meta charset="utf-8">
|
|
8741
|
-
<title>${escapeHtml(title)}</title>
|
|
9401
|
+
<title>${escapeHtml$1(title)}</title>
|
|
8742
9402
|
<style>
|
|
8743
9403
|
body { font-family: system-ui, sans-serif; max-width: 960px; margin: 40px auto; line-height: 1.5; }
|
|
8744
9404
|
pre { white-space: pre-wrap; background: #f6f8fa; padding: 16px; border-radius: 8px; }
|
|
8745
9405
|
</style>
|
|
8746
9406
|
</head>
|
|
8747
9407
|
<body>
|
|
8748
|
-
<pre>${escapeHtml(markdown)}</pre>
|
|
9408
|
+
<pre>${escapeHtml$1(markdown)}</pre>
|
|
8749
9409
|
</body>
|
|
8750
9410
|
</html>
|
|
8751
9411
|
`;
|
|
@@ -8758,9 +9418,9 @@ async function exportRunEvidence(run, options, baseUrl) {
|
|
|
8758
9418
|
});
|
|
8759
9419
|
const exportedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8760
9420
|
const evidence = {
|
|
8761
|
-
jsonPath: jsonPath(run.id),
|
|
8762
|
-
markdownPath: markdownPath(run.id),
|
|
8763
|
-
htmlPath: htmlPath(run.id),
|
|
9421
|
+
jsonPath: jsonPath$1(run.id),
|
|
9422
|
+
markdownPath: markdownPath$1(run.id),
|
|
9423
|
+
htmlPath: htmlPath$1(run.id),
|
|
8764
9424
|
exportedAt
|
|
8765
9425
|
};
|
|
8766
9426
|
const documentRun = {
|
|
@@ -8786,7 +9446,7 @@ async function exportRunEvidence(run, options, baseUrl) {
|
|
|
8786
9446
|
classification: analysis.classification,
|
|
8787
9447
|
jenkinsReport: analysis.jenkinsReport
|
|
8788
9448
|
};
|
|
8789
|
-
const markdown = buildMarkdown(document);
|
|
9449
|
+
const markdown = buildMarkdown$1(document);
|
|
8790
9450
|
mkdirSync(evidenceDir(run.id), { recursive: true });
|
|
8791
9451
|
writeFileSync(
|
|
8792
9452
|
evidence.jsonPath,
|
|
@@ -8795,7 +9455,7 @@ async function exportRunEvidence(run, options, baseUrl) {
|
|
|
8795
9455
|
"utf8"
|
|
8796
9456
|
);
|
|
8797
9457
|
writeFileSync(evidence.markdownPath, markdown, "utf8");
|
|
8798
|
-
writeFileSync(evidence.htmlPath, buildHtml(markdown, run.title), "utf8");
|
|
9458
|
+
writeFileSync(evidence.htmlPath, buildHtml$1(markdown, run.title), "utf8");
|
|
8799
9459
|
const updatedRun = updateRunEvidence(run.id, evidence) ?? documentRun;
|
|
8800
9460
|
return { ...document, run: updatedRun };
|
|
8801
9461
|
}
|
|
@@ -8808,7 +9468,7 @@ function readEvidenceMarkdown(run) {
|
|
|
8808
9468
|
return null;
|
|
8809
9469
|
}
|
|
8810
9470
|
}
|
|
8811
|
-
async function readJsonBody(request) {
|
|
9471
|
+
async function readJsonBody$2(request) {
|
|
8812
9472
|
try {
|
|
8813
9473
|
const raw = await request.text();
|
|
8814
9474
|
if (raw.trim().length === 0) return { ok: true, value: void 0 };
|
|
@@ -8817,7 +9477,7 @@ async function readJsonBody(request) {
|
|
|
8817
9477
|
return { ok: false };
|
|
8818
9478
|
}
|
|
8819
9479
|
}
|
|
8820
|
-
const Route$
|
|
9480
|
+
const Route$a = createFileRoute("/api/runs/$runId/evidence")({
|
|
8821
9481
|
server: {
|
|
8822
9482
|
handlers: {
|
|
8823
9483
|
GET: ({ params }) => {
|
|
@@ -8839,7 +9499,7 @@ const Route$8 = createFileRoute("/api/runs/$runId/evidence")({
|
|
|
8839
9499
|
if (run === null) {
|
|
8840
9500
|
return Response.json({ error: "Run not found" }, { status: 404 });
|
|
8841
9501
|
}
|
|
8842
|
-
const body = await readJsonBody(request);
|
|
9502
|
+
const body = await readJsonBody$2(request);
|
|
8843
9503
|
if (!body.ok) {
|
|
8844
9504
|
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
8845
9505
|
}
|
|
@@ -9473,7 +10133,7 @@ async function testStreamingEndpoint(baseUrl, provider, path2, model, isOpenAI)
|
|
|
9473
10133
|
clearTimeout(timeoutId);
|
|
9474
10134
|
}
|
|
9475
10135
|
}
|
|
9476
|
-
const Route$
|
|
10136
|
+
const Route$9 = createFileRoute("/api/providers/$providerId/test")({
|
|
9477
10137
|
server: {
|
|
9478
10138
|
handlers: {
|
|
9479
10139
|
POST: async ({ params }) => {
|
|
@@ -9567,7 +10227,7 @@ async function readRegistryJson(response) {
|
|
|
9567
10227
|
return null;
|
|
9568
10228
|
}
|
|
9569
10229
|
}
|
|
9570
|
-
const Route$
|
|
10230
|
+
const Route$8 = createFileRoute("/api/providers/$providerId/model-metadata")({
|
|
9571
10231
|
server: {
|
|
9572
10232
|
handlers: {
|
|
9573
10233
|
POST: async ({ params, request }) => {
|
|
@@ -9657,7 +10317,7 @@ const Route$6 = createFileRoute("/api/providers/$providerId/model-metadata")({
|
|
|
9657
10317
|
const ReplayRequestSchema = object({
|
|
9658
10318
|
modifiedBody: string()
|
|
9659
10319
|
});
|
|
9660
|
-
const Route$
|
|
10320
|
+
const Route$7 = createFileRoute("/api/logs/$id/replay")({
|
|
9661
10321
|
server: {
|
|
9662
10322
|
handlers: {
|
|
9663
10323
|
POST: async ({ params, request }) => {
|
|
@@ -9858,7 +10518,7 @@ const Route$5 = createFileRoute("/api/logs/$id/replay")({
|
|
|
9858
10518
|
}
|
|
9859
10519
|
}
|
|
9860
10520
|
});
|
|
9861
|
-
const Route$
|
|
10521
|
+
const Route$6 = createFileRoute("/api/logs/$id/chunks")({
|
|
9862
10522
|
server: {
|
|
9863
10523
|
handlers: {
|
|
9864
10524
|
GET: async ({ params }) => {
|
|
@@ -9893,7 +10553,7 @@ const CandidateUpdateSchema = object({
|
|
|
9893
10553
|
object({
|
|
9894
10554
|
candidate: KnowledgeCandidateSchema
|
|
9895
10555
|
});
|
|
9896
|
-
const Route$
|
|
10556
|
+
const Route$5 = createFileRoute("/api/knowledge/candidates/$candidateId")({
|
|
9897
10557
|
server: {
|
|
9898
10558
|
handlers: {
|
|
9899
10559
|
PATCH: async ({ params, request }) => {
|
|
@@ -9921,6 +10581,372 @@ const Route$3 = createFileRoute("/api/knowledge/candidates/$candidateId")({
|
|
|
9921
10581
|
}
|
|
9922
10582
|
}
|
|
9923
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
|
+
});
|
|
9924
10950
|
const ProviderTestErrorTypeSchema = _enum([
|
|
9925
10951
|
"timeout",
|
|
9926
10952
|
"network_unreachable",
|
|
@@ -10344,146 +11370,166 @@ const Route = createFileRoute("/api/knowledge/candidates/$candidateId/promote")(
|
|
|
10344
11370
|
}
|
|
10345
11371
|
}
|
|
10346
11372
|
});
|
|
10347
|
-
const IndexRoute = Route$
|
|
11373
|
+
const IndexRoute = Route$y.update({
|
|
10348
11374
|
id: "/",
|
|
10349
11375
|
path: "/",
|
|
10350
|
-
getParentRoute: () => Route$
|
|
11376
|
+
getParentRoute: () => Route$z
|
|
10351
11377
|
});
|
|
10352
|
-
const SessionSessionIdRoute = Route$
|
|
11378
|
+
const SessionSessionIdRoute = Route$x.update({
|
|
10353
11379
|
id: "/session/$sessionId",
|
|
10354
11380
|
path: "/session/$sessionId",
|
|
10355
|
-
getParentRoute: () => Route$
|
|
11381
|
+
getParentRoute: () => Route$z
|
|
10356
11382
|
});
|
|
10357
|
-
const ProxySplatRoute = Route$
|
|
11383
|
+
const ProxySplatRoute = Route$w.update({
|
|
10358
11384
|
id: "/proxy/$",
|
|
10359
11385
|
path: "/proxy/$",
|
|
10360
|
-
getParentRoute: () => Route$
|
|
11386
|
+
getParentRoute: () => Route$z
|
|
10361
11387
|
});
|
|
10362
|
-
const ApiSessionsRoute = Route$
|
|
11388
|
+
const ApiSessionsRoute = Route$v.update({
|
|
10363
11389
|
id: "/api/sessions",
|
|
10364
11390
|
path: "/api/sessions",
|
|
10365
|
-
getParentRoute: () => Route$
|
|
11391
|
+
getParentRoute: () => Route$z
|
|
10366
11392
|
});
|
|
10367
|
-
const ApiRunsRoute = Route$
|
|
11393
|
+
const ApiRunsRoute = Route$u.update({
|
|
10368
11394
|
id: "/api/runs",
|
|
10369
11395
|
path: "/api/runs",
|
|
10370
|
-
getParentRoute: () => Route$
|
|
11396
|
+
getParentRoute: () => Route$z
|
|
10371
11397
|
});
|
|
10372
|
-
const ApiProvidersRoute = Route$
|
|
11398
|
+
const ApiProvidersRoute = Route$t.update({
|
|
10373
11399
|
id: "/api/providers",
|
|
10374
11400
|
path: "/api/providers",
|
|
10375
|
-
getParentRoute: () => Route$
|
|
11401
|
+
getParentRoute: () => Route$z
|
|
10376
11402
|
});
|
|
10377
|
-
const ApiModelsRoute = Route$
|
|
11403
|
+
const ApiModelsRoute = Route$s.update({
|
|
10378
11404
|
id: "/api/models",
|
|
10379
11405
|
path: "/api/models",
|
|
10380
|
-
getParentRoute: () => Route$
|
|
11406
|
+
getParentRoute: () => Route$z
|
|
10381
11407
|
});
|
|
10382
|
-
const ApiMcpRoute = Route$
|
|
11408
|
+
const ApiMcpRoute = Route$r.update({
|
|
10383
11409
|
id: "/api/mcp",
|
|
10384
11410
|
path: "/api/mcp",
|
|
10385
|
-
getParentRoute: () => Route$
|
|
11411
|
+
getParentRoute: () => Route$z
|
|
10386
11412
|
});
|
|
10387
|
-
const ApiLogsRoute = Route$
|
|
11413
|
+
const ApiLogsRoute = Route$q.update({
|
|
10388
11414
|
id: "/api/logs",
|
|
10389
11415
|
path: "/api/logs",
|
|
10390
|
-
getParentRoute: () => Route$
|
|
11416
|
+
getParentRoute: () => Route$z
|
|
10391
11417
|
});
|
|
10392
|
-
const ApiHealthRoute = Route$
|
|
11418
|
+
const ApiHealthRoute = Route$p.update({
|
|
10393
11419
|
id: "/api/health",
|
|
10394
11420
|
path: "/api/health",
|
|
10395
|
-
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
|
|
10396
11427
|
});
|
|
10397
|
-
const ApiConfigRoute = Route$
|
|
11428
|
+
const ApiConfigRoute = Route$n.update({
|
|
10398
11429
|
id: "/api/config",
|
|
10399
11430
|
path: "/api/config",
|
|
10400
|
-
getParentRoute: () => Route$
|
|
11431
|
+
getParentRoute: () => Route$z
|
|
10401
11432
|
});
|
|
10402
|
-
const ApiRunsRunIdRoute = Route$
|
|
11433
|
+
const ApiRunsRunIdRoute = Route$m.update({
|
|
10403
11434
|
id: "/$runId",
|
|
10404
11435
|
path: "/$runId",
|
|
10405
11436
|
getParentRoute: () => ApiRunsRoute
|
|
10406
11437
|
});
|
|
10407
|
-
const ApiProvidersScanRoute = Route$
|
|
11438
|
+
const ApiProvidersScanRoute = Route$l.update({
|
|
10408
11439
|
id: "/scan",
|
|
10409
11440
|
path: "/scan",
|
|
10410
11441
|
getParentRoute: () => ApiProvidersRoute
|
|
10411
11442
|
});
|
|
10412
|
-
const ApiProvidersImportRoute = Route$
|
|
11443
|
+
const ApiProvidersImportRoute = Route$k.update({
|
|
10413
11444
|
id: "/import",
|
|
10414
11445
|
path: "/import",
|
|
10415
11446
|
getParentRoute: () => ApiProvidersRoute
|
|
10416
11447
|
});
|
|
10417
|
-
const ApiProvidersExportRoute = Route$
|
|
11448
|
+
const ApiProvidersExportRoute = Route$j.update({
|
|
10418
11449
|
id: "/export",
|
|
10419
11450
|
path: "/export",
|
|
10420
11451
|
getParentRoute: () => ApiProvidersRoute
|
|
10421
11452
|
});
|
|
10422
|
-
const ApiProvidersProviderIdRoute = Route$
|
|
11453
|
+
const ApiProvidersProviderIdRoute = Route$i.update({
|
|
10423
11454
|
id: "/$providerId",
|
|
10424
11455
|
path: "/$providerId",
|
|
10425
11456
|
getParentRoute: () => ApiProvidersRoute
|
|
10426
11457
|
});
|
|
10427
|
-
const ApiLogsStreamRoute = Route$
|
|
11458
|
+
const ApiLogsStreamRoute = Route$h.update({
|
|
10428
11459
|
id: "/stream",
|
|
10429
11460
|
path: "/stream",
|
|
10430
11461
|
getParentRoute: () => ApiLogsRoute
|
|
10431
11462
|
});
|
|
10432
|
-
const ApiLogsIdRoute = Route$
|
|
11463
|
+
const ApiLogsIdRoute = Route$g.update({
|
|
10433
11464
|
id: "/$id",
|
|
10434
11465
|
path: "/$id",
|
|
10435
11466
|
getParentRoute: () => ApiLogsRoute
|
|
10436
11467
|
});
|
|
10437
|
-
const ApiKnowledgeSearchRoute = Route$
|
|
11468
|
+
const ApiKnowledgeSearchRoute = Route$f.update({
|
|
10438
11469
|
id: "/api/knowledge/search",
|
|
10439
11470
|
path: "/api/knowledge/search",
|
|
10440
|
-
getParentRoute: () => Route$
|
|
11471
|
+
getParentRoute: () => Route$z
|
|
10441
11472
|
});
|
|
10442
|
-
const ApiKnowledgeProjectContextRoute = Route$
|
|
11473
|
+
const ApiKnowledgeProjectContextRoute = Route$e.update({
|
|
10443
11474
|
id: "/api/knowledge/project-context",
|
|
10444
11475
|
path: "/api/knowledge/project-context",
|
|
10445
|
-
getParentRoute: () => Route$
|
|
11476
|
+
getParentRoute: () => Route$z
|
|
10446
11477
|
});
|
|
10447
|
-
const ApiKnowledgeCandidatesRoute = Route$
|
|
11478
|
+
const ApiKnowledgeCandidatesRoute = Route$d.update({
|
|
10448
11479
|
id: "/api/knowledge/candidates",
|
|
10449
11480
|
path: "/api/knowledge/candidates",
|
|
10450
|
-
getParentRoute: () => Route$
|
|
11481
|
+
getParentRoute: () => Route$z
|
|
11482
|
+
});
|
|
11483
|
+
const ApiGroupsGroupIdRoute = Route$c.update({
|
|
11484
|
+
id: "/$groupId",
|
|
11485
|
+
path: "/$groupId",
|
|
11486
|
+
getParentRoute: () => ApiGroupsRoute
|
|
10451
11487
|
});
|
|
10452
|
-
const ApiConfigPathsRoute = Route$
|
|
11488
|
+
const ApiConfigPathsRoute = Route$b.update({
|
|
10453
11489
|
id: "/paths",
|
|
10454
11490
|
path: "/paths",
|
|
10455
11491
|
getParentRoute: () => ApiConfigRoute
|
|
10456
11492
|
});
|
|
10457
|
-
const ApiRunsRunIdEvidenceRoute = Route$
|
|
11493
|
+
const ApiRunsRunIdEvidenceRoute = Route$a.update({
|
|
10458
11494
|
id: "/evidence",
|
|
10459
11495
|
path: "/evidence",
|
|
10460
11496
|
getParentRoute: () => ApiRunsRunIdRoute
|
|
10461
11497
|
});
|
|
10462
|
-
const ApiProvidersProviderIdTestRoute = Route$
|
|
11498
|
+
const ApiProvidersProviderIdTestRoute = Route$9.update({
|
|
10463
11499
|
id: "/test",
|
|
10464
11500
|
path: "/test",
|
|
10465
11501
|
getParentRoute: () => ApiProvidersProviderIdRoute
|
|
10466
11502
|
});
|
|
10467
|
-
const ApiProvidersProviderIdModelMetadataRoute = Route$
|
|
11503
|
+
const ApiProvidersProviderIdModelMetadataRoute = Route$8.update({
|
|
10468
11504
|
id: "/model-metadata",
|
|
10469
11505
|
path: "/model-metadata",
|
|
10470
11506
|
getParentRoute: () => ApiProvidersProviderIdRoute
|
|
10471
11507
|
});
|
|
10472
|
-
const ApiLogsIdReplayRoute = Route$
|
|
11508
|
+
const ApiLogsIdReplayRoute = Route$7.update({
|
|
10473
11509
|
id: "/replay",
|
|
10474
11510
|
path: "/replay",
|
|
10475
11511
|
getParentRoute: () => ApiLogsIdRoute
|
|
10476
11512
|
});
|
|
10477
|
-
const ApiLogsIdChunksRoute = Route$
|
|
11513
|
+
const ApiLogsIdChunksRoute = Route$6.update({
|
|
10478
11514
|
id: "/chunks",
|
|
10479
11515
|
path: "/chunks",
|
|
10480
11516
|
getParentRoute: () => ApiLogsIdRoute
|
|
10481
11517
|
});
|
|
10482
|
-
const ApiKnowledgeCandidatesCandidateIdRoute = Route$
|
|
11518
|
+
const ApiKnowledgeCandidatesCandidateIdRoute = Route$5.update({
|
|
10483
11519
|
id: "/$candidateId",
|
|
10484
11520
|
path: "/$candidateId",
|
|
10485
11521
|
getParentRoute: () => ApiKnowledgeCandidatesRoute
|
|
10486
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
|
+
});
|
|
10487
11533
|
const ApiProvidersProviderIdTestLogRoute = Route$2.update({
|
|
10488
11534
|
id: "/log",
|
|
10489
11535
|
path: "/log",
|
|
@@ -10492,7 +11538,7 @@ const ApiProvidersProviderIdTestLogRoute = Route$2.update({
|
|
|
10492
11538
|
const ApiKnowledgeSessionsSessionIdCandidatesRoute = Route$1.update({
|
|
10493
11539
|
id: "/api/knowledge/sessions/$sessionId/candidates",
|
|
10494
11540
|
path: "/api/knowledge/sessions/$sessionId/candidates",
|
|
10495
|
-
getParentRoute: () => Route$
|
|
11541
|
+
getParentRoute: () => Route$z
|
|
10496
11542
|
});
|
|
10497
11543
|
const ApiKnowledgeCandidatesCandidateIdPromoteRoute = Route.update({
|
|
10498
11544
|
id: "/promote",
|
|
@@ -10505,6 +11551,17 @@ const ApiConfigRouteChildren = {
|
|
|
10505
11551
|
const ApiConfigRouteWithChildren = ApiConfigRoute._addFileChildren(
|
|
10506
11552
|
ApiConfigRouteChildren
|
|
10507
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
|
+
);
|
|
10508
11565
|
const ApiLogsIdRouteChildren = {
|
|
10509
11566
|
ApiLogsIdChunksRoute,
|
|
10510
11567
|
ApiLogsIdReplayRoute
|
|
@@ -10564,6 +11621,7 @@ const ApiKnowledgeCandidatesRouteWithChildren = ApiKnowledgeCandidatesRoute._add
|
|
|
10564
11621
|
const rootRouteChildren = {
|
|
10565
11622
|
IndexRoute,
|
|
10566
11623
|
ApiConfigRoute: ApiConfigRouteWithChildren,
|
|
11624
|
+
ApiGroupsRoute: ApiGroupsRouteWithChildren,
|
|
10567
11625
|
ApiHealthRoute,
|
|
10568
11626
|
ApiLogsRoute: ApiLogsRouteWithChildren,
|
|
10569
11627
|
ApiMcpRoute,
|
|
@@ -10578,7 +11636,7 @@ const rootRouteChildren = {
|
|
|
10578
11636
|
ApiKnowledgeSearchRoute,
|
|
10579
11637
|
ApiKnowledgeSessionsSessionIdCandidatesRoute
|
|
10580
11638
|
};
|
|
10581
|
-
const routeTree = Route$
|
|
11639
|
+
const routeTree = Route$z._addFileChildren(rootRouteChildren)._addFileTypes();
|
|
10582
11640
|
function getRouter() {
|
|
10583
11641
|
const router2 = createRouter({
|
|
10584
11642
|
routeTree,
|
|
@@ -10598,7 +11656,7 @@ export {
|
|
|
10598
11656
|
MAX_SLOW_RESPONSE_THRESHOLD_SECONDS as M,
|
|
10599
11657
|
OpenAIRequestSchema as O,
|
|
10600
11658
|
ProviderConfigSchema as P,
|
|
10601
|
-
Route$
|
|
11659
|
+
Route$x as R,
|
|
10602
11660
|
TimeDisplayFormatSchema as T,
|
|
10603
11661
|
DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS as a,
|
|
10604
11662
|
DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS as b,
|