@tonyclaw/agent-inspector 2.0.6 → 2.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/nitro.json +1 -1
- package/.output/public/assets/CompareDrawer-Djb4XFZS.js +1 -0
- package/.output/public/assets/ProxyViewerContainer-CWdkPZsJ.js +114 -0
- package/.output/public/assets/ReplayDialog-DBPMIs2I.js +1 -0
- package/.output/public/assets/RequestAnatomy-FBfRNQN7.js +1 -0
- package/.output/public/assets/ResponseView-Db4pJL7U.js +1 -0
- package/.output/public/assets/StreamingChunkSequence-BH175O6R.js +1 -0
- package/.output/public/assets/_sessionId-3ipVoQtW.js +1 -0
- package/.output/public/assets/index-Bo1dGS4R.css +1 -0
- package/.output/public/assets/index-CJgaCJo8.js +1 -0
- package/.output/public/assets/{main-CKnTJ4-O.js → main-CwhqfJqM.js} +8 -8
- package/.output/server/_libs/lucide-react.mjs +170 -108
- package/.output/server/_libs/radix-ui__react-collapsible.mjs +2 -2
- package/.output/server/{_sessionId-B-x9fRY3.mjs → _sessionId-DzBy9gLa.mjs} +58 -5
- package/.output/server/_ssr/{CompareDrawer-BQVNsAY2.mjs → CompareDrawer-C5NBvE2e.mjs} +9 -8
- package/.output/server/_ssr/{ProxyViewerContainer-CYm2Dw19.mjs → ProxyViewerContainer-DiZjOTQT.mjs} +857 -32
- package/.output/server/_ssr/{ReplayDialog-CaMQBc79.mjs → ReplayDialog-EpvTwFvp.mjs} +7 -8
- package/.output/server/_ssr/{RequestAnatomy--P5arRH2.mjs → RequestAnatomy-DaQjhixp.mjs} +512 -7
- package/.output/server/_ssr/{ResponseView-RtFwNvgD.mjs → ResponseView-D8tGHCGY.mjs} +5 -74
- package/.output/server/_ssr/{StreamingChunkSequence-B5HPkzab.mjs → StreamingChunkSequence-DGQnb1QE.mjs} +8 -7
- package/.output/server/_ssr/{index-CZIKZU43.mjs → index-N25hqa7t.mjs} +58 -5
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-DGPt3MUc.mjs → router-Bf0m6F0G.mjs} +22 -6
- package/.output/server/{_tanstack-start-manifest_v-BzH4pNaI.mjs → _tanstack-start-manifest_v-DlAyJ5DB.mjs} +1 -1
- package/.output/server/index.mjs +61 -68
- package/package.json +1 -1
- package/src/components/proxy-viewer/LogEntry.tsx +17 -2
- package/src/components/proxy-viewer/RequestToolsPanel.tsx +292 -0
- package/src/components/proxy-viewer/anatomy/RequestAnatomy.tsx +197 -1
- package/src/components/proxy-viewer/anatomy/contextIntelligence.ts +414 -0
- package/src/components/proxy-viewer/requestTools.ts +213 -0
- package/src/routes/__root.tsx +27 -0
- package/.output/public/assets/CompareDrawer-DDmqSAfl.js +0 -1
- package/.output/public/assets/ProxyViewerContainer-Cxpdziwd.js +0 -101
- package/.output/public/assets/ReplayDialog-Bt5DGzlh.js +0 -1
- package/.output/public/assets/RequestAnatomy-BxX3_N9S.js +0 -1
- package/.output/public/assets/ResponseView-Bl_5S9gZ.js +0 -1
- package/.output/public/assets/StreamingChunkSequence-RJMwNf6F.js +0 -1
- package/.output/public/assets/_sessionId-b4isaoDp.js +0 -1
- package/.output/public/assets/index-BZ4x5UI6.js +0 -1
- package/.output/public/assets/index-C624DUk9.css +0 -1
- package/.output/public/assets/json-viewer-CRL_gWEZ.js +0 -14
- package/.output/server/_ssr/json-viewer-d4obyRaA.mjs +0 -515
|
@@ -1,10 +1,9 @@
|
|
|
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-
|
|
3
|
-
import { ResponseView } from "./ResponseView-
|
|
4
|
-
import "./router-
|
|
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-DiZjOTQT.mjs";
|
|
3
|
+
import { ResponseView } from "./ResponseView-D8tGHCGY.mjs";
|
|
4
|
+
import "./router-Bf0m6F0G.mjs";
|
|
5
5
|
import "../_libs/modelcontextprotocol__server.mjs";
|
|
6
6
|
import "../_libs/jszip.mjs";
|
|
7
|
-
import "./json-viewer-d4obyRaA.mjs";
|
|
8
7
|
import { I as RotateCcw } from "../_libs/lucide-react.mjs";
|
|
9
8
|
import { d as object, c as boolean, n as number, b as string } from "../_libs/zod.mjs";
|
|
10
9
|
import "../_libs/swr.mjs";
|
|
@@ -58,9 +57,6 @@ import "../_libs/radix-ui__react-arrow.mjs";
|
|
|
58
57
|
import "../_libs/radix-ui__react-use-size.mjs";
|
|
59
58
|
import "../_libs/radix-ui__react-use-previous.mjs";
|
|
60
59
|
import "../_libs/@radix-ui/react-visually-hidden+[...].mjs";
|
|
61
|
-
import "../_libs/radix-ui__react-tooltip.mjs";
|
|
62
|
-
import "../_libs/radix-ui__react-tabs.mjs";
|
|
63
|
-
import "../_libs/radix-ui__react-roving-focus.mjs";
|
|
64
60
|
import "../_libs/react-markdown.mjs";
|
|
65
61
|
import "../_libs/devlop.mjs";
|
|
66
62
|
import "../_libs/unified.mjs";
|
|
@@ -115,9 +111,12 @@ import "../_libs/inline-style-parser.mjs";
|
|
|
115
111
|
import "../_libs/hast-util-whitespace.mjs";
|
|
116
112
|
import "../_libs/estree-util-is-identifier-name.mjs";
|
|
117
113
|
import "../_libs/html-url-attributes.mjs";
|
|
118
|
-
import "../_libs/radix-ui__react-
|
|
114
|
+
import "../_libs/radix-ui__react-tooltip.mjs";
|
|
115
|
+
import "../_libs/radix-ui__react-tabs.mjs";
|
|
116
|
+
import "../_libs/radix-ui__react-roving-focus.mjs";
|
|
119
117
|
import "../_libs/radix-ui__react-collapsible.mjs";
|
|
120
118
|
import "../_libs/radix-ui__react-scroll-area.mjs";
|
|
119
|
+
import "../_libs/radix-ui__react-separator.mjs";
|
|
121
120
|
import "../_libs/tanstack__react-router.mjs";
|
|
122
121
|
import "../_libs/tiny-warning.mjs";
|
|
123
122
|
import "../_libs/tanstack__router-core.mjs";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
|
|
2
|
-
import { f as formatTokens, k as TooltipProvider, c as cn, l as Tooltip, m as TooltipTrigger, n as TooltipContent } from "./ProxyViewerContainer-
|
|
3
|
-
import "./router-
|
|
4
|
-
import "../_libs/modelcontextprotocol__server.mjs";
|
|
2
|
+
import { f as formatTokens, k as TooltipProvider, c as cn, l as Tooltip, m as TooltipTrigger, n as TooltipContent } from "./ProxyViewerContainer-DiZjOTQT.mjs";
|
|
3
|
+
import { s as safeGetOwnProperty } from "./router-Bf0m6F0G.mjs";
|
|
5
4
|
import "../_libs/jszip.mjs";
|
|
6
|
-
import
|
|
5
|
+
import "../_libs/modelcontextprotocol__server.mjs";
|
|
6
|
+
import { aa 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";
|
|
@@ -55,10 +55,66 @@ import "../_libs/radix-ui__react-arrow.mjs";
|
|
|
55
55
|
import "../_libs/radix-ui__react-use-size.mjs";
|
|
56
56
|
import "../_libs/radix-ui__react-use-previous.mjs";
|
|
57
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";
|
|
58
112
|
import "../_libs/zod.mjs";
|
|
59
113
|
import "../_libs/radix-ui__react-tooltip.mjs";
|
|
60
114
|
import "../_libs/radix-ui__react-tabs.mjs";
|
|
61
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";
|
|
62
118
|
import "../_libs/tanstack__react-router.mjs";
|
|
63
119
|
import "../_libs/tiny-warning.mjs";
|
|
64
120
|
import "../_libs/tanstack__router-core.mjs";
|
|
@@ -73,12 +129,9 @@ import "../_libs/isbot.mjs";
|
|
|
73
129
|
import "node:fs";
|
|
74
130
|
import "node:fs/promises";
|
|
75
131
|
import "node:buffer";
|
|
76
|
-
import "node:path";
|
|
77
132
|
import "node:child_process";
|
|
78
|
-
import "node:url";
|
|
79
133
|
import "../_libs/conf.mjs";
|
|
80
134
|
import "node:util";
|
|
81
|
-
import "node:process";
|
|
82
135
|
import "node:crypto";
|
|
83
136
|
import "node:assert";
|
|
84
137
|
import "../_libs/dot-prop.mjs";
|
|
@@ -112,6 +165,297 @@ import "../_libs/lie.mjs";
|
|
|
112
165
|
import "../_libs/immediate.mjs";
|
|
113
166
|
import "../_libs/setimmediate.mjs";
|
|
114
167
|
import "../_libs/pako.mjs";
|
|
168
|
+
const WATCH_USAGE_PERCENT = 0.75;
|
|
169
|
+
const DANGER_USAGE_PERCENT = 0.9;
|
|
170
|
+
const LONG_TOOL_SCHEMA_TOKENS = 8e3;
|
|
171
|
+
const LARGE_ROLE_PERCENT = 0.35;
|
|
172
|
+
const DUPLICATE_MIN_TOKENS = 40;
|
|
173
|
+
const DUPLICATE_MIN_CHARS = 160;
|
|
174
|
+
const HISTORY_BLOAT_SEGMENTS = 18;
|
|
175
|
+
const HISTORY_BLOAT_TOKENS = 6e4;
|
|
176
|
+
const HISTORY_BLOAT_PERCENT = 0.7;
|
|
177
|
+
const SYSTEM_HEAVY_TOKENS = 3e3;
|
|
178
|
+
const SYSTEM_HEAVY_PERCENT = 0.3;
|
|
179
|
+
const EXPLICIT_CONTEXT_WINDOW_FIELDS = [
|
|
180
|
+
"context_window",
|
|
181
|
+
"contextWindow",
|
|
182
|
+
"context_length",
|
|
183
|
+
"contextLength",
|
|
184
|
+
"max_context_length",
|
|
185
|
+
"maxContextLength",
|
|
186
|
+
"max_input_tokens",
|
|
187
|
+
"maxInputTokens"
|
|
188
|
+
];
|
|
189
|
+
const OUTPUT_RESERVE_FIELDS = [
|
|
190
|
+
"max_tokens",
|
|
191
|
+
"maxTokens",
|
|
192
|
+
"max_completion_tokens",
|
|
193
|
+
"maxCompletionTokens",
|
|
194
|
+
"max_output_tokens",
|
|
195
|
+
"maxOutputTokens"
|
|
196
|
+
];
|
|
197
|
+
const MODEL_CONTEXT_RULES = [
|
|
198
|
+
{
|
|
199
|
+
family: "OpenAI GPT-4.1",
|
|
200
|
+
tokens: 1047576,
|
|
201
|
+
mode: "prefix",
|
|
202
|
+
patterns: ["gpt-4.1"]
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
family: "OpenAI GPT-4o",
|
|
206
|
+
tokens: 128e3,
|
|
207
|
+
mode: "prefix",
|
|
208
|
+
patterns: ["gpt-4o"]
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
family: "OpenAI o-series",
|
|
212
|
+
tokens: 128e3,
|
|
213
|
+
mode: "prefix",
|
|
214
|
+
patterns: ["o1", "o3", "o4"]
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
family: "Anthropic Claude",
|
|
218
|
+
tokens: 2e5,
|
|
219
|
+
mode: "prefix",
|
|
220
|
+
patterns: ["claude-"]
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
family: "DeepSeek",
|
|
224
|
+
tokens: 64e3,
|
|
225
|
+
mode: "prefix",
|
|
226
|
+
patterns: ["deepseek-"]
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
family: "MiniMax",
|
|
230
|
+
tokens: 1e6,
|
|
231
|
+
mode: "includes",
|
|
232
|
+
patterns: ["minimax"]
|
|
233
|
+
}
|
|
234
|
+
];
|
|
235
|
+
const ROLE_LABELS = {
|
|
236
|
+
system: "System",
|
|
237
|
+
user: "User messages",
|
|
238
|
+
assistant: "Assistant messages",
|
|
239
|
+
tool: "Tool results",
|
|
240
|
+
tools: "Tool definitions"
|
|
241
|
+
};
|
|
242
|
+
function readPositiveInteger(value) {
|
|
243
|
+
if (typeof value === "number") {
|
|
244
|
+
if (Number.isFinite(value) && value > 0) return Math.floor(value);
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
if (typeof value === "string") {
|
|
248
|
+
const parsed = Number(value);
|
|
249
|
+
if (Number.isFinite(parsed) && parsed > 0) return Math.floor(parsed);
|
|
250
|
+
}
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
function readPositiveIntegerField(parsed, fields) {
|
|
254
|
+
for (const field of fields) {
|
|
255
|
+
const value = readPositiveInteger(safeGetOwnProperty(parsed, field));
|
|
256
|
+
if (value !== null) return value;
|
|
257
|
+
}
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
function readRequestModel(parsed) {
|
|
261
|
+
const value = safeGetOwnProperty(parsed, "model");
|
|
262
|
+
if (typeof value !== "string") return null;
|
|
263
|
+
const trimmed = value.trim();
|
|
264
|
+
return trimmed === "" ? null : trimmed;
|
|
265
|
+
}
|
|
266
|
+
function matchesRule(model, rule) {
|
|
267
|
+
switch (rule.mode) {
|
|
268
|
+
case "prefix":
|
|
269
|
+
return rule.patterns.some((pattern) => model.startsWith(pattern));
|
|
270
|
+
case "includes":
|
|
271
|
+
return rule.patterns.some((pattern) => model.includes(pattern));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
function resolveContextWindow(model, parsed) {
|
|
275
|
+
const explicitWindow = readPositiveIntegerField(parsed, EXPLICIT_CONTEXT_WINDOW_FIELDS);
|
|
276
|
+
if (explicitWindow !== null) {
|
|
277
|
+
return {
|
|
278
|
+
tokens: explicitWindow,
|
|
279
|
+
label: "Request metadata",
|
|
280
|
+
source: "request"
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
if (model === null) {
|
|
284
|
+
return {
|
|
285
|
+
tokens: null,
|
|
286
|
+
label: "Unknown model",
|
|
287
|
+
source: "unknown"
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
const normalized = model.trim().toLowerCase();
|
|
291
|
+
for (const rule of MODEL_CONTEXT_RULES) {
|
|
292
|
+
if (matchesRule(normalized, rule)) {
|
|
293
|
+
return {
|
|
294
|
+
tokens: rule.tokens,
|
|
295
|
+
label: rule.family,
|
|
296
|
+
source: "model-rule"
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
tokens: null,
|
|
302
|
+
label: "No local rule",
|
|
303
|
+
source: "unknown"
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
function clampPercent(value) {
|
|
307
|
+
if (value < 0) return 0;
|
|
308
|
+
if (value > 1) return 1;
|
|
309
|
+
return value;
|
|
310
|
+
}
|
|
311
|
+
function riskLevel(usagePercent) {
|
|
312
|
+
if (usagePercent === null) return "unknown";
|
|
313
|
+
if (usagePercent >= DANGER_USAGE_PERCENT) return "danger";
|
|
314
|
+
if (usagePercent >= WATCH_USAGE_PERCENT) return "watch";
|
|
315
|
+
return "ok";
|
|
316
|
+
}
|
|
317
|
+
function sumSegments(segments, role) {
|
|
318
|
+
return segments.filter((segment) => segment.role === role).reduce((sum, segment) => sum + segment.size, 0);
|
|
319
|
+
}
|
|
320
|
+
function buildRoleUsages(segments, total) {
|
|
321
|
+
const roles = ["system", "user", "assistant", "tool", "tools"];
|
|
322
|
+
return roles.map((role) => {
|
|
323
|
+
const tokens = sumSegments(segments, role);
|
|
324
|
+
return {
|
|
325
|
+
role,
|
|
326
|
+
label: ROLE_LABELS[role],
|
|
327
|
+
tokens,
|
|
328
|
+
percent: total > 0 ? tokens / total : 0
|
|
329
|
+
};
|
|
330
|
+
}).filter((usage) => usage.tokens > 0).sort((a, b) => b.tokens - a.tokens);
|
|
331
|
+
}
|
|
332
|
+
function normalizeDuplicateText(text) {
|
|
333
|
+
return text.replace(/\s+/g, " ").trim().toLowerCase();
|
|
334
|
+
}
|
|
335
|
+
function duplicateDiagnostic(segments) {
|
|
336
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
337
|
+
for (const segment of segments) {
|
|
338
|
+
if (segment.size < DUPLICATE_MIN_TOKENS) continue;
|
|
339
|
+
if (segment.characters < DUPLICATE_MIN_CHARS) continue;
|
|
340
|
+
const normalized = normalizeDuplicateText(segment.text);
|
|
341
|
+
if (normalized === "") continue;
|
|
342
|
+
const existing = buckets.get(normalized);
|
|
343
|
+
if (existing === void 0) {
|
|
344
|
+
buckets.set(normalized, {
|
|
345
|
+
count: 1,
|
|
346
|
+
tokens: segment.size,
|
|
347
|
+
firstTokens: segment.size,
|
|
348
|
+
label: segment.label
|
|
349
|
+
});
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
buckets.set(normalized, {
|
|
353
|
+
count: existing.count + 1,
|
|
354
|
+
tokens: existing.tokens + segment.size,
|
|
355
|
+
firstTokens: existing.firstTokens,
|
|
356
|
+
label: existing.label
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
let repeatedGroups = 0;
|
|
360
|
+
let repeatedSegments = 0;
|
|
361
|
+
let repeatedTokens = 0;
|
|
362
|
+
let largest = null;
|
|
363
|
+
for (const bucket of buckets.values()) {
|
|
364
|
+
if (bucket.count < 2) continue;
|
|
365
|
+
repeatedGroups += 1;
|
|
366
|
+
repeatedSegments += bucket.count;
|
|
367
|
+
repeatedTokens += bucket.tokens - bucket.firstTokens;
|
|
368
|
+
if (largest === null || bucket.tokens > largest.tokens) largest = bucket;
|
|
369
|
+
}
|
|
370
|
+
if (repeatedGroups === 0 || largest === null) return null;
|
|
371
|
+
return {
|
|
372
|
+
kind: "duplicate",
|
|
373
|
+
severity: repeatedTokens >= LONG_TOOL_SCHEMA_TOKENS ? "danger" : "watch",
|
|
374
|
+
title: "Duplicate context",
|
|
375
|
+
detail: `${String(repeatedSegments)} repeated blocks across ${String(
|
|
376
|
+
repeatedGroups
|
|
377
|
+
)} group${repeatedGroups === 1 ? "" : "s"}, ~${String(repeatedTokens)} repeated tokens.`
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
function diagnosticsForRolePressure(roleUsages, total, messageSegmentCount) {
|
|
381
|
+
const diagnostics = [];
|
|
382
|
+
const toolUsage = roleUsages.find((usage) => usage.role === "tools") ?? null;
|
|
383
|
+
if (toolUsage !== null && (toolUsage.tokens >= LONG_TOOL_SCHEMA_TOKENS || toolUsage.percent >= LARGE_ROLE_PERCENT && toolUsage.tokens >= SYSTEM_HEAVY_TOKENS)) {
|
|
384
|
+
diagnostics.push({
|
|
385
|
+
kind: "tool-schema",
|
|
386
|
+
severity: toolUsage.tokens >= LONG_TOOL_SCHEMA_TOKENS ? "danger" : "watch",
|
|
387
|
+
title: "Large tool schema",
|
|
388
|
+
detail: `Tool definitions take ${Math.round(toolUsage.percent * 100)}% of request context.`
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
const systemUsage = roleUsages.find((usage) => usage.role === "system") ?? null;
|
|
392
|
+
if (systemUsage !== null && systemUsage.tokens >= SYSTEM_HEAVY_TOKENS && systemUsage.percent >= SYSTEM_HEAVY_PERCENT) {
|
|
393
|
+
diagnostics.push({
|
|
394
|
+
kind: "system-heavy",
|
|
395
|
+
severity: "watch",
|
|
396
|
+
title: "Large system prompt",
|
|
397
|
+
detail: `System instructions take ${Math.round(systemUsage.percent * 100)}% of request context.`
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
const historyTokens = roleUsages.filter((usage) => usage.role === "user" || usage.role === "assistant" || usage.role === "tool").reduce((sum, usage) => sum + usage.tokens, 0);
|
|
401
|
+
const historyPercent = total > 0 ? historyTokens / total : 0;
|
|
402
|
+
if (messageSegmentCount >= HISTORY_BLOAT_SEGMENTS && (historyTokens >= HISTORY_BLOAT_TOKENS || historyPercent >= HISTORY_BLOAT_PERCENT)) {
|
|
403
|
+
diagnostics.push({
|
|
404
|
+
kind: "history-bloat",
|
|
405
|
+
severity: historyPercent >= 0.85 ? "danger" : "watch",
|
|
406
|
+
title: "Conversation history growth",
|
|
407
|
+
detail: `${String(messageSegmentCount)} message blocks take ${Math.round(
|
|
408
|
+
historyPercent * 100
|
|
409
|
+
)}% of request context.`
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
return diagnostics;
|
|
413
|
+
}
|
|
414
|
+
function analyzeContextIntelligence({
|
|
415
|
+
segments,
|
|
416
|
+
inputTokens,
|
|
417
|
+
parsed,
|
|
418
|
+
model
|
|
419
|
+
}) {
|
|
420
|
+
const totalEstimatedTokens = segments.reduce((sum, segment) => sum + segment.size, 0);
|
|
421
|
+
const requestModel = model ?? readRequestModel(parsed);
|
|
422
|
+
const estimatedInputTokens = inputTokens ?? totalEstimatedTokens;
|
|
423
|
+
const outputReserveTokens = readPositiveIntegerField(parsed, OUTPUT_RESERVE_FIELDS);
|
|
424
|
+
const contextWindow = resolveContextWindow(requestModel, parsed);
|
|
425
|
+
const reservedTokens = outputReserveTokens ?? 0;
|
|
426
|
+
const windowUsedTokens = contextWindow.tokens === null ? null : estimatedInputTokens + reservedTokens;
|
|
427
|
+
const remainingInputTokens = contextWindow.tokens === null ? null : contextWindow.tokens - estimatedInputTokens;
|
|
428
|
+
const remainingAfterReserveTokens = contextWindow.tokens === null ? null : contextWindow.tokens - estimatedInputTokens - reservedTokens;
|
|
429
|
+
const usagePercent = contextWindow.tokens === null || windowUsedTokens === null ? null : clampPercent(windowUsedTokens / contextWindow.tokens);
|
|
430
|
+
const roleUsages = buildRoleUsages(segments, totalEstimatedTokens);
|
|
431
|
+
const largestRole = roleUsages[0] ?? null;
|
|
432
|
+
const messageSegmentCount = segments.filter((segment) => segment.role !== "tools").length;
|
|
433
|
+
const duplicate = duplicateDiagnostic(segments);
|
|
434
|
+
const diagnostics = diagnosticsForRolePressure(
|
|
435
|
+
roleUsages,
|
|
436
|
+
totalEstimatedTokens,
|
|
437
|
+
messageSegmentCount
|
|
438
|
+
);
|
|
439
|
+
if (duplicate !== null) diagnostics.unshift(duplicate);
|
|
440
|
+
return {
|
|
441
|
+
model: requestModel,
|
|
442
|
+
contextWindow,
|
|
443
|
+
estimatedInputTokens,
|
|
444
|
+
outputReserveTokens,
|
|
445
|
+
windowUsedTokens,
|
|
446
|
+
remainingInputTokens,
|
|
447
|
+
remainingAfterReserveTokens,
|
|
448
|
+
usagePercent,
|
|
449
|
+
riskLevel: riskLevel(usagePercent),
|
|
450
|
+
roleUsages,
|
|
451
|
+
largestRole,
|
|
452
|
+
diagnostics
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
const CONTEXT_USAGE_THRESHOLDS = {
|
|
456
|
+
watch: WATCH_USAGE_PERCENT,
|
|
457
|
+
danger: DANGER_USAGE_PERCENT
|
|
458
|
+
};
|
|
115
459
|
const ANATOMY_ROLE_LABELS = {
|
|
116
460
|
system: "System",
|
|
117
461
|
user: "User",
|
|
@@ -330,12 +674,155 @@ const VIEW_MODE_OPTIONS = [
|
|
|
330
674
|
{ value: "role", label: "By Role" },
|
|
331
675
|
{ value: "segment", label: "By Segment" }
|
|
332
676
|
];
|
|
677
|
+
const RISK_CLASS = {
|
|
678
|
+
unknown: "bg-muted-foreground/50",
|
|
679
|
+
ok: "bg-emerald-500/70",
|
|
680
|
+
watch: "bg-amber-400/75",
|
|
681
|
+
danger: "bg-red-500/80"
|
|
682
|
+
};
|
|
683
|
+
const RISK_TEXT_CLASS = {
|
|
684
|
+
unknown: "text-muted-foreground",
|
|
685
|
+
ok: "text-emerald-400",
|
|
686
|
+
watch: "text-amber-300",
|
|
687
|
+
danger: "text-red-300"
|
|
688
|
+
};
|
|
333
689
|
function formatPercent(value) {
|
|
334
690
|
if (value >= 10) return `${value.toFixed(0)}%`;
|
|
335
691
|
if (value >= 1) return `${value.toFixed(1)}%`;
|
|
336
692
|
if (value > 0) return "<1%";
|
|
337
693
|
return "0%";
|
|
338
694
|
}
|
|
695
|
+
function formatUsagePercent(value) {
|
|
696
|
+
if (value === null) return "Unknown";
|
|
697
|
+
return formatPercent(value * 100);
|
|
698
|
+
}
|
|
699
|
+
function formatRemainingTokens(value) {
|
|
700
|
+
if (value === null) return "Unknown";
|
|
701
|
+
if (value < 0) return `-${formatTokens(Math.abs(value))}`;
|
|
702
|
+
return formatTokens(value);
|
|
703
|
+
}
|
|
704
|
+
function formatContextLimit(intelligence) {
|
|
705
|
+
if (intelligence.contextWindow.tokens === null) return "Unknown";
|
|
706
|
+
return formatTokens(intelligence.contextWindow.tokens);
|
|
707
|
+
}
|
|
708
|
+
function formatContextSource(intelligence) {
|
|
709
|
+
switch (intelligence.contextWindow.source) {
|
|
710
|
+
case "request":
|
|
711
|
+
return intelligence.contextWindow.label;
|
|
712
|
+
case "model-rule":
|
|
713
|
+
return intelligence.contextWindow.label;
|
|
714
|
+
case "unknown":
|
|
715
|
+
return intelligence.model === null ? intelligence.contextWindow.label : `${intelligence.contextWindow.label}: ${intelligence.model}`;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
function diagnosticTone(diagnostic) {
|
|
719
|
+
switch (diagnostic.severity) {
|
|
720
|
+
case "watch":
|
|
721
|
+
return "border-amber-400/30 bg-amber-400/8 text-amber-100";
|
|
722
|
+
case "danger":
|
|
723
|
+
return "border-red-400/35 bg-red-500/10 text-red-100";
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
function ContextIntelligenceStrip({
|
|
727
|
+
intelligence
|
|
728
|
+
}) {
|
|
729
|
+
const usageWidth = intelligence.usagePercent === null ? 0 : Math.max(1, intelligence.usagePercent * 100);
|
|
730
|
+
const outputReserveLabel = intelligence.outputReserveTokens === null ? "No output reserve" : `Output reserve ${formatTokens(intelligence.outputReserveTokens)}`;
|
|
731
|
+
const largestRole = intelligence.largestRole;
|
|
732
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
733
|
+
/* @__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: [
|
|
734
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
|
|
735
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-medium uppercase text-muted-foreground", children: "Window" }),
|
|
736
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-0.5 truncate font-mono text-foreground", children: formatContextLimit(intelligence) }),
|
|
737
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "truncate text-[11px] text-muted-foreground", children: formatContextSource(intelligence) })
|
|
738
|
+
] }),
|
|
739
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
|
|
740
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-medium uppercase text-muted-foreground", children: "Used" }),
|
|
741
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("mt-0.5 font-mono", RISK_TEXT_CLASS[intelligence.riskLevel]), children: formatUsagePercent(intelligence.usagePercent) }),
|
|
742
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "truncate text-[11px] text-muted-foreground", children: outputReserveLabel })
|
|
743
|
+
] }),
|
|
744
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
|
|
745
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-medium uppercase text-muted-foreground", children: "Remaining" }),
|
|
746
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-0.5 font-mono text-foreground", children: formatRemainingTokens(intelligence.remainingAfterReserveTokens) }),
|
|
747
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "truncate text-[11px] text-muted-foreground", children: [
|
|
748
|
+
"Input only ",
|
|
749
|
+
formatRemainingTokens(intelligence.remainingInputTokens)
|
|
750
|
+
] })
|
|
751
|
+
] }),
|
|
752
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
|
|
753
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-medium uppercase text-muted-foreground", children: "Largest" }),
|
|
754
|
+
largestRole === null ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-0.5 text-muted-foreground", children: "Unknown" }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
755
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-0.5 flex min-w-0 items-center gap-1.5", children: [
|
|
756
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
757
|
+
"span",
|
|
758
|
+
{
|
|
759
|
+
"aria-hidden": "true",
|
|
760
|
+
className: cn(
|
|
761
|
+
"size-2.5 shrink-0 rounded-[2px]",
|
|
762
|
+
ROLE_COLOR_CLASSES[largestRole.role]
|
|
763
|
+
)
|
|
764
|
+
}
|
|
765
|
+
),
|
|
766
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate text-foreground", children: largestRole.label })
|
|
767
|
+
] }),
|
|
768
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "truncate font-mono text-[11px] text-muted-foreground", children: [
|
|
769
|
+
formatPercent(largestRole.percent * 100),
|
|
770
|
+
" | ~",
|
|
771
|
+
formatTokens(largestRole.tokens)
|
|
772
|
+
] })
|
|
773
|
+
] })
|
|
774
|
+
] })
|
|
775
|
+
] }),
|
|
776
|
+
intelligence.contextWindow.tokens !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5", children: [
|
|
777
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative h-2 overflow-hidden rounded-full bg-muted/40", children: [
|
|
778
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
779
|
+
"div",
|
|
780
|
+
{
|
|
781
|
+
className: cn("h-full rounded-full", RISK_CLASS[intelligence.riskLevel]),
|
|
782
|
+
style: { width: `${String(usageWidth)}%` }
|
|
783
|
+
}
|
|
784
|
+
),
|
|
785
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
786
|
+
"div",
|
|
787
|
+
{
|
|
788
|
+
"aria-hidden": "true",
|
|
789
|
+
className: "absolute top-0 h-full w-px bg-amber-200/70",
|
|
790
|
+
style: { left: `${String(CONTEXT_USAGE_THRESHOLDS.watch * 100)}%` }
|
|
791
|
+
}
|
|
792
|
+
),
|
|
793
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
794
|
+
"div",
|
|
795
|
+
{
|
|
796
|
+
"aria-hidden": "true",
|
|
797
|
+
className: "absolute top-0 h-full w-px bg-red-200/80",
|
|
798
|
+
style: { left: `${String(CONTEXT_USAGE_THRESHOLDS.danger * 100)}%` }
|
|
799
|
+
}
|
|
800
|
+
)
|
|
801
|
+
] }),
|
|
802
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-[10px] text-muted-foreground", children: [
|
|
803
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Context window" }),
|
|
804
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
805
|
+
"Watch ",
|
|
806
|
+
formatUsagePercent(CONTEXT_USAGE_THRESHOLDS.watch),
|
|
807
|
+
" / Danger",
|
|
808
|
+
" ",
|
|
809
|
+
formatUsagePercent(CONTEXT_USAGE_THRESHOLDS.danger)
|
|
810
|
+
] })
|
|
811
|
+
] })
|
|
812
|
+
] }),
|
|
813
|
+
intelligence.diagnostics.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid gap-1.5 sm:grid-cols-2", children: intelligence.diagnostics.map((diagnostic) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
814
|
+
"div",
|
|
815
|
+
{
|
|
816
|
+
className: cn("rounded border px-2 py-1.5 text-xs", diagnosticTone(diagnostic)),
|
|
817
|
+
children: [
|
|
818
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium", children: diagnostic.title }),
|
|
819
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-0.5 text-[11px] text-muted-foreground", children: diagnostic.detail })
|
|
820
|
+
]
|
|
821
|
+
},
|
|
822
|
+
`${diagnostic.kind}-${diagnostic.title}`
|
|
823
|
+
)) })
|
|
824
|
+
] });
|
|
825
|
+
}
|
|
339
826
|
function aggregateByRole(segments) {
|
|
340
827
|
const result = [];
|
|
341
828
|
for (const role of ROLE_ORDER) {
|
|
@@ -362,6 +849,7 @@ function topContributors(segments) {
|
|
|
362
849
|
function RequestAnatomy({
|
|
363
850
|
parsed,
|
|
364
851
|
inputTokens,
|
|
852
|
+
model = null,
|
|
365
853
|
onSegmentActivate,
|
|
366
854
|
segments: providedSegments
|
|
367
855
|
}) {
|
|
@@ -379,6 +867,15 @@ function RequestAnatomy({
|
|
|
379
867
|
() => segments === null ? [] : topContributors(segments),
|
|
380
868
|
[segments]
|
|
381
869
|
);
|
|
870
|
+
const intelligence = reactExports.useMemo(
|
|
871
|
+
() => segments === null ? null : analyzeContextIntelligence({
|
|
872
|
+
segments,
|
|
873
|
+
inputTokens,
|
|
874
|
+
parsed,
|
|
875
|
+
model
|
|
876
|
+
}),
|
|
877
|
+
[inputTokens, model, parsed, segments]
|
|
878
|
+
);
|
|
382
879
|
const showDivergenceWarning = reactExports.useMemo(() => {
|
|
383
880
|
if (segments === null) return false;
|
|
384
881
|
if (inputTokens === null) return false;
|
|
@@ -395,6 +892,8 @@ function RequestAnatomy({
|
|
|
395
892
|
const activateSegment = viewMode === "segment" ? onSegmentActivate : void 0;
|
|
396
893
|
const segmentCountLabel = `${String(segments.length)} segment${segments.length === 1 ? "" : "s"}`;
|
|
397
894
|
const providerInputLabel = inputTokens === null ? "Provider input unknown" : `Provider input ${formatTokens(inputTokens)}`;
|
|
895
|
+
const contextLimitLabel = intelligence === null ? "Limit unknown" : `Limit ${formatContextLimit(intelligence)}`;
|
|
896
|
+
const usageLabel = intelligence === null ? "Usage unknown" : `${formatUsagePercent(intelligence.usagePercent)} used`;
|
|
398
897
|
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
898
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [
|
|
400
899
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0", children: [
|
|
@@ -405,6 +904,11 @@ function RequestAnatomy({
|
|
|
405
904
|
" tokens | ",
|
|
406
905
|
providerInputLabel,
|
|
407
906
|
" | ",
|
|
907
|
+
contextLimitLabel,
|
|
908
|
+
" |",
|
|
909
|
+
" ",
|
|
910
|
+
usageLabel,
|
|
911
|
+
" | ",
|
|
408
912
|
segmentCountLabel
|
|
409
913
|
] })
|
|
410
914
|
] }),
|
|
@@ -446,6 +950,7 @@ function RequestAnatomy({
|
|
|
446
950
|
] }),
|
|
447
951
|
"Estimate differs from provider-reported input."
|
|
448
952
|
] }),
|
|
953
|
+
intelligence !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(ContextIntelligenceStrip, { intelligence }),
|
|
449
954
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
450
955
|
SegmentBar,
|
|
451
956
|
{
|