@tonyclaw/agent-inspector 2.0.26 → 2.0.27
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-DBTFzxG5.js → CompareDrawer-B_p6vmMQ.js} +1 -1
- package/.output/public/assets/{ProxyViewerContainer-ivZk8MgE.js → ProxyViewerContainer-DItqh1EO.js} +4 -4
- package/.output/public/assets/{ReplayDialog-syW2hDNE.js → ReplayDialog-BmprJ6D3.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-BkuRtY9o.js → RequestAnatomy-DqO0_SVJ.js} +1 -1
- package/.output/public/assets/{ResponseView-BwyvEvoE.js → ResponseView-FZbPNdHa.js} +1 -1
- package/.output/public/assets/{StreamingChunkSequence-BY4MbPKg.js → StreamingChunkSequence-BZPzfJWj.js} +1 -1
- package/.output/public/assets/_sessionId-y2ATIp51.js +1 -0
- package/.output/public/assets/index-CQT4higx.js +1 -0
- package/.output/public/assets/{main-DKRDRBdd.js → main-CzItFZlM.js} +2 -2
- package/.output/server/_libs/modelcontextprotocol__server.mjs +228 -0
- package/.output/server/{_sessionId-VDd4N_1B.mjs → _sessionId-DZH8SrEZ.mjs} +3 -3
- package/.output/server/_ssr/{CompareDrawer-BQZlxsOC.mjs → CompareDrawer-L0aE1UV1.mjs} +2 -2
- package/.output/server/_ssr/{ProxyViewerContainer-njY2oQCc.mjs → ProxyViewerContainer-B62RB9ER.mjs} +7 -7
- package/.output/server/_ssr/{ReplayDialog-B8lkdAIh.mjs → ReplayDialog-FVWnpx2C.mjs} +3 -3
- package/.output/server/_ssr/{RequestAnatomy-CwOTfdwS.mjs → RequestAnatomy-DIyqW-Ny.mjs} +2 -2
- package/.output/server/_ssr/{ResponseView-3Iz_mZpd.mjs → ResponseView-BX4mxEZ5.mjs} +2 -2
- package/.output/server/_ssr/{StreamingChunkSequence-hmJcQNW5.mjs → StreamingChunkSequence-Cs3nzOor.mjs} +2 -2
- package/.output/server/_ssr/{index-UuTKM4aC.mjs → index-Dik2Mc3h.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-C7InHrxE.mjs → router-DCPg8ykx.mjs} +1816 -151
- package/.output/server/_tanstack-start-manifest_v-BaoL3JCh.mjs +4 -0
- package/.output/server/index.mjs +57 -57
- package/README.md +55 -1
- package/package.json +1 -1
- package/src/lib/runContract.ts +162 -0
- package/src/mcp/server.ts +554 -2
- package/src/mcp/toolHandlers.ts +154 -0
- package/src/proxy/evidenceAnalysis.ts +522 -0
- package/src/proxy/evidenceExporter.ts +215 -0
- package/src/proxy/logSearch.ts +118 -0
- package/src/proxy/runFailures.ts +100 -0
- package/src/proxy/runStore.ts +159 -0
- package/src/routes/api/logs.ts +16 -0
- package/src/routes/api/runs.$runId.evidence.ts +62 -0
- package/src/routes/api/runs.$runId.ts +50 -0
- package/src/routes/api/runs.ts +58 -0
- package/.output/public/assets/_sessionId-XlPUgIIb.js +0 -1
- package/.output/public/assets/index-By11a28-.js +0 -1
- package/.output/server/_tanstack-start-manifest_v-B6yfnMHA.mjs +0 -4
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { c as createRouter, a as createRootRoute, b as createFileRoute, l as lazyRouteComponent, O as Outlet, H as HeadContent, S as Scripts } from "../_libs/tanstack__react-router.mjs";
|
|
2
2
|
import { j as jsxRuntimeExports } from "../_libs/react.mjs";
|
|
3
3
|
import { S as SWRConfig } from "../_libs/swr.mjs";
|
|
4
|
-
import { existsSync,
|
|
4
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync, renameSync, copyFileSync, unlinkSync, createReadStream, readdirSync, statSync, cpSync, rmSync, createWriteStream } from "node:fs";
|
|
5
5
|
import fs, { mkdir, appendFile, readFile, writeFile, readdir, open, stat, unlink, rename } from "node:fs/promises";
|
|
6
6
|
import { createInterface } from "node:readline";
|
|
7
7
|
import { Buffer } from "node:buffer";
|
|
8
|
-
import path, { join,
|
|
8
|
+
import path, { join, dirname, isAbsolute } from "node:path";
|
|
9
9
|
import { execFile, exec, spawn } from "node:child_process";
|
|
10
10
|
import { fileURLToPath } from "node:url";
|
|
11
11
|
import { C as Conf } from "../_libs/conf.mjs";
|
|
@@ -13,9 +13,9 @@ import { randomUUID } from "crypto";
|
|
|
13
13
|
import { promisify } from "node:util";
|
|
14
14
|
import { Worker } from "node:worker_threads";
|
|
15
15
|
import { randomUUID as randomUUID$1 } from "node:crypto";
|
|
16
|
-
import { M as McpServer, W as WebStandardStreamableHTTPServerTransport } from "../_libs/modelcontextprotocol__server.mjs";
|
|
16
|
+
import { M as McpServer, W as WebStandardStreamableHTTPServerTransport, R as ResourceTemplate } from "../_libs/modelcontextprotocol__server.mjs";
|
|
17
17
|
import { homedir } from "node:os";
|
|
18
|
-
import { d as object, b as string, a as array, _ as _enum, u as union, n as number, c as boolean, e as unknown, l as literal,
|
|
18
|
+
import { d as object, b as string, a as array, r as record, _ as _enum, u as union, n as number, c as boolean, e as unknown, l as literal, k as lazy, g as discriminatedUnion, h as _null } from "../_libs/zod.mjs";
|
|
19
19
|
import "../_libs/tiny-warning.mjs";
|
|
20
20
|
import "../_libs/tanstack__router-core.mjs";
|
|
21
21
|
import "../_libs/cookie-es.mjs";
|
|
@@ -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-DsiKfWCp.css";
|
|
54
|
-
const Route$
|
|
54
|
+
const Route$v = 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-Dik2Mc3h.mjs");
|
|
97
|
+
const Route$u = 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-DZH8SrEZ.mjs");
|
|
140
|
+
const Route$t = createFileRoute("/session/$sessionId")({
|
|
141
141
|
component: lazyRouteComponent($$splitComponentImporter, "component"),
|
|
142
142
|
parseParams: (params) => ({
|
|
143
143
|
sessionId: decodeSessionIdFromPath(params.sessionId)
|
|
@@ -4872,7 +4872,7 @@ async function handleProxy(req) {
|
|
|
4872
4872
|
}
|
|
4873
4873
|
return handleStreamingResponse(upstreamRes, req, startTime, upstreamUrl, log, captureFullDetails);
|
|
4874
4874
|
}
|
|
4875
|
-
const Route$
|
|
4875
|
+
const Route$s = createFileRoute("/proxy/$")({
|
|
4876
4876
|
server: {
|
|
4877
4877
|
handlers: {
|
|
4878
4878
|
GET: ({ request }) => handleProxy(request),
|
|
@@ -4884,7 +4884,7 @@ const Route$p = createFileRoute("/proxy/$")({
|
|
|
4884
4884
|
}
|
|
4885
4885
|
}
|
|
4886
4886
|
});
|
|
4887
|
-
function parsePositiveInt$
|
|
4887
|
+
function parsePositiveInt$2(value) {
|
|
4888
4888
|
if (value === null) return void 0;
|
|
4889
4889
|
const parsed = Number(value);
|
|
4890
4890
|
if (!Number.isInteger(parsed) || parsed < 1) return void 0;
|
|
@@ -4893,7 +4893,7 @@ function parsePositiveInt$1(value) {
|
|
|
4893
4893
|
function parseBooleanFlag(value) {
|
|
4894
4894
|
return value === "1" || value === "true";
|
|
4895
4895
|
}
|
|
4896
|
-
const Route$
|
|
4896
|
+
const Route$r = createFileRoute("/api/sessions")({
|
|
4897
4897
|
server: {
|
|
4898
4898
|
handlers: {
|
|
4899
4899
|
GET: async ({ request }) => {
|
|
@@ -4906,7 +4906,7 @@ const Route$o = createFileRoute("/api/sessions")({
|
|
|
4906
4906
|
const info = await getSessionInfo(sessionId, {
|
|
4907
4907
|
baseUrl: url.origin,
|
|
4908
4908
|
includeHistory: parseBooleanFlag(url.searchParams.get("includeHistory")),
|
|
4909
|
-
latestLogLimit: parsePositiveInt$
|
|
4909
|
+
latestLogLimit: parsePositiveInt$2(url.searchParams.get("limit"))
|
|
4910
4910
|
});
|
|
4911
4911
|
if (info === null) {
|
|
4912
4912
|
return Response.json({ error: "Session not found" }, { status: 404 });
|
|
@@ -4922,6 +4922,415 @@ const Route$o = createFileRoute("/api/sessions")({
|
|
|
4922
4922
|
}
|
|
4923
4923
|
}
|
|
4924
4924
|
});
|
|
4925
|
+
const SessionTokenUsageSchema = object({
|
|
4926
|
+
input: number().int().nonnegative(),
|
|
4927
|
+
output: number().int().nonnegative(),
|
|
4928
|
+
cacheCreate: number().int().nonnegative(),
|
|
4929
|
+
cacheRead: number().int().nonnegative(),
|
|
4930
|
+
total: number().int().nonnegative()
|
|
4931
|
+
});
|
|
4932
|
+
const SessionLogSummarySchema = object({
|
|
4933
|
+
id: number().int().positive(),
|
|
4934
|
+
timestamp: string(),
|
|
4935
|
+
provider: string().nullable(),
|
|
4936
|
+
model: string().nullable(),
|
|
4937
|
+
apiFormat: _enum(["anthropic", "openai", "unknown"]),
|
|
4938
|
+
method: string(),
|
|
4939
|
+
path: string(),
|
|
4940
|
+
status: number().nullable(),
|
|
4941
|
+
isStreaming: boolean(),
|
|
4942
|
+
hasError: boolean(),
|
|
4943
|
+
error: string().nullable(),
|
|
4944
|
+
latencyMs: number().nullable(),
|
|
4945
|
+
tokens: object({
|
|
4946
|
+
input: number().nullable(),
|
|
4947
|
+
output: number().nullable(),
|
|
4948
|
+
cacheCreate: number().nullable(),
|
|
4949
|
+
cacheRead: number().nullable()
|
|
4950
|
+
}),
|
|
4951
|
+
sessionId: string().nullable()
|
|
4952
|
+
});
|
|
4953
|
+
const SessionInfoSchema = object({
|
|
4954
|
+
id: string(),
|
|
4955
|
+
status: _enum(["active", "failed", "completed", "empty"]),
|
|
4956
|
+
logCoverage: _enum(["recent", "history"]),
|
|
4957
|
+
source: _enum(["explicit", "client-process", "client-connection", "provider-test"]).nullable(),
|
|
4958
|
+
runtimeMode: _enum(["in-process", "worker-thread", "child-process"]).nullable(),
|
|
4959
|
+
createdAt: string().nullable(),
|
|
4960
|
+
updatedAt: string().nullable(),
|
|
4961
|
+
requestCount: number().int().nonnegative(),
|
|
4962
|
+
activeRequests: number().int().nonnegative(),
|
|
4963
|
+
completedRequests: number().int().nonnegative(),
|
|
4964
|
+
failedRequests: number().int().nonnegative(),
|
|
4965
|
+
queuedTasks: number().int().nonnegative(),
|
|
4966
|
+
runningTasks: number().int().nonnegative(),
|
|
4967
|
+
lastTaskError: string().nullable(),
|
|
4968
|
+
logCount: number().int().nonnegative(),
|
|
4969
|
+
errorCount: number().int().nonnegative(),
|
|
4970
|
+
models: array(string()),
|
|
4971
|
+
providers: array(string()),
|
|
4972
|
+
tokenUsage: SessionTokenUsageSchema,
|
|
4973
|
+
lastLogId: number().nullable(),
|
|
4974
|
+
lastModel: string().nullable(),
|
|
4975
|
+
clientPid: number().nullable(),
|
|
4976
|
+
clientProjectFolder: string().nullable(),
|
|
4977
|
+
inspectorPath: string(),
|
|
4978
|
+
inspectorUrl: string(),
|
|
4979
|
+
apiPath: string(),
|
|
4980
|
+
apiUrl: string(),
|
|
4981
|
+
compactLogsPath: string(),
|
|
4982
|
+
compactLogsUrl: string(),
|
|
4983
|
+
latestLogLimit: number().int().positive(),
|
|
4984
|
+
latestLogs: array(SessionLogSummarySchema)
|
|
4985
|
+
});
|
|
4986
|
+
const InspectorRunStatusSchema = _enum([
|
|
4987
|
+
"created",
|
|
4988
|
+
"running",
|
|
4989
|
+
"completed",
|
|
4990
|
+
"failed",
|
|
4991
|
+
"cancelled"
|
|
4992
|
+
]);
|
|
4993
|
+
const InspectorRunEvidenceSchema = object({
|
|
4994
|
+
jsonPath: string(),
|
|
4995
|
+
markdownPath: string(),
|
|
4996
|
+
htmlPath: string(),
|
|
4997
|
+
exportedAt: string()
|
|
4998
|
+
});
|
|
4999
|
+
const RunTimelineEventKindSchema = _enum([
|
|
5000
|
+
"run-created",
|
|
5001
|
+
"session-started",
|
|
5002
|
+
"request",
|
|
5003
|
+
"session-finished",
|
|
5004
|
+
"evidence-exported"
|
|
5005
|
+
]);
|
|
5006
|
+
const RunTimelineEventSeveritySchema = _enum(["info", "success", "warning", "error"]);
|
|
5007
|
+
const RunTimelineEventSchema = object({
|
|
5008
|
+
timestamp: string(),
|
|
5009
|
+
kind: RunTimelineEventKindSchema,
|
|
5010
|
+
severity: RunTimelineEventSeveritySchema,
|
|
5011
|
+
title: string(),
|
|
5012
|
+
details: string(),
|
|
5013
|
+
logId: number().int().positive().nullable(),
|
|
5014
|
+
status: number().nullable(),
|
|
5015
|
+
model: string().nullable(),
|
|
5016
|
+
provider: string().nullable(),
|
|
5017
|
+
latencyMs: number().nullable(),
|
|
5018
|
+
isStreaming: boolean().nullable()
|
|
5019
|
+
});
|
|
5020
|
+
const FailureCategorySchema = _enum([
|
|
5021
|
+
"none",
|
|
5022
|
+
"active",
|
|
5023
|
+
"provider-timeout",
|
|
5024
|
+
"provider-http-error",
|
|
5025
|
+
"provider-auth-error",
|
|
5026
|
+
"provider-rate-limit",
|
|
5027
|
+
"network-or-container",
|
|
5028
|
+
"streaming-mismatch",
|
|
5029
|
+
"context-pressure",
|
|
5030
|
+
"runtime-task-error",
|
|
5031
|
+
"model-output-error",
|
|
5032
|
+
"unknown-failure",
|
|
5033
|
+
"no-session-data"
|
|
5034
|
+
]);
|
|
5035
|
+
const FailureClassificationSchema = object({
|
|
5036
|
+
outcome: _enum(["success", "failure", "active", "unknown"]),
|
|
5037
|
+
severity: _enum(["none", "low", "medium", "high"]),
|
|
5038
|
+
category: FailureCategorySchema,
|
|
5039
|
+
summary: string(),
|
|
5040
|
+
evidenceLogIds: array(number().int().positive()),
|
|
5041
|
+
hints: array(string())
|
|
5042
|
+
});
|
|
5043
|
+
const JenkinsReportSchema = object({
|
|
5044
|
+
status: _enum(["PASS", "FAIL", "RUNNING", "UNKNOWN"]),
|
|
5045
|
+
summary: string(),
|
|
5046
|
+
markdown: string()
|
|
5047
|
+
});
|
|
5048
|
+
const InspectorRunSchema = object({
|
|
5049
|
+
id: string(),
|
|
5050
|
+
sessionId: string(),
|
|
5051
|
+
title: string(),
|
|
5052
|
+
task: string().nullable(),
|
|
5053
|
+
project: string().nullable(),
|
|
5054
|
+
agent: string().nullable(),
|
|
5055
|
+
status: InspectorRunStatusSchema,
|
|
5056
|
+
tags: array(string()),
|
|
5057
|
+
metadata: record(string(), JsonValueSchema),
|
|
5058
|
+
evidence: InspectorRunEvidenceSchema.nullable(),
|
|
5059
|
+
createdAt: string(),
|
|
5060
|
+
updatedAt: string()
|
|
5061
|
+
});
|
|
5062
|
+
const CreateInspectorRunInputSchema = object({
|
|
5063
|
+
runId: string().min(1).optional(),
|
|
5064
|
+
sessionId: string().min(1).optional(),
|
|
5065
|
+
title: string().min(1).optional(),
|
|
5066
|
+
task: string().nullable().optional(),
|
|
5067
|
+
project: string().nullable().optional(),
|
|
5068
|
+
agent: string().nullable().optional(),
|
|
5069
|
+
status: InspectorRunStatusSchema.optional(),
|
|
5070
|
+
tags: array(string()).optional(),
|
|
5071
|
+
metadata: record(string(), JsonValueSchema).optional()
|
|
5072
|
+
}).optional();
|
|
5073
|
+
const UpdateInspectorRunInputSchema = object({
|
|
5074
|
+
sessionId: string().min(1).optional(),
|
|
5075
|
+
title: string().min(1).optional(),
|
|
5076
|
+
task: string().nullable().optional(),
|
|
5077
|
+
project: string().nullable().optional(),
|
|
5078
|
+
agent: string().nullable().optional(),
|
|
5079
|
+
status: InspectorRunStatusSchema.optional(),
|
|
5080
|
+
tags: array(string()).optional(),
|
|
5081
|
+
metadata: record(string(), JsonValueSchema).optional()
|
|
5082
|
+
});
|
|
5083
|
+
const EvidenceExportOptionsSchema = object({
|
|
5084
|
+
includeHistory: boolean().optional(),
|
|
5085
|
+
latestLogLimit: number().int().positive().max(50).optional()
|
|
5086
|
+
}).optional();
|
|
5087
|
+
const EvidenceExportResultSchema = object({
|
|
5088
|
+
run: InspectorRunSchema,
|
|
5089
|
+
evidence: InspectorRunEvidenceSchema,
|
|
5090
|
+
session: SessionInfoSchema.nullable(),
|
|
5091
|
+
timeline: array(RunTimelineEventSchema),
|
|
5092
|
+
classification: FailureClassificationSchema,
|
|
5093
|
+
jenkinsReport: JenkinsReportSchema
|
|
5094
|
+
});
|
|
5095
|
+
const RecentFailureSchema = object({
|
|
5096
|
+
run: InspectorRunSchema,
|
|
5097
|
+
classification: FailureClassificationSchema,
|
|
5098
|
+
evidence: InspectorRunEvidenceSchema.nullable(),
|
|
5099
|
+
jenkinsReport: JenkinsReportSchema.nullable(),
|
|
5100
|
+
sessionId: string(),
|
|
5101
|
+
inspectorUrl: string().nullable(),
|
|
5102
|
+
evidenceMarkdownPath: string().nullable(),
|
|
5103
|
+
updatedAt: string()
|
|
5104
|
+
});
|
|
5105
|
+
const RecentFailuresResponseSchema = object({
|
|
5106
|
+
failures: array(RecentFailureSchema),
|
|
5107
|
+
total: number().int().nonnegative(),
|
|
5108
|
+
limit: number().int().positive()
|
|
5109
|
+
});
|
|
5110
|
+
const RunsFileSchema = object({
|
|
5111
|
+
runs: array(InspectorRunSchema)
|
|
5112
|
+
});
|
|
5113
|
+
function runsFilePath() {
|
|
5114
|
+
return join(getDataDir(), "runs.json");
|
|
5115
|
+
}
|
|
5116
|
+
function nowIso() {
|
|
5117
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
5118
|
+
}
|
|
5119
|
+
function stableId(input) {
|
|
5120
|
+
return input.trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
5121
|
+
}
|
|
5122
|
+
function createRunId() {
|
|
5123
|
+
return `run_${Date.now().toString(36)}_${randomUUID$1().slice(0, 8)}`;
|
|
5124
|
+
}
|
|
5125
|
+
function normalizeRunId(input) {
|
|
5126
|
+
if (input === void 0) return createRunId();
|
|
5127
|
+
const normalized = stableId(input);
|
|
5128
|
+
return normalized.length > 0 ? normalized : createRunId();
|
|
5129
|
+
}
|
|
5130
|
+
function normalizeSessionId(input, runId) {
|
|
5131
|
+
if (input === void 0 || input.trim().length === 0) return runId;
|
|
5132
|
+
return input.trim();
|
|
5133
|
+
}
|
|
5134
|
+
function readRuns() {
|
|
5135
|
+
const filePath = runsFilePath();
|
|
5136
|
+
if (!existsSync(filePath)) return [];
|
|
5137
|
+
try {
|
|
5138
|
+
const parsed = JSON.parse(readFileSync(filePath, "utf8"));
|
|
5139
|
+
const result = RunsFileSchema.safeParse(parsed);
|
|
5140
|
+
return result.success ? result.data.runs : [];
|
|
5141
|
+
} catch {
|
|
5142
|
+
return [];
|
|
5143
|
+
}
|
|
5144
|
+
}
|
|
5145
|
+
function writeRuns(runs) {
|
|
5146
|
+
const filePath = runsFilePath();
|
|
5147
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
5148
|
+
writeFileSync(filePath, `${JSON.stringify({ runs }, null, 2)}
|
|
5149
|
+
`, "utf8");
|
|
5150
|
+
}
|
|
5151
|
+
function listRuns() {
|
|
5152
|
+
return readRuns().sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
5153
|
+
}
|
|
5154
|
+
function getRun(runId) {
|
|
5155
|
+
return readRuns().find((run) => run.id === runId) ?? null;
|
|
5156
|
+
}
|
|
5157
|
+
function createRun(input) {
|
|
5158
|
+
const parsed = CreateInspectorRunInputSchema.parse(input);
|
|
5159
|
+
const runId = normalizeRunId(parsed?.runId);
|
|
5160
|
+
const existing = getRun(runId);
|
|
5161
|
+
if (existing !== null) return existing;
|
|
5162
|
+
const timestamp = nowIso();
|
|
5163
|
+
const sessionId = normalizeSessionId(parsed?.sessionId, runId);
|
|
5164
|
+
const run = {
|
|
5165
|
+
id: runId,
|
|
5166
|
+
sessionId,
|
|
5167
|
+
title: parsed?.title ?? `Inspector Run ${runId}`,
|
|
5168
|
+
task: parsed?.task ?? null,
|
|
5169
|
+
project: parsed?.project ?? null,
|
|
5170
|
+
agent: parsed?.agent ?? null,
|
|
5171
|
+
status: parsed?.status ?? "created",
|
|
5172
|
+
tags: parsed?.tags ?? [],
|
|
5173
|
+
metadata: parsed?.metadata ?? {},
|
|
5174
|
+
evidence: null,
|
|
5175
|
+
createdAt: timestamp,
|
|
5176
|
+
updatedAt: timestamp
|
|
5177
|
+
};
|
|
5178
|
+
writeRuns([...readRuns(), run]);
|
|
5179
|
+
return run;
|
|
5180
|
+
}
|
|
5181
|
+
function updateRunEvidence(runId, evidence) {
|
|
5182
|
+
const runs = readRuns();
|
|
5183
|
+
let updatedRun = null;
|
|
5184
|
+
const updatedRuns = runs.map((run) => {
|
|
5185
|
+
if (run.id !== runId) return run;
|
|
5186
|
+
updatedRun = {
|
|
5187
|
+
...run,
|
|
5188
|
+
evidence,
|
|
5189
|
+
updatedAt: evidence.exportedAt
|
|
5190
|
+
};
|
|
5191
|
+
return updatedRun;
|
|
5192
|
+
});
|
|
5193
|
+
if (updatedRun === null) return null;
|
|
5194
|
+
writeRuns(updatedRuns);
|
|
5195
|
+
return updatedRun;
|
|
5196
|
+
}
|
|
5197
|
+
function updateRun(runId, input) {
|
|
5198
|
+
const parsed = UpdateInspectorRunInputSchema.parse(input);
|
|
5199
|
+
const runs = readRuns();
|
|
5200
|
+
let updatedRun = null;
|
|
5201
|
+
const updatedAt = nowIso();
|
|
5202
|
+
const updatedRuns = runs.map((run) => {
|
|
5203
|
+
if (run.id !== runId) return run;
|
|
5204
|
+
updatedRun = {
|
|
5205
|
+
...run,
|
|
5206
|
+
sessionId: parsed.sessionId === void 0 ? run.sessionId : normalizeSessionId(parsed.sessionId, run.id),
|
|
5207
|
+
title: parsed.title ?? run.title,
|
|
5208
|
+
task: parsed.task === void 0 ? run.task : parsed.task,
|
|
5209
|
+
project: parsed.project === void 0 ? run.project : parsed.project,
|
|
5210
|
+
agent: parsed.agent === void 0 ? run.agent : parsed.agent,
|
|
5211
|
+
status: parsed.status ?? run.status,
|
|
5212
|
+
tags: parsed.tags ?? run.tags,
|
|
5213
|
+
metadata: parsed.metadata === void 0 ? run.metadata : { ...run.metadata, ...parsed.metadata },
|
|
5214
|
+
updatedAt
|
|
5215
|
+
};
|
|
5216
|
+
return updatedRun;
|
|
5217
|
+
});
|
|
5218
|
+
if (updatedRun === null) return null;
|
|
5219
|
+
writeRuns(updatedRuns);
|
|
5220
|
+
return updatedRun;
|
|
5221
|
+
}
|
|
5222
|
+
const RECENT_FAILURES_DEFAULT_LIMIT = 5;
|
|
5223
|
+
const RECENT_FAILURES_MAX_LIMIT = 20;
|
|
5224
|
+
function clampRecentFailuresLimit(value) {
|
|
5225
|
+
if (!Number.isInteger(value) || value < 1) return RECENT_FAILURES_DEFAULT_LIMIT;
|
|
5226
|
+
return Math.min(value, RECENT_FAILURES_MAX_LIMIT);
|
|
5227
|
+
}
|
|
5228
|
+
function readEvidenceDocument(run) {
|
|
5229
|
+
const path2 = run.evidence?.jsonPath;
|
|
5230
|
+
if (path2 === void 0 || !existsSync(path2)) return null;
|
|
5231
|
+
try {
|
|
5232
|
+
const parsed = JSON.parse(readFileSync(path2, "utf8"));
|
|
5233
|
+
const result = EvidenceExportResultSchema.safeParse(parsed);
|
|
5234
|
+
return result.success ? result.data : null;
|
|
5235
|
+
} catch {
|
|
5236
|
+
return null;
|
|
5237
|
+
}
|
|
5238
|
+
}
|
|
5239
|
+
function syntheticFailedClassification(run) {
|
|
5240
|
+
return {
|
|
5241
|
+
outcome: "failure",
|
|
5242
|
+
severity: "high",
|
|
5243
|
+
category: "unknown-failure",
|
|
5244
|
+
summary: `Run ${run.id} is marked ${run.status}, but no exported evidence document was available.`,
|
|
5245
|
+
evidenceLogIds: [],
|
|
5246
|
+
hints: [
|
|
5247
|
+
"Call inspector_export_evidence for this run to collect session metrics, failing log ids, and artifact paths.",
|
|
5248
|
+
"Confirm the run's sessionId matches the coding agent traffic captured by Inspector."
|
|
5249
|
+
]
|
|
5250
|
+
};
|
|
5251
|
+
}
|
|
5252
|
+
function shouldIncludeRun(run, document, classification) {
|
|
5253
|
+
if (run.status === "failed" || run.status === "cancelled") return true;
|
|
5254
|
+
if (document === null) return false;
|
|
5255
|
+
return classification.outcome !== "success";
|
|
5256
|
+
}
|
|
5257
|
+
function evidenceFor(run, document) {
|
|
5258
|
+
return document?.evidence ?? run.evidence;
|
|
5259
|
+
}
|
|
5260
|
+
function jenkinsReportFor(document) {
|
|
5261
|
+
return document?.jenkinsReport ?? null;
|
|
5262
|
+
}
|
|
5263
|
+
function failureFromRun(run) {
|
|
5264
|
+
const document = readEvidenceDocument(run);
|
|
5265
|
+
const classification = document === null ? syntheticFailedClassification(run) : document.classification;
|
|
5266
|
+
if (!shouldIncludeRun(run, document, classification)) return null;
|
|
5267
|
+
const evidence = evidenceFor(run, document);
|
|
5268
|
+
return {
|
|
5269
|
+
run,
|
|
5270
|
+
classification,
|
|
5271
|
+
evidence,
|
|
5272
|
+
jenkinsReport: jenkinsReportFor(document),
|
|
5273
|
+
sessionId: run.sessionId,
|
|
5274
|
+
inspectorUrl: document?.session?.inspectorUrl ?? null,
|
|
5275
|
+
evidenceMarkdownPath: evidence?.markdownPath ?? null,
|
|
5276
|
+
updatedAt: evidence?.exportedAt ?? run.updatedAt
|
|
5277
|
+
};
|
|
5278
|
+
}
|
|
5279
|
+
function listRecentFailures(limit) {
|
|
5280
|
+
const failures = listRuns().map(failureFromRun).filter((failure) => failure !== null).sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
5281
|
+
const clampedLimit = clampRecentFailuresLimit(limit);
|
|
5282
|
+
return {
|
|
5283
|
+
failures: failures.slice(0, clampedLimit),
|
|
5284
|
+
total: failures.length,
|
|
5285
|
+
limit: clampedLimit
|
|
5286
|
+
};
|
|
5287
|
+
}
|
|
5288
|
+
async function readJsonBody$2(request) {
|
|
5289
|
+
try {
|
|
5290
|
+
const raw = await request.text();
|
|
5291
|
+
if (raw.trim().length === 0) return { ok: true, value: void 0 };
|
|
5292
|
+
return { ok: true, value: JSON.parse(raw) };
|
|
5293
|
+
} catch {
|
|
5294
|
+
return { ok: false };
|
|
5295
|
+
}
|
|
5296
|
+
}
|
|
5297
|
+
function parsePositiveInt$1(value, fallback) {
|
|
5298
|
+
if (value === null) return fallback;
|
|
5299
|
+
const parsed = Number(value);
|
|
5300
|
+
if (!Number.isInteger(parsed) || parsed < 1) return fallback;
|
|
5301
|
+
return parsed;
|
|
5302
|
+
}
|
|
5303
|
+
const Route$q = createFileRoute("/api/runs")({
|
|
5304
|
+
server: {
|
|
5305
|
+
handlers: {
|
|
5306
|
+
GET: ({ request }) => {
|
|
5307
|
+
const url = new URL(request.url);
|
|
5308
|
+
if (url.searchParams.get("failures") === "1") {
|
|
5309
|
+
const limit = parsePositiveInt$1(
|
|
5310
|
+
url.searchParams.get("limit"),
|
|
5311
|
+
RECENT_FAILURES_DEFAULT_LIMIT
|
|
5312
|
+
);
|
|
5313
|
+
return Response.json(listRecentFailures(limit));
|
|
5314
|
+
}
|
|
5315
|
+
return Response.json({ runs: listRuns() });
|
|
5316
|
+
},
|
|
5317
|
+
POST: async ({ request }) => {
|
|
5318
|
+
const body = await readJsonBody$2(request);
|
|
5319
|
+
if (!body.ok) {
|
|
5320
|
+
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
5321
|
+
}
|
|
5322
|
+
const parsed = CreateInspectorRunInputSchema.safeParse(body.value);
|
|
5323
|
+
if (!parsed.success) {
|
|
5324
|
+
return Response.json(
|
|
5325
|
+
{ error: "Invalid request body", details: parsed.error.format() },
|
|
5326
|
+
{ status: 400 }
|
|
5327
|
+
);
|
|
5328
|
+
}
|
|
5329
|
+
return Response.json(createRun(parsed.data), { status: 201 });
|
|
5330
|
+
}
|
|
5331
|
+
}
|
|
5332
|
+
}
|
|
5333
|
+
});
|
|
4925
5334
|
const ProviderInputSchema = object({
|
|
4926
5335
|
name: string().min(1, "Name is required"),
|
|
4927
5336
|
apiKey: string().min(1, "API key is required"),
|
|
@@ -4936,7 +5345,7 @@ const ProviderInputSchema = object({
|
|
|
4936
5345
|
modelMetadata: array(ProviderModelMetadataSchema).optional(),
|
|
4937
5346
|
source: _enum(["company", "personal"]).optional()
|
|
4938
5347
|
});
|
|
4939
|
-
const Route$
|
|
5348
|
+
const Route$p = createFileRoute("/api/providers")({
|
|
4940
5349
|
server: {
|
|
4941
5350
|
handlers: {
|
|
4942
5351
|
GET: ({ request }) => {
|
|
@@ -4970,7 +5379,7 @@ const Route$n = createFileRoute("/api/providers")({
|
|
|
4970
5379
|
}
|
|
4971
5380
|
}
|
|
4972
5381
|
});
|
|
4973
|
-
const Route$
|
|
5382
|
+
const Route$o = createFileRoute("/api/models")({
|
|
4974
5383
|
server: {
|
|
4975
5384
|
handlers: {
|
|
4976
5385
|
GET: () => Response.json(getModels())
|
|
@@ -5127,73 +5536,20 @@ function extractResponsePreview(log) {
|
|
|
5127
5536
|
}
|
|
5128
5537
|
return null;
|
|
5129
5538
|
}
|
|
5130
|
-
const SessionTokenUsageSchema = object({
|
|
5131
|
-
input: number().int().nonnegative(),
|
|
5132
|
-
output: number().int().nonnegative(),
|
|
5133
|
-
cacheCreate: number().int().nonnegative(),
|
|
5134
|
-
cacheRead: number().int().nonnegative(),
|
|
5135
|
-
total: number().int().nonnegative()
|
|
5136
|
-
});
|
|
5137
|
-
const SessionLogSummarySchema = object({
|
|
5138
|
-
id: number().int().positive(),
|
|
5139
|
-
timestamp: string(),
|
|
5140
|
-
provider: string().nullable(),
|
|
5141
|
-
model: string().nullable(),
|
|
5142
|
-
apiFormat: _enum(["anthropic", "openai", "unknown"]),
|
|
5143
|
-
method: string(),
|
|
5144
|
-
path: string(),
|
|
5145
|
-
status: number().nullable(),
|
|
5146
|
-
isStreaming: boolean(),
|
|
5147
|
-
hasError: boolean(),
|
|
5148
|
-
error: string().nullable(),
|
|
5149
|
-
latencyMs: number().nullable(),
|
|
5150
|
-
tokens: object({
|
|
5151
|
-
input: number().nullable(),
|
|
5152
|
-
output: number().nullable(),
|
|
5153
|
-
cacheCreate: number().nullable(),
|
|
5154
|
-
cacheRead: number().nullable()
|
|
5155
|
-
}),
|
|
5156
|
-
sessionId: string().nullable()
|
|
5157
|
-
});
|
|
5158
|
-
const SessionInfoSchema = object({
|
|
5159
|
-
id: string(),
|
|
5160
|
-
status: _enum(["active", "failed", "completed", "empty"]),
|
|
5161
|
-
logCoverage: _enum(["recent", "history"]),
|
|
5162
|
-
source: _enum(["explicit", "client-process", "client-connection", "provider-test"]).nullable(),
|
|
5163
|
-
runtimeMode: _enum(["in-process", "worker-thread", "child-process"]).nullable(),
|
|
5164
|
-
createdAt: string().nullable(),
|
|
5165
|
-
updatedAt: string().nullable(),
|
|
5166
|
-
requestCount: number().int().nonnegative(),
|
|
5167
|
-
activeRequests: number().int().nonnegative(),
|
|
5168
|
-
completedRequests: number().int().nonnegative(),
|
|
5169
|
-
failedRequests: number().int().nonnegative(),
|
|
5170
|
-
queuedTasks: number().int().nonnegative(),
|
|
5171
|
-
runningTasks: number().int().nonnegative(),
|
|
5172
|
-
lastTaskError: string().nullable(),
|
|
5173
|
-
logCount: number().int().nonnegative(),
|
|
5174
|
-
errorCount: number().int().nonnegative(),
|
|
5175
|
-
models: array(string()),
|
|
5176
|
-
providers: array(string()),
|
|
5177
|
-
tokenUsage: SessionTokenUsageSchema,
|
|
5178
|
-
lastLogId: number().nullable(),
|
|
5179
|
-
lastModel: string().nullable(),
|
|
5180
|
-
clientPid: number().nullable(),
|
|
5181
|
-
clientProjectFolder: string().nullable(),
|
|
5182
|
-
inspectorPath: string(),
|
|
5183
|
-
inspectorUrl: string(),
|
|
5184
|
-
apiPath: string(),
|
|
5185
|
-
apiUrl: string(),
|
|
5186
|
-
compactLogsPath: string(),
|
|
5187
|
-
compactLogsUrl: string(),
|
|
5188
|
-
latestLogLimit: number().int().positive(),
|
|
5189
|
-
latestLogs: array(SessionLogSummarySchema)
|
|
5190
|
-
});
|
|
5191
5539
|
const LogsListResponseSchema = object({
|
|
5192
5540
|
logs: array(CapturedLogSchema).optional(),
|
|
5193
5541
|
total: number().optional(),
|
|
5194
5542
|
offset: number().optional(),
|
|
5195
5543
|
limit: number().optional()
|
|
5196
5544
|
});
|
|
5545
|
+
const SearchLogsResponseSchema = object({
|
|
5546
|
+
query: string(),
|
|
5547
|
+
logs: array(CapturedLogSchema),
|
|
5548
|
+
total: number(),
|
|
5549
|
+
offset: number(),
|
|
5550
|
+
limit: number(),
|
|
5551
|
+
scanned: number().optional()
|
|
5552
|
+
});
|
|
5197
5553
|
const PAGINATION_DEFAULTS = { offset: 0, limit: 3 };
|
|
5198
5554
|
const LIMIT_HARD_CAP = 5;
|
|
5199
5555
|
const LOG_DETAIL_TEXT_LIMIT = 2e5;
|
|
@@ -5298,6 +5654,33 @@ async function listLogsImpl(callApi2, args) {
|
|
|
5298
5654
|
const logs = parsed.data.logs ?? [];
|
|
5299
5655
|
return textJson(logs.map(buildLogSummary));
|
|
5300
5656
|
}
|
|
5657
|
+
async function searchLogsImpl(callApi2, args) {
|
|
5658
|
+
const offset = args.offset ?? PAGINATION_DEFAULTS.offset;
|
|
5659
|
+
const limit = clampLimit(args.limit);
|
|
5660
|
+
const params = new URLSearchParams({
|
|
5661
|
+
q: args.query ?? "",
|
|
5662
|
+
offset: String(offset),
|
|
5663
|
+
limit: String(limit)
|
|
5664
|
+
});
|
|
5665
|
+
if (args.scanLimit !== void 0) {
|
|
5666
|
+
params.set("scanLimit", String(args.scanLimit));
|
|
5667
|
+
}
|
|
5668
|
+
if (args.sessionId !== void 0 && args.sessionId.length > 0) {
|
|
5669
|
+
params.set("sessionId", args.sessionId);
|
|
5670
|
+
}
|
|
5671
|
+
if (args.model !== void 0 && args.model.length > 0) {
|
|
5672
|
+
params.set("model", args.model);
|
|
5673
|
+
}
|
|
5674
|
+
const res = await callApi2(`/api/logs?${params.toString()}`);
|
|
5675
|
+
if (!res.ok) return toolError(`GET /api/logs search returned ${res.status}`);
|
|
5676
|
+
const rawBody = await res.json();
|
|
5677
|
+
const parsed = SearchLogsResponseSchema.safeParse(rawBody);
|
|
5678
|
+
if (!parsed.success) return toolError("GET /api/logs search returned an unparseable shape");
|
|
5679
|
+
return textJson({
|
|
5680
|
+
...parsed.data,
|
|
5681
|
+
logs: parsed.data.logs.map(buildLogSummary)
|
|
5682
|
+
});
|
|
5683
|
+
}
|
|
5301
5684
|
async function getLogImpl(callApi2, id) {
|
|
5302
5685
|
const res = await callApi2(`/api/logs/${id}`);
|
|
5303
5686
|
if (!res.ok) return toolError(`GET /api/logs/${id} returned ${res.status}`);
|
|
@@ -5334,6 +5717,71 @@ async function getSessionImpl(callApi2, args) {
|
|
|
5334
5717
|
if (!parsed.success) return toolError("GET /api/sessions returned an unparseable session info");
|
|
5335
5718
|
return textJson(parsed.data);
|
|
5336
5719
|
}
|
|
5720
|
+
async function createRunImpl(callApi2, args) {
|
|
5721
|
+
const res = await callApi2("/api/runs", {
|
|
5722
|
+
method: "POST",
|
|
5723
|
+
headers: { "content-type": "application/json" },
|
|
5724
|
+
body: JSON.stringify(args ?? {})
|
|
5725
|
+
});
|
|
5726
|
+
if (!res.ok) return toolError(`POST /api/runs returned ${res.status}`);
|
|
5727
|
+
const rawBody = await res.json();
|
|
5728
|
+
const parsed = InspectorRunSchema.safeParse(rawBody);
|
|
5729
|
+
if (!parsed.success) return toolError("POST /api/runs returned an unparseable run");
|
|
5730
|
+
return textJson(parsed.data);
|
|
5731
|
+
}
|
|
5732
|
+
async function getRunImpl(callApi2, args) {
|
|
5733
|
+
const path2 = `/api/runs/${encodeURIComponent(args.runId)}`;
|
|
5734
|
+
const res = await callApi2(path2);
|
|
5735
|
+
if (!res.ok) return toolError(`GET ${path2} returned ${res.status}`);
|
|
5736
|
+
const rawBody = await res.json();
|
|
5737
|
+
const parsed = InspectorRunSchema.safeParse(rawBody);
|
|
5738
|
+
if (!parsed.success) return toolError("GET /api/runs/{runId} returned an unparseable run");
|
|
5739
|
+
return textJson(parsed.data);
|
|
5740
|
+
}
|
|
5741
|
+
async function updateRunImpl(callApi2, args) {
|
|
5742
|
+
const { runId, ...patch } = args;
|
|
5743
|
+
const path2 = `/api/runs/${encodeURIComponent(runId)}`;
|
|
5744
|
+
const res = await callApi2(path2, {
|
|
5745
|
+
method: "PATCH",
|
|
5746
|
+
headers: { "content-type": "application/json" },
|
|
5747
|
+
body: JSON.stringify(patch)
|
|
5748
|
+
});
|
|
5749
|
+
if (!res.ok) return toolError(`PATCH ${path2} returned ${res.status}`);
|
|
5750
|
+
const rawBody = await res.json();
|
|
5751
|
+
const parsed = InspectorRunSchema.safeParse(rawBody);
|
|
5752
|
+
if (!parsed.success) return toolError("PATCH /api/runs/{runId} returned an unparseable run");
|
|
5753
|
+
return textJson(parsed.data);
|
|
5754
|
+
}
|
|
5755
|
+
async function getRecentFailuresImpl(callApi2, args) {
|
|
5756
|
+
const limit = args.limit ?? 5;
|
|
5757
|
+
const params = new URLSearchParams({ failures: "1", limit: String(limit) });
|
|
5758
|
+
const res = await callApi2(`/api/runs?${params.toString()}`);
|
|
5759
|
+
if (!res.ok) return toolError(`GET /api/runs?failures=1 returned ${res.status}`);
|
|
5760
|
+
const rawBody = await res.json();
|
|
5761
|
+
const parsed = RecentFailuresResponseSchema.safeParse(rawBody);
|
|
5762
|
+
if (!parsed.success) {
|
|
5763
|
+
return toolError("GET /api/runs?failures=1 returned an unparseable failure list");
|
|
5764
|
+
}
|
|
5765
|
+
return textJson(parsed.data);
|
|
5766
|
+
}
|
|
5767
|
+
async function exportEvidenceImpl(callApi2, args) {
|
|
5768
|
+
const path2 = `/api/runs/${encodeURIComponent(args.runId)}/evidence`;
|
|
5769
|
+
const res = await callApi2(path2, {
|
|
5770
|
+
method: "POST",
|
|
5771
|
+
headers: { "content-type": "application/json" },
|
|
5772
|
+
body: JSON.stringify({
|
|
5773
|
+
includeHistory: args.includeHistory,
|
|
5774
|
+
latestLogLimit: args.latestLogLimit
|
|
5775
|
+
})
|
|
5776
|
+
});
|
|
5777
|
+
if (!res.ok) return toolError(`POST ${path2} returned ${res.status}`);
|
|
5778
|
+
const rawBody = await res.json();
|
|
5779
|
+
const parsed = EvidenceExportResultSchema.safeParse(rawBody);
|
|
5780
|
+
if (!parsed.success) {
|
|
5781
|
+
return toolError("POST /api/runs/{runId}/evidence returned an unparseable evidence result");
|
|
5782
|
+
}
|
|
5783
|
+
return textJson(parsed.data);
|
|
5784
|
+
}
|
|
5337
5785
|
async function listModelsImpl(callApi2) {
|
|
5338
5786
|
const res = await callApi2("/api/models");
|
|
5339
5787
|
if (!res.ok) return toolError(`GET /api/models returned ${res.status}`);
|
|
@@ -5464,9 +5912,11 @@ let initPromise = null;
|
|
|
5464
5912
|
function buildServer() {
|
|
5465
5913
|
const server = new McpServer(
|
|
5466
5914
|
{ name: "agent-inspector", version: "1.0.0" },
|
|
5467
|
-
{ capabilities: { tools: {} } }
|
|
5915
|
+
{ capabilities: { tools: {}, resources: {}, prompts: {} } }
|
|
5468
5916
|
);
|
|
5469
5917
|
registerTools(server);
|
|
5918
|
+
registerResources(server);
|
|
5919
|
+
registerPrompts(server);
|
|
5470
5920
|
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
5471
5921
|
sessionIdGenerator: void 0
|
|
5472
5922
|
// stateless — see module docstring
|
|
@@ -5514,6 +5964,129 @@ Returns: array of "thick summary" objects, each containing:
|
|
|
5514
5964
|
|
|
5515
5965
|
Either preview field is null when the body is unknown format, unparseable, or the relevant content is non-text (e.g., image-only).`;
|
|
5516
5966
|
const PROVIDER_WRITE_WARNING = "⚠ This tool mutates provider configuration. Confirm with the user before invoking.";
|
|
5967
|
+
const RunsListResponseSchema = object({
|
|
5968
|
+
runs: array(InspectorRunSchema)
|
|
5969
|
+
});
|
|
5970
|
+
const LogResourceListResponseSchema = object({
|
|
5971
|
+
logs: array(object({ id: number().int().positive() }))
|
|
5972
|
+
});
|
|
5973
|
+
const EvidenceReadResponseSchema = object({
|
|
5974
|
+
markdown: string()
|
|
5975
|
+
});
|
|
5976
|
+
function textResource(uri, mimeType, text) {
|
|
5977
|
+
return {
|
|
5978
|
+
contents: [{ uri: uri.href, mimeType, text }]
|
|
5979
|
+
};
|
|
5980
|
+
}
|
|
5981
|
+
function jsonResource(uri, data) {
|
|
5982
|
+
return textResource(uri, "application/json", JSON.stringify(data, null, 2));
|
|
5983
|
+
}
|
|
5984
|
+
function variableString(variables, name) {
|
|
5985
|
+
const value = variables[name];
|
|
5986
|
+
if (Array.isArray(value)) return value[0] ?? null;
|
|
5987
|
+
return value ?? null;
|
|
5988
|
+
}
|
|
5989
|
+
function listResult(resources) {
|
|
5990
|
+
return { resources };
|
|
5991
|
+
}
|
|
5992
|
+
async function readApiJsonResource(uri, path2) {
|
|
5993
|
+
try {
|
|
5994
|
+
const response = await callApi(path2);
|
|
5995
|
+
if (!response.ok) {
|
|
5996
|
+
return textResource(uri, "text/plain", `GET ${path2} returned ${response.status}`);
|
|
5997
|
+
}
|
|
5998
|
+
return jsonResource(uri, await response.json());
|
|
5999
|
+
} catch (err) {
|
|
6000
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
6001
|
+
return textResource(uri, "text/plain", `Resource read failed: ${message}`);
|
|
6002
|
+
}
|
|
6003
|
+
}
|
|
6004
|
+
async function listSessionResources() {
|
|
6005
|
+
try {
|
|
6006
|
+
const response = await callApi("/api/sessions");
|
|
6007
|
+
if (!response.ok) return listResult([]);
|
|
6008
|
+
const parsed = array(string()).safeParse(await response.json());
|
|
6009
|
+
if (!parsed.success) return listResult([]);
|
|
6010
|
+
return listResult(
|
|
6011
|
+
parsed.data.map((sessionId) => ({
|
|
6012
|
+
uri: `inspector://sessions/${encodeURIComponent(sessionId)}`,
|
|
6013
|
+
name: `session:${sessionId}`,
|
|
6014
|
+
title: `Inspector session ${sessionId}`,
|
|
6015
|
+
mimeType: "application/json"
|
|
6016
|
+
}))
|
|
6017
|
+
);
|
|
6018
|
+
} catch {
|
|
6019
|
+
return listResult([]);
|
|
6020
|
+
}
|
|
6021
|
+
}
|
|
6022
|
+
async function listLogResources() {
|
|
6023
|
+
try {
|
|
6024
|
+
const response = await callApi("/api/logs?offset=0&limit=5&compact=1");
|
|
6025
|
+
if (!response.ok) return listResult([]);
|
|
6026
|
+
const parsed = LogResourceListResponseSchema.safeParse(await response.json());
|
|
6027
|
+
if (!parsed.success) return listResult([]);
|
|
6028
|
+
return listResult(
|
|
6029
|
+
parsed.data.logs.map((log) => ({
|
|
6030
|
+
uri: `inspector://logs/${String(log.id)}`,
|
|
6031
|
+
name: `log:${String(log.id)}`,
|
|
6032
|
+
title: `Inspector log ${String(log.id)}`,
|
|
6033
|
+
mimeType: "application/json"
|
|
6034
|
+
}))
|
|
6035
|
+
);
|
|
6036
|
+
} catch {
|
|
6037
|
+
return listResult([]);
|
|
6038
|
+
}
|
|
6039
|
+
}
|
|
6040
|
+
async function listRunResources() {
|
|
6041
|
+
try {
|
|
6042
|
+
const response = await callApi("/api/runs");
|
|
6043
|
+
if (!response.ok) return listResult([]);
|
|
6044
|
+
const parsed = RunsListResponseSchema.safeParse(await response.json());
|
|
6045
|
+
if (!parsed.success) return listResult([]);
|
|
6046
|
+
return listResult(
|
|
6047
|
+
parsed.data.runs.map((run) => ({
|
|
6048
|
+
uri: `inspector://runs/${encodeURIComponent(run.id)}`,
|
|
6049
|
+
name: `run:${run.id}`,
|
|
6050
|
+
title: run.title,
|
|
6051
|
+
mimeType: "application/json"
|
|
6052
|
+
}))
|
|
6053
|
+
);
|
|
6054
|
+
} catch {
|
|
6055
|
+
return listResult([]);
|
|
6056
|
+
}
|
|
6057
|
+
}
|
|
6058
|
+
async function listEvidenceResources() {
|
|
6059
|
+
try {
|
|
6060
|
+
const response = await callApi("/api/runs");
|
|
6061
|
+
if (!response.ok) return listResult([]);
|
|
6062
|
+
const parsed = RunsListResponseSchema.safeParse(await response.json());
|
|
6063
|
+
if (!parsed.success) return listResult([]);
|
|
6064
|
+
return listResult(
|
|
6065
|
+
parsed.data.runs.filter((run) => run.evidence !== null).map((run) => ({
|
|
6066
|
+
uri: `inspector://evidence/${encodeURIComponent(run.id)}`,
|
|
6067
|
+
name: `evidence:${run.id}`,
|
|
6068
|
+
title: `${run.title} evidence pack`,
|
|
6069
|
+
mimeType: "text/markdown",
|
|
6070
|
+
description: run.evidence?.markdownPath
|
|
6071
|
+
}))
|
|
6072
|
+
);
|
|
6073
|
+
} catch {
|
|
6074
|
+
return listResult([]);
|
|
6075
|
+
}
|
|
6076
|
+
}
|
|
6077
|
+
function userPrompt(text) {
|
|
6078
|
+
return {
|
|
6079
|
+
messages: [
|
|
6080
|
+
{
|
|
6081
|
+
role: "user",
|
|
6082
|
+
content: {
|
|
6083
|
+
type: "text",
|
|
6084
|
+
text
|
|
6085
|
+
}
|
|
6086
|
+
}
|
|
6087
|
+
]
|
|
6088
|
+
};
|
|
6089
|
+
}
|
|
5517
6090
|
function registerTools(server) {
|
|
5518
6091
|
server.registerTool(
|
|
5519
6092
|
"inspector_list_logs",
|
|
@@ -5529,6 +6102,22 @@ function registerTools(server) {
|
|
|
5529
6102
|
},
|
|
5530
6103
|
(args) => safeCall(() => listLogsImpl(callApi, args))
|
|
5531
6104
|
);
|
|
6105
|
+
server.registerTool(
|
|
6106
|
+
"inspector_search_logs",
|
|
6107
|
+
{
|
|
6108
|
+
title: "Search captured logs",
|
|
6109
|
+
description: "Searches recent compact proxy logs by id, session, model, provider, API path, status, error text, and client context. Results are bounded summaries; call inspector_get_log for full details after locating a candidate id.",
|
|
6110
|
+
inputSchema: object({
|
|
6111
|
+
query: string().optional().describe("Search terms. Empty or omitted returns the newest scanned logs."),
|
|
6112
|
+
offset: number().int().nonnegative().optional().describe("Skip this many matches."),
|
|
6113
|
+
limit: number().int().positive().optional().describe("How many summaries to return. Hard-capped at 5 by the MCP handler."),
|
|
6114
|
+
scanLimit: number().int().positive().max(1e3).optional().describe("How many recent compact logs to scan before filtering. Default 200."),
|
|
6115
|
+
sessionId: string().optional().describe("Optional session/affinity id filter."),
|
|
6116
|
+
model: string().optional().describe("Optional model name filter.")
|
|
6117
|
+
})
|
|
6118
|
+
},
|
|
6119
|
+
(args) => safeCall(() => searchLogsImpl(callApi, args))
|
|
6120
|
+
);
|
|
5532
6121
|
server.registerTool(
|
|
5533
6122
|
"inspector_get_log",
|
|
5534
6123
|
{
|
|
@@ -5541,37 +6130,102 @@ function registerTools(server) {
|
|
|
5541
6130
|
({ id }) => safeCall(() => getLogImpl(callApi, id))
|
|
5542
6131
|
);
|
|
5543
6132
|
server.registerTool(
|
|
5544
|
-
"inspector_get_log_chunks",
|
|
6133
|
+
"inspector_get_log_chunks",
|
|
6134
|
+
{
|
|
6135
|
+
title: "Get SSE streaming chunks for a captured log",
|
|
6136
|
+
description: "Returns the SSE chunks array for a streaming log, in the order they were received. Returns an error if the log has no chunks (i.e. was non-streaming or the log id is unknown).",
|
|
6137
|
+
inputSchema: object({
|
|
6138
|
+
id: number().int().positive().describe("The log id.")
|
|
6139
|
+
})
|
|
6140
|
+
},
|
|
6141
|
+
({ id }) => safeCall(() => getLogChunksImpl(callApi, id))
|
|
6142
|
+
);
|
|
6143
|
+
server.registerTool(
|
|
6144
|
+
"inspector_list_sessions",
|
|
6145
|
+
{
|
|
6146
|
+
title: "List known session ids",
|
|
6147
|
+
description: "Returns the array of session ids that have been observed in captured logs. Useful for discovering what sessionId values to pass to inspector_list_logs.",
|
|
6148
|
+
inputSchema: object({})
|
|
6149
|
+
},
|
|
6150
|
+
() => safeCall(() => listSessionsImpl(callApi))
|
|
6151
|
+
);
|
|
6152
|
+
server.registerTool(
|
|
6153
|
+
"inspector_get_session",
|
|
6154
|
+
{
|
|
6155
|
+
title: "Get Inspector session info",
|
|
6156
|
+
description: "Returns a lightweight, evidence-friendly summary for one Inspector session: clickable inspectorUrl, compact logs URL, status, request/error counts, token totals, models/providers, and the latest compact log summaries. Defaults to recent in-memory/cache data for speed; set includeHistory=true only when you explicitly want to scan persisted jsonl history. It avoids raw request/response bodies so it is safe to use in evaluation artifacts.",
|
|
6157
|
+
inputSchema: object({
|
|
6158
|
+
sessionId: string().min(1).describe("The Inspector session id."),
|
|
6159
|
+
includeHistory: boolean().optional().describe("Scan persisted jsonl history for this session. Slower; default false."),
|
|
6160
|
+
latestLogLimit: number().int().positive().max(50).optional().describe("How many latest compact log summaries to include. Max 50, default 10.")
|
|
6161
|
+
})
|
|
6162
|
+
},
|
|
6163
|
+
(args) => safeCall(() => getSessionImpl(callApi, args))
|
|
6164
|
+
);
|
|
6165
|
+
server.registerTool(
|
|
6166
|
+
"inspector_create_run",
|
|
6167
|
+
{
|
|
6168
|
+
title: "Create or declare an Inspector run",
|
|
6169
|
+
description: "Creates an evaluation-friendly run record before a coding-agent task starts. Use this when a benchmark or Jenkins job wants a stable runId/sessionId pair instead of inferring a task after the fact from logs.",
|
|
6170
|
+
inputSchema: object({
|
|
6171
|
+
runId: string().min(1).optional().describe("Stable run id. Generated when omitted."),
|
|
6172
|
+
sessionId: string().min(1).optional().describe("Inspector session id to attach. Defaults to the run id."),
|
|
6173
|
+
title: string().min(1).optional().describe("Human-readable run title."),
|
|
6174
|
+
task: string().nullable().optional().describe("Task statement or benchmark case."),
|
|
6175
|
+
project: string().nullable().optional().describe("Project or repository under test."),
|
|
6176
|
+
agent: string().nullable().optional().describe("Coding agent name, e.g. Codex/OpenCode."),
|
|
6177
|
+
status: InspectorRunStatusSchema.optional().describe("Initial run status."),
|
|
6178
|
+
tags: array(string()).optional().describe("Free-form run labels."),
|
|
6179
|
+
metadata: record(string(), JsonValueSchema).optional().describe("JSON metadata.")
|
|
6180
|
+
})
|
|
6181
|
+
},
|
|
6182
|
+
(args) => safeCall(() => createRunImpl(callApi, args))
|
|
6183
|
+
);
|
|
6184
|
+
server.registerTool(
|
|
6185
|
+
"inspector_get_run",
|
|
6186
|
+
{
|
|
6187
|
+
title: "Get an Inspector run",
|
|
6188
|
+
description: "Returns one declared Inspector run, including its session binding and exported evidence paths when available.",
|
|
6189
|
+
inputSchema: object({
|
|
6190
|
+
runId: string().min(1).describe("The Inspector run id.")
|
|
6191
|
+
})
|
|
6192
|
+
},
|
|
6193
|
+
(args) => safeCall(() => getRunImpl(callApi, args))
|
|
6194
|
+
);
|
|
6195
|
+
server.registerTool(
|
|
6196
|
+
"inspector_update_run",
|
|
5545
6197
|
{
|
|
5546
|
-
title: "
|
|
5547
|
-
description: "
|
|
5548
|
-
inputSchema:
|
|
5549
|
-
|
|
6198
|
+
title: "Update an Inspector run",
|
|
6199
|
+
description: "PATCH-style update for a declared run. Use this during a coding-agent task to mark status transitions such as running, failed, completed, or to attach refined task metadata. Supplied metadata keys are merged into existing metadata.",
|
|
6200
|
+
inputSchema: UpdateInspectorRunInputSchema.extend({
|
|
6201
|
+
runId: string().min(1).describe("The Inspector run id.")
|
|
5550
6202
|
})
|
|
5551
6203
|
},
|
|
5552
|
-
(
|
|
6204
|
+
(args) => safeCall(() => updateRunImpl(callApi, args))
|
|
5553
6205
|
);
|
|
5554
6206
|
server.registerTool(
|
|
5555
|
-
"
|
|
6207
|
+
"inspector_export_evidence",
|
|
5556
6208
|
{
|
|
5557
|
-
title: "
|
|
5558
|
-
description: "
|
|
5559
|
-
inputSchema: object({
|
|
6209
|
+
title: "Export an Inspector evidence pack",
|
|
6210
|
+
description: "Exports one run's evidence pack to local JSON, Markdown, and HTML files under <dataDir>/evidence/<runId> and returns the paths plus session summary.",
|
|
6211
|
+
inputSchema: object({
|
|
6212
|
+
runId: string().min(1).describe("The Inspector run id."),
|
|
6213
|
+
includeHistory: boolean().optional().describe("Scan persisted jsonl history for the bound session. Slower; default false."),
|
|
6214
|
+
latestLogLimit: number().int().positive().max(50).optional().describe("How many compact log summaries to include in the evidence pack. Max 50.")
|
|
6215
|
+
})
|
|
5560
6216
|
},
|
|
5561
|
-
() => safeCall(() =>
|
|
6217
|
+
(args) => safeCall(() => exportEvidenceImpl(callApi, args))
|
|
5562
6218
|
);
|
|
5563
6219
|
server.registerTool(
|
|
5564
|
-
"
|
|
6220
|
+
"inspector_get_recent_failures",
|
|
5565
6221
|
{
|
|
5566
|
-
title: "Get Inspector
|
|
5567
|
-
description: "Returns
|
|
6222
|
+
title: "Get recent Inspector failures",
|
|
6223
|
+
description: "Returns recent declared runs that are failed/cancelled or have non-success exported evidence, including classification, Jenkins summary, Inspector link, and evidence paths when available.",
|
|
5568
6224
|
inputSchema: object({
|
|
5569
|
-
|
|
5570
|
-
includeHistory: boolean().optional().describe("Scan persisted jsonl history for this session. Slower; default false."),
|
|
5571
|
-
latestLogLimit: number().int().positive().max(50).optional().describe("How many latest compact log summaries to include. Max 50, default 10.")
|
|
6225
|
+
limit: number().int().positive().max(20).optional().describe("Maximum failures to return. Default 5, max 20.")
|
|
5572
6226
|
})
|
|
5573
6227
|
},
|
|
5574
|
-
(args) => safeCall(() =>
|
|
6228
|
+
(args) => safeCall(() => getRecentFailuresImpl(callApi, args))
|
|
5575
6229
|
);
|
|
5576
6230
|
server.registerTool(
|
|
5577
6231
|
"inspector_list_models",
|
|
@@ -5724,7 +6378,211 @@ PATCH-style update: only the fields you supply are changed. Returns the updated
|
|
|
5724
6378
|
(args) => safeCall(() => getProjectContextImpl(callApi, args))
|
|
5725
6379
|
);
|
|
5726
6380
|
}
|
|
5727
|
-
|
|
6381
|
+
function registerResources(server) {
|
|
6382
|
+
server.registerResource(
|
|
6383
|
+
"inspector_sessions",
|
|
6384
|
+
"inspector://sessions",
|
|
6385
|
+
{
|
|
6386
|
+
title: "Inspector sessions",
|
|
6387
|
+
description: "Observed Inspector session ids.",
|
|
6388
|
+
mimeType: "application/json"
|
|
6389
|
+
},
|
|
6390
|
+
(uri) => readApiJsonResource(uri, "/api/sessions")
|
|
6391
|
+
);
|
|
6392
|
+
server.registerResource(
|
|
6393
|
+
"inspector_session",
|
|
6394
|
+
new ResourceTemplate("inspector://sessions/{sessionId}", { list: listSessionResources }),
|
|
6395
|
+
{
|
|
6396
|
+
title: "Inspector session",
|
|
6397
|
+
description: "Evidence-friendly session summary with Inspector URL, compact logs URL, counts, models, providers, token totals, and recent compact logs.",
|
|
6398
|
+
mimeType: "application/json"
|
|
6399
|
+
},
|
|
6400
|
+
(uri, variables) => {
|
|
6401
|
+
const sessionId = variableString(variables, "sessionId");
|
|
6402
|
+
if (sessionId === null) return textResource(uri, "text/plain", "Missing sessionId");
|
|
6403
|
+
const params = new URLSearchParams({ sessionId, limit: "10" });
|
|
6404
|
+
return readApiJsonResource(uri, `/api/sessions?${params.toString()}`);
|
|
6405
|
+
}
|
|
6406
|
+
);
|
|
6407
|
+
server.registerResource(
|
|
6408
|
+
"inspector_log",
|
|
6409
|
+
new ResourceTemplate("inspector://logs/{id}", { list: listLogResources }),
|
|
6410
|
+
{
|
|
6411
|
+
title: "Inspector log",
|
|
6412
|
+
description: "Single captured proxy log by numeric id.",
|
|
6413
|
+
mimeType: "application/json"
|
|
6414
|
+
},
|
|
6415
|
+
async (uri, variables) => {
|
|
6416
|
+
const id = variableString(variables, "id");
|
|
6417
|
+
const parsed = id === null ? Number.NaN : Number(id);
|
|
6418
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
6419
|
+
return textResource(uri, "text/plain", "Invalid log id");
|
|
6420
|
+
}
|
|
6421
|
+
const result = await getLogImpl(callApi, parsed);
|
|
6422
|
+
const first = result.content[0];
|
|
6423
|
+
const text = first?.text ?? "";
|
|
6424
|
+
return textResource(uri, result.isError === true ? "text/plain" : "application/json", text);
|
|
6425
|
+
}
|
|
6426
|
+
);
|
|
6427
|
+
server.registerResource(
|
|
6428
|
+
"inspector_runs",
|
|
6429
|
+
"inspector://runs",
|
|
6430
|
+
{
|
|
6431
|
+
title: "Inspector runs",
|
|
6432
|
+
description: "Declared Inspector evaluation runs.",
|
|
6433
|
+
mimeType: "application/json"
|
|
6434
|
+
},
|
|
6435
|
+
(uri) => readApiJsonResource(uri, "/api/runs")
|
|
6436
|
+
);
|
|
6437
|
+
server.registerResource(
|
|
6438
|
+
"inspector_recent_failures",
|
|
6439
|
+
"inspector://failures/recent",
|
|
6440
|
+
{
|
|
6441
|
+
title: "Recent Inspector failures",
|
|
6442
|
+
description: "Recent declared runs with failed/cancelled status or non-success exported evidence.",
|
|
6443
|
+
mimeType: "application/json"
|
|
6444
|
+
},
|
|
6445
|
+
(uri) => readApiJsonResource(uri, "/api/runs?failures=1&limit=10")
|
|
6446
|
+
);
|
|
6447
|
+
server.registerResource(
|
|
6448
|
+
"inspector_run",
|
|
6449
|
+
new ResourceTemplate("inspector://runs/{runId}", { list: listRunResources }),
|
|
6450
|
+
{
|
|
6451
|
+
title: "Inspector run",
|
|
6452
|
+
description: "One declared Inspector run, including session binding and evidence paths.",
|
|
6453
|
+
mimeType: "application/json"
|
|
6454
|
+
},
|
|
6455
|
+
(uri, variables) => {
|
|
6456
|
+
const runId = variableString(variables, "runId");
|
|
6457
|
+
if (runId === null) return textResource(uri, "text/plain", "Missing runId");
|
|
6458
|
+
return readApiJsonResource(uri, `/api/runs/${encodeURIComponent(runId)}`);
|
|
6459
|
+
}
|
|
6460
|
+
);
|
|
6461
|
+
server.registerResource(
|
|
6462
|
+
"inspector_evidence",
|
|
6463
|
+
new ResourceTemplate("inspector://evidence/{runId}", { list: listEvidenceResources }),
|
|
6464
|
+
{
|
|
6465
|
+
title: "Inspector evidence pack",
|
|
6466
|
+
description: "Markdown evidence pack for a declared Inspector run. Generate it first with inspector_export_evidence.",
|
|
6467
|
+
mimeType: "text/markdown"
|
|
6468
|
+
},
|
|
6469
|
+
async (uri, variables) => {
|
|
6470
|
+
const runId = variableString(variables, "runId");
|
|
6471
|
+
if (runId === null) return textResource(uri, "text/plain", "Missing runId");
|
|
6472
|
+
const path2 = `/api/runs/${encodeURIComponent(runId)}/evidence`;
|
|
6473
|
+
try {
|
|
6474
|
+
const response = await callApi(path2);
|
|
6475
|
+
if (!response.ok) {
|
|
6476
|
+
return textResource(uri, "text/plain", `GET ${path2} returned ${response.status}`);
|
|
6477
|
+
}
|
|
6478
|
+
const parsed = EvidenceReadResponseSchema.safeParse(await response.json());
|
|
6479
|
+
if (!parsed.success) {
|
|
6480
|
+
return textResource(uri, "text/plain", "Evidence endpoint returned an unparseable body");
|
|
6481
|
+
}
|
|
6482
|
+
return textResource(uri, "text/markdown", parsed.data.markdown);
|
|
6483
|
+
} catch (err) {
|
|
6484
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
6485
|
+
return textResource(uri, "text/plain", `Resource read failed: ${message}`);
|
|
6486
|
+
}
|
|
6487
|
+
}
|
|
6488
|
+
);
|
|
6489
|
+
}
|
|
6490
|
+
function registerPrompts(server) {
|
|
6491
|
+
server.registerPrompt(
|
|
6492
|
+
"inspector_analyze_session_failure",
|
|
6493
|
+
{
|
|
6494
|
+
title: "Analyze session failure",
|
|
6495
|
+
description: "Use Inspector session/log resources to explain why a coding-agent session failed.",
|
|
6496
|
+
argsSchema: object({
|
|
6497
|
+
sessionId: string().min(1).describe("The Inspector session id."),
|
|
6498
|
+
includeHistory: boolean().optional().describe("When true, call inspector_get_session with includeHistory=true if needed.")
|
|
6499
|
+
})
|
|
6500
|
+
},
|
|
6501
|
+
({ sessionId, includeHistory }) => userPrompt(`Analyze this Agent Inspector session and explain why it failed.
|
|
6502
|
+
|
|
6503
|
+
Evidence to read:
|
|
6504
|
+
- Session resource: inspector://sessions/${encodeURIComponent(sessionId)}
|
|
6505
|
+
- Relevant log resources: inspector://logs/{id} for the failing or suspicious log ids
|
|
6506
|
+
|
|
6507
|
+
If includeHistory is ${includeHistory === true ? "true" : "false"} or the session summary looks incomplete, call inspector_get_session with includeHistory=true and latestLogLimit=50.
|
|
6508
|
+
|
|
6509
|
+
Return:
|
|
6510
|
+
1. Outcome and severity
|
|
6511
|
+
2. Most likely root cause
|
|
6512
|
+
3. Evidence bullets with log ids, models, providers, status codes, and error text
|
|
6513
|
+
4. Concrete fix or next diagnostic step
|
|
6514
|
+
5. Confidence and what evidence is still missing`)
|
|
6515
|
+
);
|
|
6516
|
+
server.registerPrompt(
|
|
6517
|
+
"inspector_triage_recent_failures",
|
|
6518
|
+
{
|
|
6519
|
+
title: "Triage recent failures",
|
|
6520
|
+
description: "Use the recent failures resource and log search tool to prioritize coding-agent failures.",
|
|
6521
|
+
argsSchema: object({
|
|
6522
|
+
limit: number().int().positive().max(20).optional().describe("How many failures to triage.")
|
|
6523
|
+
})
|
|
6524
|
+
},
|
|
6525
|
+
({ limit }) => userPrompt(`Triage recent Agent Inspector failures.
|
|
6526
|
+
|
|
6527
|
+
Evidence to read:
|
|
6528
|
+
- Recent failures resource: inspector://failures/recent
|
|
6529
|
+
- For missing details, call inspector_get_recent_failures with limit=${String(limit ?? 5)}
|
|
6530
|
+
- For suspicious sessions/models/providers, call inspector_search_logs and then inspector_get_log for cited ids
|
|
6531
|
+
|
|
6532
|
+
Return:
|
|
6533
|
+
1. Highest-priority failure first
|
|
6534
|
+
2. Run id, session id, category, severity, and evidence links
|
|
6535
|
+
3. Likely root cause and concrete next action
|
|
6536
|
+
4. Whether evidence is sufficient or inspector_export_evidence should be run again`)
|
|
6537
|
+
);
|
|
6538
|
+
server.registerPrompt(
|
|
6539
|
+
"inspector_generate_jenkins_report",
|
|
6540
|
+
{
|
|
6541
|
+
title: "Generate Jenkins report",
|
|
6542
|
+
description: "Generate a Jenkins-friendly Markdown report from an Inspector run and evidence pack.",
|
|
6543
|
+
argsSchema: object({
|
|
6544
|
+
runId: string().min(1).describe("The Inspector run id.")
|
|
6545
|
+
})
|
|
6546
|
+
},
|
|
6547
|
+
({ runId }) => userPrompt(`Generate a Jenkins-ready Markdown report for this Inspector run.
|
|
6548
|
+
|
|
6549
|
+
Evidence to read:
|
|
6550
|
+
- Run resource: inspector://runs/${encodeURIComponent(runId)}
|
|
6551
|
+
- Evidence pack resource: inspector://evidence/${encodeURIComponent(runId)}
|
|
6552
|
+
|
|
6553
|
+
If the evidence pack resource says it has not been exported, call inspector_export_evidence for this run first.
|
|
6554
|
+
|
|
6555
|
+
The report should include:
|
|
6556
|
+
1. Build/run status summary
|
|
6557
|
+
2. Run id, session id, Inspector URLs, and artifact paths
|
|
6558
|
+
3. Models/providers used, token totals, request counts, and error counts
|
|
6559
|
+
4. Failure analysis or success evidence
|
|
6560
|
+
5. Reproducible next action for a developer`)
|
|
6561
|
+
);
|
|
6562
|
+
server.registerPrompt(
|
|
6563
|
+
"inspector_extract_repro_steps",
|
|
6564
|
+
{
|
|
6565
|
+
title: "Extract reproducible steps",
|
|
6566
|
+
description: "Turn an Inspector session into concise repro steps for a developer or evaluator.",
|
|
6567
|
+
argsSchema: object({
|
|
6568
|
+
sessionId: string().min(1).describe("The Inspector session id.")
|
|
6569
|
+
})
|
|
6570
|
+
},
|
|
6571
|
+
({ sessionId }) => userPrompt(`Extract reproducible steps from this Agent Inspector session.
|
|
6572
|
+
|
|
6573
|
+
Evidence to read:
|
|
6574
|
+
- Session resource: inspector://sessions/${encodeURIComponent(sessionId)}
|
|
6575
|
+
- Relevant log resources: inspector://logs/{id}
|
|
6576
|
+
|
|
6577
|
+
Return:
|
|
6578
|
+
1. Preconditions and environment assumptions
|
|
6579
|
+
2. Ordered user/agent actions that led to the behavior
|
|
6580
|
+
3. Exact model/provider/API path details needed to reproduce
|
|
6581
|
+
4. Expected vs actual result
|
|
6582
|
+
5. Minimal verification command or UI check`)
|
|
6583
|
+
);
|
|
6584
|
+
}
|
|
6585
|
+
const Route$n = createFileRoute("/api/mcp")({
|
|
5728
6586
|
server: {
|
|
5729
6587
|
handlers: {
|
|
5730
6588
|
// The SDK may issue either POST, GET, or DELETE. TanStack Start only
|
|
@@ -5736,6 +6594,89 @@ const Route$l = createFileRoute("/api/mcp")({
|
|
|
5736
6594
|
}
|
|
5737
6595
|
}
|
|
5738
6596
|
});
|
|
6597
|
+
const LOG_SEARCH_DEFAULT_LIMIT = 10;
|
|
6598
|
+
const LOG_SEARCH_MAX_LIMIT = 50;
|
|
6599
|
+
const LOG_SEARCH_DEFAULT_SCAN_LIMIT = 200;
|
|
6600
|
+
const LOG_SEARCH_MAX_SCAN_LIMIT = 1e3;
|
|
6601
|
+
function clampPositiveInt(value, fallback, max) {
|
|
6602
|
+
if (!Number.isInteger(value) || value < 1) return fallback;
|
|
6603
|
+
return Math.min(value, max);
|
|
6604
|
+
}
|
|
6605
|
+
function clampLogSearchLimit(value) {
|
|
6606
|
+
return clampPositiveInt(value, LOG_SEARCH_DEFAULT_LIMIT, LOG_SEARCH_MAX_LIMIT);
|
|
6607
|
+
}
|
|
6608
|
+
function clampLogSearchScanLimit(value) {
|
|
6609
|
+
return clampPositiveInt(value, LOG_SEARCH_DEFAULT_SCAN_LIMIT, LOG_SEARCH_MAX_SCAN_LIMIT);
|
|
6610
|
+
}
|
|
6611
|
+
function queryTerms(query) {
|
|
6612
|
+
return query.trim().toLowerCase().split(/\s+/).filter((term) => term.length > 0);
|
|
6613
|
+
}
|
|
6614
|
+
function optionalText(value) {
|
|
6615
|
+
if (value === null || value === void 0) return null;
|
|
6616
|
+
return String(value);
|
|
6617
|
+
}
|
|
6618
|
+
function searchableFields(log) {
|
|
6619
|
+
return [
|
|
6620
|
+
String(log.id),
|
|
6621
|
+
log.timestamp,
|
|
6622
|
+
log.method,
|
|
6623
|
+
log.path,
|
|
6624
|
+
optionalText(log.model),
|
|
6625
|
+
optionalText(log.sessionId),
|
|
6626
|
+
optionalText(log.responseStatus),
|
|
6627
|
+
optionalText(log.elapsedMs),
|
|
6628
|
+
optionalText(log.streaming),
|
|
6629
|
+
log.streaming ? "streaming" : "non-streaming",
|
|
6630
|
+
log.apiFormat,
|
|
6631
|
+
optionalText(log.providerName),
|
|
6632
|
+
optionalText(log.userAgent),
|
|
6633
|
+
optionalText(log.origin),
|
|
6634
|
+
optionalText(log.clientPid),
|
|
6635
|
+
optionalText(log.clientCwd),
|
|
6636
|
+
optionalText(log.clientProjectFolder),
|
|
6637
|
+
optionalText(log.error)
|
|
6638
|
+
].filter((value) => value !== null && value.length > 0);
|
|
6639
|
+
}
|
|
6640
|
+
function matchesTerms(log, terms) {
|
|
6641
|
+
if (terms.length === 0) return true;
|
|
6642
|
+
const haystack = searchableFields(log).join("\n").toLowerCase();
|
|
6643
|
+
return terms.every((term) => haystack.includes(term));
|
|
6644
|
+
}
|
|
6645
|
+
function sortNewestFirst(logs) {
|
|
6646
|
+
return logs.sort((left, right) => {
|
|
6647
|
+
const timestampCompare = right.timestamp.localeCompare(left.timestamp);
|
|
6648
|
+
return timestampCompare !== 0 ? timestampCompare : right.id - left.id;
|
|
6649
|
+
});
|
|
6650
|
+
}
|
|
6651
|
+
async function searchLogsPage(options) {
|
|
6652
|
+
const limit = clampLogSearchLimit(options.limit);
|
|
6653
|
+
const scanLimit = clampLogSearchScanLimit(Math.max(options.scanLimit, options.offset + limit));
|
|
6654
|
+
const firstPage = await listLogsPage({
|
|
6655
|
+
sessionId: options.sessionId,
|
|
6656
|
+
model: options.model,
|
|
6657
|
+
offset: 0,
|
|
6658
|
+
limit: 1,
|
|
6659
|
+
includeBodies: false
|
|
6660
|
+
});
|
|
6661
|
+
const scanOffset = Math.max(firstPage.total - scanLimit, 0);
|
|
6662
|
+
const scanPage = await listLogsPage({
|
|
6663
|
+
sessionId: options.sessionId,
|
|
6664
|
+
model: options.model,
|
|
6665
|
+
offset: scanOffset,
|
|
6666
|
+
limit: scanLimit,
|
|
6667
|
+
includeBodies: false
|
|
6668
|
+
});
|
|
6669
|
+
const terms = queryTerms(options.query);
|
|
6670
|
+
const matches = sortNewestFirst(scanPage.logs.filter((log) => matchesTerms(log, terms)));
|
|
6671
|
+
return {
|
|
6672
|
+
query: options.query,
|
|
6673
|
+
logs: matches.slice(options.offset, options.offset + limit),
|
|
6674
|
+
total: matches.length,
|
|
6675
|
+
offset: options.offset,
|
|
6676
|
+
limit,
|
|
6677
|
+
scanned: scanPage.logs.length
|
|
6678
|
+
};
|
|
6679
|
+
}
|
|
5739
6680
|
const DeleteBodySchema = object({
|
|
5740
6681
|
ids: array(number().int().positive()).optional()
|
|
5741
6682
|
}).optional();
|
|
@@ -5751,7 +6692,7 @@ function parsePositiveInt(value, fallback) {
|
|
|
5751
6692
|
if (!Number.isInteger(parsed) || parsed < 1) return fallback;
|
|
5752
6693
|
return parsed;
|
|
5753
6694
|
}
|
|
5754
|
-
const Route$
|
|
6695
|
+
const Route$m = createFileRoute("/api/logs")({
|
|
5755
6696
|
server: {
|
|
5756
6697
|
handlers: {
|
|
5757
6698
|
GET: async ({ request }) => {
|
|
@@ -5770,7 +6711,18 @@ const Route$k = createFileRoute("/api/logs")({
|
|
|
5770
6711
|
}
|
|
5771
6712
|
const sessionId = url.searchParams.get("sessionId") ?? void 0;
|
|
5772
6713
|
const model = url.searchParams.get("model") ?? void 0;
|
|
6714
|
+
const query = url.searchParams.get("q") ?? url.searchParams.get("search");
|
|
5773
6715
|
const offset = parseNonNegativeInt(url.searchParams.get("offset"), 0);
|
|
6716
|
+
if (query !== null) {
|
|
6717
|
+
const limit2 = parsePositiveInt(url.searchParams.get("limit"), LOG_SEARCH_DEFAULT_LIMIT);
|
|
6718
|
+
const scanLimit = parsePositiveInt(
|
|
6719
|
+
url.searchParams.get("scanLimit"),
|
|
6720
|
+
LOG_SEARCH_DEFAULT_SCAN_LIMIT
|
|
6721
|
+
);
|
|
6722
|
+
return Response.json(
|
|
6723
|
+
await searchLogsPage({ query, sessionId, model, offset, limit: limit2, scanLimit })
|
|
6724
|
+
);
|
|
6725
|
+
}
|
|
5774
6726
|
const limit = parsePositiveInt(url.searchParams.get("limit"), 50);
|
|
5775
6727
|
const includeBodies = url.searchParams.get("compact") !== "1";
|
|
5776
6728
|
return Response.json(
|
|
@@ -5816,7 +6768,7 @@ const Route$k = createFileRoute("/api/logs")({
|
|
|
5816
6768
|
}
|
|
5817
6769
|
});
|
|
5818
6770
|
logger.debug("Health endpoint loaded");
|
|
5819
|
-
const Route$
|
|
6771
|
+
const Route$l = createFileRoute("/api/health")({
|
|
5820
6772
|
server: {
|
|
5821
6773
|
handlers: {
|
|
5822
6774
|
GET: () => {
|
|
@@ -5834,7 +6786,7 @@ const RuntimeConfigPatchSchema = object({
|
|
|
5834
6786
|
}).strict().refine((v) => Object.keys(v).length > 0, {
|
|
5835
6787
|
message: "At least one field must be provided"
|
|
5836
6788
|
});
|
|
5837
|
-
const Route$
|
|
6789
|
+
const Route$k = createFileRoute("/api/config")({
|
|
5838
6790
|
server: {
|
|
5839
6791
|
handlers: {
|
|
5840
6792
|
GET: () => {
|
|
@@ -5863,6 +6815,46 @@ const Route$i = createFileRoute("/api/config")({
|
|
|
5863
6815
|
}
|
|
5864
6816
|
}
|
|
5865
6817
|
});
|
|
6818
|
+
async function readJsonBody$1(request) {
|
|
6819
|
+
try {
|
|
6820
|
+
const raw = await request.text();
|
|
6821
|
+
if (raw.trim().length === 0) return { ok: true, value: {} };
|
|
6822
|
+
return { ok: true, value: JSON.parse(raw) };
|
|
6823
|
+
} catch {
|
|
6824
|
+
return { ok: false };
|
|
6825
|
+
}
|
|
6826
|
+
}
|
|
6827
|
+
const Route$j = createFileRoute("/api/runs/$runId")({
|
|
6828
|
+
server: {
|
|
6829
|
+
handlers: {
|
|
6830
|
+
GET: ({ params }) => {
|
|
6831
|
+
const run = getRun(params.runId);
|
|
6832
|
+
if (run === null) {
|
|
6833
|
+
return Response.json({ error: "Run not found" }, { status: 404 });
|
|
6834
|
+
}
|
|
6835
|
+
return Response.json(run);
|
|
6836
|
+
},
|
|
6837
|
+
PATCH: async ({ params, request }) => {
|
|
6838
|
+
const body = await readJsonBody$1(request);
|
|
6839
|
+
if (!body.ok) {
|
|
6840
|
+
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
6841
|
+
}
|
|
6842
|
+
const parsed = UpdateInspectorRunInputSchema.safeParse(body.value);
|
|
6843
|
+
if (!parsed.success) {
|
|
6844
|
+
return Response.json(
|
|
6845
|
+
{ error: "Invalid request body", details: parsed.error.format() },
|
|
6846
|
+
{ status: 400 }
|
|
6847
|
+
);
|
|
6848
|
+
}
|
|
6849
|
+
const updated = updateRun(params.runId, parsed.data);
|
|
6850
|
+
if (updated === null) {
|
|
6851
|
+
return Response.json({ error: "Run not found" }, { status: 404 });
|
|
6852
|
+
}
|
|
6853
|
+
return Response.json(updated);
|
|
6854
|
+
}
|
|
6855
|
+
}
|
|
6856
|
+
}
|
|
6857
|
+
});
|
|
5866
6858
|
const ZHIPU_OPENAI_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
|
|
5867
6859
|
const ZHIPU_CODING_OPENAI_BASE_URL = "https://open.bigmodel.cn/api/coding/paas/v4";
|
|
5868
6860
|
const ZHIPU_CODING_ANTHROPIC_BASE_URL = "https://open.bigmodel.cn/api/anthropic";
|
|
@@ -6289,7 +7281,7 @@ function scanExternalProviders() {
|
|
|
6289
7281
|
}
|
|
6290
7282
|
return { providers: filteredProviders, warnings };
|
|
6291
7283
|
}
|
|
6292
|
-
const Route$
|
|
7284
|
+
const Route$i = createFileRoute("/api/providers/scan")({
|
|
6293
7285
|
server: {
|
|
6294
7286
|
handlers: {
|
|
6295
7287
|
GET: () => {
|
|
@@ -6310,7 +7302,7 @@ const Route$h = createFileRoute("/api/providers/scan")({
|
|
|
6310
7302
|
}
|
|
6311
7303
|
});
|
|
6312
7304
|
union([string(), object({ providers: unknown() })]);
|
|
6313
|
-
const Route$
|
|
7305
|
+
const Route$h = createFileRoute("/api/providers/import")({
|
|
6314
7306
|
server: {
|
|
6315
7307
|
handlers: {
|
|
6316
7308
|
POST: async ({ request }) => {
|
|
@@ -6343,7 +7335,7 @@ const Route$g = createFileRoute("/api/providers/import")({
|
|
|
6343
7335
|
}
|
|
6344
7336
|
}
|
|
6345
7337
|
});
|
|
6346
|
-
const Route$
|
|
7338
|
+
const Route$g = createFileRoute("/api/providers/export")({
|
|
6347
7339
|
server: {
|
|
6348
7340
|
handlers: {
|
|
6349
7341
|
GET: ({ request }) => {
|
|
@@ -6376,7 +7368,7 @@ const ProviderUpdateSchema = object({
|
|
|
6376
7368
|
modelMetadata: array(ProviderModelMetadataSchema).optional(),
|
|
6377
7369
|
source: _enum(["company", "personal"]).optional()
|
|
6378
7370
|
});
|
|
6379
|
-
const Route$
|
|
7371
|
+
const Route$f = createFileRoute("/api/providers/$providerId")({
|
|
6380
7372
|
server: {
|
|
6381
7373
|
handlers: {
|
|
6382
7374
|
GET: ({ params, request }) => {
|
|
@@ -6411,7 +7403,7 @@ const Route$e = createFileRoute("/api/providers/$providerId")({
|
|
|
6411
7403
|
}
|
|
6412
7404
|
});
|
|
6413
7405
|
const INITIAL_STREAM_LOG_LIMIT = 100;
|
|
6414
|
-
const Route$
|
|
7406
|
+
const Route$e = createFileRoute("/api/logs/stream")({
|
|
6415
7407
|
server: {
|
|
6416
7408
|
handlers: {
|
|
6417
7409
|
GET: ({ request }) => {
|
|
@@ -6484,7 +7476,7 @@ const Route$d = createFileRoute("/api/logs/stream")({
|
|
|
6484
7476
|
}
|
|
6485
7477
|
}
|
|
6486
7478
|
});
|
|
6487
|
-
const Route$
|
|
7479
|
+
const Route$d = createFileRoute("/api/logs/$id")({
|
|
6488
7480
|
server: {
|
|
6489
7481
|
handlers: {
|
|
6490
7482
|
GET: async ({ params }) => {
|
|
@@ -6826,10 +7818,10 @@ function normalizePathSegment(value, fallback) {
|
|
|
6826
7818
|
const segment = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 96);
|
|
6827
7819
|
return segment === "" ? fallback : segment;
|
|
6828
7820
|
}
|
|
6829
|
-
function formatNullable(value) {
|
|
7821
|
+
function formatNullable$1(value) {
|
|
6830
7822
|
return value === null || value === "" ? "unknown" : value;
|
|
6831
7823
|
}
|
|
6832
|
-
function formatList(values) {
|
|
7824
|
+
function formatList$2(values) {
|
|
6833
7825
|
return values.length === 0 ? "none" : values.join(", ");
|
|
6834
7826
|
}
|
|
6835
7827
|
function buildEvidenceLink(candidate) {
|
|
@@ -6852,16 +7844,16 @@ function buildOpenClawMemoryMarkdown(candidate) {
|
|
|
6852
7844
|
"",
|
|
6853
7845
|
`- Type: ${sanitized.type}`,
|
|
6854
7846
|
`- Status: ${sanitized.status}`,
|
|
6855
|
-
`- Project: ${formatNullable(sanitized.evidence.project)}`,
|
|
7847
|
+
`- Project: ${formatNullable$1(sanitized.evidence.project)}`,
|
|
6856
7848
|
`- Session: ${sanitized.sessionId}`,
|
|
6857
7849
|
`- Log IDs: ${sanitized.logIds.join(", ")}`,
|
|
6858
|
-
`- Models: ${formatList(sanitized.evidence.models)}`,
|
|
6859
|
-
`- Tags: ${formatList(sanitized.tags)}`,
|
|
7850
|
+
`- Models: ${formatList$2(sanitized.evidence.models)}`,
|
|
7851
|
+
`- Tags: ${formatList$2(sanitized.tags)}`,
|
|
6860
7852
|
`- Created: ${sanitized.createdAt}`,
|
|
6861
7853
|
`- Updated: ${sanitized.updatedAt}`,
|
|
6862
7854
|
`- Evidence: ${buildEvidenceLink(sanitized)}`,
|
|
6863
7855
|
`- Redacted: ${String(sanitized.redaction.redacted)}`,
|
|
6864
|
-
`- Redaction patterns: ${formatList(sanitized.redaction.patterns)}`,
|
|
7856
|
+
`- Redaction patterns: ${formatList$2(sanitized.redaction.patterns)}`,
|
|
6865
7857
|
"",
|
|
6866
7858
|
"## Durable Knowledge Candidate",
|
|
6867
7859
|
"",
|
|
@@ -7021,7 +8013,7 @@ const SearchBodySchema = object({
|
|
|
7021
8013
|
query: string().min(1),
|
|
7022
8014
|
project: string().optional()
|
|
7023
8015
|
});
|
|
7024
|
-
const Route$
|
|
8016
|
+
const Route$c = createFileRoute("/api/knowledge/search")({
|
|
7025
8017
|
server: {
|
|
7026
8018
|
handlers: {
|
|
7027
8019
|
GET: async ({ request }) => {
|
|
@@ -7043,7 +8035,7 @@ const Route$b = createFileRoute("/api/knowledge/search")({
|
|
|
7043
8035
|
}
|
|
7044
8036
|
}
|
|
7045
8037
|
});
|
|
7046
|
-
const Route$
|
|
8038
|
+
const Route$b = createFileRoute("/api/knowledge/project-context")({
|
|
7047
8039
|
server: {
|
|
7048
8040
|
handlers: {
|
|
7049
8041
|
GET: async ({ request }) => {
|
|
@@ -7125,14 +8117,14 @@ function updateCandidateDraft(id, updates) {
|
|
|
7125
8117
|
candidates.set(id, updated);
|
|
7126
8118
|
return updated;
|
|
7127
8119
|
}
|
|
7128
|
-
const Route$
|
|
8120
|
+
const Route$a = createFileRoute("/api/knowledge/candidates")({
|
|
7129
8121
|
server: {
|
|
7130
8122
|
handlers: {
|
|
7131
8123
|
GET: () => Response.json({ candidates: listCandidates() })
|
|
7132
8124
|
}
|
|
7133
8125
|
}
|
|
7134
8126
|
});
|
|
7135
|
-
const Route$
|
|
8127
|
+
const Route$9 = createFileRoute("/api/config/paths")({
|
|
7136
8128
|
server: {
|
|
7137
8129
|
handlers: {
|
|
7138
8130
|
GET: () => {
|
|
@@ -7143,6 +8135,653 @@ const Route$8 = createFileRoute("/api/config/paths")({
|
|
|
7143
8135
|
}
|
|
7144
8136
|
}
|
|
7145
8137
|
});
|
|
8138
|
+
function formatNullable(value) {
|
|
8139
|
+
return value === null ? "n/a" : String(value);
|
|
8140
|
+
}
|
|
8141
|
+
function formatList$1(values) {
|
|
8142
|
+
return values.length > 0 ? values.join(", ") : "n/a";
|
|
8143
|
+
}
|
|
8144
|
+
function lower(value) {
|
|
8145
|
+
return value.toLowerCase();
|
|
8146
|
+
}
|
|
8147
|
+
function logEvidenceText(log) {
|
|
8148
|
+
return lower(
|
|
8149
|
+
[
|
|
8150
|
+
log.error,
|
|
8151
|
+
log.path,
|
|
8152
|
+
log.model,
|
|
8153
|
+
log.provider,
|
|
8154
|
+
log.status === null ? null : String(log.status),
|
|
8155
|
+
log.isStreaming ? "streaming" : "non-streaming"
|
|
8156
|
+
].filter((value) => value !== null).join(" ")
|
|
8157
|
+
);
|
|
8158
|
+
}
|
|
8159
|
+
function collectErrorCandidates(session) {
|
|
8160
|
+
const candidates2 = session.latestLogs.filter((log) => log.hasError).map((log) => ({ log, text: logEvidenceText(log) }));
|
|
8161
|
+
if (session.lastTaskError !== null) {
|
|
8162
|
+
candidates2.push({ log: null, text: lower(session.lastTaskError) });
|
|
8163
|
+
}
|
|
8164
|
+
return candidates2;
|
|
8165
|
+
}
|
|
8166
|
+
function hasText(candidates2, patterns) {
|
|
8167
|
+
return candidates2.some(
|
|
8168
|
+
(candidate) => patterns.some((pattern) => candidate.text.includes(pattern))
|
|
8169
|
+
);
|
|
8170
|
+
}
|
|
8171
|
+
function hasStatus(session, predicate) {
|
|
8172
|
+
return session.latestLogs.some((log) => log.status !== null && predicate(log.status));
|
|
8173
|
+
}
|
|
8174
|
+
function evidenceIds(candidates2) {
|
|
8175
|
+
const ids = /* @__PURE__ */ new Set();
|
|
8176
|
+
for (const candidate of candidates2) {
|
|
8177
|
+
if (candidate.log !== null) {
|
|
8178
|
+
ids.add(candidate.log.id);
|
|
8179
|
+
}
|
|
8180
|
+
}
|
|
8181
|
+
return [...ids].sort((left, right) => left - right);
|
|
8182
|
+
}
|
|
8183
|
+
function hasStreamingMismatch(session) {
|
|
8184
|
+
for (const failed of session.latestLogs.filter((log) => log.hasError)) {
|
|
8185
|
+
const matchingSuccess = session.latestLogs.some(
|
|
8186
|
+
(log) => !log.hasError && log.model === failed.model && log.provider === failed.provider && log.isStreaming !== failed.isStreaming
|
|
8187
|
+
);
|
|
8188
|
+
if (matchingSuccess) return true;
|
|
8189
|
+
}
|
|
8190
|
+
return false;
|
|
8191
|
+
}
|
|
8192
|
+
function categorySummary(category) {
|
|
8193
|
+
switch (category) {
|
|
8194
|
+
case "none":
|
|
8195
|
+
return "Session completed without captured errors.";
|
|
8196
|
+
case "active":
|
|
8197
|
+
return "Session still has active requests or running tasks.";
|
|
8198
|
+
case "provider-timeout":
|
|
8199
|
+
return "Provider call appears to have timed out.";
|
|
8200
|
+
case "provider-http-error":
|
|
8201
|
+
return "Provider returned an HTTP error.";
|
|
8202
|
+
case "provider-auth-error":
|
|
8203
|
+
return "Provider authentication or API key configuration appears invalid.";
|
|
8204
|
+
case "provider-rate-limit":
|
|
8205
|
+
return "Provider rejected the request because of rate limit or quota pressure.";
|
|
8206
|
+
case "network-or-container":
|
|
8207
|
+
return "Network connectivity looks suspicious; check container boundaries and localhost use.";
|
|
8208
|
+
case "streaming-mismatch":
|
|
8209
|
+
return "Streaming and non-streaming behavior differ for the same provider/model.";
|
|
8210
|
+
case "context-pressure":
|
|
8211
|
+
return "The failure looks related to context window or token pressure.";
|
|
8212
|
+
case "runtime-task-error":
|
|
8213
|
+
return "Inspector session runtime reported a task error.";
|
|
8214
|
+
case "model-output-error":
|
|
8215
|
+
return "The model output or upstream payload shape appears invalid.";
|
|
8216
|
+
case "unknown-failure":
|
|
8217
|
+
return "Inspector captured errors, but the root cause is not yet classified.";
|
|
8218
|
+
case "no-session-data":
|
|
8219
|
+
return "No Inspector session data was available for this run.";
|
|
8220
|
+
}
|
|
8221
|
+
}
|
|
8222
|
+
function categoryHints(category) {
|
|
8223
|
+
switch (category) {
|
|
8224
|
+
case "none":
|
|
8225
|
+
return ["Keep the evidence pack as the success proof for CI or release notes."];
|
|
8226
|
+
case "active":
|
|
8227
|
+
return ["Wait for the session to settle, then export evidence again."];
|
|
8228
|
+
case "provider-timeout":
|
|
8229
|
+
return [
|
|
8230
|
+
"Increase the provider test timeout for slow models.",
|
|
8231
|
+
"Compare streaming and non-streaming probes for the same model."
|
|
8232
|
+
];
|
|
8233
|
+
case "provider-http-error":
|
|
8234
|
+
return [
|
|
8235
|
+
"Open the cited log ids and inspect upstream status, response body, and provider URL."
|
|
8236
|
+
];
|
|
8237
|
+
case "provider-auth-error":
|
|
8238
|
+
return ["Verify the provider API key, auth header mode, and configured base URL."];
|
|
8239
|
+
case "provider-rate-limit":
|
|
8240
|
+
return [
|
|
8241
|
+
"Retry after provider quota recovers or switch to a less constrained provider/model."
|
|
8242
|
+
];
|
|
8243
|
+
case "network-or-container":
|
|
8244
|
+
return [
|
|
8245
|
+
"If the coding agent and Inspector are in different containers, replace localhost with a reachable host.",
|
|
8246
|
+
"Check DNS, proxy, firewall, and container network routes."
|
|
8247
|
+
];
|
|
8248
|
+
case "streaming-mismatch":
|
|
8249
|
+
return [
|
|
8250
|
+
"Compare the streaming and non-streaming captured logs side by side.",
|
|
8251
|
+
"Check whether the provider's OpenAI-compatible endpoint handles stream=false differently."
|
|
8252
|
+
];
|
|
8253
|
+
case "context-pressure":
|
|
8254
|
+
return [
|
|
8255
|
+
"Reduce prompt/tool schema/history size or configure the model context window metadata."
|
|
8256
|
+
];
|
|
8257
|
+
case "runtime-task-error":
|
|
8258
|
+
return ["Inspect the session runtime error and retry after clearing stuck session tasks."];
|
|
8259
|
+
case "model-output-error":
|
|
8260
|
+
return ["Inspect the raw response and schema parsing details for the cited log ids."];
|
|
8261
|
+
case "unknown-failure":
|
|
8262
|
+
return [
|
|
8263
|
+
"Open the cited logs and inspect error/status/latency fields to refine the diagnosis."
|
|
8264
|
+
];
|
|
8265
|
+
case "no-session-data":
|
|
8266
|
+
return [
|
|
8267
|
+
"Confirm the run's sessionId matches captured traffic and that history scanning is enabled when needed."
|
|
8268
|
+
];
|
|
8269
|
+
}
|
|
8270
|
+
}
|
|
8271
|
+
function classifyCategory(session, candidates2) {
|
|
8272
|
+
if (session.status === "active") return "active";
|
|
8273
|
+
if (session.errorCount === 0 && session.failedRequests === 0 && session.lastTaskError === null) {
|
|
8274
|
+
return "none";
|
|
8275
|
+
}
|
|
8276
|
+
if (hasStreamingMismatch(session)) return "streaming-mismatch";
|
|
8277
|
+
if (hasText(candidates2, [
|
|
8278
|
+
"timeout",
|
|
8279
|
+
"timed out",
|
|
8280
|
+
"etimedout",
|
|
8281
|
+
"deadline",
|
|
8282
|
+
"aborterror",
|
|
8283
|
+
"econnaborted"
|
|
8284
|
+
])) {
|
|
8285
|
+
return "provider-timeout";
|
|
8286
|
+
}
|
|
8287
|
+
if (hasText(candidates2, ["localhost", "econnrefused", "enotfound", "network", "fetch failed"])) {
|
|
8288
|
+
return "network-or-container";
|
|
8289
|
+
}
|
|
8290
|
+
if (hasStatus(session, (status) => status === 401 || status === 403)) {
|
|
8291
|
+
return "provider-auth-error";
|
|
8292
|
+
}
|
|
8293
|
+
if (hasText(candidates2, ["unauthorized", "forbidden", "invalid api key", "api key"])) {
|
|
8294
|
+
return "provider-auth-error";
|
|
8295
|
+
}
|
|
8296
|
+
if (hasStatus(session, (status) => status === 429)) return "provider-rate-limit";
|
|
8297
|
+
if (hasText(candidates2, ["rate limit", "quota"])) return "provider-rate-limit";
|
|
8298
|
+
if (hasText(candidates2, ["context", "too many tokens", "token limit", "maximum context"])) {
|
|
8299
|
+
return "context-pressure";
|
|
8300
|
+
}
|
|
8301
|
+
if (session.lastTaskError !== null) return "runtime-task-error";
|
|
8302
|
+
if (hasText(candidates2, ["invalid json", "schema", "parse", "malformed"])) {
|
|
8303
|
+
return "model-output-error";
|
|
8304
|
+
}
|
|
8305
|
+
if (hasStatus(session, (status) => status >= 400)) return "provider-http-error";
|
|
8306
|
+
return "unknown-failure";
|
|
8307
|
+
}
|
|
8308
|
+
function severityFor(category) {
|
|
8309
|
+
switch (category) {
|
|
8310
|
+
case "none":
|
|
8311
|
+
return "none";
|
|
8312
|
+
case "active":
|
|
8313
|
+
return "low";
|
|
8314
|
+
case "provider-timeout":
|
|
8315
|
+
case "provider-http-error":
|
|
8316
|
+
case "provider-auth-error":
|
|
8317
|
+
case "provider-rate-limit":
|
|
8318
|
+
case "network-or-container":
|
|
8319
|
+
case "streaming-mismatch":
|
|
8320
|
+
case "runtime-task-error":
|
|
8321
|
+
return "high";
|
|
8322
|
+
case "context-pressure":
|
|
8323
|
+
case "model-output-error":
|
|
8324
|
+
case "unknown-failure":
|
|
8325
|
+
case "no-session-data":
|
|
8326
|
+
return "medium";
|
|
8327
|
+
}
|
|
8328
|
+
}
|
|
8329
|
+
function outcomeFor$1(category) {
|
|
8330
|
+
switch (category) {
|
|
8331
|
+
case "none":
|
|
8332
|
+
return "success";
|
|
8333
|
+
case "active":
|
|
8334
|
+
return "active";
|
|
8335
|
+
case "no-session-data":
|
|
8336
|
+
return "unknown";
|
|
8337
|
+
case "provider-timeout":
|
|
8338
|
+
case "provider-http-error":
|
|
8339
|
+
case "provider-auth-error":
|
|
8340
|
+
case "provider-rate-limit":
|
|
8341
|
+
case "network-or-container":
|
|
8342
|
+
case "streaming-mismatch":
|
|
8343
|
+
case "context-pressure":
|
|
8344
|
+
case "runtime-task-error":
|
|
8345
|
+
case "model-output-error":
|
|
8346
|
+
case "unknown-failure":
|
|
8347
|
+
return "failure";
|
|
8348
|
+
}
|
|
8349
|
+
}
|
|
8350
|
+
function classifyRunFailure(run, session) {
|
|
8351
|
+
if (session === null) {
|
|
8352
|
+
const category2 = "no-session-data";
|
|
8353
|
+
return {
|
|
8354
|
+
outcome: outcomeFor$1(category2),
|
|
8355
|
+
severity: severityFor(category2),
|
|
8356
|
+
category: category2,
|
|
8357
|
+
summary: `${categorySummary(category2)} Run ${run.id} is bound to session ${run.sessionId}.`,
|
|
8358
|
+
evidenceLogIds: [],
|
|
8359
|
+
hints: categoryHints(category2)
|
|
8360
|
+
};
|
|
8361
|
+
}
|
|
8362
|
+
const candidates2 = collectErrorCandidates(session);
|
|
8363
|
+
const category = classifyCategory(session, candidates2);
|
|
8364
|
+
const summary = category === "none" ? `${categorySummary(category)} ${String(session.requestCount)} request(s), ${String(
|
|
8365
|
+
session.tokenUsage.total
|
|
8366
|
+
)} token(s).` : `${categorySummary(category)} ${String(session.errorCount)} error log(s), ${String(
|
|
8367
|
+
session.failedRequests
|
|
8368
|
+
)} failed request(s).`;
|
|
8369
|
+
return {
|
|
8370
|
+
outcome: outcomeFor$1(category),
|
|
8371
|
+
severity: severityFor(category),
|
|
8372
|
+
category,
|
|
8373
|
+
summary,
|
|
8374
|
+
evidenceLogIds: evidenceIds(candidates2),
|
|
8375
|
+
hints: categoryHints(category)
|
|
8376
|
+
};
|
|
8377
|
+
}
|
|
8378
|
+
function logTitle(log) {
|
|
8379
|
+
if (log.hasError) return `Request failed: log ${String(log.id)}`;
|
|
8380
|
+
if (log.status !== null && log.status >= 200 && log.status < 400) {
|
|
8381
|
+
return `Request succeeded: log ${String(log.id)}`;
|
|
8382
|
+
}
|
|
8383
|
+
return `Request captured: log ${String(log.id)}`;
|
|
8384
|
+
}
|
|
8385
|
+
function logDetails(log) {
|
|
8386
|
+
const parts = [
|
|
8387
|
+
`path=${log.path}`,
|
|
8388
|
+
`status=${formatNullable(log.status)}`,
|
|
8389
|
+
`model=${formatNullable(log.model)}`,
|
|
8390
|
+
`provider=${formatNullable(log.provider)}`,
|
|
8391
|
+
`streaming=${log.isStreaming ? "yes" : "no"}`,
|
|
8392
|
+
`latencyMs=${formatNullable(log.latencyMs)}`
|
|
8393
|
+
];
|
|
8394
|
+
if (log.error !== null) {
|
|
8395
|
+
parts.push(`error=${log.error}`);
|
|
8396
|
+
}
|
|
8397
|
+
return parts.join(", ");
|
|
8398
|
+
}
|
|
8399
|
+
function buildRunTimeline(run, session, exportedAt) {
|
|
8400
|
+
const events = [
|
|
8401
|
+
{
|
|
8402
|
+
timestamp: run.createdAt,
|
|
8403
|
+
kind: "run-created",
|
|
8404
|
+
severity: "info",
|
|
8405
|
+
title: "Run declared",
|
|
8406
|
+
details: `Run ${run.id} was declared for session ${run.sessionId}.`,
|
|
8407
|
+
logId: null,
|
|
8408
|
+
status: null,
|
|
8409
|
+
model: null,
|
|
8410
|
+
provider: null,
|
|
8411
|
+
latencyMs: null,
|
|
8412
|
+
isStreaming: null
|
|
8413
|
+
}
|
|
8414
|
+
];
|
|
8415
|
+
if (session !== null && session.createdAt !== null) {
|
|
8416
|
+
events.push({
|
|
8417
|
+
timestamp: session.createdAt,
|
|
8418
|
+
kind: "session-started",
|
|
8419
|
+
severity: "info",
|
|
8420
|
+
title: "Session started",
|
|
8421
|
+
details: `Inspector session ${session.id} started with source ${session.source ?? "unknown"}.`,
|
|
8422
|
+
logId: null,
|
|
8423
|
+
status: null,
|
|
8424
|
+
model: null,
|
|
8425
|
+
provider: null,
|
|
8426
|
+
latencyMs: null,
|
|
8427
|
+
isStreaming: null
|
|
8428
|
+
});
|
|
8429
|
+
}
|
|
8430
|
+
if (session !== null) {
|
|
8431
|
+
const logs = [...session.latestLogs].sort(
|
|
8432
|
+
(left, right) => left.timestamp.localeCompare(right.timestamp)
|
|
8433
|
+
);
|
|
8434
|
+
for (const log of logs) {
|
|
8435
|
+
events.push({
|
|
8436
|
+
timestamp: log.timestamp,
|
|
8437
|
+
kind: "request",
|
|
8438
|
+
severity: log.hasError ? "error" : "success",
|
|
8439
|
+
title: logTitle(log),
|
|
8440
|
+
details: logDetails(log),
|
|
8441
|
+
logId: log.id,
|
|
8442
|
+
status: log.status,
|
|
8443
|
+
model: log.model,
|
|
8444
|
+
provider: log.provider,
|
|
8445
|
+
latencyMs: log.latencyMs,
|
|
8446
|
+
isStreaming: log.isStreaming
|
|
8447
|
+
});
|
|
8448
|
+
}
|
|
8449
|
+
if (session.updatedAt !== null) {
|
|
8450
|
+
events.push({
|
|
8451
|
+
timestamp: session.updatedAt,
|
|
8452
|
+
kind: "session-finished",
|
|
8453
|
+
severity: session.status === "failed" ? "error" : session.status === "active" ? "warning" : "success",
|
|
8454
|
+
title: `Session ${session.status}`,
|
|
8455
|
+
details: `${String(session.requestCount)} request(s), ${String(
|
|
8456
|
+
session.errorCount
|
|
8457
|
+
)} error(s), ${String(session.tokenUsage.total)} token(s).`,
|
|
8458
|
+
logId: session.lastLogId,
|
|
8459
|
+
status: null,
|
|
8460
|
+
model: session.lastModel,
|
|
8461
|
+
provider: null,
|
|
8462
|
+
latencyMs: null,
|
|
8463
|
+
isStreaming: null
|
|
8464
|
+
});
|
|
8465
|
+
}
|
|
8466
|
+
}
|
|
8467
|
+
events.push({
|
|
8468
|
+
timestamp: exportedAt,
|
|
8469
|
+
kind: "evidence-exported",
|
|
8470
|
+
severity: "info",
|
|
8471
|
+
title: "Evidence exported",
|
|
8472
|
+
details: `Evidence pack exported at ${exportedAt}.`,
|
|
8473
|
+
logId: null,
|
|
8474
|
+
status: null,
|
|
8475
|
+
model: null,
|
|
8476
|
+
provider: null,
|
|
8477
|
+
latencyMs: null,
|
|
8478
|
+
isStreaming: null
|
|
8479
|
+
});
|
|
8480
|
+
return events.sort((left, right) => left.timestamp.localeCompare(right.timestamp));
|
|
8481
|
+
}
|
|
8482
|
+
function reportStatus(classification) {
|
|
8483
|
+
switch (classification.outcome) {
|
|
8484
|
+
case "success":
|
|
8485
|
+
return "PASS";
|
|
8486
|
+
case "failure":
|
|
8487
|
+
return "FAIL";
|
|
8488
|
+
case "active":
|
|
8489
|
+
return "RUNNING";
|
|
8490
|
+
case "unknown":
|
|
8491
|
+
return "UNKNOWN";
|
|
8492
|
+
}
|
|
8493
|
+
}
|
|
8494
|
+
function timelineMarkdown(timeline) {
|
|
8495
|
+
if (timeline.length === 0) return ["No timeline events were available."];
|
|
8496
|
+
return [
|
|
8497
|
+
"| Time | Event | Severity | Evidence |",
|
|
8498
|
+
"| --- | --- | --- | --- |",
|
|
8499
|
+
...timeline.map((event) => {
|
|
8500
|
+
const evidence = event.logId === null ? "n/a" : `log ${String(event.logId)}`;
|
|
8501
|
+
return `| ${event.timestamp} | ${event.title} | ${event.severity} | ${evidence} |`;
|
|
8502
|
+
})
|
|
8503
|
+
];
|
|
8504
|
+
}
|
|
8505
|
+
function buildJenkinsReport(input) {
|
|
8506
|
+
const status = reportStatus(input.classification);
|
|
8507
|
+
const session = input.session;
|
|
8508
|
+
const summary = `[${status}] ${input.classification.summary}`;
|
|
8509
|
+
const lines = [
|
|
8510
|
+
`# Jenkins Report: ${input.run.title}`,
|
|
8511
|
+
"",
|
|
8512
|
+
`- Status: ${status}`,
|
|
8513
|
+
`- Run ID: ${input.run.id}`,
|
|
8514
|
+
`- Session ID: ${input.run.sessionId}`,
|
|
8515
|
+
`- Inspector URL: ${session?.inspectorUrl ?? "n/a"}`,
|
|
8516
|
+
`- Category: ${input.classification.category}`,
|
|
8517
|
+
`- Severity: ${input.classification.severity}`,
|
|
8518
|
+
`- Summary: ${input.classification.summary}`,
|
|
8519
|
+
`- Evidence Logs: ${input.classification.evidenceLogIds.length > 0 ? input.classification.evidenceLogIds.map((id) => `#${String(id)}`).join(", ") : "n/a"}`,
|
|
8520
|
+
"",
|
|
8521
|
+
"## Session Metrics",
|
|
8522
|
+
"",
|
|
8523
|
+
`- Requests: ${String(session?.requestCount ?? 0)}`,
|
|
8524
|
+
`- Errors: ${String(session?.errorCount ?? 0)}`,
|
|
8525
|
+
`- Models: ${formatList$1(session?.models ?? [])}`,
|
|
8526
|
+
`- Providers: ${formatList$1(session?.providers ?? [])}`,
|
|
8527
|
+
`- Tokens: ${String(session?.tokenUsage.total ?? 0)}`,
|
|
8528
|
+
"",
|
|
8529
|
+
"## Timeline",
|
|
8530
|
+
"",
|
|
8531
|
+
...timelineMarkdown(input.timeline),
|
|
8532
|
+
"",
|
|
8533
|
+
"## Artifacts",
|
|
8534
|
+
"",
|
|
8535
|
+
`- JSON: ${input.evidencePaths.jsonPath}`,
|
|
8536
|
+
`- Markdown: ${input.evidencePaths.markdownPath}`,
|
|
8537
|
+
`- HTML: ${input.evidencePaths.htmlPath}`,
|
|
8538
|
+
"",
|
|
8539
|
+
"## Next Actions",
|
|
8540
|
+
"",
|
|
8541
|
+
...input.classification.hints.map((hint) => `- ${hint}`),
|
|
8542
|
+
""
|
|
8543
|
+
];
|
|
8544
|
+
return {
|
|
8545
|
+
status,
|
|
8546
|
+
summary,
|
|
8547
|
+
markdown: lines.join("\n")
|
|
8548
|
+
};
|
|
8549
|
+
}
|
|
8550
|
+
function analyzeEvidence(input) {
|
|
8551
|
+
const classification = classifyRunFailure(input.run, input.session);
|
|
8552
|
+
const timeline = buildRunTimeline(input.run, input.session, input.exportedAt);
|
|
8553
|
+
const jenkinsReport = buildJenkinsReport({
|
|
8554
|
+
run: input.run,
|
|
8555
|
+
session: input.session,
|
|
8556
|
+
timeline,
|
|
8557
|
+
classification,
|
|
8558
|
+
evidencePaths: input.evidencePaths
|
|
8559
|
+
});
|
|
8560
|
+
return { classification, timeline, jenkinsReport };
|
|
8561
|
+
}
|
|
8562
|
+
function evidenceDir(runId) {
|
|
8563
|
+
return join(getDataDir(), "evidence", runId);
|
|
8564
|
+
}
|
|
8565
|
+
function jsonPath(runId) {
|
|
8566
|
+
return join(evidenceDir(runId), "evidence.json");
|
|
8567
|
+
}
|
|
8568
|
+
function markdownPath(runId) {
|
|
8569
|
+
return join(evidenceDir(runId), "evidence.md");
|
|
8570
|
+
}
|
|
8571
|
+
function htmlPath(runId) {
|
|
8572
|
+
return join(evidenceDir(runId), "evidence.html");
|
|
8573
|
+
}
|
|
8574
|
+
function formatList(values) {
|
|
8575
|
+
return values.length > 0 ? values.join(", ") : "n/a";
|
|
8576
|
+
}
|
|
8577
|
+
function escapeHtml(value) {
|
|
8578
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
8579
|
+
}
|
|
8580
|
+
function buildMarkdown(document) {
|
|
8581
|
+
const session = document.session;
|
|
8582
|
+
const lines = [
|
|
8583
|
+
`# ${document.run.title}`,
|
|
8584
|
+
"",
|
|
8585
|
+
`- Run ID: ${document.run.id}`,
|
|
8586
|
+
`- Session ID: ${document.run.sessionId}`,
|
|
8587
|
+
`- Status: ${document.run.status}`,
|
|
8588
|
+
`- Project: ${document.run.project ?? "n/a"}`,
|
|
8589
|
+
`- Agent: ${document.run.agent ?? "n/a"}`,
|
|
8590
|
+
`- Created: ${document.run.createdAt}`,
|
|
8591
|
+
"",
|
|
8592
|
+
`- Outcome: ${document.classification.outcome}`,
|
|
8593
|
+
`- Failure Category: ${document.classification.category}`,
|
|
8594
|
+
`- Severity: ${document.classification.severity}`,
|
|
8595
|
+
`- Evidence JSON: ${document.evidence.jsonPath}`,
|
|
8596
|
+
`- Evidence HTML: ${document.evidence.htmlPath}`,
|
|
8597
|
+
""
|
|
8598
|
+
];
|
|
8599
|
+
if (document.run.task !== null) {
|
|
8600
|
+
lines.push("## Task", "", document.run.task, "");
|
|
8601
|
+
}
|
|
8602
|
+
if (session === null) {
|
|
8603
|
+
lines.push("## Session", "", "No Inspector session data was available for this run.", "");
|
|
8604
|
+
} else {
|
|
8605
|
+
lines.push(
|
|
8606
|
+
"## Session",
|
|
8607
|
+
"",
|
|
8608
|
+
`- Inspector URL: ${session.inspectorUrl}`,
|
|
8609
|
+
`- Compact Logs URL: ${session.compactLogsUrl}`,
|
|
8610
|
+
`- Status: ${session.status}`,
|
|
8611
|
+
`- Coverage: ${session.logCoverage}`,
|
|
8612
|
+
`- Requests: ${session.requestCount}`,
|
|
8613
|
+
`- Errors: ${session.errorCount}`,
|
|
8614
|
+
`- Models: ${formatList(session.models)}`,
|
|
8615
|
+
`- Providers: ${formatList(session.providers)}`,
|
|
8616
|
+
`- Tokens: ${session.tokenUsage.total}`,
|
|
8617
|
+
"",
|
|
8618
|
+
"## Failure Classification",
|
|
8619
|
+
"",
|
|
8620
|
+
document.classification.summary,
|
|
8621
|
+
"",
|
|
8622
|
+
"### Evidence Logs",
|
|
8623
|
+
"",
|
|
8624
|
+
document.classification.evidenceLogIds.length > 0 ? document.classification.evidenceLogIds.map((id) => `- #${id}`).join("\n") : "No failing log ids were identified.",
|
|
8625
|
+
"",
|
|
8626
|
+
"### Suggested Next Actions",
|
|
8627
|
+
"",
|
|
8628
|
+
...document.classification.hints.map((hint) => `- ${hint}`),
|
|
8629
|
+
"",
|
|
8630
|
+
"## Run Timeline",
|
|
8631
|
+
"",
|
|
8632
|
+
"| Time | Event | Severity | Evidence |",
|
|
8633
|
+
"| --- | --- | --- | --- |",
|
|
8634
|
+
...document.timeline.map((event) => {
|
|
8635
|
+
const evidence = event.logId === null ? "n/a" : `log ${event.logId}`;
|
|
8636
|
+
return `| ${event.timestamp} | ${event.title} | ${event.severity} | ${evidence} |`;
|
|
8637
|
+
}),
|
|
8638
|
+
"",
|
|
8639
|
+
"## Latest Logs",
|
|
8640
|
+
""
|
|
8641
|
+
);
|
|
8642
|
+
if (session.latestLogs.length === 0) {
|
|
8643
|
+
lines.push("No compact logs were available.", "");
|
|
8644
|
+
} else {
|
|
8645
|
+
lines.push(
|
|
8646
|
+
"| ID | Status | Model | Latency | Path | Error |",
|
|
8647
|
+
"| --- | --- | --- | --- | --- | --- |"
|
|
8648
|
+
);
|
|
8649
|
+
for (const log of session.latestLogs) {
|
|
8650
|
+
lines.push(
|
|
8651
|
+
`| ${log.id} | ${log.status ?? "n/a"} | ${log.model ?? "n/a"} | ${log.latencyMs ?? "n/a"} | ${log.path} | ${log.hasError ? "yes" : "no"} |`
|
|
8652
|
+
);
|
|
8653
|
+
}
|
|
8654
|
+
lines.push("");
|
|
8655
|
+
}
|
|
8656
|
+
}
|
|
8657
|
+
lines.push("## Jenkins Report", "", document.jenkinsReport.markdown, "");
|
|
8658
|
+
return `${lines.join("\n")}
|
|
8659
|
+
`;
|
|
8660
|
+
}
|
|
8661
|
+
function buildHtml(markdown, title) {
|
|
8662
|
+
return `<!doctype html>
|
|
8663
|
+
<html lang="en">
|
|
8664
|
+
<head>
|
|
8665
|
+
<meta charset="utf-8">
|
|
8666
|
+
<title>${escapeHtml(title)}</title>
|
|
8667
|
+
<style>
|
|
8668
|
+
body { font-family: system-ui, sans-serif; max-width: 960px; margin: 40px auto; line-height: 1.5; }
|
|
8669
|
+
pre { white-space: pre-wrap; background: #f6f8fa; padding: 16px; border-radius: 8px; }
|
|
8670
|
+
</style>
|
|
8671
|
+
</head>
|
|
8672
|
+
<body>
|
|
8673
|
+
<pre>${escapeHtml(markdown)}</pre>
|
|
8674
|
+
</body>
|
|
8675
|
+
</html>
|
|
8676
|
+
`;
|
|
8677
|
+
}
|
|
8678
|
+
async function exportRunEvidence(run, options, baseUrl) {
|
|
8679
|
+
const session = await getSessionInfo(run.sessionId, {
|
|
8680
|
+
baseUrl,
|
|
8681
|
+
includeHistory: options?.includeHistory,
|
|
8682
|
+
latestLogLimit: options?.latestLogLimit
|
|
8683
|
+
});
|
|
8684
|
+
const exportedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8685
|
+
const evidence = {
|
|
8686
|
+
jsonPath: jsonPath(run.id),
|
|
8687
|
+
markdownPath: markdownPath(run.id),
|
|
8688
|
+
htmlPath: htmlPath(run.id),
|
|
8689
|
+
exportedAt
|
|
8690
|
+
};
|
|
8691
|
+
const documentRun = {
|
|
8692
|
+
...run,
|
|
8693
|
+
evidence,
|
|
8694
|
+
updatedAt: exportedAt
|
|
8695
|
+
};
|
|
8696
|
+
const analysis = analyzeEvidence({
|
|
8697
|
+
run: documentRun,
|
|
8698
|
+
session,
|
|
8699
|
+
exportedAt,
|
|
8700
|
+
evidencePaths: {
|
|
8701
|
+
jsonPath: evidence.jsonPath,
|
|
8702
|
+
markdownPath: evidence.markdownPath,
|
|
8703
|
+
htmlPath: evidence.htmlPath
|
|
8704
|
+
}
|
|
8705
|
+
});
|
|
8706
|
+
const document = {
|
|
8707
|
+
run: documentRun,
|
|
8708
|
+
evidence,
|
|
8709
|
+
session,
|
|
8710
|
+
timeline: analysis.timeline,
|
|
8711
|
+
classification: analysis.classification,
|
|
8712
|
+
jenkinsReport: analysis.jenkinsReport
|
|
8713
|
+
};
|
|
8714
|
+
const markdown = buildMarkdown(document);
|
|
8715
|
+
mkdirSync(evidenceDir(run.id), { recursive: true });
|
|
8716
|
+
writeFileSync(
|
|
8717
|
+
evidence.jsonPath,
|
|
8718
|
+
`${JSON.stringify({ ...document, evidence }, null, 2)}
|
|
8719
|
+
`,
|
|
8720
|
+
"utf8"
|
|
8721
|
+
);
|
|
8722
|
+
writeFileSync(evidence.markdownPath, markdown, "utf8");
|
|
8723
|
+
writeFileSync(evidence.htmlPath, buildHtml(markdown, run.title), "utf8");
|
|
8724
|
+
const updatedRun = updateRunEvidence(run.id, evidence) ?? documentRun;
|
|
8725
|
+
return { ...document, run: updatedRun };
|
|
8726
|
+
}
|
|
8727
|
+
function readEvidenceMarkdown(run) {
|
|
8728
|
+
const path2 = run.evidence?.markdownPath;
|
|
8729
|
+
if (path2 === void 0 || !existsSync(path2)) return null;
|
|
8730
|
+
try {
|
|
8731
|
+
return readFileSync(path2, "utf8");
|
|
8732
|
+
} catch {
|
|
8733
|
+
return null;
|
|
8734
|
+
}
|
|
8735
|
+
}
|
|
8736
|
+
async function readJsonBody(request) {
|
|
8737
|
+
try {
|
|
8738
|
+
const raw = await request.text();
|
|
8739
|
+
if (raw.trim().length === 0) return { ok: true, value: void 0 };
|
|
8740
|
+
return { ok: true, value: JSON.parse(raw) };
|
|
8741
|
+
} catch {
|
|
8742
|
+
return { ok: false };
|
|
8743
|
+
}
|
|
8744
|
+
}
|
|
8745
|
+
const Route$8 = createFileRoute("/api/runs/$runId/evidence")({
|
|
8746
|
+
server: {
|
|
8747
|
+
handlers: {
|
|
8748
|
+
GET: ({ params }) => {
|
|
8749
|
+
const run = getRun(params.runId);
|
|
8750
|
+
if (run === null) {
|
|
8751
|
+
return Response.json({ error: "Run not found" }, { status: 404 });
|
|
8752
|
+
}
|
|
8753
|
+
const markdown = readEvidenceMarkdown(run);
|
|
8754
|
+
if (run.evidence === null || markdown === null) {
|
|
8755
|
+
return Response.json(
|
|
8756
|
+
{ error: "Evidence has not been exported for this run" },
|
|
8757
|
+
{ status: 404 }
|
|
8758
|
+
);
|
|
8759
|
+
}
|
|
8760
|
+
return Response.json({ run, evidence: run.evidence, markdown });
|
|
8761
|
+
},
|
|
8762
|
+
POST: async ({ params, request }) => {
|
|
8763
|
+
const run = getRun(params.runId);
|
|
8764
|
+
if (run === null) {
|
|
8765
|
+
return Response.json({ error: "Run not found" }, { status: 404 });
|
|
8766
|
+
}
|
|
8767
|
+
const body = await readJsonBody(request);
|
|
8768
|
+
if (!body.ok) {
|
|
8769
|
+
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
8770
|
+
}
|
|
8771
|
+
const parsed = EvidenceExportOptionsSchema.safeParse(body.value);
|
|
8772
|
+
if (!parsed.success) {
|
|
8773
|
+
return Response.json(
|
|
8774
|
+
{ error: "Invalid request body", details: parsed.error.format() },
|
|
8775
|
+
{ status: 400 }
|
|
8776
|
+
);
|
|
8777
|
+
}
|
|
8778
|
+
return Response.json(
|
|
8779
|
+
await exportRunEvidence(run, parsed.data, new URL(request.url).origin)
|
|
8780
|
+
);
|
|
8781
|
+
}
|
|
8782
|
+
}
|
|
8783
|
+
}
|
|
8784
|
+
});
|
|
7146
8785
|
const MEMORY_PROBE_FACTS = [
|
|
7147
8786
|
"Project fact: Agent Inspector captures LLM traffic and turns it into Raw Trace, Session Episode, and Memory Candidate layers.",
|
|
7148
8787
|
"Procedure: before release, run bun test, npm run typecheck, npm run lint, npm run build, and openspec validate --all --strict.",
|
|
@@ -8562,106 +10201,121 @@ const Route = createFileRoute("/api/knowledge/candidates/$candidateId/promote")(
|
|
|
8562
10201
|
}
|
|
8563
10202
|
}
|
|
8564
10203
|
});
|
|
8565
|
-
const IndexRoute = Route$
|
|
10204
|
+
const IndexRoute = Route$u.update({
|
|
8566
10205
|
id: "/",
|
|
8567
10206
|
path: "/",
|
|
8568
|
-
getParentRoute: () => Route$
|
|
10207
|
+
getParentRoute: () => Route$v
|
|
8569
10208
|
});
|
|
8570
|
-
const SessionSessionIdRoute = Route$
|
|
10209
|
+
const SessionSessionIdRoute = Route$t.update({
|
|
8571
10210
|
id: "/session/$sessionId",
|
|
8572
10211
|
path: "/session/$sessionId",
|
|
8573
|
-
getParentRoute: () => Route$
|
|
10212
|
+
getParentRoute: () => Route$v
|
|
8574
10213
|
});
|
|
8575
|
-
const ProxySplatRoute = Route$
|
|
10214
|
+
const ProxySplatRoute = Route$s.update({
|
|
8576
10215
|
id: "/proxy/$",
|
|
8577
10216
|
path: "/proxy/$",
|
|
8578
|
-
getParentRoute: () => Route$
|
|
10217
|
+
getParentRoute: () => Route$v
|
|
8579
10218
|
});
|
|
8580
|
-
const ApiSessionsRoute = Route$
|
|
10219
|
+
const ApiSessionsRoute = Route$r.update({
|
|
8581
10220
|
id: "/api/sessions",
|
|
8582
10221
|
path: "/api/sessions",
|
|
8583
|
-
getParentRoute: () => Route$
|
|
10222
|
+
getParentRoute: () => Route$v
|
|
8584
10223
|
});
|
|
8585
|
-
const
|
|
10224
|
+
const ApiRunsRoute = Route$q.update({
|
|
10225
|
+
id: "/api/runs",
|
|
10226
|
+
path: "/api/runs",
|
|
10227
|
+
getParentRoute: () => Route$v
|
|
10228
|
+
});
|
|
10229
|
+
const ApiProvidersRoute = Route$p.update({
|
|
8586
10230
|
id: "/api/providers",
|
|
8587
10231
|
path: "/api/providers",
|
|
8588
|
-
getParentRoute: () => Route$
|
|
10232
|
+
getParentRoute: () => Route$v
|
|
8589
10233
|
});
|
|
8590
|
-
const ApiModelsRoute = Route$
|
|
10234
|
+
const ApiModelsRoute = Route$o.update({
|
|
8591
10235
|
id: "/api/models",
|
|
8592
10236
|
path: "/api/models",
|
|
8593
|
-
getParentRoute: () => Route$
|
|
10237
|
+
getParentRoute: () => Route$v
|
|
8594
10238
|
});
|
|
8595
|
-
const ApiMcpRoute = Route$
|
|
10239
|
+
const ApiMcpRoute = Route$n.update({
|
|
8596
10240
|
id: "/api/mcp",
|
|
8597
10241
|
path: "/api/mcp",
|
|
8598
|
-
getParentRoute: () => Route$
|
|
10242
|
+
getParentRoute: () => Route$v
|
|
8599
10243
|
});
|
|
8600
|
-
const ApiLogsRoute = Route$
|
|
10244
|
+
const ApiLogsRoute = Route$m.update({
|
|
8601
10245
|
id: "/api/logs",
|
|
8602
10246
|
path: "/api/logs",
|
|
8603
|
-
getParentRoute: () => Route$
|
|
10247
|
+
getParentRoute: () => Route$v
|
|
8604
10248
|
});
|
|
8605
|
-
const ApiHealthRoute = Route$
|
|
10249
|
+
const ApiHealthRoute = Route$l.update({
|
|
8606
10250
|
id: "/api/health",
|
|
8607
10251
|
path: "/api/health",
|
|
8608
|
-
getParentRoute: () => Route$
|
|
10252
|
+
getParentRoute: () => Route$v
|
|
8609
10253
|
});
|
|
8610
|
-
const ApiConfigRoute = Route$
|
|
10254
|
+
const ApiConfigRoute = Route$k.update({
|
|
8611
10255
|
id: "/api/config",
|
|
8612
10256
|
path: "/api/config",
|
|
8613
|
-
getParentRoute: () => Route$
|
|
10257
|
+
getParentRoute: () => Route$v
|
|
10258
|
+
});
|
|
10259
|
+
const ApiRunsRunIdRoute = Route$j.update({
|
|
10260
|
+
id: "/$runId",
|
|
10261
|
+
path: "/$runId",
|
|
10262
|
+
getParentRoute: () => ApiRunsRoute
|
|
8614
10263
|
});
|
|
8615
|
-
const ApiProvidersScanRoute = Route$
|
|
10264
|
+
const ApiProvidersScanRoute = Route$i.update({
|
|
8616
10265
|
id: "/scan",
|
|
8617
10266
|
path: "/scan",
|
|
8618
10267
|
getParentRoute: () => ApiProvidersRoute
|
|
8619
10268
|
});
|
|
8620
|
-
const ApiProvidersImportRoute = Route$
|
|
10269
|
+
const ApiProvidersImportRoute = Route$h.update({
|
|
8621
10270
|
id: "/import",
|
|
8622
10271
|
path: "/import",
|
|
8623
10272
|
getParentRoute: () => ApiProvidersRoute
|
|
8624
10273
|
});
|
|
8625
|
-
const ApiProvidersExportRoute = Route$
|
|
10274
|
+
const ApiProvidersExportRoute = Route$g.update({
|
|
8626
10275
|
id: "/export",
|
|
8627
10276
|
path: "/export",
|
|
8628
10277
|
getParentRoute: () => ApiProvidersRoute
|
|
8629
10278
|
});
|
|
8630
|
-
const ApiProvidersProviderIdRoute = Route$
|
|
10279
|
+
const ApiProvidersProviderIdRoute = Route$f.update({
|
|
8631
10280
|
id: "/$providerId",
|
|
8632
10281
|
path: "/$providerId",
|
|
8633
10282
|
getParentRoute: () => ApiProvidersRoute
|
|
8634
10283
|
});
|
|
8635
|
-
const ApiLogsStreamRoute = Route$
|
|
10284
|
+
const ApiLogsStreamRoute = Route$e.update({
|
|
8636
10285
|
id: "/stream",
|
|
8637
10286
|
path: "/stream",
|
|
8638
10287
|
getParentRoute: () => ApiLogsRoute
|
|
8639
10288
|
});
|
|
8640
|
-
const ApiLogsIdRoute = Route$
|
|
10289
|
+
const ApiLogsIdRoute = Route$d.update({
|
|
8641
10290
|
id: "/$id",
|
|
8642
10291
|
path: "/$id",
|
|
8643
10292
|
getParentRoute: () => ApiLogsRoute
|
|
8644
10293
|
});
|
|
8645
|
-
const ApiKnowledgeSearchRoute = Route$
|
|
10294
|
+
const ApiKnowledgeSearchRoute = Route$c.update({
|
|
8646
10295
|
id: "/api/knowledge/search",
|
|
8647
10296
|
path: "/api/knowledge/search",
|
|
8648
|
-
getParentRoute: () => Route$
|
|
10297
|
+
getParentRoute: () => Route$v
|
|
8649
10298
|
});
|
|
8650
|
-
const ApiKnowledgeProjectContextRoute = Route$
|
|
10299
|
+
const ApiKnowledgeProjectContextRoute = Route$b.update({
|
|
8651
10300
|
id: "/api/knowledge/project-context",
|
|
8652
10301
|
path: "/api/knowledge/project-context",
|
|
8653
|
-
getParentRoute: () => Route$
|
|
10302
|
+
getParentRoute: () => Route$v
|
|
8654
10303
|
});
|
|
8655
|
-
const ApiKnowledgeCandidatesRoute = Route$
|
|
10304
|
+
const ApiKnowledgeCandidatesRoute = Route$a.update({
|
|
8656
10305
|
id: "/api/knowledge/candidates",
|
|
8657
10306
|
path: "/api/knowledge/candidates",
|
|
8658
|
-
getParentRoute: () => Route$
|
|
10307
|
+
getParentRoute: () => Route$v
|
|
8659
10308
|
});
|
|
8660
|
-
const ApiConfigPathsRoute = Route$
|
|
10309
|
+
const ApiConfigPathsRoute = Route$9.update({
|
|
8661
10310
|
id: "/paths",
|
|
8662
10311
|
path: "/paths",
|
|
8663
10312
|
getParentRoute: () => ApiConfigRoute
|
|
8664
10313
|
});
|
|
10314
|
+
const ApiRunsRunIdEvidenceRoute = Route$8.update({
|
|
10315
|
+
id: "/evidence",
|
|
10316
|
+
path: "/evidence",
|
|
10317
|
+
getParentRoute: () => ApiRunsRunIdRoute
|
|
10318
|
+
});
|
|
8665
10319
|
const ApiProvidersProviderIdTestRoute = Route$7.update({
|
|
8666
10320
|
id: "/test",
|
|
8667
10321
|
path: "/test",
|
|
@@ -8695,7 +10349,7 @@ const ApiProvidersProviderIdTestLogRoute = Route$2.update({
|
|
|
8695
10349
|
const ApiKnowledgeSessionsSessionIdCandidatesRoute = Route$1.update({
|
|
8696
10350
|
id: "/api/knowledge/sessions/$sessionId/candidates",
|
|
8697
10351
|
path: "/api/knowledge/sessions/$sessionId/candidates",
|
|
8698
|
-
getParentRoute: () => Route$
|
|
10352
|
+
getParentRoute: () => Route$v
|
|
8699
10353
|
});
|
|
8700
10354
|
const ApiKnowledgeCandidatesCandidateIdPromoteRoute = Route.update({
|
|
8701
10355
|
id: "/promote",
|
|
@@ -8742,6 +10396,16 @@ const ApiProvidersRouteChildren = {
|
|
|
8742
10396
|
const ApiProvidersRouteWithChildren = ApiProvidersRoute._addFileChildren(
|
|
8743
10397
|
ApiProvidersRouteChildren
|
|
8744
10398
|
);
|
|
10399
|
+
const ApiRunsRunIdRouteChildren = {
|
|
10400
|
+
ApiRunsRunIdEvidenceRoute
|
|
10401
|
+
};
|
|
10402
|
+
const ApiRunsRunIdRouteWithChildren = ApiRunsRunIdRoute._addFileChildren(
|
|
10403
|
+
ApiRunsRunIdRouteChildren
|
|
10404
|
+
);
|
|
10405
|
+
const ApiRunsRouteChildren = {
|
|
10406
|
+
ApiRunsRunIdRoute: ApiRunsRunIdRouteWithChildren
|
|
10407
|
+
};
|
|
10408
|
+
const ApiRunsRouteWithChildren = ApiRunsRoute._addFileChildren(ApiRunsRouteChildren);
|
|
8745
10409
|
const ApiKnowledgeCandidatesCandidateIdRouteChildren = {
|
|
8746
10410
|
ApiKnowledgeCandidatesCandidateIdPromoteRoute
|
|
8747
10411
|
};
|
|
@@ -8762,6 +10426,7 @@ const rootRouteChildren = {
|
|
|
8762
10426
|
ApiMcpRoute,
|
|
8763
10427
|
ApiModelsRoute,
|
|
8764
10428
|
ApiProvidersRoute: ApiProvidersRouteWithChildren,
|
|
10429
|
+
ApiRunsRoute: ApiRunsRouteWithChildren,
|
|
8765
10430
|
ApiSessionsRoute,
|
|
8766
10431
|
ProxySplatRoute,
|
|
8767
10432
|
SessionSessionIdRoute,
|
|
@@ -8770,7 +10435,7 @@ const rootRouteChildren = {
|
|
|
8770
10435
|
ApiKnowledgeSearchRoute,
|
|
8771
10436
|
ApiKnowledgeSessionsSessionIdCandidatesRoute
|
|
8772
10437
|
};
|
|
8773
|
-
const routeTree = Route$
|
|
10438
|
+
const routeTree = Route$v._addFileChildren(rootRouteChildren)._addFileTypes();
|
|
8774
10439
|
function getRouter() {
|
|
8775
10440
|
const router2 = createRouter({
|
|
8776
10441
|
routeTree,
|
|
@@ -8790,7 +10455,7 @@ export {
|
|
|
8790
10455
|
MAX_SLOW_RESPONSE_THRESHOLD_SECONDS as M,
|
|
8791
10456
|
OpenAIRequestSchema as O,
|
|
8792
10457
|
ProviderConfigSchema as P,
|
|
8793
|
-
Route$
|
|
10458
|
+
Route$t as R,
|
|
8794
10459
|
TimeDisplayFormatSchema as T,
|
|
8795
10460
|
DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS as a,
|
|
8796
10461
|
DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS as b,
|