@tonyclaw/agent-inspector 2.0.26 → 2.0.28
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/cli.js +169 -13
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-DBTFzxG5.js → CompareDrawer-CicCP3Hb.js} +1 -1
- package/.output/public/assets/{ProxyViewerContainer-ivZk8MgE.js → ProxyViewerContainer-BccuA6p5.js} +4 -4
- package/.output/public/assets/{ReplayDialog-syW2hDNE.js → ReplayDialog-Bc8q3ujm.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-BkuRtY9o.js → RequestAnatomy-Coyy3zcH.js} +1 -1
- package/.output/public/assets/{ResponseView-BwyvEvoE.js → ResponseView-BWJzgh0c.js} +1 -1
- package/.output/public/assets/{StreamingChunkSequence-BY4MbPKg.js → StreamingChunkSequence-BSC3uuE5.js} +1 -1
- package/.output/public/assets/_sessionId-9rEF0uSE.js +1 -0
- package/.output/public/assets/index-B9_VaAWl.js +1 -0
- package/.output/public/assets/{main-DKRDRBdd.js → main-Brj0Gn91.js} +2 -2
- package/.output/server/_libs/modelcontextprotocol__server.mjs +228 -0
- package/.output/server/{_sessionId-VDd4N_1B.mjs → _sessionId-DDdyKVG-.mjs} +3 -3
- package/.output/server/_ssr/{CompareDrawer-BQZlxsOC.mjs → CompareDrawer-XSExe2ml.mjs} +2 -2
- package/.output/server/_ssr/{ProxyViewerContainer-njY2oQCc.mjs → ProxyViewerContainer-B5pIiBZN.mjs} +7 -7
- package/.output/server/_ssr/{ReplayDialog-B8lkdAIh.mjs → ReplayDialog-BOAu0ric.mjs} +3 -3
- package/.output/server/_ssr/{RequestAnatomy-CwOTfdwS.mjs → RequestAnatomy-C8Q5lozD.mjs} +2 -2
- package/.output/server/_ssr/{ResponseView-3Iz_mZpd.mjs → ResponseView-a_iJfPUF.mjs} +2 -2
- package/.output/server/_ssr/{StreamingChunkSequence-hmJcQNW5.mjs → StreamingChunkSequence-YMKC0j8U.mjs} +2 -2
- package/.output/server/_ssr/{index-UuTKM4aC.mjs → index-CkDwBPzI.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-C7InHrxE.mjs → router-DXOXdFFM.mjs} +1816 -151
- package/.output/server/_tanstack-start-manifest_v-DPf3uJys.mjs +4 -0
- package/.output/server/index.mjs +64 -64
- package/README.md +55 -1
- package/package.json +1 -1
- package/src/cli/networkHints.ts +150 -0
- package/src/cli.ts +72 -13
- 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
package/src/mcp/server.ts
CHANGED
|
@@ -16,13 +16,31 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { z } from "zod";
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
type GetPromptResult,
|
|
21
|
+
type ListResourcesResult,
|
|
22
|
+
McpServer,
|
|
23
|
+
type ReadResourceResult,
|
|
24
|
+
ResourceTemplate,
|
|
25
|
+
type Variables,
|
|
26
|
+
WebStandardStreamableHTTPServerTransport,
|
|
27
|
+
} from "@modelcontextprotocol/server";
|
|
28
|
+
import {
|
|
29
|
+
InspectorRunSchema,
|
|
30
|
+
InspectorRunStatusSchema,
|
|
31
|
+
UpdateInspectorRunInputSchema,
|
|
32
|
+
} from "../lib/runContract";
|
|
20
33
|
import { setCurrentPort } from "../lib/serverPort";
|
|
34
|
+
import { JsonValueSchema } from "../proxy/schemas";
|
|
21
35
|
import { callApi } from "./loopback";
|
|
22
36
|
import {
|
|
23
37
|
addProviderImpl,
|
|
38
|
+
createRunImpl,
|
|
24
39
|
createSessionKnowledgeImpl,
|
|
40
|
+
exportEvidenceImpl,
|
|
41
|
+
getRecentFailuresImpl,
|
|
25
42
|
getProjectContextImpl,
|
|
43
|
+
getRunImpl,
|
|
26
44
|
getSessionImpl,
|
|
27
45
|
getLogChunksImpl,
|
|
28
46
|
getLogImpl,
|
|
@@ -35,8 +53,10 @@ import {
|
|
|
35
53
|
promoteKnowledgeCandidateImpl,
|
|
36
54
|
replayLogImpl,
|
|
37
55
|
safeCall,
|
|
56
|
+
searchLogsImpl,
|
|
38
57
|
searchKnowledgeImpl,
|
|
39
58
|
testProviderImpl,
|
|
59
|
+
updateRunImpl,
|
|
40
60
|
updateProviderImpl,
|
|
41
61
|
} from "./toolHandlers";
|
|
42
62
|
|
|
@@ -52,9 +72,11 @@ let initPromise: Promise<ServerPair> | null = null;
|
|
|
52
72
|
function buildServer(): ServerPair {
|
|
53
73
|
const server = new McpServer(
|
|
54
74
|
{ name: "agent-inspector", version: "1.0.0" },
|
|
55
|
-
{ capabilities: { tools: {} } },
|
|
75
|
+
{ capabilities: { tools: {}, resources: {}, prompts: {} } },
|
|
56
76
|
);
|
|
57
77
|
registerTools(server);
|
|
78
|
+
registerResources(server);
|
|
79
|
+
registerPrompts(server);
|
|
58
80
|
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
59
81
|
sessionIdGenerator: undefined, // stateless — see module docstring
|
|
60
82
|
});
|
|
@@ -138,6 +160,152 @@ Either preview field is null when the body is unknown format, unparseable, or th
|
|
|
138
160
|
const PROVIDER_WRITE_WARNING =
|
|
139
161
|
"⚠ This tool mutates provider configuration. Confirm with the user before invoking.";
|
|
140
162
|
|
|
163
|
+
const RunsListResponseSchema = z.object({
|
|
164
|
+
runs: z.array(InspectorRunSchema),
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const LogResourceListResponseSchema = z.object({
|
|
168
|
+
logs: z.array(z.object({ id: z.number().int().positive() })),
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const EvidenceReadResponseSchema = z.object({
|
|
172
|
+
markdown: z.string(),
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
type ResourceDescriptor = {
|
|
176
|
+
uri: string;
|
|
177
|
+
name: string;
|
|
178
|
+
title?: string;
|
|
179
|
+
mimeType?: string;
|
|
180
|
+
description?: string;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
function textResource(uri: URL, mimeType: string, text: string): ReadResourceResult {
|
|
184
|
+
return {
|
|
185
|
+
contents: [{ uri: uri.href, mimeType, text }],
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function jsonResource(uri: URL, data: unknown): ReadResourceResult {
|
|
190
|
+
return textResource(uri, "application/json", JSON.stringify(data, null, 2));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function variableString(variables: Variables, name: string): string | null {
|
|
194
|
+
const value = variables[name];
|
|
195
|
+
if (Array.isArray(value)) return value[0] ?? null;
|
|
196
|
+
return value ?? null;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function listResult(resources: ResourceDescriptor[]): ListResourcesResult {
|
|
200
|
+
return { resources };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async function readApiJsonResource(uri: URL, path: string): Promise<ReadResourceResult> {
|
|
204
|
+
try {
|
|
205
|
+
const response = await callApi(path);
|
|
206
|
+
if (!response.ok) {
|
|
207
|
+
return textResource(uri, "text/plain", `GET ${path} returned ${response.status}`);
|
|
208
|
+
}
|
|
209
|
+
return jsonResource(uri, await response.json());
|
|
210
|
+
} catch (err) {
|
|
211
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
212
|
+
return textResource(uri, "text/plain", `Resource read failed: ${message}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async function listSessionResources(): Promise<ListResourcesResult> {
|
|
217
|
+
try {
|
|
218
|
+
const response = await callApi("/api/sessions");
|
|
219
|
+
if (!response.ok) return listResult([]);
|
|
220
|
+
const parsed = z.array(z.string()).safeParse(await response.json());
|
|
221
|
+
if (!parsed.success) return listResult([]);
|
|
222
|
+
return listResult(
|
|
223
|
+
parsed.data.map((sessionId) => ({
|
|
224
|
+
uri: `inspector://sessions/${encodeURIComponent(sessionId)}`,
|
|
225
|
+
name: `session:${sessionId}`,
|
|
226
|
+
title: `Inspector session ${sessionId}`,
|
|
227
|
+
mimeType: "application/json",
|
|
228
|
+
})),
|
|
229
|
+
);
|
|
230
|
+
} catch {
|
|
231
|
+
return listResult([]);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
async function listLogResources(): Promise<ListResourcesResult> {
|
|
236
|
+
try {
|
|
237
|
+
const response = await callApi("/api/logs?offset=0&limit=5&compact=1");
|
|
238
|
+
if (!response.ok) return listResult([]);
|
|
239
|
+
const parsed = LogResourceListResponseSchema.safeParse(await response.json());
|
|
240
|
+
if (!parsed.success) return listResult([]);
|
|
241
|
+
return listResult(
|
|
242
|
+
parsed.data.logs.map((log) => ({
|
|
243
|
+
uri: `inspector://logs/${String(log.id)}`,
|
|
244
|
+
name: `log:${String(log.id)}`,
|
|
245
|
+
title: `Inspector log ${String(log.id)}`,
|
|
246
|
+
mimeType: "application/json",
|
|
247
|
+
})),
|
|
248
|
+
);
|
|
249
|
+
} catch {
|
|
250
|
+
return listResult([]);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async function listRunResources(): Promise<ListResourcesResult> {
|
|
255
|
+
try {
|
|
256
|
+
const response = await callApi("/api/runs");
|
|
257
|
+
if (!response.ok) return listResult([]);
|
|
258
|
+
const parsed = RunsListResponseSchema.safeParse(await response.json());
|
|
259
|
+
if (!parsed.success) return listResult([]);
|
|
260
|
+
return listResult(
|
|
261
|
+
parsed.data.runs.map((run) => ({
|
|
262
|
+
uri: `inspector://runs/${encodeURIComponent(run.id)}`,
|
|
263
|
+
name: `run:${run.id}`,
|
|
264
|
+
title: run.title,
|
|
265
|
+
mimeType: "application/json",
|
|
266
|
+
})),
|
|
267
|
+
);
|
|
268
|
+
} catch {
|
|
269
|
+
return listResult([]);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
async function listEvidenceResources(): Promise<ListResourcesResult> {
|
|
274
|
+
try {
|
|
275
|
+
const response = await callApi("/api/runs");
|
|
276
|
+
if (!response.ok) return listResult([]);
|
|
277
|
+
const parsed = RunsListResponseSchema.safeParse(await response.json());
|
|
278
|
+
if (!parsed.success) return listResult([]);
|
|
279
|
+
return listResult(
|
|
280
|
+
parsed.data.runs
|
|
281
|
+
.filter((run) => run.evidence !== null)
|
|
282
|
+
.map((run) => ({
|
|
283
|
+
uri: `inspector://evidence/${encodeURIComponent(run.id)}`,
|
|
284
|
+
name: `evidence:${run.id}`,
|
|
285
|
+
title: `${run.title} evidence pack`,
|
|
286
|
+
mimeType: "text/markdown",
|
|
287
|
+
description: run.evidence?.markdownPath,
|
|
288
|
+
})),
|
|
289
|
+
);
|
|
290
|
+
} catch {
|
|
291
|
+
return listResult([]);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function userPrompt(text: string): GetPromptResult {
|
|
296
|
+
return {
|
|
297
|
+
messages: [
|
|
298
|
+
{
|
|
299
|
+
role: "user",
|
|
300
|
+
content: {
|
|
301
|
+
type: "text",
|
|
302
|
+
text,
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
],
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
141
309
|
// ---------------------------------------------------------------------------
|
|
142
310
|
// Tool registration (thin wiring of impls to the SDK)
|
|
143
311
|
// ---------------------------------------------------------------------------
|
|
@@ -165,6 +333,38 @@ function registerTools(server: McpServer): void {
|
|
|
165
333
|
(args) => safeCall(() => listLogsImpl(callApi, args)),
|
|
166
334
|
);
|
|
167
335
|
|
|
336
|
+
server.registerTool(
|
|
337
|
+
"inspector_search_logs",
|
|
338
|
+
{
|
|
339
|
+
title: "Search captured logs",
|
|
340
|
+
description:
|
|
341
|
+
"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.",
|
|
342
|
+
inputSchema: z.object({
|
|
343
|
+
query: z
|
|
344
|
+
.string()
|
|
345
|
+
.optional()
|
|
346
|
+
.describe("Search terms. Empty or omitted returns the newest scanned logs."),
|
|
347
|
+
offset: z.number().int().nonnegative().optional().describe("Skip this many matches."),
|
|
348
|
+
limit: z
|
|
349
|
+
.number()
|
|
350
|
+
.int()
|
|
351
|
+
.positive()
|
|
352
|
+
.optional()
|
|
353
|
+
.describe("How many summaries to return. Hard-capped at 5 by the MCP handler."),
|
|
354
|
+
scanLimit: z
|
|
355
|
+
.number()
|
|
356
|
+
.int()
|
|
357
|
+
.positive()
|
|
358
|
+
.max(1000)
|
|
359
|
+
.optional()
|
|
360
|
+
.describe("How many recent compact logs to scan before filtering. Default 200."),
|
|
361
|
+
sessionId: z.string().optional().describe("Optional session/affinity id filter."),
|
|
362
|
+
model: z.string().optional().describe("Optional model name filter."),
|
|
363
|
+
}),
|
|
364
|
+
},
|
|
365
|
+
(args) => safeCall(() => searchLogsImpl(callApi, args)),
|
|
366
|
+
);
|
|
367
|
+
|
|
168
368
|
server.registerTool(
|
|
169
369
|
"inspector_get_log",
|
|
170
370
|
{
|
|
@@ -226,6 +426,100 @@ function registerTools(server: McpServer): void {
|
|
|
226
426
|
(args) => safeCall(() => getSessionImpl(callApi, args)),
|
|
227
427
|
);
|
|
228
428
|
|
|
429
|
+
server.registerTool(
|
|
430
|
+
"inspector_create_run",
|
|
431
|
+
{
|
|
432
|
+
title: "Create or declare an Inspector run",
|
|
433
|
+
description:
|
|
434
|
+
"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.",
|
|
435
|
+
inputSchema: z.object({
|
|
436
|
+
runId: z.string().min(1).optional().describe("Stable run id. Generated when omitted."),
|
|
437
|
+
sessionId: z
|
|
438
|
+
.string()
|
|
439
|
+
.min(1)
|
|
440
|
+
.optional()
|
|
441
|
+
.describe("Inspector session id to attach. Defaults to the run id."),
|
|
442
|
+
title: z.string().min(1).optional().describe("Human-readable run title."),
|
|
443
|
+
task: z.string().nullable().optional().describe("Task statement or benchmark case."),
|
|
444
|
+
project: z.string().nullable().optional().describe("Project or repository under test."),
|
|
445
|
+
agent: z.string().nullable().optional().describe("Coding agent name, e.g. Codex/OpenCode."),
|
|
446
|
+
status: InspectorRunStatusSchema.optional().describe("Initial run status."),
|
|
447
|
+
tags: z.array(z.string()).optional().describe("Free-form run labels."),
|
|
448
|
+
metadata: z.record(z.string(), JsonValueSchema).optional().describe("JSON metadata."),
|
|
449
|
+
}),
|
|
450
|
+
},
|
|
451
|
+
(args) => safeCall(() => createRunImpl(callApi, args)),
|
|
452
|
+
);
|
|
453
|
+
|
|
454
|
+
server.registerTool(
|
|
455
|
+
"inspector_get_run",
|
|
456
|
+
{
|
|
457
|
+
title: "Get an Inspector run",
|
|
458
|
+
description:
|
|
459
|
+
"Returns one declared Inspector run, including its session binding and exported evidence paths when available.",
|
|
460
|
+
inputSchema: z.object({
|
|
461
|
+
runId: z.string().min(1).describe("The Inspector run id."),
|
|
462
|
+
}),
|
|
463
|
+
},
|
|
464
|
+
(args) => safeCall(() => getRunImpl(callApi, args)),
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
server.registerTool(
|
|
468
|
+
"inspector_update_run",
|
|
469
|
+
{
|
|
470
|
+
title: "Update an Inspector run",
|
|
471
|
+
description:
|
|
472
|
+
"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.",
|
|
473
|
+
inputSchema: UpdateInspectorRunInputSchema.extend({
|
|
474
|
+
runId: z.string().min(1).describe("The Inspector run id."),
|
|
475
|
+
}),
|
|
476
|
+
},
|
|
477
|
+
(args) => safeCall(() => updateRunImpl(callApi, args)),
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
server.registerTool(
|
|
481
|
+
"inspector_export_evidence",
|
|
482
|
+
{
|
|
483
|
+
title: "Export an Inspector evidence pack",
|
|
484
|
+
description:
|
|
485
|
+
"Exports one run's evidence pack to local JSON, Markdown, and HTML files under <dataDir>/evidence/<runId> and returns the paths plus session summary.",
|
|
486
|
+
inputSchema: z.object({
|
|
487
|
+
runId: z.string().min(1).describe("The Inspector run id."),
|
|
488
|
+
includeHistory: z
|
|
489
|
+
.boolean()
|
|
490
|
+
.optional()
|
|
491
|
+
.describe("Scan persisted jsonl history for the bound session. Slower; default false."),
|
|
492
|
+
latestLogLimit: z
|
|
493
|
+
.number()
|
|
494
|
+
.int()
|
|
495
|
+
.positive()
|
|
496
|
+
.max(50)
|
|
497
|
+
.optional()
|
|
498
|
+
.describe("How many compact log summaries to include in the evidence pack. Max 50."),
|
|
499
|
+
}),
|
|
500
|
+
},
|
|
501
|
+
(args) => safeCall(() => exportEvidenceImpl(callApi, args)),
|
|
502
|
+
);
|
|
503
|
+
|
|
504
|
+
server.registerTool(
|
|
505
|
+
"inspector_get_recent_failures",
|
|
506
|
+
{
|
|
507
|
+
title: "Get recent Inspector failures",
|
|
508
|
+
description:
|
|
509
|
+
"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.",
|
|
510
|
+
inputSchema: z.object({
|
|
511
|
+
limit: z
|
|
512
|
+
.number()
|
|
513
|
+
.int()
|
|
514
|
+
.positive()
|
|
515
|
+
.max(20)
|
|
516
|
+
.optional()
|
|
517
|
+
.describe("Maximum failures to return. Default 5, max 20."),
|
|
518
|
+
}),
|
|
519
|
+
},
|
|
520
|
+
(args) => safeCall(() => getRecentFailuresImpl(callApi, args)),
|
|
521
|
+
);
|
|
522
|
+
|
|
229
523
|
server.registerTool(
|
|
230
524
|
"inspector_list_models",
|
|
231
525
|
{
|
|
@@ -408,13 +702,254 @@ PATCH-style update: only the fields you supply are changed. Returns the updated
|
|
|
408
702
|
);
|
|
409
703
|
}
|
|
410
704
|
|
|
705
|
+
function registerResources(server: McpServer): void {
|
|
706
|
+
server.registerResource(
|
|
707
|
+
"inspector_sessions",
|
|
708
|
+
"inspector://sessions",
|
|
709
|
+
{
|
|
710
|
+
title: "Inspector sessions",
|
|
711
|
+
description: "Observed Inspector session ids.",
|
|
712
|
+
mimeType: "application/json",
|
|
713
|
+
},
|
|
714
|
+
(uri) => readApiJsonResource(uri, "/api/sessions"),
|
|
715
|
+
);
|
|
716
|
+
|
|
717
|
+
server.registerResource(
|
|
718
|
+
"inspector_session",
|
|
719
|
+
new ResourceTemplate("inspector://sessions/{sessionId}", { list: listSessionResources }),
|
|
720
|
+
{
|
|
721
|
+
title: "Inspector session",
|
|
722
|
+
description:
|
|
723
|
+
"Evidence-friendly session summary with Inspector URL, compact logs URL, counts, models, providers, token totals, and recent compact logs.",
|
|
724
|
+
mimeType: "application/json",
|
|
725
|
+
},
|
|
726
|
+
(uri, variables) => {
|
|
727
|
+
const sessionId = variableString(variables, "sessionId");
|
|
728
|
+
if (sessionId === null) return textResource(uri, "text/plain", "Missing sessionId");
|
|
729
|
+
const params = new URLSearchParams({ sessionId, limit: "10" });
|
|
730
|
+
return readApiJsonResource(uri, `/api/sessions?${params.toString()}`);
|
|
731
|
+
},
|
|
732
|
+
);
|
|
733
|
+
|
|
734
|
+
server.registerResource(
|
|
735
|
+
"inspector_log",
|
|
736
|
+
new ResourceTemplate("inspector://logs/{id}", { list: listLogResources }),
|
|
737
|
+
{
|
|
738
|
+
title: "Inspector log",
|
|
739
|
+
description: "Single captured proxy log by numeric id.",
|
|
740
|
+
mimeType: "application/json",
|
|
741
|
+
},
|
|
742
|
+
async (uri, variables) => {
|
|
743
|
+
const id = variableString(variables, "id");
|
|
744
|
+
const parsed = id === null ? Number.NaN : Number(id);
|
|
745
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
746
|
+
return textResource(uri, "text/plain", "Invalid log id");
|
|
747
|
+
}
|
|
748
|
+
const result = await getLogImpl(callApi, parsed);
|
|
749
|
+
const first = result.content[0];
|
|
750
|
+
const text = first?.text ?? "";
|
|
751
|
+
return textResource(uri, result.isError === true ? "text/plain" : "application/json", text);
|
|
752
|
+
},
|
|
753
|
+
);
|
|
754
|
+
|
|
755
|
+
server.registerResource(
|
|
756
|
+
"inspector_runs",
|
|
757
|
+
"inspector://runs",
|
|
758
|
+
{
|
|
759
|
+
title: "Inspector runs",
|
|
760
|
+
description: "Declared Inspector evaluation runs.",
|
|
761
|
+
mimeType: "application/json",
|
|
762
|
+
},
|
|
763
|
+
(uri) => readApiJsonResource(uri, "/api/runs"),
|
|
764
|
+
);
|
|
765
|
+
|
|
766
|
+
server.registerResource(
|
|
767
|
+
"inspector_recent_failures",
|
|
768
|
+
"inspector://failures/recent",
|
|
769
|
+
{
|
|
770
|
+
title: "Recent Inspector failures",
|
|
771
|
+
description:
|
|
772
|
+
"Recent declared runs with failed/cancelled status or non-success exported evidence.",
|
|
773
|
+
mimeType: "application/json",
|
|
774
|
+
},
|
|
775
|
+
(uri) => readApiJsonResource(uri, "/api/runs?failures=1&limit=10"),
|
|
776
|
+
);
|
|
777
|
+
|
|
778
|
+
server.registerResource(
|
|
779
|
+
"inspector_run",
|
|
780
|
+
new ResourceTemplate("inspector://runs/{runId}", { list: listRunResources }),
|
|
781
|
+
{
|
|
782
|
+
title: "Inspector run",
|
|
783
|
+
description: "One declared Inspector run, including session binding and evidence paths.",
|
|
784
|
+
mimeType: "application/json",
|
|
785
|
+
},
|
|
786
|
+
(uri, variables) => {
|
|
787
|
+
const runId = variableString(variables, "runId");
|
|
788
|
+
if (runId === null) return textResource(uri, "text/plain", "Missing runId");
|
|
789
|
+
return readApiJsonResource(uri, `/api/runs/${encodeURIComponent(runId)}`);
|
|
790
|
+
},
|
|
791
|
+
);
|
|
792
|
+
|
|
793
|
+
server.registerResource(
|
|
794
|
+
"inspector_evidence",
|
|
795
|
+
new ResourceTemplate("inspector://evidence/{runId}", { list: listEvidenceResources }),
|
|
796
|
+
{
|
|
797
|
+
title: "Inspector evidence pack",
|
|
798
|
+
description:
|
|
799
|
+
"Markdown evidence pack for a declared Inspector run. Generate it first with inspector_export_evidence.",
|
|
800
|
+
mimeType: "text/markdown",
|
|
801
|
+
},
|
|
802
|
+
async (uri, variables) => {
|
|
803
|
+
const runId = variableString(variables, "runId");
|
|
804
|
+
if (runId === null) return textResource(uri, "text/plain", "Missing runId");
|
|
805
|
+
const path = `/api/runs/${encodeURIComponent(runId)}/evidence`;
|
|
806
|
+
try {
|
|
807
|
+
const response = await callApi(path);
|
|
808
|
+
if (!response.ok) {
|
|
809
|
+
return textResource(uri, "text/plain", `GET ${path} returned ${response.status}`);
|
|
810
|
+
}
|
|
811
|
+
const parsed = EvidenceReadResponseSchema.safeParse(await response.json());
|
|
812
|
+
if (!parsed.success) {
|
|
813
|
+
return textResource(uri, "text/plain", "Evidence endpoint returned an unparseable body");
|
|
814
|
+
}
|
|
815
|
+
return textResource(uri, "text/markdown", parsed.data.markdown);
|
|
816
|
+
} catch (err) {
|
|
817
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
818
|
+
return textResource(uri, "text/plain", `Resource read failed: ${message}`);
|
|
819
|
+
}
|
|
820
|
+
},
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
function registerPrompts(server: McpServer): void {
|
|
825
|
+
server.registerPrompt(
|
|
826
|
+
"inspector_analyze_session_failure",
|
|
827
|
+
{
|
|
828
|
+
title: "Analyze session failure",
|
|
829
|
+
description:
|
|
830
|
+
"Use Inspector session/log resources to explain why a coding-agent session failed.",
|
|
831
|
+
argsSchema: z.object({
|
|
832
|
+
sessionId: z.string().min(1).describe("The Inspector session id."),
|
|
833
|
+
includeHistory: z
|
|
834
|
+
.boolean()
|
|
835
|
+
.optional()
|
|
836
|
+
.describe("When true, call inspector_get_session with includeHistory=true if needed."),
|
|
837
|
+
}),
|
|
838
|
+
},
|
|
839
|
+
({ sessionId, includeHistory }) =>
|
|
840
|
+
userPrompt(`Analyze this Agent Inspector session and explain why it failed.
|
|
841
|
+
|
|
842
|
+
Evidence to read:
|
|
843
|
+
- Session resource: inspector://sessions/${encodeURIComponent(sessionId)}
|
|
844
|
+
- Relevant log resources: inspector://logs/{id} for the failing or suspicious log ids
|
|
845
|
+
|
|
846
|
+
If includeHistory is ${includeHistory === true ? "true" : "false"} or the session summary looks incomplete, call inspector_get_session with includeHistory=true and latestLogLimit=50.
|
|
847
|
+
|
|
848
|
+
Return:
|
|
849
|
+
1. Outcome and severity
|
|
850
|
+
2. Most likely root cause
|
|
851
|
+
3. Evidence bullets with log ids, models, providers, status codes, and error text
|
|
852
|
+
4. Concrete fix or next diagnostic step
|
|
853
|
+
5. Confidence and what evidence is still missing`),
|
|
854
|
+
);
|
|
855
|
+
|
|
856
|
+
server.registerPrompt(
|
|
857
|
+
"inspector_triage_recent_failures",
|
|
858
|
+
{
|
|
859
|
+
title: "Triage recent failures",
|
|
860
|
+
description:
|
|
861
|
+
"Use the recent failures resource and log search tool to prioritize coding-agent failures.",
|
|
862
|
+
argsSchema: z.object({
|
|
863
|
+
limit: z
|
|
864
|
+
.number()
|
|
865
|
+
.int()
|
|
866
|
+
.positive()
|
|
867
|
+
.max(20)
|
|
868
|
+
.optional()
|
|
869
|
+
.describe("How many failures to triage."),
|
|
870
|
+
}),
|
|
871
|
+
},
|
|
872
|
+
({ limit }) =>
|
|
873
|
+
userPrompt(`Triage recent Agent Inspector failures.
|
|
874
|
+
|
|
875
|
+
Evidence to read:
|
|
876
|
+
- Recent failures resource: inspector://failures/recent
|
|
877
|
+
- For missing details, call inspector_get_recent_failures with limit=${String(limit ?? 5)}
|
|
878
|
+
- For suspicious sessions/models/providers, call inspector_search_logs and then inspector_get_log for cited ids
|
|
879
|
+
|
|
880
|
+
Return:
|
|
881
|
+
1. Highest-priority failure first
|
|
882
|
+
2. Run id, session id, category, severity, and evidence links
|
|
883
|
+
3. Likely root cause and concrete next action
|
|
884
|
+
4. Whether evidence is sufficient or inspector_export_evidence should be run again`),
|
|
885
|
+
);
|
|
886
|
+
|
|
887
|
+
server.registerPrompt(
|
|
888
|
+
"inspector_generate_jenkins_report",
|
|
889
|
+
{
|
|
890
|
+
title: "Generate Jenkins report",
|
|
891
|
+
description:
|
|
892
|
+
"Generate a Jenkins-friendly Markdown report from an Inspector run and evidence pack.",
|
|
893
|
+
argsSchema: z.object({
|
|
894
|
+
runId: z.string().min(1).describe("The Inspector run id."),
|
|
895
|
+
}),
|
|
896
|
+
},
|
|
897
|
+
({ runId }) =>
|
|
898
|
+
userPrompt(`Generate a Jenkins-ready Markdown report for this Inspector run.
|
|
899
|
+
|
|
900
|
+
Evidence to read:
|
|
901
|
+
- Run resource: inspector://runs/${encodeURIComponent(runId)}
|
|
902
|
+
- Evidence pack resource: inspector://evidence/${encodeURIComponent(runId)}
|
|
903
|
+
|
|
904
|
+
If the evidence pack resource says it has not been exported, call inspector_export_evidence for this run first.
|
|
905
|
+
|
|
906
|
+
The report should include:
|
|
907
|
+
1. Build/run status summary
|
|
908
|
+
2. Run id, session id, Inspector URLs, and artifact paths
|
|
909
|
+
3. Models/providers used, token totals, request counts, and error counts
|
|
910
|
+
4. Failure analysis or success evidence
|
|
911
|
+
5. Reproducible next action for a developer`),
|
|
912
|
+
);
|
|
913
|
+
|
|
914
|
+
server.registerPrompt(
|
|
915
|
+
"inspector_extract_repro_steps",
|
|
916
|
+
{
|
|
917
|
+
title: "Extract reproducible steps",
|
|
918
|
+
description:
|
|
919
|
+
"Turn an Inspector session into concise repro steps for a developer or evaluator.",
|
|
920
|
+
argsSchema: z.object({
|
|
921
|
+
sessionId: z.string().min(1).describe("The Inspector session id."),
|
|
922
|
+
}),
|
|
923
|
+
},
|
|
924
|
+
({ sessionId }) =>
|
|
925
|
+
userPrompt(`Extract reproducible steps from this Agent Inspector session.
|
|
926
|
+
|
|
927
|
+
Evidence to read:
|
|
928
|
+
- Session resource: inspector://sessions/${encodeURIComponent(sessionId)}
|
|
929
|
+
- Relevant log resources: inspector://logs/{id}
|
|
930
|
+
|
|
931
|
+
Return:
|
|
932
|
+
1. Preconditions and environment assumptions
|
|
933
|
+
2. Ordered user/agent actions that led to the behavior
|
|
934
|
+
3. Exact model/provider/API path details needed to reproduce
|
|
935
|
+
4. Expected vs actual result
|
|
936
|
+
5. Minimal verification command or UI check`),
|
|
937
|
+
);
|
|
938
|
+
}
|
|
939
|
+
|
|
411
940
|
// Surface the tool catalog for tests that assert on the tool name set.
|
|
412
941
|
export const TOOL_NAMES = [
|
|
413
942
|
"inspector_list_logs",
|
|
943
|
+
"inspector_search_logs",
|
|
414
944
|
"inspector_get_log",
|
|
415
945
|
"inspector_get_log_chunks",
|
|
416
946
|
"inspector_list_sessions",
|
|
417
947
|
"inspector_get_session",
|
|
948
|
+
"inspector_create_run",
|
|
949
|
+
"inspector_get_run",
|
|
950
|
+
"inspector_update_run",
|
|
951
|
+
"inspector_export_evidence",
|
|
952
|
+
"inspector_get_recent_failures",
|
|
418
953
|
"inspector_list_models",
|
|
419
954
|
"inspector_list_providers",
|
|
420
955
|
"inspector_get_provider",
|
|
@@ -428,3 +963,20 @@ export const TOOL_NAMES = [
|
|
|
428
963
|
"inspector_search_knowledge",
|
|
429
964
|
"inspector_get_project_context",
|
|
430
965
|
] as const;
|
|
966
|
+
|
|
967
|
+
export const RESOURCE_NAMES = [
|
|
968
|
+
"inspector_sessions",
|
|
969
|
+
"inspector_session",
|
|
970
|
+
"inspector_log",
|
|
971
|
+
"inspector_runs",
|
|
972
|
+
"inspector_recent_failures",
|
|
973
|
+
"inspector_run",
|
|
974
|
+
"inspector_evidence",
|
|
975
|
+
] as const;
|
|
976
|
+
|
|
977
|
+
export const PROMPT_NAMES = [
|
|
978
|
+
"inspector_analyze_session_failure",
|
|
979
|
+
"inspector_triage_recent_failures",
|
|
980
|
+
"inspector_generate_jenkins_report",
|
|
981
|
+
"inspector_extract_repro_steps",
|
|
982
|
+
] as const;
|