@tonyclaw/agent-inspector 2.0.43 → 2.1.1
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-CxM1gCfL.js → CompareDrawer-DkDpl_Sg.js} +1 -1
- package/.output/public/assets/ProxyViewerContainer-D_-e1qn7.js +117 -0
- package/.output/public/assets/{ReplayDialog-UseUkucS.js → ReplayDialog-CKqYfD0A.js} +1 -1
- package/.output/public/assets/RequestAnatomy-CQZl-YIx.js +1 -0
- package/.output/public/assets/ResponseView-DW9tFPi0.js +1 -0
- package/.output/public/assets/{StreamingChunkSequence-JSQEPeNS.js → StreamingChunkSequence-m8zKc3L1.js} +1 -1
- package/.output/public/assets/_sessionId-DyfzgUXv.js +1 -0
- package/.output/public/assets/index-B6bobhTz.js +1 -0
- package/.output/public/assets/index-CLQKZ5A5.css +1 -0
- package/.output/public/assets/{main-BpGVJcpB.js → main-BjXd3DR-.js} +2 -2
- package/.output/server/_libs/lucide-react.mjs +219 -178
- package/.output/server/{_sessionId-DGn-TENM.mjs → _sessionId-LjzdyWF4.mjs} +3 -3
- package/.output/server/_ssr/{CompareDrawer-CFElCSYY.mjs → CompareDrawer-YX2uOwh9.mjs} +4 -4
- package/.output/server/_ssr/{ProxyViewerContainer-B7SR9mrD.mjs → ProxyViewerContainer-BcKHl2E3.mjs} +1016 -582
- package/.output/server/_ssr/{ReplayDialog-DfKapj0k.mjs → ReplayDialog-B9AxvV2j.mjs} +5 -5
- package/.output/server/_ssr/{RequestAnatomy-CUxTCg31.mjs → RequestAnatomy-DxmUOcz8.mjs} +4 -4
- package/.output/server/_ssr/{ResponseView-BXY0w197.mjs → ResponseView-B73PHDQ0.mjs} +4 -4
- package/.output/server/_ssr/{StreamingChunkSequence-CzMnES9H.mjs → StreamingChunkSequence-Bkwxu5Ev.mjs} +4 -4
- package/.output/server/_ssr/{index-CVlT-REW.mjs → index-Dfl6uxit.mjs} +3 -3
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-B2d1LUx6.mjs → router-B5cpU5Hi.mjs} +458 -10
- package/.output/server/{_tanstack-start-manifest_v-Drpi28BM.mjs → _tanstack-start-manifest_v-CHhxRQY_.mjs} +1 -1
- package/.output/server/index.mjs +62 -62
- package/package.json +1 -1
- package/src/components/OnboardingBanner.tsx +60 -70
- package/src/components/ProxyViewer.tsx +838 -366
- package/src/components/ProxyViewerContainer.tsx +136 -5
- package/src/components/providers/SettingsDialog.tsx +0 -13
- package/src/components/proxy-viewer/LogEntry.tsx +198 -89
- package/src/components/proxy-viewer/LogEntryHeader.tsx +23 -13
- package/src/components/proxy-viewer/RequestToolsPanel.tsx +8 -8
- package/src/components/ui/crab-logo.tsx +0 -50
- package/src/components/ui/json-viewer.tsx +6 -0
- package/src/proxy/logIndex.ts +188 -1
- package/src/proxy/store.ts +405 -3
- package/src/routes/api/logs.ts +36 -0
- package/styles/globals.css +53 -8
- package/.output/public/assets/ProxyViewerContainer-TtRG-0E7.js +0 -117
- package/.output/public/assets/RequestAnatomy-aPxgEJ2L.js +0 -1
- package/.output/public/assets/ResponseView-DA-F4F97.js +0 -1
- package/.output/public/assets/_sessionId-BEXuCWq5.js +0 -1
- package/.output/public/assets/index-Bhsa_2xX.js +0 -1
- package/.output/public/assets/index-DOWlRJ0W.css +0 -1
|
@@ -438,6 +438,12 @@ export function JsonViewer({
|
|
|
438
438
|
<CopyValueButton value={data} />
|
|
439
439
|
</div>
|
|
440
440
|
)}
|
|
441
|
+
{entries.length === 0 && (
|
|
442
|
+
<div className="rounded-md border border-white/10 bg-black/20 px-3 py-2 text-muted-foreground">
|
|
443
|
+
<span className="text-cyan-300">{isArray ? "[]" : "{}"}</span>
|
|
444
|
+
<span className="ml-2 text-[10px] uppercase">0 items</span>
|
|
445
|
+
</div>
|
|
446
|
+
)}
|
|
441
447
|
<div key={bulkRevision}>
|
|
442
448
|
{entries.map(([key, childValue]) => (
|
|
443
449
|
<JsonNode
|
package/src/proxy/logIndex.ts
CHANGED
|
@@ -4,12 +4,56 @@ import { join, dirname } from "node:path";
|
|
|
4
4
|
import { createInterface } from "node:readline";
|
|
5
5
|
import { Buffer } from "node:buffer";
|
|
6
6
|
import { resolveLogDir, logger } from "./logger";
|
|
7
|
+
import type { ApiFormat, CapturedLog } from "./schemas";
|
|
8
|
+
|
|
9
|
+
export type LogIndexSummary = {
|
|
10
|
+
id: number;
|
|
11
|
+
timestamp: string;
|
|
12
|
+
method: string;
|
|
13
|
+
path: string;
|
|
14
|
+
model: string | null;
|
|
15
|
+
sessionId: string | null;
|
|
16
|
+
responseStatus: number | null;
|
|
17
|
+
inputTokens: number | null;
|
|
18
|
+
outputTokens: number | null;
|
|
19
|
+
cacheCreationInputTokens: number | null;
|
|
20
|
+
cacheReadInputTokens: number | null;
|
|
21
|
+
elapsedMs: number | null;
|
|
22
|
+
firstChunkMs: number | null;
|
|
23
|
+
totalStreamMs: number | null;
|
|
24
|
+
tokensPerSecond: number | null;
|
|
25
|
+
streaming: boolean;
|
|
26
|
+
userAgent: string | null;
|
|
27
|
+
origin: string | null;
|
|
28
|
+
apiFormat: ApiFormat;
|
|
29
|
+
isTest: boolean;
|
|
30
|
+
replayOfLogId: number | null;
|
|
31
|
+
providerName: string | null;
|
|
32
|
+
clientPort: number | null;
|
|
33
|
+
clientPid: number | null;
|
|
34
|
+
clientCwd: string | null;
|
|
35
|
+
clientProjectFolder: string | null;
|
|
36
|
+
streamingChunksPath: string | null;
|
|
37
|
+
rawRequestBodyBytes: number | null;
|
|
38
|
+
responseTextBytes: number | null;
|
|
39
|
+
warnings?: string[];
|
|
40
|
+
error: string | null;
|
|
41
|
+
};
|
|
7
42
|
|
|
8
43
|
export type LogIndexEntry = {
|
|
9
44
|
id: number;
|
|
10
45
|
file: string;
|
|
11
46
|
byteOffset: number;
|
|
12
47
|
byteLength: number;
|
|
48
|
+
sessionId?: string | null;
|
|
49
|
+
model?: string | null;
|
|
50
|
+
summary?: LogIndexSummary;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export type LogIndexEntryMetadata = {
|
|
54
|
+
sessionId: string | null;
|
|
55
|
+
model: string | null;
|
|
56
|
+
summary: LogIndexSummary;
|
|
13
57
|
};
|
|
14
58
|
|
|
15
59
|
type LogIndex = {
|
|
@@ -29,6 +73,50 @@ function getIndexPath(): string {
|
|
|
29
73
|
|
|
30
74
|
let cachedIndex: LogIndex | null = null;
|
|
31
75
|
|
|
76
|
+
function textByteLength(value: string | null): number | null {
|
|
77
|
+
return value === null ? null : Buffer.byteLength(value, "utf8");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function createLogIndexEntryMetadata(log: CapturedLog): LogIndexEntryMetadata {
|
|
81
|
+
return {
|
|
82
|
+
sessionId: log.sessionId,
|
|
83
|
+
model: log.model,
|
|
84
|
+
summary: {
|
|
85
|
+
id: log.id,
|
|
86
|
+
timestamp: log.timestamp,
|
|
87
|
+
method: log.method,
|
|
88
|
+
path: log.path,
|
|
89
|
+
model: log.model,
|
|
90
|
+
sessionId: log.sessionId,
|
|
91
|
+
responseStatus: log.responseStatus,
|
|
92
|
+
inputTokens: log.inputTokens,
|
|
93
|
+
outputTokens: log.outputTokens,
|
|
94
|
+
cacheCreationInputTokens: log.cacheCreationInputTokens,
|
|
95
|
+
cacheReadInputTokens: log.cacheReadInputTokens,
|
|
96
|
+
elapsedMs: log.elapsedMs,
|
|
97
|
+
firstChunkMs: log.firstChunkMs ?? null,
|
|
98
|
+
totalStreamMs: log.totalStreamMs ?? null,
|
|
99
|
+
tokensPerSecond: log.tokensPerSecond ?? null,
|
|
100
|
+
streaming: log.streaming,
|
|
101
|
+
userAgent: log.userAgent,
|
|
102
|
+
origin: log.origin,
|
|
103
|
+
apiFormat: log.apiFormat,
|
|
104
|
+
isTest: log.isTest ?? false,
|
|
105
|
+
replayOfLogId: log.replayOfLogId ?? null,
|
|
106
|
+
providerName: log.providerName ?? null,
|
|
107
|
+
clientPort: log.clientPort ?? null,
|
|
108
|
+
clientPid: log.clientPid ?? null,
|
|
109
|
+
clientCwd: log.clientCwd ?? null,
|
|
110
|
+
clientProjectFolder: log.clientProjectFolder ?? null,
|
|
111
|
+
streamingChunksPath: log.streamingChunksPath ?? null,
|
|
112
|
+
rawRequestBodyBytes: log.rawRequestBodyBytes ?? textByteLength(log.rawRequestBody),
|
|
113
|
+
responseTextBytes: log.responseTextBytes ?? textByteLength(log.responseText),
|
|
114
|
+
warnings: log.warnings,
|
|
115
|
+
error: log.error ?? null,
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
32
120
|
function createEmptyIndex(): LogIndex {
|
|
33
121
|
return {
|
|
34
122
|
version: INDEX_VERSION,
|
|
@@ -100,9 +188,13 @@ export async function addToIndex(
|
|
|
100
188
|
file: string,
|
|
101
189
|
byteOffset: number,
|
|
102
190
|
byteLength: number,
|
|
191
|
+
metadata?: LogIndexEntryMetadata,
|
|
103
192
|
): Promise<void> {
|
|
104
193
|
const index = await loadIndex();
|
|
105
|
-
index.entries[id] =
|
|
194
|
+
index.entries[id] =
|
|
195
|
+
metadata === undefined
|
|
196
|
+
? { id, file, byteOffset, byteLength }
|
|
197
|
+
: { id, file, byteOffset, byteLength, ...metadata };
|
|
106
198
|
if (id > index.maxId) {
|
|
107
199
|
index.maxId = id;
|
|
108
200
|
}
|
|
@@ -154,6 +246,98 @@ type FileIndexResult = {
|
|
|
154
246
|
maxId: number;
|
|
155
247
|
};
|
|
156
248
|
|
|
249
|
+
function readStringOrNullField(entry: object, field: string): string | null {
|
|
250
|
+
const desc = Object.getOwnPropertyDescriptor(entry, field);
|
|
251
|
+
if (desc === undefined) return null;
|
|
252
|
+
if (typeof desc.value === "string") return desc.value;
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function readStringField(entry: object, field: string): string {
|
|
257
|
+
return readStringOrNullField(entry, field) ?? "";
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function readNumberOrNullField(entry: object, field: string): number | null {
|
|
261
|
+
const desc = Object.getOwnPropertyDescriptor(entry, field);
|
|
262
|
+
if (desc === undefined) return null;
|
|
263
|
+
return typeof desc.value === "number" ? desc.value : null;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function readBooleanField(entry: object, field: string): boolean {
|
|
267
|
+
const desc = Object.getOwnPropertyDescriptor(entry, field);
|
|
268
|
+
if (desc === undefined) return false;
|
|
269
|
+
return typeof desc.value === "boolean" ? desc.value : false;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function readApiFormatField(entry: object): ApiFormat {
|
|
273
|
+
const value = readStringOrNullField(entry, "apiFormat");
|
|
274
|
+
switch (value) {
|
|
275
|
+
case "anthropic":
|
|
276
|
+
return "anthropic";
|
|
277
|
+
case "openai":
|
|
278
|
+
return "openai";
|
|
279
|
+
case "unknown":
|
|
280
|
+
case null:
|
|
281
|
+
return "unknown";
|
|
282
|
+
default:
|
|
283
|
+
return "unknown";
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function readStringArrayField(entry: object, field: string): string[] | undefined {
|
|
288
|
+
const desc = Object.getOwnPropertyDescriptor(entry, field);
|
|
289
|
+
if (desc === undefined || !Array.isArray(desc.value)) return undefined;
|
|
290
|
+
|
|
291
|
+
const values: string[] = [];
|
|
292
|
+
for (const item of desc.value) {
|
|
293
|
+
if (typeof item !== "string") return undefined;
|
|
294
|
+
values.push(item);
|
|
295
|
+
}
|
|
296
|
+
return values;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function readTextByteLength(entry: object, bytesField: string, textField: string): number | null {
|
|
300
|
+
const explicitBytes = readNumberOrNullField(entry, bytesField);
|
|
301
|
+
if (explicitBytes !== null && explicitBytes >= 0) return explicitBytes;
|
|
302
|
+
return textByteLength(readStringOrNullField(entry, textField));
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function readLogIndexSummary(entry: object, id: number): LogIndexSummary {
|
|
306
|
+
return {
|
|
307
|
+
id,
|
|
308
|
+
timestamp: readStringField(entry, "timestamp"),
|
|
309
|
+
method: readStringField(entry, "method"),
|
|
310
|
+
path: readStringField(entry, "path"),
|
|
311
|
+
model: readStringOrNullField(entry, "model"),
|
|
312
|
+
sessionId: readStringOrNullField(entry, "sessionId"),
|
|
313
|
+
responseStatus: readNumberOrNullField(entry, "responseStatus"),
|
|
314
|
+
inputTokens: readNumberOrNullField(entry, "inputTokens"),
|
|
315
|
+
outputTokens: readNumberOrNullField(entry, "outputTokens"),
|
|
316
|
+
cacheCreationInputTokens: readNumberOrNullField(entry, "cacheCreationInputTokens"),
|
|
317
|
+
cacheReadInputTokens: readNumberOrNullField(entry, "cacheReadInputTokens"),
|
|
318
|
+
elapsedMs: readNumberOrNullField(entry, "elapsedMs"),
|
|
319
|
+
firstChunkMs: readNumberOrNullField(entry, "firstChunkMs"),
|
|
320
|
+
totalStreamMs: readNumberOrNullField(entry, "totalStreamMs"),
|
|
321
|
+
tokensPerSecond: readNumberOrNullField(entry, "tokensPerSecond"),
|
|
322
|
+
streaming: readBooleanField(entry, "streaming"),
|
|
323
|
+
userAgent: readStringOrNullField(entry, "userAgent"),
|
|
324
|
+
origin: readStringOrNullField(entry, "origin"),
|
|
325
|
+
apiFormat: readApiFormatField(entry),
|
|
326
|
+
isTest: readBooleanField(entry, "isTest"),
|
|
327
|
+
replayOfLogId: readNumberOrNullField(entry, "replayOfLogId"),
|
|
328
|
+
providerName: readStringOrNullField(entry, "providerName"),
|
|
329
|
+
clientPort: readNumberOrNullField(entry, "clientPort"),
|
|
330
|
+
clientPid: readNumberOrNullField(entry, "clientPid"),
|
|
331
|
+
clientCwd: readStringOrNullField(entry, "clientCwd"),
|
|
332
|
+
clientProjectFolder: readStringOrNullField(entry, "clientProjectFolder"),
|
|
333
|
+
streamingChunksPath: readStringOrNullField(entry, "streamingChunksPath"),
|
|
334
|
+
rawRequestBodyBytes: readTextByteLength(entry, "rawRequestBodyBytes", "rawRequestBody"),
|
|
335
|
+
responseTextBytes: readTextByteLength(entry, "responseTextBytes", "responseText"),
|
|
336
|
+
warnings: readStringArrayField(entry, "warnings"),
|
|
337
|
+
error: readStringOrNullField(entry, "error"),
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
157
341
|
async function indexFile(filePath: string, file: string): Promise<FileIndexResult> {
|
|
158
342
|
const entries: Record<number, LogIndexEntry> = {};
|
|
159
343
|
let maxId = 0;
|
|
@@ -179,6 +363,9 @@ async function indexFile(filePath: string, file: string): Promise<FileIndexResul
|
|
|
179
363
|
file,
|
|
180
364
|
byteOffset,
|
|
181
365
|
byteLength: lineBytes,
|
|
366
|
+
sessionId: readStringOrNullField(entry, "sessionId"),
|
|
367
|
+
model: readStringOrNullField(entry, "model"),
|
|
368
|
+
summary: readLogIndexSummary(entry, entryId),
|
|
182
369
|
};
|
|
183
370
|
}
|
|
184
371
|
}
|