@tonyclaw/agent-inspector 2.0.17 → 2.0.19
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 +149 -40
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-DDg7Cs4N.js → CompareDrawer-D-90PIPw.js} +1 -1
- package/.output/public/assets/ProxyViewerContainer-CxRDWacg.js +114 -0
- package/.output/public/assets/ReplayDialog-DzlLYoTO.js +1 -0
- package/.output/public/assets/{RequestAnatomy-DR8OICOJ.js → RequestAnatomy-0hbyf6oa.js} +1 -1
- package/.output/public/assets/ResponseView-CKe0tNqr.js +1 -0
- package/.output/public/assets/StreamingChunkSequence-enhfdeNh.js +1 -0
- package/.output/public/assets/_sessionId-CJ-SusES.js +1 -0
- package/.output/public/assets/index-BbFsmQRC.js +1 -0
- package/.output/public/assets/index-BfBgrkgU.css +1 -0
- package/.output/public/assets/{main-bwZlEXw2.js → main-o9-hg8g1.js} +2 -2
- package/.output/server/_libs/lucide-react.mjs +141 -118
- package/.output/server/_libs/tanstack__react-virtual.mjs +13 -2
- package/.output/server/_libs/tanstack__virtual-core.mjs +24 -1
- package/.output/server/{_sessionId-BEuJJhqT.mjs → _sessionId-F8lm6PIb.mjs} +3 -2
- package/.output/server/_ssr/{CompareDrawer-yTO93GMz.mjs → CompareDrawer-Cf1yfwfd.mjs} +4 -3
- package/.output/server/_ssr/{ProxyViewerContainer-C8qCkHGB.mjs → ProxyViewerContainer-Bmu9867L.mjs} +349 -74
- package/.output/server/_ssr/{ReplayDialog-DRF9PG7Z.mjs → ReplayDialog-DxZfLBOe.mjs} +199 -17
- package/.output/server/_ssr/{RequestAnatomy-DBcuV_jV.mjs → RequestAnatomy-CbdERGZd.mjs} +4 -3
- package/.output/server/_ssr/{ResponseView-JJm78HZT.mjs → ResponseView-CvLd6qxI.mjs} +4 -3
- package/.output/server/_ssr/{StreamingChunkSequence-DyGKjBYx.mjs → StreamingChunkSequence-B_lkRB6o.mjs} +4 -3
- package/.output/server/_ssr/{index-T7JG28t6.mjs → index-ejrSItfz.mjs} +3 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-BJob8RN3.mjs → router-SbCnbDc2.mjs} +896 -240
- package/.output/server/{_tanstack-start-manifest_v-CuiFi3XC.mjs → _tanstack-start-manifest_v-yx8ftqWz.mjs} +1 -1
- package/.output/server/index.mjs +60 -60
- package/README.md +26 -109
- package/package.json +2 -1
- package/src/cli/doctor.ts +160 -8
- package/src/cli/templates/skill-onboard.ts +2 -20
- package/src/components/OnboardingBanner.tsx +13 -13
- package/src/components/ProxyViewer.tsx +55 -38
- package/src/components/ProxyViewerContainer.tsx +5 -0
- package/src/components/providers/SettingsDialog.tsx +113 -2
- package/src/components/proxy-viewer/ConversationGroup.tsx +20 -3
- package/src/components/proxy-viewer/ConversationGroupList.tsx +144 -0
- package/src/components/proxy-viewer/ConversationHeader.tsx +0 -2
- package/src/components/proxy-viewer/ReplayDialog.tsx +200 -13
- package/src/components/proxy-viewer/index.ts +1 -1
- package/src/knowledge/openclawClient.ts +0 -8
- package/src/knowledge/types.ts +0 -2
- package/src/lib/export-logs.ts +72 -5
- package/src/lib/providerTestContract.ts +0 -1
- package/src/lib/useProviders.ts +1 -1
- package/src/mcp/server.ts +14 -6
- package/src/mcp/toolHandlers.ts +21 -4
- package/src/proxy/chunkStorage.ts +2 -4
- package/src/proxy/dataDir.ts +37 -15
- package/src/proxy/formats/anthropic/index.ts +0 -1
- package/src/proxy/formats/anthropic/schemas.ts +0 -2
- package/src/proxy/handler.ts +41 -29
- package/src/proxy/logFinalizer.ts +93 -11
- package/src/proxy/logger.ts +35 -10
- package/src/proxy/providers.ts +12 -5
- package/src/proxy/rawStreamCapture.ts +85 -0
- package/src/proxy/schemas.ts +1 -51
- package/src/proxy/sessionRuntime.ts +0 -9
- package/src/proxy/socketTracker.ts +15 -8
- package/src/proxy/store.ts +414 -13
- package/src/routes/api/logs.$id.replay.ts +66 -1
- package/src/routes/api/logs.stream.ts +11 -3
- package/src/routes/api/logs.ts +51 -17
- package/src/routes/api/providers.$providerId.ts +10 -3
- package/src/routes/api/providers.ts +6 -3
- package/.output/public/assets/ProxyViewerContainer-DbbK1y7N.js +0 -114
- package/.output/public/assets/ReplayDialog-C1zWNkoz.js +0 -1
- package/.output/public/assets/ResponseView-Dh9iSj6h.js +0 -1
- package/.output/public/assets/StreamingChunkSequence-B_xElyH3.js +0 -1
- package/.output/public/assets/_sessionId-gv1a_NNu.js +0 -1
- package/.output/public/assets/index-D_nZj9Vt.css +0 -1
- package/.output/public/assets/index-u-LwDaeH.js +0 -1
- package/src/components/ui/json-expansion-button.tsx +0 -56
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { getLogById } from "../../proxy/store";
|
|
3
|
+
import { addTestLogEntry, getLogById } from "../../proxy/store";
|
|
4
4
|
import { findProviderByModel } from "../../proxy/providers";
|
|
5
5
|
import { registry } from "../../proxy/formats";
|
|
6
6
|
import { formatForPath } from "../../proxy/formats";
|
|
@@ -39,6 +39,7 @@ type ReplayResponse = {
|
|
|
39
39
|
outputTokens?: number;
|
|
40
40
|
elapsedMs?: number;
|
|
41
41
|
streaming?: boolean;
|
|
42
|
+
replayLogId?: number;
|
|
42
43
|
};
|
|
43
44
|
|
|
44
45
|
export const Route = createFileRoute("/api/logs/$id/replay")({
|
|
@@ -161,6 +162,37 @@ export const Route = createFileRoute("/api/logs/$id/replay")({
|
|
|
161
162
|
const mockLog: typeof log = { ...log };
|
|
162
163
|
const responseText = formatHandler.extractStream(fullResponse, mockLog, model, false);
|
|
163
164
|
const tokens = formatHandler.extractTokens(responseText);
|
|
165
|
+
const savedReplayLog = await addTestLogEntry({
|
|
166
|
+
timestamp: new Date().toISOString(),
|
|
167
|
+
method: log.method,
|
|
168
|
+
path: log.path,
|
|
169
|
+
model,
|
|
170
|
+
sessionId: log.sessionId,
|
|
171
|
+
rawRequestBody: modifiedBody,
|
|
172
|
+
responseStatus: upstreamRes.status,
|
|
173
|
+
responseText,
|
|
174
|
+
inputTokens: tokens.inputTokens ?? null,
|
|
175
|
+
outputTokens: tokens.outputTokens ?? null,
|
|
176
|
+
cacheCreationInputTokens: tokens.cacheCreationInputTokens ?? null,
|
|
177
|
+
cacheReadInputTokens: tokens.cacheReadInputTokens ?? null,
|
|
178
|
+
elapsedMs,
|
|
179
|
+
streaming: true,
|
|
180
|
+
userAgent: log.userAgent,
|
|
181
|
+
origin: log.origin,
|
|
182
|
+
rawHeaders: log.rawHeaders,
|
|
183
|
+
headers: log.headers,
|
|
184
|
+
apiFormat: log.apiFormat,
|
|
185
|
+
isTest: true,
|
|
186
|
+
replayOfLogId: log.id,
|
|
187
|
+
providerName: log.providerName,
|
|
188
|
+
clientPort: log.clientPort,
|
|
189
|
+
clientPid: log.clientPid,
|
|
190
|
+
clientCwd: log.clientCwd,
|
|
191
|
+
clientProjectFolder: log.clientProjectFolder,
|
|
192
|
+
streamingChunks: undefined,
|
|
193
|
+
streamingChunksPath: null,
|
|
194
|
+
error: null,
|
|
195
|
+
});
|
|
164
196
|
|
|
165
197
|
return Response.json({
|
|
166
198
|
success: true,
|
|
@@ -170,10 +202,42 @@ export const Route = createFileRoute("/api/logs/$id/replay")({
|
|
|
170
202
|
outputTokens: tokens.outputTokens ?? undefined,
|
|
171
203
|
elapsedMs,
|
|
172
204
|
streaming: true,
|
|
205
|
+
replayLogId: savedReplayLog.id,
|
|
173
206
|
} satisfies ReplayResponse);
|
|
174
207
|
} else {
|
|
175
208
|
const responseText = await upstreamRes.text();
|
|
176
209
|
const tokens = formatHandler.extractTokens(responseText);
|
|
210
|
+
const savedReplayLog = await addTestLogEntry({
|
|
211
|
+
timestamp: new Date().toISOString(),
|
|
212
|
+
method: log.method,
|
|
213
|
+
path: log.path,
|
|
214
|
+
model,
|
|
215
|
+
sessionId: log.sessionId,
|
|
216
|
+
rawRequestBody: modifiedBody,
|
|
217
|
+
responseStatus: upstreamRes.status,
|
|
218
|
+
responseText,
|
|
219
|
+
inputTokens: tokens.inputTokens ?? null,
|
|
220
|
+
outputTokens: tokens.outputTokens ?? null,
|
|
221
|
+
cacheCreationInputTokens: tokens.cacheCreationInputTokens ?? null,
|
|
222
|
+
cacheReadInputTokens: tokens.cacheReadInputTokens ?? null,
|
|
223
|
+
elapsedMs,
|
|
224
|
+
streaming: false,
|
|
225
|
+
userAgent: log.userAgent,
|
|
226
|
+
origin: log.origin,
|
|
227
|
+
rawHeaders: log.rawHeaders,
|
|
228
|
+
headers: log.headers,
|
|
229
|
+
apiFormat: log.apiFormat,
|
|
230
|
+
isTest: true,
|
|
231
|
+
replayOfLogId: log.id,
|
|
232
|
+
providerName: log.providerName,
|
|
233
|
+
clientPort: log.clientPort,
|
|
234
|
+
clientPid: log.clientPid,
|
|
235
|
+
clientCwd: log.clientCwd,
|
|
236
|
+
clientProjectFolder: log.clientProjectFolder,
|
|
237
|
+
streamingChunks: undefined,
|
|
238
|
+
streamingChunksPath: null,
|
|
239
|
+
error: null,
|
|
240
|
+
});
|
|
177
241
|
|
|
178
242
|
return Response.json({
|
|
179
243
|
success: true,
|
|
@@ -183,6 +247,7 @@ export const Route = createFileRoute("/api/logs/$id/replay")({
|
|
|
183
247
|
outputTokens: tokens.outputTokens ?? undefined,
|
|
184
248
|
elapsedMs,
|
|
185
249
|
streaming: false,
|
|
250
|
+
replayLogId: savedReplayLog.id,
|
|
186
251
|
} satisfies ReplayResponse);
|
|
187
252
|
}
|
|
188
253
|
},
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
|
-
import { onLogUpdate,
|
|
2
|
+
import { onLogUpdate, getLogSessionId, listLogsPage } from "../../proxy/store";
|
|
3
3
|
import { type CapturedLog } from "../../proxy/schemas";
|
|
4
4
|
|
|
5
|
+
const INITIAL_STREAM_LOG_LIMIT = 500;
|
|
6
|
+
|
|
5
7
|
export const Route = createFileRoute("/api/logs/stream")({
|
|
6
8
|
server: {
|
|
7
9
|
handlers: {
|
|
@@ -49,10 +51,16 @@ export const Route = createFileRoute("/api/logs/stream")({
|
|
|
49
51
|
request.signal.addEventListener("abort", cleanup, { once: true });
|
|
50
52
|
|
|
51
53
|
const stream = new ReadableStream<Uint8Array>({
|
|
52
|
-
start(controller) {
|
|
54
|
+
async start(controller) {
|
|
53
55
|
controllerRef = controller;
|
|
54
56
|
// Send initial batch of logs immediately
|
|
55
|
-
const
|
|
57
|
+
const result = await listLogsPage({
|
|
58
|
+
sessionId,
|
|
59
|
+
model,
|
|
60
|
+
offset: 0,
|
|
61
|
+
limit: INITIAL_STREAM_LOG_LIMIT,
|
|
62
|
+
});
|
|
63
|
+
const logs = result.logs;
|
|
56
64
|
const initData = `data: ${JSON.stringify({ type: "init", logs })}\n\n`;
|
|
57
65
|
controller.enqueue(new TextEncoder().encode(initData));
|
|
58
66
|
},
|
package/src/routes/api/logs.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
clearPersistedLogStorage,
|
|
5
|
+
clearPersistedLogsByIds,
|
|
6
|
+
getLogStorageStats,
|
|
7
|
+
getReplayLogsForSource,
|
|
8
|
+
listLogsPage,
|
|
9
|
+
} from "../../proxy/store";
|
|
4
10
|
|
|
5
11
|
const DeleteBodySchema = z
|
|
6
12
|
.object({
|
|
@@ -8,25 +14,43 @@ const DeleteBodySchema = z
|
|
|
8
14
|
})
|
|
9
15
|
.optional();
|
|
10
16
|
|
|
17
|
+
function parseNonNegativeInt(value: string | null, fallback: number): number {
|
|
18
|
+
if (value === null) return fallback;
|
|
19
|
+
const parsed = Number(value);
|
|
20
|
+
if (!Number.isInteger(parsed) || parsed < 0) return fallback;
|
|
21
|
+
return parsed;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function parsePositiveInt(value: string | null, fallback: number): number {
|
|
25
|
+
if (value === null) return fallback;
|
|
26
|
+
const parsed = Number(value);
|
|
27
|
+
if (!Number.isInteger(parsed) || parsed < 1) return fallback;
|
|
28
|
+
return parsed;
|
|
29
|
+
}
|
|
30
|
+
|
|
11
31
|
export const Route = createFileRoute("/api/logs")({
|
|
12
32
|
server: {
|
|
13
33
|
handlers: {
|
|
14
|
-
GET: ({ request }: { request: Request }) => {
|
|
34
|
+
GET: async ({ request }: { request: Request }) => {
|
|
15
35
|
const url = new URL(request.url);
|
|
36
|
+
if (url.searchParams.get("stats") === "1") {
|
|
37
|
+
return Response.json(getLogStorageStats());
|
|
38
|
+
}
|
|
39
|
+
const replayOf = url.searchParams.get("replayOf");
|
|
40
|
+
if (replayOf !== null) {
|
|
41
|
+
const id = Number(replayOf);
|
|
42
|
+
if (!Number.isInteger(id) || id <= 0) {
|
|
43
|
+
return Response.json({ error: "Invalid replayOf log ID" }, { status: 400 });
|
|
44
|
+
}
|
|
45
|
+
const logs = getReplayLogsForSource(id);
|
|
46
|
+
return Response.json({ logs, total: logs.length, offset: 0, limit: logs.length });
|
|
47
|
+
}
|
|
16
48
|
const sessionId = url.searchParams.get("sessionId") ?? undefined;
|
|
17
49
|
const model = url.searchParams.get("model") ?? undefined;
|
|
18
|
-
const offset =
|
|
19
|
-
const limit =
|
|
50
|
+
const offset = parseNonNegativeInt(url.searchParams.get("offset"), 0);
|
|
51
|
+
const limit = parsePositiveInt(url.searchParams.get("limit"), 50);
|
|
20
52
|
|
|
21
|
-
|
|
22
|
-
const paginatedLogs = allLogs.slice(offset, offset + limit);
|
|
23
|
-
|
|
24
|
-
return Response.json({
|
|
25
|
-
logs: paginatedLogs,
|
|
26
|
-
total: allLogs.length,
|
|
27
|
-
offset,
|
|
28
|
-
limit,
|
|
29
|
-
});
|
|
53
|
+
return Response.json(await listLogsPage({ sessionId, model, offset, limit }));
|
|
30
54
|
},
|
|
31
55
|
DELETE: async ({ request }: { request: Request }) => {
|
|
32
56
|
let body: z.infer<typeof DeleteBodySchema> = undefined;
|
|
@@ -48,11 +72,21 @@ export const Route = createFileRoute("/api/logs")({
|
|
|
48
72
|
}
|
|
49
73
|
|
|
50
74
|
if (body?.ids !== undefined && body.ids.length > 0) {
|
|
51
|
-
const result =
|
|
52
|
-
return Response.json({
|
|
75
|
+
const result = await clearPersistedLogsByIds(body.ids);
|
|
76
|
+
return Response.json({
|
|
77
|
+
success: true,
|
|
78
|
+
cleared: result.cleared,
|
|
79
|
+
logFilesRewritten: result.logFilesRewritten,
|
|
80
|
+
chunkFilesDeleted: result.chunkFilesDeleted,
|
|
81
|
+
});
|
|
53
82
|
}
|
|
54
|
-
const result =
|
|
55
|
-
return Response.json({
|
|
83
|
+
const result = await clearPersistedLogStorage();
|
|
84
|
+
return Response.json({
|
|
85
|
+
success: true,
|
|
86
|
+
cleared: result.cleared,
|
|
87
|
+
logFilesDeleted: result.logFilesDeleted,
|
|
88
|
+
chunkFilesDeleted: result.chunkFilesDeleted,
|
|
89
|
+
});
|
|
56
90
|
},
|
|
57
91
|
},
|
|
58
92
|
},
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
getProviders,
|
|
5
|
+
updateProvider,
|
|
6
|
+
deleteProvider,
|
|
7
|
+
redactProvider,
|
|
8
|
+
} from "../../proxy/providers";
|
|
4
9
|
import { ProviderModelMetadataSchema } from "../../lib/providerContract";
|
|
5
10
|
|
|
6
11
|
const ProviderUpdateSchema = z.object({
|
|
@@ -22,13 +27,15 @@ const ProviderUpdateSchema = z.object({
|
|
|
22
27
|
export const Route = createFileRoute("/api/providers/$providerId")({
|
|
23
28
|
server: {
|
|
24
29
|
handlers: {
|
|
25
|
-
GET: ({ params }: { params: { providerId: string } }) => {
|
|
30
|
+
GET: ({ params, request }: { params: { providerId: string }; request: Request }) => {
|
|
31
|
+
const url = new URL(request.url);
|
|
32
|
+
const includeSecrets = url.searchParams.get("includeSecrets") === "1";
|
|
26
33
|
const providers = getProviders();
|
|
27
34
|
const provider = providers.find((p) => p.id === params.providerId);
|
|
28
35
|
if (!provider) {
|
|
29
36
|
return Response.json({ error: "Provider not found" }, { status: 404 });
|
|
30
37
|
}
|
|
31
|
-
return Response.json(provider);
|
|
38
|
+
return Response.json(includeSecrets ? provider : redactProvider(provider));
|
|
32
39
|
},
|
|
33
40
|
PUT: async ({ params, request }: { params: { providerId: string }; request: Request }) => {
|
|
34
41
|
const parsed = ProviderUpdateSchema.safeParse(await request.json());
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { getProviders, addProvider } from "../../proxy/providers";
|
|
3
|
+
import { getProviders, addProvider, redactProviders } from "../../proxy/providers";
|
|
4
4
|
import { ProviderModelMetadataSchema } from "../../lib/providerContract";
|
|
5
5
|
|
|
6
6
|
const ProviderInputSchema = z.object({
|
|
@@ -21,8 +21,11 @@ const ProviderInputSchema = z.object({
|
|
|
21
21
|
export const Route = createFileRoute("/api/providers")({
|
|
22
22
|
server: {
|
|
23
23
|
handlers: {
|
|
24
|
-
GET: () => {
|
|
25
|
-
|
|
24
|
+
GET: ({ request }: { request: Request }) => {
|
|
25
|
+
const url = new URL(request.url);
|
|
26
|
+
const includeSecrets = url.searchParams.get("includeSecrets") === "1";
|
|
27
|
+
const providers = getProviders();
|
|
28
|
+
return Response.json(includeSecrets ? providers : redactProviders(providers));
|
|
26
29
|
},
|
|
27
30
|
POST: async ({ request }: { request: Request }) => {
|
|
28
31
|
const parsed = ProviderInputSchema.safeParse(await request.json());
|