@tonyclaw/agent-inspector 2.0.5 → 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 (39) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{CompareDrawer-3nRwtk8J.js → CompareDrawer-DDmqSAfl.js} +1 -1
  3. package/.output/public/assets/{ProxyViewerContainer-CbW5VRER.js → ProxyViewerContainer-Cxpdziwd.js} +5 -5
  4. package/.output/public/assets/{ReplayDialog-Cl62N9PI.js → ReplayDialog-Bt5DGzlh.js} +1 -1
  5. package/.output/public/assets/RequestAnatomy-BxX3_N9S.js +1 -0
  6. package/.output/public/assets/{ResponseView-Cvc-ct4E.js → ResponseView-Bl_5S9gZ.js} +1 -1
  7. package/.output/public/assets/{StreamingChunkSequence-BCQaCAIe.js → StreamingChunkSequence-RJMwNf6F.js} +1 -1
  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-C624DUk9.css +1 -0
  11. package/.output/public/assets/{json-viewer-IXejqXB0.js → json-viewer-CRL_gWEZ.js} +1 -1
  12. package/.output/public/assets/{main-2NlGzgOe.js → main-CKnTJ4-O.js} +6 -6
  13. package/.output/server/{_sessionId-DWCTasJU.mjs → _sessionId-B-x9fRY3.mjs} +2 -2
  14. package/.output/server/_ssr/{CompareDrawer-DhrN1uC2.mjs → CompareDrawer-BQVNsAY2.mjs} +3 -3
  15. package/.output/server/_ssr/{ProxyViewerContainer-DRl51s_n.mjs → ProxyViewerContainer-CYm2Dw19.mjs} +12 -12
  16. package/.output/server/_ssr/{ReplayDialog-BQT_ygxC.mjs → ReplayDialog-CaMQBc79.mjs} +4 -4
  17. package/.output/server/_ssr/{RequestAnatomy-DS2tZOgq.mjs → RequestAnatomy--P5arRH2.mjs} +235 -65
  18. package/.output/server/_ssr/{ResponseView-e0kL2C3x.mjs → ResponseView-RtFwNvgD.mjs} +3 -3
  19. package/.output/server/_ssr/{StreamingChunkSequence-BJG-m7xs.mjs → StreamingChunkSequence-B5HPkzab.mjs} +3 -3
  20. package/.output/server/_ssr/{index-Dea3OeRw.mjs → index-CZIKZU43.mjs} +2 -2
  21. package/.output/server/_ssr/index.mjs +2 -2
  22. package/.output/server/_ssr/{json-viewer-DDU55MLK.mjs → json-viewer-d4obyRaA.mjs} +2 -2
  23. package/.output/server/_ssr/{router-Dl7oh0zx.mjs → router-DGPt3MUc.mjs} +3 -3
  24. package/.output/server/{_tanstack-start-manifest_v-m-FJNBVf.mjs → _tanstack-start-manifest_v-BzH4pNaI.mjs} +1 -1
  25. package/.output/server/index.mjs +68 -68
  26. package/package.json +1 -1
  27. package/src/components/proxy-viewer/LogEntry.tsx +4 -4
  28. package/src/components/proxy-viewer/LogEntryHeader.tsx +3 -3
  29. package/src/components/proxy-viewer/anatomy/RequestAnatomy.tsx +196 -45
  30. package/src/components/proxy-viewer/anatomy/SegmentBar.tsx +92 -67
  31. package/src/components/proxy-viewer/anatomy/types.ts +15 -13
  32. package/src/components/proxy-viewer/log-formats/anthropic.ts +1 -1
  33. package/src/components/proxy-viewer/log-formats/openai.ts +1 -1
  34. package/src/components/proxy-viewer/log-formats/types.ts +1 -1
  35. package/src/components/ui/json-viewer.tsx +1 -1
  36. package/.output/public/assets/RequestAnatomy-DgQWGvjs.js +0 -1
  37. package/.output/public/assets/_sessionId-CcD_aLGq.js +0 -1
  38. package/.output/public/assets/index-B_dffD3u.js +0 -1
  39. package/.output/public/assets/index-CX796gvi.css +0 -1
@@ -1,6 +1,6 @@
1
1
  import { j as jsxRuntimeExports } from "./_libs/react.mjs";
2
- import { P as ProxyViewerContainer } from "./_ssr/ProxyViewerContainer-DRl51s_n.mjs";
3
- import { R as Route$p } from "./_ssr/router-Dl7oh0zx.mjs";
2
+ import { P as ProxyViewerContainer } from "./_ssr/ProxyViewerContainer-CYm2Dw19.mjs";
3
+ import { R as Route$p } from "./_ssr/router-DGPt3MUc.mjs";
4
4
  import "./_libs/jszip.mjs";
5
5
  import "./_libs/modelcontextprotocol__server.mjs";
6
6
  import "./_libs/swr.mjs";
@@ -1,7 +1,7 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
- import { g as getLogFormatAdapter, r as resolveLogFormat, a as getConversationId, c as cn, B as Badge, f as formatTokens } from "./ProxyViewerContainer-DRl51s_n.mjs";
3
- import { JsonViewerFromString } from "./json-viewer-DDU55MLK.mjs";
4
- import "./router-Dl7oh0zx.mjs";
2
+ import { g as getLogFormatAdapter, r as resolveLogFormat, a as getConversationId, c as cn, B as Badge, f as formatTokens } from "./ProxyViewerContainer-CYm2Dw19.mjs";
3
+ import { JsonViewerFromString } 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 { X, a1 as Rows3, a2 as Columns2, n as Minus, P as Plus, m as Pencil, f as ChevronRight, a3 as Equal, C as Check, a as Copy } from "../_libs/lucide-react.mjs";
@@ -1,5 +1,5 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports, a as React } from "../_libs/react.mjs";
2
- import { C as CapturedLogSchema, D as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, a as DEFAULT_TIME_DISPLAY_FORMAT, b as RuntimeConfigSchema, r as requestFormatForPath, e as createPendingProviderTestResults, P as ProviderTestResultsSchema, f as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, T as TimeDisplayFormatSchema, g as getSessionPath, h as ProviderConfigSchema, K as KnowledgeCandidateSchema, s as stripClaudeCodeBillingHeader, d as safeGetOwnProperty, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, c as AnthropicRequestSchema } from "./router-Dl7oh0zx.mjs";
2
+ import { C as CapturedLogSchema, D as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, a as DEFAULT_TIME_DISPLAY_FORMAT, b as RuntimeConfigSchema, r as requestFormatForPath, e as createPendingProviderTestResults, P as ProviderTestResultsSchema, f as createFailedProviderTestResults, M as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, T as TimeDisplayFormatSchema, g as getSessionPath, h as ProviderConfigSchema, K as KnowledgeCandidateSchema, s as stripClaudeCodeBillingHeader, d as safeGetOwnProperty, p as parseOpenAIResponse, O as OpenAIRequestSchema, A as AnthropicResponseSchema$1, c as AnthropicRequestSchema } from "./router-DGPt3MUc.mjs";
3
3
  import { u as useSWR, a as useSWRConfig } from "../_libs/swr.mjs";
4
4
  import { J as JSZip } from "../_libs/jszip.mjs";
5
5
  import { c as clsx } from "../_libs/clsx.mjs";
@@ -295,7 +295,7 @@ function getStatusCategory(status) {
295
295
  if (status >= 500) return "server_error";
296
296
  return "pending";
297
297
  }
298
- const version = "2.0.5";
298
+ const version = "2.0.6";
299
299
  const packageJson = {
300
300
  version
301
301
  };
@@ -1356,27 +1356,27 @@ function useCopyFeedback(text) {
1356
1356
  return { copied, copy };
1357
1357
  }
1358
1358
  const LazyCompareDrawer = reactExports.lazy(
1359
- () => import("./CompareDrawer-DhrN1uC2.mjs").then((m) => ({ default: m.CompareDrawer }))
1359
+ () => import("./CompareDrawer-BQVNsAY2.mjs").then((m) => ({ default: m.CompareDrawer }))
1360
1360
  );
1361
1361
  const LazyReplayDialog = reactExports.lazy(
1362
- () => import("./ReplayDialog-BQT_ygxC.mjs").then((m) => ({ default: m.ReplayDialog }))
1362
+ () => import("./ReplayDialog-CaMQBc79.mjs").then((m) => ({ default: m.ReplayDialog }))
1363
1363
  );
1364
1364
  const LazyRequestAnatomy = reactExports.lazy(
1365
- () => import("./RequestAnatomy-DS2tZOgq.mjs").then((m) => ({ default: m.RequestAnatomy }))
1365
+ () => import("./RequestAnatomy--P5arRH2.mjs").then((m) => ({ default: m.RequestAnatomy }))
1366
1366
  );
1367
1367
  const LazyResponseView = reactExports.lazy(
1368
- () => import("./ResponseView-e0kL2C3x.mjs").then((m) => ({ default: m.ResponseView }))
1368
+ () => import("./ResponseView-RtFwNvgD.mjs").then((m) => ({ default: m.ResponseView }))
1369
1369
  );
1370
1370
  const LazyStreamingChunkSequence = reactExports.lazy(
1371
- () => import("./StreamingChunkSequence-BJG-m7xs.mjs").then((m) => ({
1371
+ () => import("./StreamingChunkSequence-B5HPkzab.mjs").then((m) => ({
1372
1372
  default: m.StreamingChunkSequence
1373
1373
  }))
1374
1374
  );
1375
1375
  const LazyJsonViewer = reactExports.lazy(
1376
- () => import("./json-viewer-DDU55MLK.mjs").then((m) => ({ default: m.JsonViewer }))
1376
+ () => import("./json-viewer-d4obyRaA.mjs").then((m) => ({ default: m.JsonViewer }))
1377
1377
  );
1378
1378
  const LazyJsonViewerFromString = reactExports.lazy(
1379
- () => import("./json-viewer-DDU55MLK.mjs").then((m) => ({ default: m.JsonViewerFromString }))
1379
+ () => import("./json-viewer-d4obyRaA.mjs").then((m) => ({ default: m.JsonViewerFromString }))
1380
1380
  );
1381
1381
  const HIGHLIGHT_DURATION_MS = 1200;
1382
1382
  const MAX_HIGHLIGHT_ATTEMPTS = 12;
@@ -2570,7 +2570,7 @@ const LogEntry = reactExports.memo(function({
2570
2570
  viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "headers", children: "Headers" }),
2571
2571
  shouldShowRawRequestTab(resolvedFormat, viewMode, strip) && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "raw-request", children: "Raw Request" }),
2572
2572
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "request", children: "Request" }),
2573
- anatomySegments !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "anatomy", children: "Anatomy" }),
2573
+ anatomySegments !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "anatomy", children: "Context" }),
2574
2574
  viewMode === "full" && /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "raw", children: "Raw Response" }),
2575
2575
  /* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "parsed", children: "Response" })
2576
2576
  ] }),
@@ -2587,7 +2587,7 @@ const LogEntry = reactExports.memo(function({
2587
2587
  {
2588
2588
  rawBody: log.rawRequestBody,
2589
2589
  displayedBody: displayedRequestBody,
2590
- emptyLabel: "No transformation applied raw and sent request bodies are identical."
2590
+ emptyLabel: "No transformation applied; raw and sent request bodies are identical."
2591
2591
  }
2592
2592
  ) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: requestJsonRef, children: displayedRequestBody === null ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No request body" }) : requestExpansion.parsedData !== null ? /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx(TabFallback, {}), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
2593
2593
  LazyJsonViewer,
@@ -2627,7 +2627,7 @@ const LogEntry = reactExports.memo(function({
2627
2627
  {
2628
2628
  rawHeaders: log.rawHeaders,
2629
2629
  headers: log.headers,
2630
- emptyLabel: "No transformation applied raw and processed headers are identical."
2630
+ emptyLabel: "No transformation applied; raw and processed headers are identical."
2631
2631
  }
2632
2632
  ) : log.headers && Object.keys(log.headers).length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 font-mono text-xs", children: Object.entries(log.headers).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
2633
2633
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-600 dark:text-blue-400 font-semibold shrink-0", children: [
@@ -1,10 +1,10 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
- import { u as useProviders, D as Dialog, b as DialogContent, d as DialogHeader, e as DialogTitle, T as Tabs, h as TabsList, i as TabsTrigger, j as TabsContent, k as TooltipProvider, l as Tooltip, m as TooltipTrigger, n as TooltipContent, o as Button } from "./ProxyViewerContainer-DRl51s_n.mjs";
3
- import { ResponseView } from "./ResponseView-e0kL2C3x.mjs";
4
- import "./router-Dl7oh0zx.mjs";
2
+ import { u as useProviders, D as Dialog, b as DialogContent, d as DialogHeader, e as DialogTitle, T as Tabs, h as TabsList, i as TabsTrigger, j as TabsContent, k as TooltipProvider, l as Tooltip, m as TooltipTrigger, n as TooltipContent, o as Button } from "./ProxyViewerContainer-CYm2Dw19.mjs";
3
+ import { ResponseView } from "./ResponseView-RtFwNvgD.mjs";
4
+ import "./router-DGPt3MUc.mjs";
5
5
  import "../_libs/modelcontextprotocol__server.mjs";
6
6
  import "../_libs/jszip.mjs";
7
- import "./json-viewer-DDU55MLK.mjs";
7
+ import "./json-viewer-d4obyRaA.mjs";
8
8
  import { I as RotateCcw } from "../_libs/lucide-react.mjs";
9
9
  import { d as object, c as boolean, n as number, b as string } from "../_libs/zod.mjs";
10
10
  import "../_libs/swr.mjs";
@@ -1,6 +1,6 @@
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-DRl51s_n.mjs";
3
- import "./router-Dl7oh0zx.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
6
  import { a4 as Info } from "../_libs/lucide-react.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,7 +1,7 @@
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-DRl51s_n.mjs";
3
- import { JsonViewer } from "./json-viewer-DDU55MLK.mjs";
4
- import "./router-Dl7oh0zx.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
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";
@@ -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-DRl51s_n.mjs";
3
- import { JsonViewer } from "./json-viewer-DDU55MLK.mjs";
4
- import "./router-Dl7oh0zx.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-DRl51s_n.mjs";
1
+ import { P as ProxyViewerContainer } from "./ProxyViewerContainer-CYm2Dw19.mjs";
2
2
  import "../_libs/react.mjs";
3
- import "./router-Dl7oh0zx.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-m-FJNBVf.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-Dl7oh0zx.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,6 +1,6 @@
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-DRl51s_n.mjs";
3
- import "./router-Dl7oh0zx.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
6
  import { C as Check, a as Copy, b as ChevronDown, f as ChevronRight, y as ChevronsDown } from "../_libs/lucide-react.mjs";