@tonyclaw/agent-inspector 2.0.10 → 2.0.12

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 (47) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{CompareDrawer-BWMipEjS.js → CompareDrawer-ClM_uVRy.js} +1 -1
  3. package/.output/public/assets/ProxyViewerContainer-CTNNzXSa.js +114 -0
  4. package/.output/public/assets/{ReplayDialog-DaSzZsvM.js → ReplayDialog-7rp7N_KJ.js} +1 -1
  5. package/.output/public/assets/RequestAnatomy-sL2FFo_N.js +1 -0
  6. package/.output/public/assets/ResponseView-Cjlf3b6-.js +1 -0
  7. package/.output/public/assets/{StreamingChunkSequence-B4atnL99.js → StreamingChunkSequence-Ctx3sT3r.js} +1 -1
  8. package/.output/public/assets/_sessionId-DEWzDQ8-.js +1 -0
  9. package/.output/public/assets/index-DGIIhZTn.js +1 -0
  10. package/.output/public/assets/index-D_nZj9Vt.css +1 -0
  11. package/.output/public/assets/{main-DE6Y4-wV.js → main-FvIQopAy.js} +2 -2
  12. package/.output/server/_libs/lucide-react.mjs +51 -39
  13. package/.output/server/{_sessionId-61HO9rUI.mjs → _sessionId-BDSgtrsI.mjs} +2 -2
  14. package/.output/server/_ssr/{CompareDrawer-CSPqneYm.mjs → CompareDrawer-Cqvv0I3x.mjs} +3 -3
  15. package/.output/server/_ssr/{ProxyViewerContainer-DrSMa5O7.mjs → ProxyViewerContainer-C0YEoG8N.mjs} +1611 -183
  16. package/.output/server/_ssr/{ReplayDialog-Dn3naENv.mjs → ReplayDialog-CrsynUKI.mjs} +4 -4
  17. package/.output/server/_ssr/RequestAnatomy-CR_JUkcL.mjs +688 -0
  18. package/.output/server/_ssr/{ResponseView-CwXAWOoE.mjs → ResponseView-Dba2Et69.mjs} +3 -3
  19. package/.output/server/_ssr/{StreamingChunkSequence-DRSR2FfN.mjs → StreamingChunkSequence-BIMHLstI.mjs} +2 -2
  20. package/.output/server/_ssr/{index-D4zn5CAg.mjs → index-DveIUTm5.mjs} +2 -2
  21. package/.output/server/_ssr/index.mjs +2 -2
  22. package/.output/server/_ssr/{router-CSRaa_tu.mjs → router-D0yXVG0Q.mjs} +85 -22
  23. package/.output/server/{_tanstack-start-manifest_v-CfvVUYYj.mjs → _tanstack-start-manifest_v-pe0xJFuQ.mjs} +1 -1
  24. package/.output/server/index.mjs +70 -70
  25. package/package.json +1 -1
  26. package/src/components/ProxyViewer.tsx +453 -52
  27. package/src/components/providers/ProviderCard.tsx +45 -2
  28. package/src/components/providers/ProviderForm.tsx +245 -80
  29. package/src/components/providers/ProvidersPanel.tsx +7 -1
  30. package/src/components/proxy-viewer/ConversationGroup.tsx +18 -1
  31. package/src/components/proxy-viewer/LogEntry.tsx +25 -0
  32. package/src/components/proxy-viewer/TurnGroup.tsx +15 -0
  33. package/src/components/proxy-viewer/anatomy/RequestAnatomy.tsx +144 -80
  34. package/src/components/proxy-viewer/anatomy/contextIntelligence.ts +70 -5
  35. package/src/components/proxy-viewer/anatomy/sessionContextSummary.ts +196 -0
  36. package/src/components/proxy-viewer/logFocus.ts +33 -0
  37. package/src/lib/providerModelMetadata.ts +64 -12
  38. package/src/lib/utils.ts +7 -0
  39. package/src/proxy/providers.ts +25 -0
  40. package/src/routes/api/providers.ts +3 -0
  41. package/.output/public/assets/ProxyViewerContainer-DIAgurux.js +0 -114
  42. package/.output/public/assets/RequestAnatomy-BfQmPHCd.js +0 -1
  43. package/.output/public/assets/ResponseView-CblEWDMx.js +0 -1
  44. package/.output/public/assets/_sessionId-DUzYnZXV.js +0 -1
  45. package/.output/public/assets/index-CxhRsekH.css +0 -1
  46. package/.output/public/assets/index-jagRsQaV.js +0 -1
  47. package/.output/server/_ssr/RequestAnatomy-D1X3f3AX.mjs +0 -1322
@@ -0,0 +1,688 @@
1
+ import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
+ import { u as useProviders, p as analyzeContextIntelligence, f as formatTokens, k as TooltipProvider, c as cn, l as Tooltip, m as TooltipTrigger, n as TooltipContent, S as SegmentBar, R as ROLE_COLOR_CLASSES, A as ANATOMY_ROLE_LABELS, q as formatContextWindowTokens, C as CONTEXT_USAGE_THRESHOLDS } from "./ProxyViewerContainer-C0YEoG8N.mjs";
3
+ import "./router-D0yXVG0Q.mjs";
4
+ import "../_libs/modelcontextprotocol__server.mjs";
5
+ import "../_libs/jszip.mjs";
6
+ import { ac as Info, b as ChevronDown, f as ChevronRight } from "../_libs/lucide-react.mjs";
7
+ import "../_libs/swr.mjs";
8
+ import "../_libs/use-sync-external-store.mjs";
9
+ import "../_libs/dequal.mjs";
10
+ import "../_libs/clsx.mjs";
11
+ import "../_libs/tailwind-merge.mjs";
12
+ import "../_libs/class-variance-authority.mjs";
13
+ import "../_libs/radix-ui__react-dialog.mjs";
14
+ import "../_libs/radix-ui__primitive.mjs";
15
+ import "../_libs/radix-ui__react-compose-refs.mjs";
16
+ import "../_libs/radix-ui__react-context.mjs";
17
+ import "../_libs/radix-ui__react-id.mjs";
18
+ import "../_libs/@radix-ui/react-use-layout-effect+[...].mjs";
19
+ import "../_libs/@radix-ui/react-use-controllable-state+[...].mjs";
20
+ import "../_libs/@radix-ui/react-dismissable-layer+[...].mjs";
21
+ import "../_libs/radix-ui__react-primitive.mjs";
22
+ import "../_libs/react-dom.mjs";
23
+ import "util";
24
+ import "async_hooks";
25
+ import "stream";
26
+ import "crypto";
27
+ import "../_libs/radix-ui__react-slot.mjs";
28
+ import "../_libs/@radix-ui/react-use-callback-ref+[...].mjs";
29
+ import "../_libs/@radix-ui/react-use-escape-keydown+[...].mjs";
30
+ import "../_libs/radix-ui__react-focus-scope.mjs";
31
+ import "../_libs/radix-ui__react-portal.mjs";
32
+ import "../_libs/radix-ui__react-presence.mjs";
33
+ import "../_libs/radix-ui__react-focus-guards.mjs";
34
+ import "../_libs/react-remove-scroll.mjs";
35
+ import "tslib";
36
+ import "../_libs/react-remove-scroll-bar.mjs";
37
+ import "../_libs/react-style-singleton.mjs";
38
+ import "../_libs/get-nonce.mjs";
39
+ import "../_libs/use-sidecar.mjs";
40
+ import "../_libs/use-callback-ref.mjs";
41
+ import "../_libs/aria-hidden.mjs";
42
+ import "../_libs/diff.mjs";
43
+ import "../_libs/tanstack__react-virtual.mjs";
44
+ import "../_libs/tanstack__virtual-core.mjs";
45
+ import "../_libs/radix-ui__react-select.mjs";
46
+ import "../_libs/radix-ui__number.mjs";
47
+ import "../_libs/radix-ui__react-collection.mjs";
48
+ import "../_libs/radix-ui__react-direction.mjs";
49
+ import "../_libs/radix-ui__react-popper.mjs";
50
+ import "../_libs/floating-ui__react-dom.mjs";
51
+ import "../_libs/floating-ui__dom.mjs";
52
+ import "../_libs/floating-ui__core.mjs";
53
+ import "../_libs/floating-ui__utils.mjs";
54
+ import "../_libs/radix-ui__react-arrow.mjs";
55
+ import "../_libs/radix-ui__react-use-size.mjs";
56
+ import "../_libs/radix-ui__react-use-previous.mjs";
57
+ import "../_libs/@radix-ui/react-visually-hidden+[...].mjs";
58
+ import "../_libs/react-markdown.mjs";
59
+ import "../_libs/devlop.mjs";
60
+ import "../_libs/unified.mjs";
61
+ import "../_libs/bail.mjs";
62
+ import "../_libs/extend.mjs";
63
+ import "../_libs/is-plain-obj.mjs";
64
+ import "../_libs/trough.mjs";
65
+ import "../_libs/vfile.mjs";
66
+ import "../_libs/vfile-message.mjs";
67
+ import "../_libs/unist-util-stringify-position.mjs";
68
+ import "node:process";
69
+ import "node:path";
70
+ import "node:url";
71
+ import "../_libs/remark-parse.mjs";
72
+ import "../_libs/mdast-util-from-markdown.mjs";
73
+ import "../_libs/micromark-util-decode-numeric-character-reference+[...].mjs";
74
+ import "../_libs/micromark-util-decode-string.mjs";
75
+ import "../_libs/decode-named-character-reference+[...].mjs";
76
+ import "../_libs/character-entities.mjs";
77
+ import "../_libs/micromark-util-normalize-identifier+[...].mjs";
78
+ import "../_libs/micromark.mjs";
79
+ import "../_libs/micromark-util-combine-extensions+[...].mjs";
80
+ import "../_libs/micromark-util-chunked.mjs";
81
+ import "../_libs/micromark-factory-space.mjs";
82
+ import "../_libs/micromark-util-character.mjs";
83
+ import "../_libs/micromark-core-commonmark.mjs";
84
+ import "../_libs/micromark-util-classify-character+[...].mjs";
85
+ import "../_libs/micromark-util-resolve-all.mjs";
86
+ import "../_libs/micromark-util-subtokenize.mjs";
87
+ import "../_libs/micromark-factory-destination.mjs";
88
+ import "../_libs/micromark-factory-label.mjs";
89
+ import "../_libs/micromark-factory-title.mjs";
90
+ import "../_libs/micromark-factory-whitespace.mjs";
91
+ import "../_libs/micromark-util-html-tag-name.mjs";
92
+ import "../_libs/mdast-util-to-string.mjs";
93
+ import "../_libs/remark-rehype.mjs";
94
+ import "../_libs/mdast-util-to-hast.mjs";
95
+ import "../_libs/ungap__structured-clone.mjs";
96
+ import "../_libs/micromark-util-sanitize-uri.mjs";
97
+ import "../_libs/unist-util-position.mjs";
98
+ import "../_libs/trim-lines.mjs";
99
+ import "../_libs/unist-util-visit.mjs";
100
+ import "../_libs/unist-util-visit-parents.mjs";
101
+ import "../_libs/unist-util-is.mjs";
102
+ import "../_libs/hast-util-to-jsx-runtime.mjs";
103
+ import "../_libs/comma-separated-tokens.mjs";
104
+ import "../_libs/property-information.mjs";
105
+ import "../_libs/space-separated-tokens.mjs";
106
+ import "../_libs/style-to-js.mjs";
107
+ import "../_libs/style-to-object.mjs";
108
+ import "../_libs/inline-style-parser.mjs";
109
+ import "../_libs/hast-util-whitespace.mjs";
110
+ import "../_libs/estree-util-is-identifier-name.mjs";
111
+ import "../_libs/html-url-attributes.mjs";
112
+ import "../_libs/zod.mjs";
113
+ import "../_libs/radix-ui__react-tooltip.mjs";
114
+ import "../_libs/radix-ui__react-tabs.mjs";
115
+ import "../_libs/radix-ui__react-roving-focus.mjs";
116
+ import "../_libs/radix-ui__react-collapsible.mjs";
117
+ import "../_libs/radix-ui__react-scroll-area.mjs";
118
+ import "../_libs/tanstack__react-router.mjs";
119
+ import "../_libs/tiny-warning.mjs";
120
+ import "../_libs/tanstack__router-core.mjs";
121
+ import "../_libs/cookie-es.mjs";
122
+ import "../_libs/tanstack__history.mjs";
123
+ import "../_libs/tiny-invariant.mjs";
124
+ import "../_libs/seroval.mjs";
125
+ import "../_libs/seroval-plugins.mjs";
126
+ import "node:stream/web";
127
+ import "node:stream";
128
+ import "../_libs/isbot.mjs";
129
+ import "node:fs";
130
+ import "node:fs/promises";
131
+ import "node:buffer";
132
+ import "node:child_process";
133
+ import "../_libs/conf.mjs";
134
+ import "node:util";
135
+ import "node:crypto";
136
+ import "node:assert";
137
+ import "../_libs/dot-prop.mjs";
138
+ import "../_libs/env-paths.mjs";
139
+ import "node:os";
140
+ import "../_libs/atomically.mjs";
141
+ import "../_libs/stubborn-fs.mjs";
142
+ import "../_libs/stubborn-utils.mjs";
143
+ import "../_libs/when-exit.mjs";
144
+ import "../_libs/ajv.mjs";
145
+ import "../_libs/fast-deep-equal.mjs";
146
+ import "../_libs/json-schema-traverse.mjs";
147
+ import "../_libs/fast-uri.mjs";
148
+ import "../_libs/ajv-formats.mjs";
149
+ import "../_libs/debounce-fn.mjs";
150
+ import "../_libs/mimic-function.mjs";
151
+ import "../_libs/semver.mjs";
152
+ import "../_libs/uint8array-extras.mjs";
153
+ import "node:worker_threads";
154
+ import "../_libs/readable-stream.mjs";
155
+ import "events";
156
+ import "node:string_decoder";
157
+ import "../_libs/process-nextick-args.mjs";
158
+ import "../_libs/isarray.mjs";
159
+ import "../_libs/safe-buffer.mjs";
160
+ import "buffer";
161
+ import "../_libs/core-util-is.mjs";
162
+ import "../_libs/inherits.mjs";
163
+ import "../_libs/util-deprecate.mjs";
164
+ import "../_libs/lie.mjs";
165
+ import "../_libs/immediate.mjs";
166
+ import "../_libs/setimmediate.mjs";
167
+ import "../_libs/pako.mjs";
168
+ const DIVERGENCE_AMBER_THRESHOLD = 0.25;
169
+ const TOP_CONTRIBUTOR_COUNT = 5;
170
+ const DUPLICATE_GROUP_DISPLAY_COUNT = 4;
171
+ const DUPLICATE_SEGMENT_DISPLAY_COUNT = 6;
172
+ const ROLE_ORDER = ["system", "user", "assistant", "tool", "tools"];
173
+ const ROLE_DESCRIPTIONS = {
174
+ system: "instructions",
175
+ user: "user turns",
176
+ assistant: "assistant turns",
177
+ tool: "tool results",
178
+ tools: "tool schemas"
179
+ };
180
+ const VIEW_MODE_OPTIONS = [
181
+ { value: "role", label: "By Role" },
182
+ { value: "segment", label: "By Segment" }
183
+ ];
184
+ const RISK_CLASS = {
185
+ unknown: "bg-muted-foreground/50",
186
+ ok: "bg-emerald-500/70",
187
+ watch: "bg-amber-400/75",
188
+ danger: "bg-red-500/80"
189
+ };
190
+ const RISK_TEXT_CLASS = {
191
+ unknown: "text-muted-foreground",
192
+ ok: "text-emerald-400",
193
+ watch: "text-amber-300",
194
+ danger: "text-red-300"
195
+ };
196
+ const HEALTH_BADGE_CLASS = {
197
+ ok: "border-emerald-400/30 bg-emerald-400/8 text-emerald-200",
198
+ optimizable: "border-amber-400/30 bg-amber-400/8 text-amber-100",
199
+ risk: "border-red-400/35 bg-red-500/10 text-red-100"
200
+ };
201
+ const HEALTH_LABEL = {
202
+ ok: "OK",
203
+ optimizable: "Optimizable",
204
+ risk: "Risk"
205
+ };
206
+ function formatPercent(value) {
207
+ if (value >= 10) return `${value.toFixed(0)}%`;
208
+ if (value >= 1) return `${value.toFixed(1)}%`;
209
+ if (value > 0) return "<1%";
210
+ return "0%";
211
+ }
212
+ function formatUsagePercent(value) {
213
+ if (value === null) return "Unknown";
214
+ return formatPercent(value * 100);
215
+ }
216
+ function formatRemainingTokens(value) {
217
+ if (value === null) return "Unknown";
218
+ if (value < 0) return `-${formatTokens(Math.abs(value))}`;
219
+ return formatTokens(value);
220
+ }
221
+ function formatContextLimit(intelligence) {
222
+ if (intelligence.contextWindow.tokens === null) return "Unknown";
223
+ return formatContextWindowTokens(intelligence.contextWindow.tokens);
224
+ }
225
+ function formatContextSource(intelligence) {
226
+ switch (intelligence.contextWindow.source) {
227
+ case "request":
228
+ return intelligence.contextWindow.label;
229
+ case "provider":
230
+ return intelligence.contextWindow.label;
231
+ case "model-rule":
232
+ return intelligence.contextWindow.label;
233
+ case "unknown":
234
+ return intelligence.model === null ? intelligence.contextWindow.label : `${intelligence.contextWindow.label}: ${intelligence.model}`;
235
+ }
236
+ }
237
+ function diagnosticTone(diagnostic) {
238
+ switch (diagnostic.severity) {
239
+ case "watch":
240
+ return "border-amber-400/30 bg-amber-400/8 text-amber-100";
241
+ case "danger":
242
+ return "border-red-400/35 bg-red-500/10 text-red-100";
243
+ }
244
+ }
245
+ function formatContextHealth(health) {
246
+ const label = HEALTH_LABEL[health.level];
247
+ if (health.level === "ok") return label;
248
+ const countLabel = health.level === "risk" ? `${String(health.opportunityCount)} signal${health.opportunityCount === 1 ? "" : "s"}` : `${String(health.opportunityCount)} opportunit${health.opportunityCount === 1 ? "y" : "ies"}`;
249
+ if (health.reclaimableTokens <= 0) return `${label} | ${countLabel}`;
250
+ return `${label} | ${countLabel} | ~${formatTokens(health.reclaimableTokens)} tokens`;
251
+ }
252
+ function ContextHealthBadge({ health }) {
253
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
254
+ "span",
255
+ {
256
+ className: cn(
257
+ "inline-flex h-5 max-w-full items-center rounded border px-1.5 font-mono text-[10px]",
258
+ HEALTH_BADGE_CLASS[health.level]
259
+ ),
260
+ "aria-label": `Context health ${formatContextHealth(health)}`,
261
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: formatContextHealth(health) })
262
+ }
263
+ );
264
+ }
265
+ function ContextIntelligenceStrip({
266
+ intelligence
267
+ }) {
268
+ const usageWidth = intelligence.usagePercent === null ? 0 : Math.max(1, intelligence.usagePercent * 100);
269
+ const outputReserveLabel = intelligence.outputReserveTokens === null ? "No output reserve" : `Output reserve ${formatTokens(intelligence.outputReserveTokens)}`;
270
+ const largestRole = intelligence.largestRole;
271
+ const visibleDiagnostics = intelligence.duplicateGroups.length === 0 ? intelligence.diagnostics : intelligence.diagnostics.filter((diagnostic) => diagnostic.kind !== "duplicate");
272
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
273
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid gap-x-4 gap-y-2 border-y border-border/60 py-2 text-xs sm:grid-cols-4", children: [
274
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
275
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-medium uppercase text-muted-foreground", children: "Window" }),
276
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-0.5 truncate font-mono text-foreground", children: formatContextLimit(intelligence) }),
277
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "truncate text-[11px] text-muted-foreground", children: formatContextSource(intelligence) })
278
+ ] }),
279
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
280
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-medium uppercase text-muted-foreground", children: "Used" }),
281
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("mt-0.5 font-mono", RISK_TEXT_CLASS[intelligence.riskLevel]), children: formatUsagePercent(intelligence.usagePercent) }),
282
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "truncate text-[11px] text-muted-foreground", children: outputReserveLabel })
283
+ ] }),
284
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
285
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-medium uppercase text-muted-foreground", children: "Remaining" }),
286
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-0.5 font-mono text-foreground", children: formatRemainingTokens(intelligence.remainingAfterReserveTokens) }),
287
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "truncate text-[11px] text-muted-foreground", children: [
288
+ "Input only ",
289
+ formatRemainingTokens(intelligence.remainingInputTokens)
290
+ ] })
291
+ ] }),
292
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
293
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-medium uppercase text-muted-foreground", children: "Largest" }),
294
+ largestRole === null ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-0.5 text-muted-foreground", children: "Unknown" }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
295
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-0.5 flex min-w-0 items-center gap-1.5", children: [
296
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
297
+ "span",
298
+ {
299
+ "aria-hidden": "true",
300
+ className: cn(
301
+ "size-2.5 shrink-0 rounded-[2px]",
302
+ ROLE_COLOR_CLASSES[largestRole.role]
303
+ )
304
+ }
305
+ ),
306
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate text-foreground", children: largestRole.label })
307
+ ] }),
308
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "truncate font-mono text-[11px] text-muted-foreground", children: [
309
+ formatPercent(largestRole.percent * 100),
310
+ " | ~",
311
+ formatTokens(largestRole.tokens)
312
+ ] })
313
+ ] })
314
+ ] })
315
+ ] }),
316
+ intelligence.contextWindow.tokens !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
317
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative h-2 overflow-hidden rounded-full bg-muted/40", children: [
318
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
319
+ "div",
320
+ {
321
+ className: cn("h-full rounded-full", RISK_CLASS[intelligence.riskLevel]),
322
+ style: { width: `${String(usageWidth)}%` }
323
+ }
324
+ ),
325
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
326
+ "div",
327
+ {
328
+ "aria-hidden": "true",
329
+ className: "absolute top-0 h-full w-px bg-amber-200/70",
330
+ style: { left: `${String(CONTEXT_USAGE_THRESHOLDS.watch * 100)}%` }
331
+ }
332
+ ),
333
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
334
+ "div",
335
+ {
336
+ "aria-hidden": "true",
337
+ className: "absolute top-0 h-full w-px bg-red-200/80",
338
+ style: { left: `${String(CONTEXT_USAGE_THRESHOLDS.danger * 100)}%` }
339
+ }
340
+ )
341
+ ] }),
342
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-[10px] text-muted-foreground", children: [
343
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Context window" }),
344
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
345
+ "Watch ",
346
+ formatUsagePercent(CONTEXT_USAGE_THRESHOLDS.watch),
347
+ " / Danger",
348
+ " ",
349
+ formatUsagePercent(CONTEXT_USAGE_THRESHOLDS.danger)
350
+ ] })
351
+ ] })
352
+ ] }),
353
+ visibleDiagnostics.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid gap-1.5 sm:grid-cols-2", children: visibleDiagnostics.map((diagnostic) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
354
+ "div",
355
+ {
356
+ className: cn("rounded border px-2 py-1.5 text-xs", diagnosticTone(diagnostic)),
357
+ children: [
358
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium", children: diagnostic.title }),
359
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-0.5 text-[11px] text-muted-foreground", children: diagnostic.detail })
360
+ ]
361
+ },
362
+ `${diagnostic.kind}-${diagnostic.title}`
363
+ )) })
364
+ ] });
365
+ }
366
+ function resolveDuplicateSegment(duplicateSegment, segments) {
367
+ return segments.find((segment) => segment.path === duplicateSegment.path) ?? null;
368
+ }
369
+ function DuplicateContentPanel({
370
+ groups,
371
+ segments,
372
+ onSegmentActivate
373
+ }) {
374
+ const [expanded, setExpanded] = reactExports.useState(false);
375
+ if (groups.length === 0) return null;
376
+ const visibleGroups = groups.slice(0, DUPLICATE_GROUP_DISPLAY_COUNT);
377
+ const hiddenGroupCount = groups.length - visibleGroups.length;
378
+ const totalRepeatedTokens = groups.reduce((sum, group) => sum + group.repeatedTokens, 0);
379
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "space-y-2 rounded border border-border/70 bg-muted/15 p-2", children: [
380
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
381
+ "button",
382
+ {
383
+ type: "button",
384
+ onClick: () => setExpanded((current) => !current),
385
+ "aria-expanded": expanded,
386
+ className: "flex w-full flex-wrap items-center justify-between gap-2 rounded px-1 py-0.5 text-left transition-colors hover:bg-muted/30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
387
+ children: [
388
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex min-w-0 items-center gap-1.5", children: [
389
+ expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-3.5 shrink-0 text-muted-foreground" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-3.5 shrink-0 text-muted-foreground" }),
390
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate text-xs font-medium text-foreground", children: "Duplicate Content" })
391
+ ] }),
392
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-[11px] text-muted-foreground", children: [
393
+ String(groups.length),
394
+ " group",
395
+ groups.length === 1 ? "" : "s",
396
+ " | ~",
397
+ formatTokens(totalRepeatedTokens),
398
+ " repeated"
399
+ ] })
400
+ ]
401
+ }
402
+ ),
403
+ expanded && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
404
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2", children: visibleGroups.map((group, groupIndex) => {
405
+ const visibleSegments = group.segments.slice(0, DUPLICATE_SEGMENT_DISPLAY_COUNT);
406
+ const hiddenSegmentCount = group.segments.length - visibleSegments.length;
407
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
408
+ "div",
409
+ {
410
+ className: "space-y-1.5 border-t border-border/50 pt-2 first:border-t-0 first:pt-0",
411
+ children: [
412
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 items-center gap-2 text-xs", children: [
413
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-5 shrink-0 text-right font-mono text-muted-foreground/70", children: String(groupIndex + 1) }),
414
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0 flex-1 truncate text-foreground", children: group.firstLabel }),
415
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "shrink-0 font-mono text-muted-foreground", children: [
416
+ "x",
417
+ String(group.count),
418
+ " | ~",
419
+ formatTokens(group.repeatedTokens),
420
+ " saved"
421
+ ] })
422
+ ] }),
423
+ group.preview.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ml-7 line-clamp-2 break-words rounded bg-background/40 px-2 py-1 font-mono text-[11px] leading-4 text-muted-foreground", children: group.preview }),
424
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ml-7 flex flex-wrap gap-1", children: [
425
+ visibleSegments.map((duplicateSegment, segmentIndex) => {
426
+ const target = resolveDuplicateSegment(duplicateSegment, segments);
427
+ const activate = target === null || onSegmentActivate === void 0 ? void 0 : onSegmentActivate;
428
+ const label = `${duplicateSegment.label} ~${formatTokens(
429
+ duplicateSegment.tokens
430
+ )}`;
431
+ if (activate === void 0 || target === null) {
432
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
433
+ "span",
434
+ {
435
+ className: "inline-flex h-6 max-w-40 items-center rounded border border-border/60 px-1.5 text-[11px] text-muted-foreground",
436
+ title: label,
437
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: label })
438
+ },
439
+ `${duplicateSegment.path}-${segmentIndex}`
440
+ );
441
+ }
442
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
443
+ "button",
444
+ {
445
+ type: "button",
446
+ onClick: () => activate(target),
447
+ className: "inline-flex h-6 max-w-40 items-center rounded border border-border/60 px-1.5 text-[11px] text-muted-foreground hover:border-border hover:bg-muted/40 hover:text-foreground",
448
+ title: "Jump to this duplicate block",
449
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: label })
450
+ },
451
+ `${duplicateSegment.path}-${segmentIndex}`
452
+ );
453
+ }),
454
+ hiddenSegmentCount > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex h-6 items-center rounded border border-border/40 px-1.5 font-mono text-[11px] text-muted-foreground/70", children: [
455
+ "+",
456
+ String(hiddenSegmentCount)
457
+ ] })
458
+ ] })
459
+ ]
460
+ },
461
+ group.key
462
+ );
463
+ }) }),
464
+ hiddenGroupCount > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-border/50 pt-2 font-mono text-[11px] text-muted-foreground", children: [
465
+ "+",
466
+ String(hiddenGroupCount),
467
+ " more duplicate group",
468
+ hiddenGroupCount === 1 ? "" : "s"
469
+ ] })
470
+ ] })
471
+ ] });
472
+ }
473
+ function aggregateByRole(segments) {
474
+ const result = [];
475
+ for (const role of ROLE_ORDER) {
476
+ const matching = segments.filter((segment) => segment.role === role);
477
+ if (matching.length === 0) continue;
478
+ const size = matching.reduce((sum, segment) => sum + segment.size, 0);
479
+ const characters = matching.reduce((sum, segment) => sum + segment.characters, 0);
480
+ const label = ANATOMY_ROLE_LABELS[role];
481
+ const text = `${matching.length} segment${matching.length === 1 ? "" : "s"} grouped as ${ROLE_DESCRIPTIONS[role]}`;
482
+ result.push({
483
+ role,
484
+ label,
485
+ size,
486
+ characters,
487
+ text,
488
+ path: `role:${role}`
489
+ });
490
+ }
491
+ return result;
492
+ }
493
+ function topContributors(segments) {
494
+ return [...segments].sort((a, b) => b.size - a.size).slice(0, TOP_CONTRIBUTOR_COUNT);
495
+ }
496
+ function RequestAnatomy({
497
+ parsed,
498
+ inputTokens,
499
+ model = null,
500
+ onSegmentActivate,
501
+ segments: providedSegments
502
+ }) {
503
+ const { providers } = useProviders();
504
+ const [viewMode, setViewMode] = reactExports.useState("role");
505
+ const segments = reactExports.useMemo(() => providedSegments ?? null, [providedSegments]);
506
+ const total = reactExports.useMemo(
507
+ () => (segments ?? []).reduce((sum, segment) => sum + segment.size, 0),
508
+ [segments]
509
+ );
510
+ const roleSegments = reactExports.useMemo(
511
+ () => segments === null ? [] : aggregateByRole(segments),
512
+ [segments]
513
+ );
514
+ const topSegments = reactExports.useMemo(
515
+ () => segments === null ? [] : topContributors(segments),
516
+ [segments]
517
+ );
518
+ const intelligence = reactExports.useMemo(
519
+ () => segments === null ? null : analyzeContextIntelligence({
520
+ segments,
521
+ inputTokens,
522
+ parsed,
523
+ model,
524
+ providers
525
+ }),
526
+ [inputTokens, model, parsed, providers, segments]
527
+ );
528
+ const showDivergenceWarning = reactExports.useMemo(() => {
529
+ if (segments === null) return false;
530
+ if (inputTokens === null) return false;
531
+ if (total === 0) return false;
532
+ const ratio = Math.abs(inputTokens - total) / Math.max(inputTokens, total);
533
+ return ratio >= DIVERGENCE_AMBER_THRESHOLD;
534
+ }, [inputTokens, segments, total]);
535
+ if (segments === null) return null;
536
+ if (segments.length === 0) return null;
537
+ if (parsed === null && providedSegments === void 0) return null;
538
+ const summaryColorClass = inputTokens !== null && showDivergenceWarning ? "text-amber-400" : "text-muted-foreground";
539
+ const displayedSegments = viewMode === "role" ? roleSegments : segments;
540
+ const displayedTotal = total > 0 ? total : displayedSegments.reduce((sum, item) => sum + item.size, 0);
541
+ const activateSegment = viewMode === "segment" ? onSegmentActivate : void 0;
542
+ const segmentCountLabel = `${String(segments.length)} segment${segments.length === 1 ? "" : "s"}`;
543
+ const providerInputLabel = inputTokens === null ? "Provider input unknown" : `Provider input ${formatTokens(inputTokens)}`;
544
+ const contextLimitLabel = intelligence === null ? "Limit unknown" : `Limit ${formatContextLimit(intelligence)}`;
545
+ const usageLabel = intelligence === null ? "Usage unknown" : `${formatUsagePercent(intelligence.usagePercent)} used`;
546
+ 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: [
547
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [
548
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
549
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-2", children: [
550
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm font-semibold text-foreground", children: "Request Context" }),
551
+ intelligence !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(ContextHealthBadge, { health: intelligence.health })
552
+ ] }),
553
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cn("mt-0.5 text-xs font-mono tabular-nums", summaryColorClass), children: [
554
+ "Estimated ~",
555
+ formatTokens(total),
556
+ " tokens | ",
557
+ providerInputLabel,
558
+ " | ",
559
+ contextLimitLabel,
560
+ " |",
561
+ " ",
562
+ usageLabel,
563
+ " | ",
564
+ segmentCountLabel
565
+ ] })
566
+ ] }),
567
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
568
+ "div",
569
+ {
570
+ className: "inline-flex shrink-0 rounded border border-border bg-muted/20 p-0.5",
571
+ role: "group",
572
+ "aria-label": "Context breakdown mode",
573
+ children: VIEW_MODE_OPTIONS.map((option) => /* @__PURE__ */ jsxRuntimeExports.jsx(
574
+ "button",
575
+ {
576
+ type: "button",
577
+ "aria-pressed": viewMode === option.value,
578
+ onClick: () => setViewMode(option.value),
579
+ className: cn(
580
+ "h-6 rounded-sm px-2 text-[11px] font-medium transition-colors",
581
+ viewMode === option.value ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
582
+ ),
583
+ children: option.label
584
+ },
585
+ option.value
586
+ ))
587
+ }
588
+ )
589
+ ] }),
590
+ showDivergenceWarning && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "inline-flex items-center gap-1.5 text-xs text-amber-400", children: [
591
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
592
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
593
+ "button",
594
+ {
595
+ type: "button",
596
+ className: "inline-flex items-center hover:text-amber-300",
597
+ "aria-label": "Token estimate differs from provider input",
598
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(Info, { className: "size-3.5" })
599
+ }
600
+ ) }),
601
+ /* @__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." })
602
+ ] }),
603
+ "Estimate differs from provider-reported input."
604
+ ] }),
605
+ intelligence !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(ContextIntelligenceStrip, { intelligence }),
606
+ intelligence !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(
607
+ DuplicateContentPanel,
608
+ {
609
+ groups: intelligence.duplicateGroups,
610
+ segments,
611
+ onSegmentActivate
612
+ }
613
+ ),
614
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
615
+ SegmentBar,
616
+ {
617
+ segments: displayedSegments,
618
+ totalTokens: displayedTotal,
619
+ showLabels: viewMode === "segment",
620
+ onActivate: activateSegment
621
+ }
622
+ ),
623
+ /* @__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) => {
624
+ const percent = total > 0 ? segment.size / total * 100 : 0;
625
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "inline-flex items-center gap-1.5", children: [
626
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
627
+ "span",
628
+ {
629
+ "aria-hidden": "true",
630
+ className: cn("size-2.5 rounded-[2px]", ROLE_COLOR_CLASSES[segment.role])
631
+ }
632
+ ),
633
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: segment.label }),
634
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-muted-foreground/70", children: formatPercent(percent) })
635
+ ] }, segment.role);
636
+ }) }),
637
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
638
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-medium text-foreground", children: "Top Contributors" }),
639
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid gap-1", children: topSegments.map((segment, index) => {
640
+ const percent = total > 0 ? segment.size / total * 100 : 0;
641
+ const activate = onSegmentActivate;
642
+ const content = /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
643
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-5 shrink-0 text-right font-mono text-muted-foreground/70", children: String(index + 1) }),
644
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
645
+ "span",
646
+ {
647
+ "aria-hidden": "true",
648
+ className: cn(
649
+ "size-2.5 shrink-0 rounded-[2px]",
650
+ ROLE_COLOR_CLASSES[segment.role]
651
+ )
652
+ }
653
+ ),
654
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0 flex-1 truncate text-left", children: segment.label }),
655
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "shrink-0 font-mono text-muted-foreground", children: [
656
+ formatPercent(percent),
657
+ " | ~",
658
+ formatTokens(segment.size)
659
+ ] })
660
+ ] });
661
+ if (activate !== void 0) {
662
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
663
+ "button",
664
+ {
665
+ type: "button",
666
+ onClick: () => activate(segment),
667
+ className: "flex h-7 items-center gap-2 rounded px-1.5 text-xs text-muted-foreground hover:bg-muted/40 hover:text-foreground",
668
+ title: "Jump to this request block",
669
+ children: content
670
+ },
671
+ `${segment.path}-${index}`
672
+ );
673
+ }
674
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
675
+ "div",
676
+ {
677
+ className: "flex h-7 items-center gap-2 rounded px-1.5 text-xs text-muted-foreground",
678
+ children: content
679
+ },
680
+ `${segment.path}-${index}`
681
+ );
682
+ }) })
683
+ ] })
684
+ ] }) });
685
+ }
686
+ export {
687
+ RequestAnatomy
688
+ };