@tonyclaw/agent-inspector 2.0.28 → 2.0.29

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.
Files changed (44) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{CompareDrawer-CicCP3Hb.js → CompareDrawer-DcqxlgSQ.js} +1 -1
  3. package/.output/public/assets/ProxyViewerContainer-D650kQlv.js +115 -0
  4. package/.output/public/assets/{ReplayDialog-Bc8q3ujm.js → ReplayDialog-CBcnPgx1.js} +1 -1
  5. package/.output/public/assets/{RequestAnatomy-Coyy3zcH.js → RequestAnatomy-DSgSqCYt.js} +1 -1
  6. package/.output/public/assets/{ResponseView-BWJzgh0c.js → ResponseView-CjqzBSoF.js} +1 -1
  7. package/.output/public/assets/{StreamingChunkSequence-BSC3uuE5.js → StreamingChunkSequence-DdBBKolI.js} +1 -1
  8. package/.output/public/assets/_sessionId-wctOoGh_.js +1 -0
  9. package/.output/public/assets/index-BhQGSdhG.js +1 -0
  10. package/.output/public/assets/{index-DsiKfWCp.css → index-CwlHPmgL.css} +1 -1
  11. package/.output/public/assets/{main-Brj0Gn91.js → main-B6OLZCp9.js} +2 -2
  12. package/.output/server/_libs/lucide-react.mjs +13 -13
  13. package/.output/server/{_sessionId-DDdyKVG-.mjs → _sessionId-CCfKJJ19.mjs} +2 -2
  14. package/.output/server/_ssr/{CompareDrawer-XSExe2ml.mjs → CompareDrawer-uaPI5R6e.mjs} +2 -2
  15. package/.output/server/_ssr/{ProxyViewerContainer-B5pIiBZN.mjs → ProxyViewerContainer-BV2nIxXy.mjs} +83 -20
  16. package/.output/server/_ssr/{ReplayDialog-BOAu0ric.mjs → ReplayDialog-eE2Hy2Nl.mjs} +4 -4
  17. package/.output/server/_ssr/{RequestAnatomy-C8Q5lozD.mjs → RequestAnatomy-B7vwWo57.mjs} +2 -2
  18. package/.output/server/_ssr/{ResponseView-a_iJfPUF.mjs → ResponseView-Bm6Qp8mo.mjs} +2 -2
  19. package/.output/server/_ssr/{StreamingChunkSequence-YMKC0j8U.mjs → StreamingChunkSequence-CbAJKJQx.mjs} +2 -2
  20. package/.output/server/_ssr/{index-CkDwBPzI.mjs → index-u14_Aj60.mjs} +2 -2
  21. package/.output/server/_ssr/index.mjs +2 -2
  22. package/.output/server/_ssr/{router-DXOXdFFM.mjs → router-qgeGUp1k.mjs} +161 -18
  23. package/.output/server/{_tanstack-start-manifest_v-DPf3uJys.mjs → _tanstack-start-manifest_v-BrfUXnre.mjs} +1 -1
  24. package/.output/server/index.mjs +66 -66
  25. package/package.json +1 -1
  26. package/src/components/ProxyViewer.tsx +3 -0
  27. package/src/components/providers/ProviderCard.tsx +32 -0
  28. package/src/components/proxy-viewer/LogEntryHeader.tsx +38 -1
  29. package/src/lib/providerTestContract.ts +3 -0
  30. package/src/lib/sessionInfoContract.ts +3 -0
  31. package/src/mcp/toolHandlers.ts +3 -0
  32. package/src/proxy/evidenceAnalysis.ts +5 -0
  33. package/src/proxy/evidenceExporter.ts +8 -3
  34. package/src/proxy/handler.ts +8 -1
  35. package/src/proxy/logFinalizer.ts +36 -0
  36. package/src/proxy/schemas.ts +3 -0
  37. package/src/proxy/sessionInfo.ts +3 -0
  38. package/src/proxy/store.ts +3 -0
  39. package/src/proxy/streamTiming.ts +31 -0
  40. package/src/routes/api/logs.$id.replay.ts +25 -2
  41. package/src/routes/api/providers.$providerId.test.log.ts +34 -2
  42. package/.output/public/assets/ProxyViewerContainer-BccuA6p5.js +0 -115
  43. package/.output/public/assets/_sessionId-9rEF0uSE.js +0 -1
  44. package/.output/public/assets/index-B9_VaAWl.js +0 -1
@@ -21,6 +21,7 @@ import {
21
21
  selectUpstreamBase,
22
22
  setUpstreamHost,
23
23
  } from "../../proxy/upstream";
24
+ import { computeTokensPerSecond } from "../../proxy/streamTiming";
24
25
 
25
26
  type ReplayRequest = {
26
27
  modifiedBody: string;
@@ -38,6 +39,9 @@ type ReplayResponse = {
38
39
  inputTokens?: number;
39
40
  outputTokens?: number;
40
41
  elapsedMs?: number;
42
+ firstChunkMs?: number | null;
43
+ totalStreamMs?: number | null;
44
+ tokensPerSecond?: number | null;
41
45
  streaming?: boolean;
42
46
  replayLogId?: number;
43
47
  };
@@ -135,7 +139,6 @@ export const Route = createFileRoute("/api/logs/$id/replay")({
135
139
  } satisfies ReplayResponse);
136
140
  }
137
141
 
138
- const elapsedMs = Date.now() - startTime;
139
142
  const isStream =
140
143
  upstreamRes.headers.get(HEADER_CONTENT_TYPE)?.includes(CONTENT_TYPE_EVENT_STREAM) ??
141
144
  false;
@@ -145,11 +148,13 @@ export const Route = createFileRoute("/api/logs/$id/replay")({
145
148
  const chunks: string[] = [];
146
149
  const decoder = new TextDecoder();
147
150
  const reader = upstreamRes.body?.getReader();
151
+ let firstChunkMs: number | null = null;
148
152
  if (reader) {
149
153
  try {
150
154
  while (true) {
151
155
  const { done, value } = await reader.read();
152
156
  if (done) break;
157
+ if (firstChunkMs === null) firstChunkMs = Date.now() - startTime;
153
158
  chunks.push(decoder.decode(value, { stream: true }));
154
159
  }
155
160
  } catch {
@@ -157,11 +162,19 @@ export const Route = createFileRoute("/api/logs/$id/replay")({
157
162
  }
158
163
  }
159
164
  const fullResponse = chunks.join("");
165
+ const elapsedMs = Date.now() - startTime;
166
+ const totalStreamMs = elapsedMs;
160
167
 
161
168
  // Create a mock log for streaming extraction
162
169
  const mockLog: typeof log = { ...log };
163
170
  const responseText = formatHandler.extractStream(fullResponse, mockLog, model, false);
164
171
  const tokens = formatHandler.extractTokens(responseText);
172
+ const outputTokens = tokens.outputTokens ?? null;
173
+ const tokensPerSecond = computeTokensPerSecond({
174
+ outputTokens,
175
+ firstChunkMs,
176
+ totalStreamMs,
177
+ });
165
178
  const savedReplayLog = await addTestLogEntry({
166
179
  timestamp: new Date().toISOString(),
167
180
  method: log.method,
@@ -172,10 +185,13 @@ export const Route = createFileRoute("/api/logs/$id/replay")({
172
185
  responseStatus: upstreamRes.status,
173
186
  responseText,
174
187
  inputTokens: tokens.inputTokens ?? null,
175
- outputTokens: tokens.outputTokens ?? null,
188
+ outputTokens,
176
189
  cacheCreationInputTokens: tokens.cacheCreationInputTokens ?? null,
177
190
  cacheReadInputTokens: tokens.cacheReadInputTokens ?? null,
178
191
  elapsedMs,
192
+ firstChunkMs,
193
+ totalStreamMs,
194
+ tokensPerSecond,
179
195
  streaming: true,
180
196
  userAgent: log.userAgent,
181
197
  origin: log.origin,
@@ -201,11 +217,15 @@ export const Route = createFileRoute("/api/logs/$id/replay")({
201
217
  inputTokens: tokens.inputTokens ?? undefined,
202
218
  outputTokens: tokens.outputTokens ?? undefined,
203
219
  elapsedMs,
220
+ firstChunkMs,
221
+ totalStreamMs,
222
+ tokensPerSecond,
204
223
  streaming: true,
205
224
  replayLogId: savedReplayLog.id,
206
225
  } satisfies ReplayResponse);
207
226
  } else {
208
227
  const responseText = await upstreamRes.text();
228
+ const elapsedMs = Date.now() - startTime;
209
229
  const tokens = formatHandler.extractTokens(responseText);
210
230
  const savedReplayLog = await addTestLogEntry({
211
231
  timestamp: new Date().toISOString(),
@@ -221,6 +241,9 @@ export const Route = createFileRoute("/api/logs/$id/replay")({
221
241
  cacheCreationInputTokens: tokens.cacheCreationInputTokens ?? null,
222
242
  cacheReadInputTokens: tokens.cacheReadInputTokens ?? null,
223
243
  elapsedMs,
244
+ firstChunkMs: null,
245
+ totalStreamMs: null,
246
+ tokensPerSecond: null,
224
247
  streaming: false,
225
248
  userAgent: log.userAgent,
226
249
  origin: log.origin,
@@ -8,6 +8,7 @@ import {
8
8
  type ProviderTestResult as TestResult,
9
9
  type ProviderTestState,
10
10
  } from "../../lib/providerTestContract";
11
+ import { computeTokensPerSecond, firstChunkMsFromChunks } from "../../proxy/streamTiming";
11
12
 
12
13
  function hasSuccessField(result: ProviderTestState): result is TestResult {
13
14
  return Object.prototype.hasOwnProperty.call(result, "success");
@@ -29,6 +30,25 @@ function getResultHeaders(result: TestResult): Record<string, string> {
29
30
  return result.requestHeaders ?? result.debug?.requestHeaders ?? {};
30
31
  }
31
32
 
33
+ function getResultTotalStreamMs(result: TestResult): number | null {
34
+ return result.totalStreamMs ?? (result.streaming === true ? (result.latencyMs ?? null) : null);
35
+ }
36
+
37
+ function getResultFirstChunkMs(result: TestResult): number | null {
38
+ return result.firstChunkMs ?? firstChunkMsFromChunks(result.streamingChunks?.chunks);
39
+ }
40
+
41
+ function getResultTokensPerSecond(result: TestResult): number | null {
42
+ return (
43
+ result.tokensPerSecond ??
44
+ computeTokensPerSecond({
45
+ outputTokens: result.outputTokens,
46
+ firstChunkMs: getResultFirstChunkMs(result),
47
+ totalStreamMs: getResultTotalStreamMs(result),
48
+ })
49
+ );
50
+ }
51
+
32
52
  async function logModelResults(
33
53
  displayName: string,
34
54
  providerName: string,
@@ -65,6 +85,9 @@ async function logModelResults(
65
85
  cacheCreationInputTokens: nonStreamingResult.cacheCreationInputTokens ?? null,
66
86
  cacheReadInputTokens: nonStreamingResult.cacheReadInputTokens ?? null,
67
87
  elapsedMs: nonStreamingResult.latencyMs ?? 0,
88
+ firstChunkMs: null,
89
+ totalStreamMs: null,
90
+ tokensPerSecond: null,
68
91
  streaming: false,
69
92
  userAgent: "provider-test",
70
93
  origin: null,
@@ -91,7 +114,10 @@ async function logModelResults(
91
114
  outputTokens: streamingResult.outputTokens ?? null,
92
115
  cacheCreationInputTokens: streamingResult.cacheCreationInputTokens ?? null,
93
116
  cacheReadInputTokens: streamingResult.cacheReadInputTokens ?? null,
94
- elapsedMs: streamingResult.latencyMs ?? 0,
117
+ elapsedMs: getResultTotalStreamMs(streamingResult) ?? 0,
118
+ firstChunkMs: getResultFirstChunkMs(streamingResult),
119
+ totalStreamMs: getResultTotalStreamMs(streamingResult),
120
+ tokensPerSecond: getResultTokensPerSecond(streamingResult),
95
121
  streaming: true,
96
122
  streamingChunks: captureFullDetails ? streamingResult.streamingChunks : undefined,
97
123
  userAgent: "provider-test",
@@ -127,6 +153,9 @@ async function logModelResults(
127
153
  cacheCreationInputTokens: null,
128
154
  cacheReadInputTokens: null,
129
155
  elapsedMs: nonStreamingResult.latencyMs ?? 0,
156
+ firstChunkMs: null,
157
+ totalStreamMs: null,
158
+ tokensPerSecond: null,
130
159
  streaming: false,
131
160
  userAgent: "provider-test",
132
161
  origin: null,
@@ -153,7 +182,10 @@ async function logModelResults(
153
182
  outputTokens: streamingResult.outputTokens ?? null,
154
183
  cacheCreationInputTokens: null,
155
184
  cacheReadInputTokens: null,
156
- elapsedMs: streamingResult.latencyMs ?? 0,
185
+ elapsedMs: getResultTotalStreamMs(streamingResult) ?? 0,
186
+ firstChunkMs: getResultFirstChunkMs(streamingResult),
187
+ totalStreamMs: getResultTotalStreamMs(streamingResult),
188
+ tokensPerSecond: getResultTokensPerSecond(streamingResult),
157
189
  streaming: true,
158
190
  streamingChunks: captureFullDetails ? streamingResult.streamingChunks : undefined,
159
191
  userAgent: "provider-test",