@tonyclaw/agent-inspector 2.0.4 → 2.0.6

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 (61) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{CompareDrawer-BCH_fsLm.js → CompareDrawer-DDmqSAfl.js} +1 -1
  3. package/.output/public/assets/ProxyViewerContainer-Cxpdziwd.js +101 -0
  4. package/.output/public/assets/ReplayDialog-Bt5DGzlh.js +1 -0
  5. package/.output/public/assets/RequestAnatomy-BxX3_N9S.js +1 -0
  6. package/.output/public/assets/ResponseView-Bl_5S9gZ.js +1 -0
  7. package/.output/public/assets/StreamingChunkSequence-RJMwNf6F.js +1 -0
  8. package/.output/public/assets/_sessionId-b4isaoDp.js +1 -0
  9. package/.output/public/assets/index-BZ4x5UI6.js +1 -0
  10. package/.output/public/assets/{index-CobXD0yH.css → index-C624DUk9.css} +1 -1
  11. package/.output/public/assets/{json-viewer-BrzjD7qI.js → json-viewer-CRL_gWEZ.js} +1 -1
  12. package/.output/public/assets/{main-mgxeUdZQ.js → main-CKnTJ4-O.js} +6 -6
  13. package/.output/server/_libs/lucide-react.mjs +181 -114
  14. package/.output/server/{_sessionId-C4xsxIWm.mjs → _sessionId-B-x9fRY3.mjs} +3 -3
  15. package/.output/server/_ssr/{CompareDrawer-DuWEpqQ7.mjs → CompareDrawer-BQVNsAY2.mjs} +6 -6
  16. package/.output/server/_ssr/{ProxyViewerContainer-Cckz5qKu.mjs → ProxyViewerContainer-CYm2Dw19.mjs} +766 -122
  17. package/.output/server/_ssr/{ReplayDialog-BDRcr8E5.mjs → ReplayDialog-CaMQBc79.mjs} +240 -14
  18. package/.output/server/_ssr/{RequestAnatomy-BoO2_Ij0.mjs → RequestAnatomy--P5arRH2.mjs} +236 -66
  19. package/.output/server/_ssr/{ResponseView-DZiPBxvO.mjs → ResponseView-RtFwNvgD.mjs} +8 -8
  20. package/.output/server/_ssr/{StreamingChunkSequence-D-be7KEL.mjs → StreamingChunkSequence-B5HPkzab.mjs} +3 -3
  21. package/.output/server/_ssr/{index-5RImHKfu.mjs → index-CZIKZU43.mjs} +2 -2
  22. package/.output/server/_ssr/index.mjs +2 -2
  23. package/.output/server/_ssr/{json-viewer-aJhb93ZK.mjs → json-viewer-d4obyRaA.mjs} +3 -3
  24. package/.output/server/_ssr/{router-Dgkv5nKP.mjs → router-DGPt3MUc.mjs} +145 -71
  25. package/.output/server/_tanstack-start-manifest_v-BzH4pNaI.mjs +4 -0
  26. package/.output/server/index.mjs +64 -64
  27. package/package.json +1 -1
  28. package/src/components/OnboardingBanner.tsx +11 -19
  29. package/src/components/ProxyViewer.tsx +1 -1
  30. package/src/components/providers/ProviderCard.tsx +6 -20
  31. package/src/components/providers/SettingsDialog.tsx +95 -2
  32. package/src/components/proxy-viewer/AgentTraceSummary.tsx +639 -38
  33. package/src/components/proxy-viewer/CompareDrawer.tsx +4 -2
  34. package/src/components/proxy-viewer/LogEntry.tsx +4 -4
  35. package/src/components/proxy-viewer/LogEntryHeader.tsx +15 -25
  36. package/src/components/proxy-viewer/ReplayDialog.tsx +190 -8
  37. package/src/components/proxy-viewer/ResponseView.tsx +2 -2
  38. package/src/components/proxy-viewer/ToolTraceEvents.tsx +37 -16
  39. package/src/components/proxy-viewer/TurnGroup.tsx +14 -2
  40. package/src/components/proxy-viewer/anatomy/RequestAnatomy.tsx +196 -45
  41. package/src/components/proxy-viewer/anatomy/SegmentBar.tsx +92 -67
  42. package/src/components/proxy-viewer/anatomy/types.ts +15 -13
  43. package/src/components/proxy-viewer/formats/anthropic/ResponseView.tsx +2 -2
  44. package/src/components/proxy-viewer/log-formats/anthropic.ts +1 -1
  45. package/src/components/proxy-viewer/log-formats/openai.ts +1 -1
  46. package/src/components/proxy-viewer/log-formats/types.ts +1 -1
  47. package/src/components/proxy-viewer/replayComparison.ts +131 -0
  48. package/src/components/proxy-viewer/useKeyboardNavigation.ts +64 -22
  49. package/src/components/proxy-viewer/viewerState.ts +14 -2
  50. package/src/components/ui/json-viewer.tsx +1 -1
  51. package/src/knowledge/candidateStore.ts +32 -1
  52. package/src/routes/api/knowledge.candidates.$candidateId.ts +50 -0
  53. package/src/routes/api/knowledge.sessions.$sessionId.candidates.ts +12 -2
  54. package/.output/public/assets/ProxyViewerContainer-D85_UANk.js +0 -101
  55. package/.output/public/assets/ReplayDialog-DTeaHHit.js +0 -1
  56. package/.output/public/assets/RequestAnatomy-DZ8grAih.js +0 -1
  57. package/.output/public/assets/ResponseView-Cldm6RCi.js +0 -1
  58. package/.output/public/assets/StreamingChunkSequence-3x4p-yT7.js +0 -1
  59. package/.output/public/assets/_sessionId-YqWFBu6d.js +0 -1
  60. package/.output/public/assets/index-BIw2H6jO.js +0 -1
  61. package/.output/server/_tanstack-start-manifest_v-B8rrWXjr.mjs +0 -4
@@ -1,9 +1,9 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
- import { k as TooltipProvider, f as formatTokens, c as cn, l as Tooltip, m as TooltipTrigger, n as TooltipContent } from "./ProxyViewerContainer-Cckz5qKu.mjs";
3
- import "./router-Dgkv5nKP.mjs";
2
+ import { f as formatTokens, k as TooltipProvider, c as cn, l as Tooltip, m as TooltipTrigger, n as TooltipContent } from "./ProxyViewerContainer-CYm2Dw19.mjs";
3
+ import "./router-DGPt3MUc.mjs";
4
4
  import "../_libs/modelcontextprotocol__server.mjs";
5
5
  import "../_libs/jszip.mjs";
6
- import { V as Info } from "../_libs/lucide-react.mjs";
6
+ import { a4 as Info } from "../_libs/lucide-react.mjs";
7
7
  import "../_libs/swr.mjs";
8
8
  import "../_libs/use-sync-external-store.mjs";
9
9
  import "../_libs/dequal.mjs";
@@ -112,6 +112,13 @@ import "../_libs/lie.mjs";
112
112
  import "../_libs/immediate.mjs";
113
113
  import "../_libs/setimmediate.mjs";
114
114
  import "../_libs/pako.mjs";
115
+ const ANATOMY_ROLE_LABELS = {
116
+ system: "System",
117
+ user: "User",
118
+ assistant: "Assistant",
119
+ tool: "Tool Results",
120
+ tools: "Tool Definitions"
121
+ };
115
122
  const ROLE_COLOR_CLASSES = {
116
123
  system: "bg-sky-500/70",
117
124
  user: "bg-emerald-500/70",
@@ -132,35 +139,43 @@ const TOOLTIP_PREVIEW_LIMIT = 80;
132
139
  const LABEL_TRUNCATE_LIMIT = 24;
133
140
  function truncateLabel(label) {
134
141
  if (label.length <= LABEL_TRUNCATE_LIMIT) return label;
135
- return `${label.slice(0, LABEL_TRUNCATE_LIMIT - 1)}…`;
142
+ return `${label.slice(0, LABEL_TRUNCATE_LIMIT - 3)}...`;
136
143
  }
137
144
  function truncatePreview(text) {
138
145
  const singleLine = text.replace(/\s+/g, " ").trim();
139
146
  if (singleLine.length <= TOOLTIP_PREVIEW_LIMIT) return singleLine;
140
- return `${singleLine.slice(0, TOOLTIP_PREVIEW_LIMIT)}…`;
147
+ return `${singleLine.slice(0, TOOLTIP_PREVIEW_LIMIT)}...`;
148
+ }
149
+ function formatPercent$1(value) {
150
+ if (value >= 10) return `${value.toFixed(0)}%`;
151
+ if (value >= 1) return `${value.toFixed(1)}%`;
152
+ if (value > 0) return "<1%";
153
+ return "0%";
141
154
  }
142
155
  const SegmentBar = reactExports.memo(function SegmentBar2({
143
156
  segments,
144
157
  totalTokens,
158
+ showLabels = true,
145
159
  onActivate
146
160
  }) {
147
161
  const total = reactExports.useMemo(() => {
148
162
  if (totalTokens > 0) return totalTokens;
149
- return segments.reduce((sum, s) => sum + s.size, 0);
163
+ return segments.reduce((sum, segment) => sum + segment.size, 0);
150
164
  }, [segments, totalTokens]);
151
165
  const visibleSegments = segments.slice(0, MAX_VISIBLE_SEGMENTS);
152
166
  const overflowSegments = segments.slice(MAX_VISIBLE_SEGMENTS);
153
- const overflowSize = overflowSegments.reduce((sum, s) => sum + s.size, 0);
167
+ const overflowSize = overflowSegments.reduce((sum, segment) => sum + segment.size, 0);
154
168
  const overflowCount = overflowSegments.length;
155
169
  const overflowStartIndex = MAX_VISIBLE_SEGMENTS;
156
170
  const overflowEndIndex = overflowStartIndex + overflowCount - 1;
157
171
  const hasOverflow = overflowCount > 0;
172
+ const interactive = onActivate !== void 0;
158
173
  const visibleTotal = reactExports.useMemo(
159
- () => visibleSegments.reduce((sum, s) => sum + s.size, 0),
174
+ () => visibleSegments.reduce((sum, segment) => sum + segment.size, 0),
160
175
  [visibleSegments]
161
176
  );
162
177
  const ariaLabel = reactExports.useMemo(
163
- () => `Request anatomy: ~${formatTokens(total)} tokens across ${segments.length} segment${segments.length === 1 ? "" : "s"}`,
178
+ () => `Request context: ~${formatTokens(total)} tokens across ${segments.length} segment${segments.length === 1 ? "" : "s"}`,
164
179
  [segments.length, total]
165
180
  );
166
181
  if (segments.length === 0 || total <= 0) {
@@ -176,39 +191,47 @@ const SegmentBar = reactExports.memo(function SegmentBar2({
176
191
  visibleSegments.map((segment, index) => {
177
192
  const rawPercent = total > 0 ? segment.size / total * 100 : 0;
178
193
  const percent = Math.max(MIN_SEGMENT_PERCENT, rawPercent);
194
+ const segmentClassName = cn(
195
+ "h-full border-r border-background/80 last:border-r-0",
196
+ interactive ? "opacity-90 hover:opacity-100 focus:opacity-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-offset-background" : "opacity-90",
197
+ ROLE_COLOR_CLASSES[segment.role],
198
+ interactive ? ROLE_FOCUS_RING[segment.role] : ""
199
+ );
200
+ const segmentStyle = { width: `${percent}%` };
201
+ const ariaText = `${segment.label}, ${formatPercent$1(rawPercent)}, ~${formatTokens(
202
+ segment.size
203
+ )} tokens`;
179
204
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
180
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
205
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: interactive ? /* @__PURE__ */ jsxRuntimeExports.jsx(
181
206
  "button",
182
207
  {
183
208
  type: "button",
184
209
  role: "button",
185
210
  tabIndex: 0,
186
- onClick: () => onActivate?.(segment),
187
- onKeyDown: (e) => {
188
- if (e.key === "Enter" || e.key === " ") {
189
- e.preventDefault();
190
- onActivate?.(segment);
211
+ onClick: () => onActivate(segment),
212
+ onKeyDown: (event) => {
213
+ if (event.key === "Enter" || event.key === " ") {
214
+ event.preventDefault();
215
+ onActivate(segment);
191
216
  }
192
217
  },
193
218
  "data-anatomy-path": segment.path,
194
- "aria-label": `${segment.label}, ~${formatTokens(segment.size)} tokens`,
195
- className: cn(
196
- "h-full border-r border-background/80 last:border-r-0",
197
- "opacity-90 hover:opacity-100 focus:opacity-100",
198
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-offset-background",
199
- ROLE_COLOR_CLASSES[segment.role],
200
- ROLE_FOCUS_RING[segment.role]
201
- ),
202
- style: { width: `${percent}%` }
219
+ "aria-label": ariaText,
220
+ className: segmentClassName,
221
+ style: segmentStyle
203
222
  }
204
- ) }),
223
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { "aria-label": ariaText, className: segmentClassName, style: segmentStyle }) }),
205
224
  /* @__PURE__ */ jsxRuntimeExports.jsxs(TooltipContent, { side: "bottom", className: "max-w-sm text-xs p-2 space-y-0.5", children: [
206
225
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "font-semibold", children: [
207
226
  segment.label,
208
- " · ~",
227
+ " - ",
228
+ formatPercent$1(rawPercent),
229
+ " - ~",
209
230
  formatTokens(segment.size),
210
- " tokens"
231
+ " ",
232
+ "tokens"
211
233
  ] }),
234
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-muted-foreground", children: ANATOMY_ROLE_LABELS[segment.role] }),
212
235
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-muted-foreground", children: [
213
236
  segment.characters.toLocaleString(),
214
237
  " chars"
@@ -228,7 +251,7 @@ const SegmentBar = reactExports.memo(function SegmentBar2({
228
251
  width: `${Math.max(MIN_SEGMENT_PERCENT, overflowSize / total * 100)}%`
229
252
  },
230
253
  children: [
231
- " +",
254
+ "... +",
232
255
  overflowCount
233
256
  ]
234
257
  }
@@ -240,7 +263,7 @@ const SegmentBar = reactExports.memo(function SegmentBar2({
240
263
  " (indices",
241
264
  " ",
242
265
  overflowStartIndex,
243
- "",
266
+ "-",
244
267
  overflowEndIndex,
245
268
  ")"
246
269
  ] })
@@ -248,7 +271,7 @@ const SegmentBar = reactExports.memo(function SegmentBar2({
248
271
  ]
249
272
  }
250
273
  ),
251
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex w-full gap-1 text-[10px] text-muted-foreground", children: [
274
+ showLabels && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex w-full gap-1 text-[10px] text-muted-foreground", children: [
252
275
  visibleSegments.map((segment, index) => {
253
276
  const rawPercent = total > 0 ? segment.size / total * 100 : 0;
254
277
  const percent = Math.max(MIN_SEGMENT_PERCENT, rawPercent);
@@ -257,11 +280,14 @@ const SegmentBar = reactExports.memo(function SegmentBar2({
257
280
  {
258
281
  className: "flex flex-col gap-0.5 truncate",
259
282
  style: { width: `${percent}%` },
260
- title: `${segment.label} · ~${formatTokens(segment.size)} tokens`,
283
+ title: `${segment.label} - ${formatPercent$1(rawPercent)} - ~${formatTokens(
284
+ segment.size
285
+ )} tokens`,
261
286
  children: [
262
287
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate font-mono text-foreground/80", children: truncateLabel(segment.label) }),
263
288
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "truncate font-mono text-muted-foreground/70", children: [
264
- "~",
289
+ formatPercent$1(rawPercent),
290
+ " - ~",
265
291
  formatTokens(segment.size)
266
292
  ] })
267
293
  ]
@@ -276,7 +302,7 @@ const SegmentBar = reactExports.memo(function SegmentBar2({
276
302
  style: { width: `${Math.max(MIN_SEGMENT_PERCENT, overflowSize / total * 100)}%` },
277
303
  children: [
278
304
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "truncate font-mono text-foreground/60", children: [
279
- " +",
305
+ "... +",
280
306
  overflowCount
281
307
  ] }),
282
308
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "truncate font-mono text-muted-foreground/60", children: [
@@ -291,61 +317,205 @@ const SegmentBar = reactExports.memo(function SegmentBar2({
291
317
  ] }) });
292
318
  });
293
319
  const DIVERGENCE_AMBER_THRESHOLD = 0.25;
320
+ const TOP_CONTRIBUTOR_COUNT = 5;
321
+ const ROLE_ORDER = ["system", "user", "assistant", "tool", "tools"];
322
+ const ROLE_DESCRIPTIONS = {
323
+ system: "instructions",
324
+ user: "user turns",
325
+ assistant: "assistant turns",
326
+ tool: "tool results",
327
+ tools: "tool schemas"
328
+ };
329
+ const VIEW_MODE_OPTIONS = [
330
+ { value: "role", label: "By Role" },
331
+ { value: "segment", label: "By Segment" }
332
+ ];
333
+ function formatPercent(value) {
334
+ if (value >= 10) return `${value.toFixed(0)}%`;
335
+ if (value >= 1) return `${value.toFixed(1)}%`;
336
+ if (value > 0) return "<1%";
337
+ return "0%";
338
+ }
339
+ function aggregateByRole(segments) {
340
+ const result = [];
341
+ for (const role of ROLE_ORDER) {
342
+ const matching = segments.filter((segment) => segment.role === role);
343
+ if (matching.length === 0) continue;
344
+ const size = matching.reduce((sum, segment) => sum + segment.size, 0);
345
+ const characters = matching.reduce((sum, segment) => sum + segment.characters, 0);
346
+ const label = ANATOMY_ROLE_LABELS[role];
347
+ const text = `${matching.length} segment${matching.length === 1 ? "" : "s"} grouped as ${ROLE_DESCRIPTIONS[role]}`;
348
+ result.push({
349
+ role,
350
+ label,
351
+ size,
352
+ characters,
353
+ text,
354
+ path: `role:${role}`
355
+ });
356
+ }
357
+ return result;
358
+ }
359
+ function topContributors(segments) {
360
+ return [...segments].sort((a, b) => b.size - a.size).slice(0, TOP_CONTRIBUTOR_COUNT);
361
+ }
294
362
  function RequestAnatomy({
295
363
  parsed,
296
364
  inputTokens,
297
365
  onSegmentActivate,
298
366
  segments: providedSegments
299
367
  }) {
368
+ const [viewMode, setViewMode] = reactExports.useState("role");
300
369
  const segments = reactExports.useMemo(() => providedSegments ?? null, [providedSegments]);
301
- const total = reactExports.useMemo(() => (segments ?? []).reduce((sum, s) => sum + s.size, 0), [segments]);
370
+ const total = reactExports.useMemo(
371
+ () => (segments ?? []).reduce((sum, segment) => sum + segment.size, 0),
372
+ [segments]
373
+ );
374
+ const roleSegments = reactExports.useMemo(
375
+ () => segments === null ? [] : aggregateByRole(segments),
376
+ [segments]
377
+ );
378
+ const topSegments = reactExports.useMemo(
379
+ () => segments === null ? [] : topContributors(segments),
380
+ [segments]
381
+ );
302
382
  const showDivergenceWarning = reactExports.useMemo(() => {
303
- if (segments === null || segments === void 0) return false;
383
+ if (segments === null) return false;
304
384
  if (inputTokens === null) return false;
305
385
  if (total === 0) return false;
306
386
  const ratio = Math.abs(inputTokens - total) / Math.max(inputTokens, total);
307
387
  return ratio >= DIVERGENCE_AMBER_THRESHOLD;
308
388
  }, [inputTokens, segments, total]);
309
- const summaryColorClass = reactExports.useMemo(() => {
310
- if (inputTokens === null) return "text-muted-foreground";
311
- if (showDivergenceWarning) return "text-amber-400";
312
- return "text-muted-foreground";
313
- }, [inputTokens, showDivergenceWarning]);
314
- if (segments === null || segments === void 0) {
315
- return null;
316
- }
317
- if (segments.length === 0) {
318
- return null;
319
- }
320
- if (parsed === null && providedSegments === void 0) {
321
- return null;
322
- }
323
- return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { delayDuration: 150, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3 space-y-2", "data-testid": "anatomy-root", children: [
324
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-xs", children: [
325
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-foreground", children: [
326
- "~",
327
- formatTokens(total),
328
- " tokens"
329
- ] }),
330
- inputTokens !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: cn("font-mono tabular-nums", summaryColorClass), children: [
331
- "(server: ",
332
- formatTokens(inputTokens),
333
- ")"
389
+ if (segments === null) return null;
390
+ if (segments.length === 0) return null;
391
+ if (parsed === null && providedSegments === void 0) return null;
392
+ const summaryColorClass = inputTokens !== null && showDivergenceWarning ? "text-amber-400" : "text-muted-foreground";
393
+ const displayedSegments = viewMode === "role" ? roleSegments : segments;
394
+ const displayedTotal = total > 0 ? total : displayedSegments.reduce((sum, item) => sum + item.size, 0);
395
+ const activateSegment = viewMode === "segment" ? onSegmentActivate : void 0;
396
+ const segmentCountLabel = `${String(segments.length)} segment${segments.length === 1 ? "" : "s"}`;
397
+ const providerInputLabel = inputTokens === null ? "Provider input unknown" : `Provider input ${formatTokens(inputTokens)}`;
398
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { delayDuration: 150, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-3 space-y-3", "data-testid": "anatomy-root", children: [
399
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [
400
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
401
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm font-semibold text-foreground", children: "Request Context" }),
402
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cn("mt-0.5 text-xs font-mono tabular-nums", summaryColorClass), children: [
403
+ "Estimated ~",
404
+ formatTokens(total),
405
+ " tokens | ",
406
+ providerInputLabel,
407
+ " | ",
408
+ segmentCountLabel
409
+ ] })
334
410
  ] }),
335
- showDivergenceWarning && /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
411
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
412
+ "div",
413
+ {
414
+ className: "inline-flex shrink-0 rounded border border-border bg-muted/20 p-0.5",
415
+ role: "group",
416
+ "aria-label": "Context breakdown mode",
417
+ children: VIEW_MODE_OPTIONS.map((option) => /* @__PURE__ */ jsxRuntimeExports.jsx(
418
+ "button",
419
+ {
420
+ type: "button",
421
+ "aria-pressed": viewMode === option.value,
422
+ onClick: () => setViewMode(option.value),
423
+ className: cn(
424
+ "h-6 rounded-sm px-2 text-[11px] font-medium transition-colors",
425
+ viewMode === option.value ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
426
+ ),
427
+ children: option.label
428
+ },
429
+ option.value
430
+ ))
431
+ }
432
+ )
433
+ ] }),
434
+ showDivergenceWarning && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "inline-flex items-center gap-1.5 text-xs text-amber-400", children: [
435
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
336
436
  /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
337
437
  "button",
338
438
  {
339
439
  type: "button",
340
- className: "inline-flex items-center text-amber-400 hover:text-amber-300",
341
- "aria-label": "Token estimate diverges from server",
440
+ className: "inline-flex items-center hover:text-amber-300",
441
+ "aria-label": "Token estimate differs from provider input",
342
442
  children: /* @__PURE__ */ jsxRuntimeExports.jsx(Info, { className: "size-3.5" })
343
443
  }
344
444
  ) }),
345
- /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { className: "max-w-xs text-xs", children: "Bar uses a token estimate heuristic (~4 ASCII chars / token, ~1 CJK / emoji char per token). The server's reported value is the source of truth for cost." })
346
- ] })
445
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { className: "max-w-xs text-xs", children: "The bar uses a local token estimate. Provider input tokens remain the source of truth for billing and context-window usage." })
446
+ ] }),
447
+ "Estimate differs from provider-reported input."
347
448
  ] }),
348
- /* @__PURE__ */ jsxRuntimeExports.jsx(SegmentBar, { segments, totalTokens: total, onActivate: onSegmentActivate })
449
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
450
+ SegmentBar,
451
+ {
452
+ segments: displayedSegments,
453
+ totalTokens: displayedTotal,
454
+ showLabels: viewMode === "segment",
455
+ onActivate: activateSegment
456
+ }
457
+ ),
458
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1.5 text-[11px] text-muted-foreground", children: roleSegments.map((segment) => {
459
+ const percent = total > 0 ? segment.size / total * 100 : 0;
460
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "inline-flex items-center gap-1.5", children: [
461
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
462
+ "span",
463
+ {
464
+ "aria-hidden": "true",
465
+ className: cn("size-2.5 rounded-[2px]", ROLE_COLOR_CLASSES[segment.role])
466
+ }
467
+ ),
468
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: segment.label }),
469
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-muted-foreground/70", children: formatPercent(percent) })
470
+ ] }, segment.role);
471
+ }) }),
472
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
473
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-medium text-foreground", children: "Top Contributors" }),
474
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid gap-1", children: topSegments.map((segment, index) => {
475
+ const percent = total > 0 ? segment.size / total * 100 : 0;
476
+ const activate = onSegmentActivate;
477
+ const content = /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
478
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-5 shrink-0 text-right font-mono text-muted-foreground/70", children: String(index + 1) }),
479
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
480
+ "span",
481
+ {
482
+ "aria-hidden": "true",
483
+ className: cn(
484
+ "size-2.5 shrink-0 rounded-[2px]",
485
+ ROLE_COLOR_CLASSES[segment.role]
486
+ )
487
+ }
488
+ ),
489
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: segment.label }),
490
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "shrink-0 font-mono text-muted-foreground", children: [
491
+ formatPercent(percent),
492
+ " | ~",
493
+ formatTokens(segment.size)
494
+ ] })
495
+ ] });
496
+ if (activate !== void 0) {
497
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
498
+ "button",
499
+ {
500
+ type: "button",
501
+ onClick: () => activate(segment),
502
+ className: "flex h-7 items-center gap-2 rounded px-1.5 text-xs text-muted-foreground hover:bg-muted/40 hover:text-foreground",
503
+ title: "Jump to this request block",
504
+ children: content
505
+ },
506
+ `${segment.path}-${index}`
507
+ );
508
+ }
509
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
510
+ "div",
511
+ {
512
+ className: "flex h-7 items-center gap-2 rounded px-1.5 text-xs text-muted-foreground",
513
+ children: content
514
+ },
515
+ `${segment.path}-${index}`
516
+ );
517
+ }) })
518
+ ] })
349
519
  ] }) });
350
520
  }
351
521
  export {
@@ -1,10 +1,10 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
- import { g as getLogFormatAdapter, f as formatTokens, c as cn, p as getStatusCategory, B as Badge, s as safeJsonValue } from "./ProxyViewerContainer-Cckz5qKu.mjs";
3
- import { JsonViewer } from "./json-viewer-aJhb93ZK.mjs";
4
- import "./router-Dgkv5nKP.mjs";
2
+ import { g as getLogFormatAdapter, f as formatTokens, c as cn, p as getStatusCategory, B as Badge, s as safeJsonValue } from "./ProxyViewerContainer-CYm2Dw19.mjs";
3
+ import { JsonViewer } from "./json-viewer-d4obyRaA.mjs";
4
+ import "./router-DGPt3MUc.mjs";
5
5
  import "../_libs/modelcontextprotocol__server.mjs";
6
6
  import "../_libs/jszip.mjs";
7
- import { Z as Zap, i as TriangleAlert, Y as CircleStop, B as Brain, b as ChevronDown, f as ChevronRight, _ as Terminal } from "../_libs/lucide-react.mjs";
7
+ import { Z as Zap, j as TriangleAlert, a5 as CircleStop, B as Brain, b as ChevronDown, f as ChevronRight, T as Terminal } from "../_libs/lucide-react.mjs";
8
8
  import { M as Markdown } from "../_libs/react-markdown.mjs";
9
9
  import { R as Root } from "../_libs/radix-ui__react-separator.mjs";
10
10
  import { R as Root$1, C as CollapsibleTrigger$1, a as CollapsibleContent$1 } from "../_libs/radix-ui__react-collapsible.mjs";
@@ -376,11 +376,11 @@ const StructuredResponseViewAnthropic = reactExports.memo(function StructuredRes
376
376
  " out"
377
377
  ] }),
378
378
  response.usage.cache_creation_input_tokens !== void 0 && response.usage.cache_creation_input_tokens !== null && response.usage.cache_creation_input_tokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-emerald-400", children: [
379
- "Cache +",
379
+ "KV Cache +",
380
380
  formatTokens(response.usage.cache_creation_input_tokens)
381
381
  ] }),
382
382
  response.usage.cache_read_input_tokens !== void 0 && response.usage.cache_read_input_tokens !== null && response.usage.cache_read_input_tokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-purple-400", children: [
383
- "Cache ~",
383
+ "KV Cache ~",
384
384
  formatTokens(response.usage.cache_read_input_tokens)
385
385
  ] })
386
386
  ] })
@@ -589,11 +589,11 @@ const ResponseView = reactExports.memo(function ResponseView2({
589
589
  " out"
590
590
  ] }),
591
591
  cacheCreationInputTokens !== null && cacheCreationInputTokens !== void 0 && cacheCreationInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-emerald-400", children: [
592
- "Cache +",
592
+ "KV Cache +",
593
593
  formatTokens(cacheCreationInputTokens)
594
594
  ] }),
595
595
  cacheReadInputTokens !== null && cacheReadInputTokens !== void 0 && cacheReadInputTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono tabular-nums text-purple-400", children: [
596
- "Cache ~",
596
+ "KV Cache ~",
597
597
  formatTokens(cacheReadInputTokens)
598
598
  ] })
599
599
  ] })
@@ -1,7 +1,7 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
- import { k as TooltipProvider, l as Tooltip, m as TooltipTrigger, B as Badge, n as TooltipContent } from "./ProxyViewerContainer-Cckz5qKu.mjs";
3
- import { JsonViewer } from "./json-viewer-aJhb93ZK.mjs";
4
- import "./router-Dgkv5nKP.mjs";
2
+ import { k as TooltipProvider, l as Tooltip, m as TooltipTrigger, B as Badge, n as TooltipContent } from "./ProxyViewerContainer-CYm2Dw19.mjs";
3
+ import { JsonViewer } from "./json-viewer-d4obyRaA.mjs";
4
+ import "./router-DGPt3MUc.mjs";
5
5
  import "../_libs/modelcontextprotocol__server.mjs";
6
6
  import "../_libs/jszip.mjs";
7
7
  import { b as ChevronDown, f as ChevronRight, L as LoaderCircle } from "../_libs/lucide-react.mjs";
@@ -1,6 +1,6 @@
1
- import { P as ProxyViewerContainer } from "./ProxyViewerContainer-Cckz5qKu.mjs";
1
+ import { P as ProxyViewerContainer } from "./ProxyViewerContainer-CYm2Dw19.mjs";
2
2
  import "../_libs/react.mjs";
3
- import "./router-Dgkv5nKP.mjs";
3
+ import "./router-DGPt3MUc.mjs";
4
4
  import "../_libs/modelcontextprotocol__server.mjs";
5
5
  import "../_libs/jszip.mjs";
6
6
  import "../_libs/swr.mjs";
@@ -198,7 +198,7 @@ function getResponse() {
198
198
  return event.res;
199
199
  }
200
200
  async function getStartManifest(matchedRoutes) {
201
- const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-B8rrWXjr.mjs");
201
+ const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-BzH4pNaI.mjs");
202
202
  const startManifest = tsrStartManifest();
203
203
  const rootRoute = startManifest.routes[rootRouteId] = startManifest.routes[rootRouteId] || {};
204
204
  rootRoute.assets = rootRoute.assets || [];
@@ -767,7 +767,7 @@ let entriesPromise;
767
767
  let baseManifestPromise;
768
768
  let cachedFinalManifestPromise;
769
769
  async function loadEntries() {
770
- const routerEntry = await import("./router-Dgkv5nKP.mjs").then((n) => n.i);
770
+ const routerEntry = await import("./router-DGPt3MUc.mjs").then((n) => n.i);
771
771
  const startEntry = await import("./start-HYkvq4Ni.mjs");
772
772
  return { startEntry, routerEntry };
773
773
  }
@@ -1,9 +1,9 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
- import { q as parseJsonText, c as cn, k as TooltipProvider, l as Tooltip, m as TooltipTrigger, n as TooltipContent } from "./ProxyViewerContainer-Cckz5qKu.mjs";
3
- import "./router-Dgkv5nKP.mjs";
2
+ import { q as parseJsonText, c as cn, k as TooltipProvider, l as Tooltip, m as TooltipTrigger, n as TooltipContent } from "./ProxyViewerContainer-CYm2Dw19.mjs";
3
+ import "./router-DGPt3MUc.mjs";
4
4
  import "../_libs/modelcontextprotocol__server.mjs";
5
5
  import "../_libs/jszip.mjs";
6
- import { C as Check, a as Copy, b as ChevronDown, f as ChevronRight, q as ChevronsDown } from "../_libs/lucide-react.mjs";
6
+ import { C as Check, a as Copy, b as ChevronDown, f as ChevronRight, y as ChevronsDown } from "../_libs/lucide-react.mjs";
7
7
  import { M as Markdown } from "../_libs/react-markdown.mjs";
8
8
  import "../_libs/swr.mjs";
9
9
  import "../_libs/use-sync-external-store.mjs";