@tonyclaw/agent-inspector 2.0.38 → 2.0.40
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 +528 -24
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-hc5OoAls.js → CompareDrawer-p0uYxW7_.js} +1 -1
- package/.output/public/assets/{ProxyViewerContainer-BMKBs8Qz.js → ProxyViewerContainer-BGqeiYKD.js} +26 -26
- package/.output/public/assets/{ReplayDialog-CN-KM2nu.js → ReplayDialog-TTTVCMe9.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-B1kTlAUk.js → RequestAnatomy-c8ru0pS-.js} +1 -1
- package/.output/public/assets/{ResponseView-BchUjKjt.js → ResponseView-D59jTMy4.js} +1 -1
- package/.output/public/assets/{StreamingChunkSequence-BQOxI9Hi.js → StreamingChunkSequence-UlAMVF9j.js} +1 -1
- package/.output/public/assets/_sessionId-EHPexdPl.js +1 -0
- package/.output/public/assets/index-CZP-XfpB.js +1 -0
- package/.output/public/assets/{main-Blykwzsn.js → main-CKYe6UUv.js} +2 -2
- package/.output/server/{_sessionId-BUNZz2zZ.mjs → _sessionId-CkwhOzdS.mjs} +2 -2
- package/.output/server/_ssr/{CompareDrawer-VaDYPM5G.mjs → CompareDrawer-BHDiuYMw.mjs} +2 -2
- package/.output/server/_ssr/{ProxyViewerContainer-CpdWs7Pk.mjs → ProxyViewerContainer-0c2_DBMX.mjs} +57 -6
- package/.output/server/_ssr/{ReplayDialog-DbfIjJhb.mjs → ReplayDialog-CTjwzDDH.mjs} +3 -3
- package/.output/server/_ssr/{RequestAnatomy-CrD8h6As.mjs → RequestAnatomy-D36oujv2.mjs} +2 -2
- package/.output/server/_ssr/{ResponseView-BalvDwtU.mjs → ResponseView-ClZ3oODE.mjs} +2 -2
- package/.output/server/_ssr/{StreamingChunkSequence-RxatDbPV.mjs → StreamingChunkSequence-Ck5l4p1m.mjs} +2 -2
- package/.output/server/_ssr/{index-11qAtV9d.mjs → index-DKBYH0TC.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-C4OdRnqX.mjs → router-D4I3ZyVS.mjs} +434 -6
- package/.output/server/{_tanstack-start-manifest_v-F6bwcl33.mjs → _tanstack-start-manifest_v-D4vSn_wD.mjs} +1 -1
- package/.output/server/index.mjs +54 -54
- package/README.md +7 -0
- package/package.json +1 -1
- package/src/cli/onboard.ts +629 -21
- package/src/components/providers/SettingsDialog.tsx +30 -0
- package/src/components/proxy-viewer/LogEntry.tsx +15 -1
- package/src/components/proxy-viewer/LogEntryHeader.tsx +20 -0
- package/src/contracts/log.ts +1 -0
- package/src/proxy/logFinalizer.ts +58 -0
- package/src/proxy/logSearch.ts +1 -0
- package/src/proxy/toolSchemaWarnings.ts +515 -0
- package/.output/public/assets/_sessionId-CVw5e8TK.js +0 -1
- package/.output/public/assets/index-BdUTMQL6.js +0 -1
|
@@ -293,6 +293,18 @@ function OnboardingSettingsTab(): JSX.Element {
|
|
|
293
293
|
label: "Codex prompt",
|
|
294
294
|
value: "Use the agent-inspector-onboard skill",
|
|
295
295
|
},
|
|
296
|
+
{
|
|
297
|
+
id: "opencode-config",
|
|
298
|
+
label: "OpenCode config",
|
|
299
|
+
value: "agent-inspector onboard --opencode-only",
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
id: "opencode-status",
|
|
303
|
+
label: "OpenCode status",
|
|
304
|
+
value: "agent-inspector onboard --status --opencode-only",
|
|
305
|
+
},
|
|
306
|
+
{ id: "opencode-verify", label: "OpenCode verify", value: "opencode mcp list" },
|
|
307
|
+
{ id: "opencode-proxy", label: "OpenCode proxy", value: `LLM_BASE_URL=${origin}/proxy` },
|
|
296
308
|
{ id: "mcp", label: "MCP URL", value: `${origin}/api/mcp` },
|
|
297
309
|
{ id: "proxy", label: "Proxy URL", value: `${origin}/proxy` },
|
|
298
310
|
{ id: "anthropic", label: "Anthropic base", value: `ANTHROPIC_BASE_URL=${origin}/proxy` },
|
|
@@ -345,6 +357,24 @@ function OnboardingSettingsTab(): JSX.Element {
|
|
|
345
357
|
instead. Configure only one entry for the same Inspector.
|
|
346
358
|
</span>
|
|
347
359
|
</div>
|
|
360
|
+
<div className="flex items-start gap-2">
|
|
361
|
+
<Check className="mt-0.5 size-3.5 text-emerald-500" />
|
|
362
|
+
<span>
|
|
363
|
+
OpenCode onboarding safely merges{" "}
|
|
364
|
+
<code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px] text-foreground">
|
|
365
|
+
mcp.agent-inspector
|
|
366
|
+
</code>{" "}
|
|
367
|
+
into{" "}
|
|
368
|
+
<code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px] text-foreground">
|
|
369
|
+
opencode.json
|
|
370
|
+
</code>
|
|
371
|
+
, then verify with{" "}
|
|
372
|
+
<code className="rounded bg-muted px-1 py-0.5 font-mono text-[11px] text-foreground">
|
|
373
|
+
opencode mcp list
|
|
374
|
+
</code>
|
|
375
|
+
.
|
|
376
|
+
</span>
|
|
377
|
+
</div>
|
|
348
378
|
<div className="flex items-start gap-2">
|
|
349
379
|
<Check className="mt-0.5 size-3.5 text-emerald-500" />
|
|
350
380
|
<span>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GitCompareArrows } from "lucide-react";
|
|
1
|
+
import { AlertTriangle, GitCompareArrows } from "lucide-react";
|
|
2
2
|
import { Suspense, type JSX } from "react";
|
|
3
3
|
import { useEffect, useMemo, useRef, useState, memo } from "react";
|
|
4
4
|
import type { CapturedLog } from "../../contracts";
|
|
@@ -295,6 +295,7 @@ export const LogEntry = memo(function ({
|
|
|
295
295
|
() => parseRequestTools(requestExpansion.parsedData),
|
|
296
296
|
[requestExpansion.parsedData],
|
|
297
297
|
);
|
|
298
|
+
const warnings = log.warnings ?? [];
|
|
298
299
|
const anatomyPaths = useMemo(() => {
|
|
299
300
|
if (anatomySegments === null) return undefined;
|
|
300
301
|
return new Set(anatomySegments.map((s) => s.path));
|
|
@@ -392,6 +393,19 @@ export const LogEntry = memo(function ({
|
|
|
392
393
|
<TabsContent value="request">
|
|
393
394
|
{activeTab === "request" && (
|
|
394
395
|
<div className="px-4 pt-1 pb-3">
|
|
396
|
+
{warnings.length > 0 && (
|
|
397
|
+
<div className="mb-3 rounded border border-amber-500/30 bg-amber-500/10 p-3 text-xs">
|
|
398
|
+
<div className="flex items-center gap-2 font-semibold text-amber-300">
|
|
399
|
+
<AlertTriangle className="size-3.5" />
|
|
400
|
+
Tool schema warnings
|
|
401
|
+
</div>
|
|
402
|
+
<ul className="mt-2 space-y-1 text-muted-foreground">
|
|
403
|
+
{warnings.map((warning) => (
|
|
404
|
+
<li key={warning}>{warning}</li>
|
|
405
|
+
))}
|
|
406
|
+
</ul>
|
|
407
|
+
</div>
|
|
408
|
+
)}
|
|
395
409
|
<RequestTools
|
|
396
410
|
summary={requestTools}
|
|
397
411
|
calledToolNames={responseAnalysis.toolNames ?? []}
|
|
@@ -159,6 +159,7 @@ export const LogEntryHeader = memo(function ({
|
|
|
159
159
|
const firstChunkLabel = firstChunkMs === null ? null : formatElapsed(firstChunkMs);
|
|
160
160
|
const tokenRateLabel =
|
|
161
161
|
tokensPerSecond === null || tokensPerSecond <= 0 ? null : formatTokenRate(tokensPerSecond);
|
|
162
|
+
const warningCount = log.warnings?.length ?? 0;
|
|
162
163
|
|
|
163
164
|
return (
|
|
164
165
|
<TooltipProvider>
|
|
@@ -229,6 +230,25 @@ export const LogEntryHeader = memo(function ({
|
|
|
229
230
|
</Badge>
|
|
230
231
|
)}
|
|
231
232
|
|
|
233
|
+
{warningCount > 0 && (
|
|
234
|
+
<Tooltip>
|
|
235
|
+
<TooltipTrigger asChild>
|
|
236
|
+
<Badge
|
|
237
|
+
variant="outline"
|
|
238
|
+
className="text-[10px] px-1.5 py-0 h-5 font-mono tabular-nums gap-1 bg-amber-500/15 text-amber-400 border-amber-500/25"
|
|
239
|
+
>
|
|
240
|
+
<AlertTriangle className="size-3" aria-label="Tool schema warnings" />
|
|
241
|
+
{warningCount}
|
|
242
|
+
</Badge>
|
|
243
|
+
</TooltipTrigger>
|
|
244
|
+
<TooltipContent>
|
|
245
|
+
{warningCount === 1
|
|
246
|
+
? "1 tool schema warning"
|
|
247
|
+
: `${warningCount} tool schema warnings`}
|
|
248
|
+
</TooltipContent>
|
|
249
|
+
</Tooltip>
|
|
250
|
+
)}
|
|
251
|
+
|
|
232
252
|
{/* Elapsed time */}
|
|
233
253
|
{log.elapsedMs !== null && (
|
|
234
254
|
<Tooltip>
|
package/src/contracts/log.ts
CHANGED
|
@@ -58,6 +58,7 @@ export const CapturedLogSchema = z.object({
|
|
|
58
58
|
rawRequestBodyBytes: z.number().int().nonnegative().nullable().optional(),
|
|
59
59
|
responseTextBytes: z.number().int().nonnegative().nullable().optional(),
|
|
60
60
|
bodyContentMode: z.enum(["full", "compact", "truncated"]).optional(),
|
|
61
|
+
warnings: z.array(z.string()).optional(),
|
|
61
62
|
/** Error message from streaming response (e.g., SSE error event) */
|
|
62
63
|
error: z.string().nullable().optional(),
|
|
63
64
|
});
|
|
@@ -9,6 +9,7 @@ import type { CapturedLog } from "./schemas";
|
|
|
9
9
|
import { getSessionProcess, isSessionProcessAvailable } from "./sessionProcess";
|
|
10
10
|
import { finalizeLogUpdate } from "./store";
|
|
11
11
|
import { computeTokensPerSecond } from "./streamTiming";
|
|
12
|
+
import { analyzeToolSchemaWarnings } from "./toolSchemaWarnings";
|
|
12
13
|
|
|
13
14
|
type BaseFinalizeLogJob = {
|
|
14
15
|
log: CapturedLog;
|
|
@@ -91,6 +92,7 @@ export function buildFileLogEntry(log: CapturedLog, upstreamUrl: string): Record
|
|
|
91
92
|
clientProjectFolder: log.clientProjectFolder,
|
|
92
93
|
streamingChunks: log.streamingChunks,
|
|
93
94
|
streamingChunksPath: log.streamingChunksPath,
|
|
95
|
+
warnings: log.warnings,
|
|
94
96
|
error: log.error,
|
|
95
97
|
};
|
|
96
98
|
}
|
|
@@ -152,6 +154,57 @@ function applyOptionalStreamingTiming(log: CapturedLog, job: FinalizeLogJob): vo
|
|
|
152
154
|
}
|
|
153
155
|
}
|
|
154
156
|
|
|
157
|
+
type ToolSchemaWarningAnalysisJob = {
|
|
158
|
+
log: CapturedLog;
|
|
159
|
+
upstreamUrl: string;
|
|
160
|
+
error: string | null;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
let toolSchemaWarningQueue: Promise<void> = Promise.resolve();
|
|
164
|
+
|
|
165
|
+
function deferToolSchemaWarningAnalysis(): Promise<void> {
|
|
166
|
+
return new Promise((resolve) => {
|
|
167
|
+
setTimeout(resolve, 0);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function withToolSchemaWarnings(log: CapturedLog): CapturedLog | null {
|
|
172
|
+
const warnings = analyzeToolSchemaWarnings({
|
|
173
|
+
rawRequestBody: log.rawRequestBody,
|
|
174
|
+
responseText: log.responseText,
|
|
175
|
+
apiFormat: log.apiFormat,
|
|
176
|
+
});
|
|
177
|
+
if (warnings.length === 0) return null;
|
|
178
|
+
const mergedWarnings = Array.from(new Set([...(log.warnings ?? []), ...warnings]));
|
|
179
|
+
if (mergedWarnings.length === (log.warnings?.length ?? 0)) return null;
|
|
180
|
+
return { ...log, warnings: mergedWarnings };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async function runToolSchemaWarningAnalysis(job: ToolSchemaWarningAnalysisJob): Promise<void> {
|
|
184
|
+
await deferToolSchemaWarningAnalysis();
|
|
185
|
+
const updatedLog = withToolSchemaWarnings(job.log);
|
|
186
|
+
if (updatedLog === null) return;
|
|
187
|
+
|
|
188
|
+
appendLogEntry({ ...buildFileLogEntry(updatedLog, job.upstreamUrl), error: job.error });
|
|
189
|
+
finalizeLogUpdate(updatedLog);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function scheduleToolSchemaWarningAnalysis(job: ToolSchemaWarningAnalysisJob): void {
|
|
193
|
+
toolSchemaWarningQueue = toolSchemaWarningQueue
|
|
194
|
+
.catch(() => undefined)
|
|
195
|
+
.then(() => runToolSchemaWarningAnalysis(job))
|
|
196
|
+
.catch((err: unknown) => {
|
|
197
|
+
logger.warn(
|
|
198
|
+
`[logFinalizer] Tool schema warning analysis failed for log #${job.log.id}:`,
|
|
199
|
+
errorMessage(err),
|
|
200
|
+
);
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export async function flushToolSchemaWarningAnalysis(): Promise<void> {
|
|
205
|
+
await toolSchemaWarningQueue;
|
|
206
|
+
}
|
|
207
|
+
|
|
155
208
|
function finalizeNonStreaming(
|
|
156
209
|
job: FinalizeNonStreamingLogJob,
|
|
157
210
|
log: CapturedLog,
|
|
@@ -384,6 +437,11 @@ export function buildFinalizeLogResult(job: FinalizeLogJob): FinalizeLogResult {
|
|
|
384
437
|
export function commitFinalizeLogResult(result: FinalizeLogResult): void {
|
|
385
438
|
appendLogEntry({ ...buildFileLogEntry(result.log, result.upstreamUrl), error: result.error });
|
|
386
439
|
finalizeLogUpdate(result.log);
|
|
440
|
+
scheduleToolSchemaWarningAnalysis({
|
|
441
|
+
log: cloneLog(result.log),
|
|
442
|
+
upstreamUrl: result.upstreamUrl,
|
|
443
|
+
error: result.error,
|
|
444
|
+
});
|
|
387
445
|
if (result.cleanupRawStreamPath !== undefined && result.cleanupRawStreamPath !== null) {
|
|
388
446
|
try {
|
|
389
447
|
rmSync(result.cleanupRawStreamPath, { force: true });
|
package/src/proxy/logSearch.ts
CHANGED
|
@@ -70,6 +70,7 @@ function searchableFields(log: CapturedLog): string[] {
|
|
|
70
70
|
optionalText(log.clientCwd),
|
|
71
71
|
optionalText(log.clientProjectFolder),
|
|
72
72
|
optionalText(log.error),
|
|
73
|
+
...(log.warnings ?? []),
|
|
73
74
|
].filter((value): value is string => value !== null && value.length > 0);
|
|
74
75
|
}
|
|
75
76
|
|