@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.
- package/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-3nRwtk8J.js → CompareDrawer-DDmqSAfl.js} +1 -1
- package/.output/public/assets/{ProxyViewerContainer-CbW5VRER.js → ProxyViewerContainer-Cxpdziwd.js} +5 -5
- package/.output/public/assets/{ReplayDialog-Cl62N9PI.js → ReplayDialog-Bt5DGzlh.js} +1 -1
- package/.output/public/assets/RequestAnatomy-BxX3_N9S.js +1 -0
- package/.output/public/assets/{ResponseView-Cvc-ct4E.js → ResponseView-Bl_5S9gZ.js} +1 -1
- package/.output/public/assets/{StreamingChunkSequence-BCQaCAIe.js → StreamingChunkSequence-RJMwNf6F.js} +1 -1
- package/.output/public/assets/_sessionId-b4isaoDp.js +1 -0
- package/.output/public/assets/index-BZ4x5UI6.js +1 -0
- package/.output/public/assets/index-C624DUk9.css +1 -0
- package/.output/public/assets/{json-viewer-IXejqXB0.js → json-viewer-CRL_gWEZ.js} +1 -1
- package/.output/public/assets/{main-2NlGzgOe.js → main-CKnTJ4-O.js} +6 -6
- package/.output/server/{_sessionId-DWCTasJU.mjs → _sessionId-B-x9fRY3.mjs} +2 -2
- package/.output/server/_ssr/{CompareDrawer-DhrN1uC2.mjs → CompareDrawer-BQVNsAY2.mjs} +3 -3
- package/.output/server/_ssr/{ProxyViewerContainer-DRl51s_n.mjs → ProxyViewerContainer-CYm2Dw19.mjs} +12 -12
- package/.output/server/_ssr/{ReplayDialog-BQT_ygxC.mjs → ReplayDialog-CaMQBc79.mjs} +4 -4
- package/.output/server/_ssr/{RequestAnatomy-DS2tZOgq.mjs → RequestAnatomy--P5arRH2.mjs} +235 -65
- package/.output/server/_ssr/{ResponseView-e0kL2C3x.mjs → ResponseView-RtFwNvgD.mjs} +3 -3
- package/.output/server/_ssr/{StreamingChunkSequence-BJG-m7xs.mjs → StreamingChunkSequence-B5HPkzab.mjs} +3 -3
- package/.output/server/_ssr/{index-Dea3OeRw.mjs → index-CZIKZU43.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{json-viewer-DDU55MLK.mjs → json-viewer-d4obyRaA.mjs} +2 -2
- package/.output/server/_ssr/{router-Dl7oh0zx.mjs → router-DGPt3MUc.mjs} +3 -3
- package/.output/server/{_tanstack-start-manifest_v-m-FJNBVf.mjs → _tanstack-start-manifest_v-BzH4pNaI.mjs} +1 -1
- package/.output/server/index.mjs +68 -68
- package/package.json +1 -1
- package/src/components/proxy-viewer/LogEntry.tsx +4 -4
- package/src/components/proxy-viewer/LogEntryHeader.tsx +3 -3
- package/src/components/proxy-viewer/anatomy/RequestAnatomy.tsx +196 -45
- package/src/components/proxy-viewer/anatomy/SegmentBar.tsx +92 -67
- package/src/components/proxy-viewer/anatomy/types.ts +15 -13
- package/src/components/proxy-viewer/log-formats/anthropic.ts +1 -1
- package/src/components/proxy-viewer/log-formats/openai.ts +1 -1
- package/src/components/proxy-viewer/log-formats/types.ts +1 -1
- package/src/components/ui/json-viewer.tsx +1 -1
- package/.output/public/assets/RequestAnatomy-DgQWGvjs.js +0 -1
- package/.output/public/assets/_sessionId-CcD_aLGq.js +0 -1
- package/.output/public/assets/index-B_dffD3u.js +0 -1
- package/.output/public/assets/index-CX796gvi.css +0 -1
|
@@ -49,7 +49,7 @@ import "../_libs/mimic-function.mjs";
|
|
|
49
49
|
import "../_libs/semver.mjs";
|
|
50
50
|
import "../_libs/uint8array-extras.mjs";
|
|
51
51
|
const faviconSvg = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2064%2064'%20role='img'%20aria-label='Agent%20Inspector'%3e%3crect%20width='64'%20height='64'%20rx='14'%20fill='%23111827'%20/%3e%3cg%20fill='none'%20stroke='%23f59e0b'%20stroke-width='4.2'%20stroke-linecap='round'%20stroke-linejoin='round'%3e%3cpath%20fill='%23f59e0b'%20d='M15%2036c0-11%207-18%2017-18s17%207%2017%2018c0%208-7%2013-17%2013s-17-5-17-13z'%20/%3e%3cpath%20d='M16%2031c-6-5-12-3-12%204%200%205%206%206%2011%202'%20/%3e%3cpath%20d='M48%2031c6-5%2012-3%2012%204%200%205-6%206-11%202'%20/%3e%3cpath%20d='M27%2019l-3-7'%20/%3e%3cpath%20d='M37%2019l3-7'%20/%3e%3cpath%20d='M19%2045l-6%209'%20/%3e%3cpath%20d='M27%2048l-3%209'%20/%3e%3cpath%20d='M37%2048l3%209'%20/%3e%3cpath%20d='M45%2045l6%209'%20/%3e%3c/g%3e%3cpath%20d='M14%2047l9-8%208%209c-5%203.5-12%203-17-1z'%20fill='%232f6b3f'%20opacity='.95'%20/%3e%3cpath%20d='M18%2046l5-5%205%206c-3%201.6-7%201.4-10-1z'%20fill='%236fb36f'%20opacity='.95'%20/%3e%3cpath%20d='M23%2041v10'%20fill='none'%20stroke='%23d6b45f'%20stroke-width='1.6'%20stroke-linecap='round'%20/%3e%3ccircle%20cx='31'%20cy='48'%20r='1.8'%20fill='%23c2412d'%20/%3e%3cpath%20d='M24%2044l13-11%2014%2013c-8%205.8-18%205.3-27-2z'%20fill='%232f6b3f'%20opacity='.97'%20/%3e%3cpath%20d='M30%2043l7-7%209%209c-5%202.7-11%202.5-16-2z'%20fill='%236fb36f'%20opacity='.95'%20/%3e%3cpath%20d='M37%2036v14'%20fill='none'%20stroke='%23d6b45f'%20stroke-width='2'%20stroke-linecap='round'%20/%3e%3cpath%20d='M30%2043c5-2%2011-1.5%2016%202'%20fill='none'%20stroke='%239fca78'%20stroke-width='1.8'%20stroke-linecap='round'%20/%3e%3ccircle%20cx='51'%20cy='46'%20r='2'%20fill='%23c2412d'%20/%3e%3cpath%20d='M40%2050l8-8%207%208c-4.2%203.2-10%203-15%200z'%20fill='%232f6b3f'%20opacity='.95'%20/%3e%3cpath%20d='M43%2049l5-5%204.5%205.5c-3%201.5-6%201.2-9.5-.5z'%20fill='%236fb36f'%20opacity='.95'%20/%3e%3cpath%20d='M48%2044v9'%20fill='none'%20stroke='%23d6b45f'%20stroke-width='1.5'%20stroke-linecap='round'%20/%3e%3ccircle%20cx='55'%20cy='50'%20r='1.7'%20fill='%23c2412d'%20/%3e%3ccircle%20cx='24'%20cy='11'%20r='3.2'%20fill='%23f59e0b'%20/%3e%3ccircle%20cx='40'%20cy='11'%20r='3.2'%20fill='%23f59e0b'%20/%3e%3ccircle%20cx='25'%20cy='34'%20r='2.1'%20fill='%23111827'%20/%3e%3ccircle%20cx='39'%20cy='34'%20r='2.1'%20fill='%23111827'%20/%3e%3c/svg%3e";
|
|
52
|
-
const appCss = "/assets/index-
|
|
52
|
+
const appCss = "/assets/index-C624DUk9.css";
|
|
53
53
|
const Route$r = createRootRoute({
|
|
54
54
|
head: () => ({
|
|
55
55
|
meta: [
|
|
@@ -76,7 +76,7 @@ function RootDocument({ children }) {
|
|
|
76
76
|
] })
|
|
77
77
|
] });
|
|
78
78
|
}
|
|
79
|
-
const $$splitComponentImporter$1 = () => import("./index-
|
|
79
|
+
const $$splitComponentImporter$1 = () => import("./index-CZIKZU43.mjs");
|
|
80
80
|
const Route$q = createFileRoute("/")({
|
|
81
81
|
component: lazyRouteComponent($$splitComponentImporter$1, "component")
|
|
82
82
|
});
|
|
@@ -119,7 +119,7 @@ function decodeSessionIdFromPath(encoded) {
|
|
|
119
119
|
function getSessionPath(sessionId) {
|
|
120
120
|
return `/session/${encodeSessionIdForPath(sessionId)}`;
|
|
121
121
|
}
|
|
122
|
-
const $$splitComponentImporter = () => import("../_sessionId-
|
|
122
|
+
const $$splitComponentImporter = () => import("../_sessionId-B-x9fRY3.mjs");
|
|
123
123
|
const Route$p = createFileRoute("/session/$sessionId")({
|
|
124
124
|
component: lazyRouteComponent($$splitComponentImporter, "component"),
|
|
125
125
|
parseParams: (params) => ({
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/__root.tsx", "children": ["/", "/api/config", "/api/health", "/api/logs", "/api/mcp", "/api/models", "/api/providers", "/api/sessions", "/proxy/$", "/session/$sessionId", "/api/knowledge/candidates", "/api/knowledge/project-context", "/api/knowledge/search", "/api/knowledge/sessions/$sessionId/candidates"], "preloads": ["/assets/main-
|
|
1
|
+
const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/__root.tsx", "children": ["/", "/api/config", "/api/health", "/api/logs", "/api/mcp", "/api/models", "/api/providers", "/api/sessions", "/proxy/$", "/session/$sessionId", "/api/knowledge/candidates", "/api/knowledge/project-context", "/api/knowledge/search", "/api/knowledge/sessions/$sessionId/candidates"], "preloads": ["/assets/main-CKnTJ4-O.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-BZ4x5UI6.js", "/assets/ProxyViewerContainer-Cxpdziwd.js"] }, "/api/config": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/config.ts", "children": ["/api/config/paths"] }, "/api/health": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/health.ts" }, "/api/logs": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.ts", "children": ["/api/logs/$id", "/api/logs/stream"] }, "/api/mcp": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/mcp.ts" }, "/api/models": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/models.ts" }, "/api/providers": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.ts", "children": ["/api/providers/$providerId", "/api/providers/export", "/api/providers/import", "/api/providers/scan"] }, "/api/sessions": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/sessions.ts" }, "/proxy/$": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/proxy/$.ts" }, "/session/$sessionId": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/session/$sessionId.tsx", "assets": [], "preloads": ["/assets/_sessionId-b4isaoDp.js", "/assets/ProxyViewerContainer-Cxpdziwd.js"] }, "/api/config/paths": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/config.paths.ts" }, "/api/knowledge/candidates": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.candidates.ts", "children": ["/api/knowledge/candidates/$candidateId"] }, "/api/knowledge/project-context": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.project-context.ts" }, "/api/knowledge/search": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.search.ts" }, "/api/logs/$id": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.$id.ts", "children": ["/api/logs/$id/chunks", "/api/logs/$id/replay"] }, "/api/logs/stream": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.stream.ts" }, "/api/providers/$providerId": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.$providerId.ts", "children": ["/api/providers/$providerId/test"] }, "/api/providers/export": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.export.ts" }, "/api/providers/import": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.import.ts" }, "/api/providers/scan": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.scan.ts" }, "/api/knowledge/candidates/$candidateId": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.candidates.$candidateId.ts", "children": ["/api/knowledge/candidates/$candidateId/promote"] }, "/api/logs/$id/chunks": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.$id.chunks.ts" }, "/api/logs/$id/replay": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.$id.replay.ts" }, "/api/providers/$providerId/test": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.$providerId.test.ts", "children": ["/api/providers/$providerId/test/log"] }, "/api/knowledge/candidates/$candidateId/promote": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.candidates.$candidateId.promote.ts" }, "/api/knowledge/sessions/$sessionId/candidates": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.sessions.$sessionId.candidates.ts" }, "/api/providers/$providerId/test/log": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.$providerId.test.log.ts" } }, "clientEntry": "/assets/main-CKnTJ4-O.js" });
|
|
2
2
|
export {
|
|
3
3
|
tsrStartManifest
|
|
4
4
|
};
|
package/.output/server/index.mjs
CHANGED
|
@@ -38,107 +38,107 @@ const assets = {
|
|
|
38
38
|
"/assets/alibaba-TTwafVwX.svg": {
|
|
39
39
|
"type": "image/svg+xml",
|
|
40
40
|
"etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
|
|
41
|
-
"mtime": "2026-06-
|
|
41
|
+
"mtime": "2026-06-21T03:27:09.298Z",
|
|
42
42
|
"size": 5915,
|
|
43
43
|
"path": "../public/assets/alibaba-TTwafVwX.svg"
|
|
44
44
|
},
|
|
45
|
-
"/assets/
|
|
46
|
-
"type": "image/jpeg",
|
|
47
|
-
"etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
|
|
48
|
-
"mtime": "2026-06-21T02:55:38.892Z",
|
|
49
|
-
"size": 6918,
|
|
50
|
-
"path": "../public/assets/minimax-BPMzvuL-.jpeg"
|
|
51
|
-
},
|
|
52
|
-
"/assets/CompareDrawer-3nRwtk8J.js": {
|
|
45
|
+
"/assets/CompareDrawer-DDmqSAfl.js": {
|
|
53
46
|
"type": "text/javascript; charset=utf-8",
|
|
54
|
-
"etag": '"4a25-
|
|
55
|
-
"mtime": "2026-06-
|
|
47
|
+
"etag": '"4a25-ax+lNTJqeO5Uw5iRn0IINDghlL8"',
|
|
48
|
+
"mtime": "2026-06-21T03:27:09.300Z",
|
|
56
49
|
"size": 18981,
|
|
57
|
-
"path": "../public/assets/CompareDrawer-
|
|
50
|
+
"path": "../public/assets/CompareDrawer-DDmqSAfl.js"
|
|
58
51
|
},
|
|
59
|
-
"/assets/index-
|
|
52
|
+
"/assets/index-BZ4x5UI6.js": {
|
|
60
53
|
"type": "text/javascript; charset=utf-8",
|
|
61
|
-
"etag": '"74-
|
|
62
|
-
"mtime": "2026-06-
|
|
54
|
+
"etag": '"74-I7Q+PS5hgyBfKRdQxaKtu+fOxCI"',
|
|
55
|
+
"mtime": "2026-06-21T03:27:09.300Z",
|
|
63
56
|
"size": 116,
|
|
64
|
-
"path": "../public/assets/index-
|
|
57
|
+
"path": "../public/assets/index-BZ4x5UI6.js"
|
|
65
58
|
},
|
|
66
|
-
"/assets/index-
|
|
59
|
+
"/assets/index-C624DUk9.css": {
|
|
67
60
|
"type": "text/css; charset=utf-8",
|
|
68
|
-
"etag": '"
|
|
69
|
-
"mtime": "2026-06-
|
|
70
|
-
"size":
|
|
71
|
-
"path": "../public/assets/index-
|
|
61
|
+
"etag": '"17b64-fA2ShN0vgWgtCNH7S8ke3+06+1g"',
|
|
62
|
+
"mtime": "2026-06-21T03:27:09.300Z",
|
|
63
|
+
"size": 97124,
|
|
64
|
+
"path": "../public/assets/index-C624DUk9.css"
|
|
72
65
|
},
|
|
73
|
-
"/assets/
|
|
66
|
+
"/assets/ReplayDialog-Bt5DGzlh.js": {
|
|
74
67
|
"type": "text/javascript; charset=utf-8",
|
|
75
|
-
"etag": '"
|
|
76
|
-
"mtime": "2026-06-
|
|
77
|
-
"size":
|
|
78
|
-
"path": "../public/assets/
|
|
68
|
+
"etag": '"2383-209uDqfCNP9kp/Eo1OJGkQf5K7o"',
|
|
69
|
+
"mtime": "2026-06-21T03:27:09.300Z",
|
|
70
|
+
"size": 9091,
|
|
71
|
+
"path": "../public/assets/ReplayDialog-Bt5DGzlh.js"
|
|
79
72
|
},
|
|
80
|
-
"/assets/
|
|
73
|
+
"/assets/RequestAnatomy-BxX3_N9S.js": {
|
|
81
74
|
"type": "text/javascript; charset=utf-8",
|
|
82
|
-
"etag": '"
|
|
83
|
-
"mtime": "2026-06-
|
|
84
|
-
"size":
|
|
85
|
-
"path": "../public/assets/
|
|
75
|
+
"etag": '"21df-RsC1hle1XaaRP0DDNQAtrI26Ohw"',
|
|
76
|
+
"mtime": "2026-06-21T03:27:09.300Z",
|
|
77
|
+
"size": 8671,
|
|
78
|
+
"path": "../public/assets/RequestAnatomy-BxX3_N9S.js"
|
|
86
79
|
},
|
|
87
|
-
"/assets/
|
|
88
|
-
"type": "
|
|
89
|
-
"etag": '"
|
|
90
|
-
"mtime": "2026-06-
|
|
91
|
-
"size":
|
|
92
|
-
"path": "../public/assets/
|
|
80
|
+
"/assets/minimax-BPMzvuL-.jpeg": {
|
|
81
|
+
"type": "image/jpeg",
|
|
82
|
+
"etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
|
|
83
|
+
"mtime": "2026-06-21T03:27:09.300Z",
|
|
84
|
+
"size": 6918,
|
|
85
|
+
"path": "../public/assets/minimax-BPMzvuL-.jpeg"
|
|
93
86
|
},
|
|
94
|
-
"/assets/
|
|
87
|
+
"/assets/json-viewer-CRL_gWEZ.js": {
|
|
95
88
|
"type": "text/javascript; charset=utf-8",
|
|
96
|
-
"etag": '"
|
|
97
|
-
"mtime": "2026-06-
|
|
98
|
-
"size":
|
|
99
|
-
"path": "../public/assets/
|
|
89
|
+
"etag": '"1e653-xRVAXa9/k/0cz9lZfPZsShTfToA"',
|
|
90
|
+
"mtime": "2026-06-21T03:27:09.301Z",
|
|
91
|
+
"size": 124499,
|
|
92
|
+
"path": "../public/assets/json-viewer-CRL_gWEZ.js"
|
|
100
93
|
},
|
|
101
|
-
"/assets/StreamingChunkSequence-
|
|
94
|
+
"/assets/StreamingChunkSequence-RJMwNf6F.js": {
|
|
102
95
|
"type": "text/javascript; charset=utf-8",
|
|
103
|
-
"etag": '"d82-
|
|
104
|
-
"mtime": "2026-06-
|
|
96
|
+
"etag": '"d82-23sq9u+7FJWOVlw2ZwY9VyBv1us"',
|
|
97
|
+
"mtime": "2026-06-21T03:27:09.300Z",
|
|
105
98
|
"size": 3458,
|
|
106
|
-
"path": "../public/assets/StreamingChunkSequence-
|
|
99
|
+
"path": "../public/assets/StreamingChunkSequence-RJMwNf6F.js"
|
|
107
100
|
},
|
|
108
|
-
"/assets/
|
|
101
|
+
"/assets/ResponseView-Bl_5S9gZ.js": {
|
|
109
102
|
"type": "text/javascript; charset=utf-8",
|
|
110
|
-
"etag": '"
|
|
111
|
-
"mtime": "2026-06-
|
|
112
|
-
"size":
|
|
113
|
-
"path": "../public/assets/
|
|
114
|
-
},
|
|
115
|
-
"/assets/qwen-CONDcHqt.png": {
|
|
116
|
-
"type": "image/png",
|
|
117
|
-
"etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
|
|
118
|
-
"mtime": "2026-06-21T02:55:38.892Z",
|
|
119
|
-
"size": 357059,
|
|
120
|
-
"path": "../public/assets/qwen-CONDcHqt.png"
|
|
103
|
+
"etag": '"6aab-UCFRuWGhCGLKb2s5NCp1phbPUzQ"',
|
|
104
|
+
"mtime": "2026-06-21T03:27:09.300Z",
|
|
105
|
+
"size": 27307,
|
|
106
|
+
"path": "../public/assets/ResponseView-Bl_5S9gZ.js"
|
|
121
107
|
},
|
|
122
108
|
"/assets/zhipuai-BPNAnxo-.svg": {
|
|
123
109
|
"type": "image/svg+xml",
|
|
124
110
|
"etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
|
|
125
|
-
"mtime": "2026-06-
|
|
111
|
+
"mtime": "2026-06-21T03:27:09.298Z",
|
|
126
112
|
"size": 11256,
|
|
127
113
|
"path": "../public/assets/zhipuai-BPNAnxo-.svg"
|
|
128
114
|
},
|
|
129
|
-
"/assets/
|
|
115
|
+
"/assets/_sessionId-b4isaoDp.js": {
|
|
130
116
|
"type": "text/javascript; charset=utf-8",
|
|
131
|
-
"etag": '"
|
|
132
|
-
"mtime": "2026-06-
|
|
117
|
+
"etag": '"d2-p8zHXMHP91ArIYS6WLwFbKor58Y"',
|
|
118
|
+
"mtime": "2026-06-21T03:27:09.300Z",
|
|
119
|
+
"size": 210,
|
|
120
|
+
"path": "../public/assets/_sessionId-b4isaoDp.js"
|
|
121
|
+
},
|
|
122
|
+
"/assets/main-CKnTJ4-O.js": {
|
|
123
|
+
"type": "text/javascript; charset=utf-8",
|
|
124
|
+
"etag": '"5138c-MlPN81hCf/6HY5xIpWbk5sw0drc"',
|
|
125
|
+
"mtime": "2026-06-21T03:27:09.300Z",
|
|
133
126
|
"size": 332684,
|
|
134
|
-
"path": "../public/assets/main-
|
|
127
|
+
"path": "../public/assets/main-CKnTJ4-O.js"
|
|
128
|
+
},
|
|
129
|
+
"/assets/qwen-CONDcHqt.png": {
|
|
130
|
+
"type": "image/png",
|
|
131
|
+
"etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
|
|
132
|
+
"mtime": "2026-06-21T03:27:09.300Z",
|
|
133
|
+
"size": 357059,
|
|
134
|
+
"path": "../public/assets/qwen-CONDcHqt.png"
|
|
135
135
|
},
|
|
136
|
-
"/assets/
|
|
136
|
+
"/assets/ProxyViewerContainer-Cxpdziwd.js": {
|
|
137
137
|
"type": "text/javascript; charset=utf-8",
|
|
138
|
-
"etag": '"
|
|
139
|
-
"mtime": "2026-06-
|
|
140
|
-
"size":
|
|
141
|
-
"path": "../public/assets/
|
|
138
|
+
"etag": '"7d8f5-2o+HRUWRh8QXo5PbcEDo+/1GGt0"',
|
|
139
|
+
"mtime": "2026-06-21T03:27:09.300Z",
|
|
140
|
+
"size": 514293,
|
|
141
|
+
"path": "../public/assets/ProxyViewerContainer-Cxpdziwd.js"
|
|
142
142
|
}
|
|
143
143
|
};
|
|
144
144
|
function readAsset(id) {
|
package/package.json
CHANGED
|
@@ -177,7 +177,7 @@ export const LogEntry = memo(function ({
|
|
|
177
177
|
const responseCopy = useCopyFeedback(log.responseText);
|
|
178
178
|
|
|
179
179
|
// Per-tab action bundles consumed by the header. The header renders the
|
|
180
|
-
// entry whose key matches `activeTab`. Tabs without an entry (
|
|
180
|
+
// entry whose key matches `activeTab`. Tabs without an entry (Context,
|
|
181
181
|
// Parsed Response) render no header buttons.
|
|
182
182
|
const tabActions: HeaderTabActions = useMemo(
|
|
183
183
|
() => ({
|
|
@@ -320,7 +320,7 @@ export const LogEntry = memo(function ({
|
|
|
320
320
|
<TabsTrigger value="raw-request">Raw Request</TabsTrigger>
|
|
321
321
|
)}
|
|
322
322
|
<TabsTrigger value="request">Request</TabsTrigger>
|
|
323
|
-
{anatomySegments !== null && <TabsTrigger value="anatomy">
|
|
323
|
+
{anatomySegments !== null && <TabsTrigger value="anatomy">Context</TabsTrigger>}
|
|
324
324
|
{viewMode === "full" && <TabsTrigger value="raw">Raw Response</TabsTrigger>}
|
|
325
325
|
<TabsTrigger value="parsed">Response</TabsTrigger>
|
|
326
326
|
</TabsList>
|
|
@@ -359,7 +359,7 @@ export const LogEntry = memo(function ({
|
|
|
359
359
|
<RequestDiffContent
|
|
360
360
|
rawBody={log.rawRequestBody}
|
|
361
361
|
displayedBody={displayedRequestBody}
|
|
362
|
-
emptyLabel="No transformation applied
|
|
362
|
+
emptyLabel="No transformation applied; raw and sent request bodies are identical."
|
|
363
363
|
/>
|
|
364
364
|
) : (
|
|
365
365
|
<div ref={requestJsonRef}>
|
|
@@ -424,7 +424,7 @@ export const LogEntry = memo(function ({
|
|
|
424
424
|
<HeadersDiffContent
|
|
425
425
|
rawHeaders={log.rawHeaders}
|
|
426
426
|
headers={log.headers}
|
|
427
|
-
emptyLabel="No transformation applied
|
|
427
|
+
emptyLabel="No transformation applied; raw and processed headers are identical."
|
|
428
428
|
/>
|
|
429
429
|
) : log.headers && Object.keys(log.headers).length > 0 ? (
|
|
430
430
|
<div className="space-y-1 font-mono text-xs">
|
|
@@ -92,7 +92,7 @@ export type HeaderTabAction = {
|
|
|
92
92
|
};
|
|
93
93
|
|
|
94
94
|
/**
|
|
95
|
-
* Tab actions keyed by Tabs value. Tabs without an entry (
|
|
95
|
+
* Tab actions keyed by Tabs value. Tabs without an entry (Context, Parsed
|
|
96
96
|
* Response) leave the corresponding key unset, so the header renders no
|
|
97
97
|
* action buttons for them. Typed as a record (rather than a `Partial<...>`
|
|
98
98
|
* union) so the per-tab lookup in the header is type-safe.
|
|
@@ -109,14 +109,14 @@ export type LogEntryHeaderProps = {
|
|
|
109
109
|
onToggle: () => void;
|
|
110
110
|
/** Per-log cache token trend (creation + read) relative to the previous log
|
|
111
111
|
* in the same conversation group. When `undefined` or a field is `null`,
|
|
112
|
-
* the corresponding cache span renders as it did before
|
|
112
|
+
* the corresponding cache span renders as it did before: no arrow.
|
|
113
113
|
*/
|
|
114
114
|
cacheTrend?: { creation: CacheTrend | null; read: CacheTrend | null } | null;
|
|
115
115
|
/** Currently-active tab value (matches the `Tabs` value prop). The header
|
|
116
116
|
* uses this to pick the right entry from `tabActions`. */
|
|
117
117
|
activeTab?: string;
|
|
118
118
|
/** Per-tab Copy + Expand-all actions. Only tabs with an entry will show
|
|
119
|
-
* buttons when active. Tabs without an entry (
|
|
119
|
+
* buttons when active. Tabs without an entry (Context, Parsed Response)
|
|
120
120
|
* render no header buttons. */
|
|
121
121
|
tabActions?: HeaderTabActions;
|
|
122
122
|
/** Re-send this request to the provider. Rendered in the header row when
|
|
@@ -1,27 +1,77 @@
|
|
|
1
1
|
import { Info } from "lucide-react";
|
|
2
|
-
import { type JSX, useMemo } from "react";
|
|
2
|
+
import { type JSX, useMemo, useState } from "react";
|
|
3
3
|
import { cn, formatTokens } from "../../../lib/utils";
|
|
4
4
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../../ui/tooltip";
|
|
5
|
-
import { SegmentBar } from "./SegmentBar";
|
|
6
|
-
import type
|
|
5
|
+
import { ROLE_COLOR_CLASSES, SegmentBar } from "./SegmentBar";
|
|
6
|
+
import { ANATOMY_ROLE_LABELS, type AnatomyRole, type AnatomySegment } from "./types";
|
|
7
7
|
|
|
8
8
|
export type RequestAnatomyProps = {
|
|
9
9
|
/** Parsed request body, or `null` if it cannot be parsed. */
|
|
10
10
|
parsed: unknown | null;
|
|
11
11
|
/** Server-reported input token count, or `null` if unknown. */
|
|
12
12
|
inputTokens: number | null;
|
|
13
|
-
/** Optional callback fired when the user activates a segment. */
|
|
13
|
+
/** Optional callback fired when the user activates a concrete request segment. */
|
|
14
14
|
onSegmentActivate?: (segment: AnatomySegment) => void;
|
|
15
15
|
/** Pre-computed segments; if provided, `parsed` is ignored. */
|
|
16
16
|
segments?: AnatomySegment[] | null;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
+
type ContextViewMode = "role" | "segment";
|
|
20
|
+
|
|
19
21
|
const DIVERGENCE_AMBER_THRESHOLD = 0.25;
|
|
22
|
+
const TOP_CONTRIBUTOR_COUNT = 5;
|
|
23
|
+
const ROLE_ORDER: AnatomyRole[] = ["system", "user", "assistant", "tool", "tools"];
|
|
24
|
+
|
|
25
|
+
const ROLE_DESCRIPTIONS: Record<AnatomyRole, string> = {
|
|
26
|
+
system: "instructions",
|
|
27
|
+
user: "user turns",
|
|
28
|
+
assistant: "assistant turns",
|
|
29
|
+
tool: "tool results",
|
|
30
|
+
tools: "tool schemas",
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const VIEW_MODE_OPTIONS: Array<{ value: ContextViewMode; label: string }> = [
|
|
34
|
+
{ value: "role", label: "By Role" },
|
|
35
|
+
{ value: "segment", label: "By Segment" },
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
function formatPercent(value: number): string {
|
|
39
|
+
if (value >= 10) return `${value.toFixed(0)}%`;
|
|
40
|
+
if (value >= 1) return `${value.toFixed(1)}%`;
|
|
41
|
+
if (value > 0) return "<1%";
|
|
42
|
+
return "0%";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function aggregateByRole(segments: AnatomySegment[]): AnatomySegment[] {
|
|
46
|
+
const result: AnatomySegment[] = [];
|
|
47
|
+
for (const role of ROLE_ORDER) {
|
|
48
|
+
const matching = segments.filter((segment) => segment.role === role);
|
|
49
|
+
if (matching.length === 0) continue;
|
|
50
|
+
const size = matching.reduce((sum, segment) => sum + segment.size, 0);
|
|
51
|
+
const characters = matching.reduce((sum, segment) => sum + segment.characters, 0);
|
|
52
|
+
const label = ANATOMY_ROLE_LABELS[role];
|
|
53
|
+
const text = `${matching.length} segment${matching.length === 1 ? "" : "s"} grouped as ${
|
|
54
|
+
ROLE_DESCRIPTIONS[role]
|
|
55
|
+
}`;
|
|
56
|
+
result.push({
|
|
57
|
+
role,
|
|
58
|
+
label,
|
|
59
|
+
size,
|
|
60
|
+
characters,
|
|
61
|
+
text,
|
|
62
|
+
path: `role:${role}`,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function topContributors(segments: AnatomySegment[]): AnatomySegment[] {
|
|
69
|
+
return [...segments].sort((a, b) => b.size - a.size).slice(0, TOP_CONTRIBUTOR_COUNT);
|
|
70
|
+
}
|
|
20
71
|
|
|
21
72
|
/**
|
|
22
|
-
* Render
|
|
23
|
-
*
|
|
24
|
-
* parsed or the segment list is empty.
|
|
73
|
+
* Render a request context breakdown: headline metrics, a stacked token bar,
|
|
74
|
+
* role legend, and the largest individual context blocks.
|
|
25
75
|
*/
|
|
26
76
|
export function RequestAnatomy({
|
|
27
77
|
parsed,
|
|
@@ -29,69 +79,170 @@ export function RequestAnatomy({
|
|
|
29
79
|
onSegmentActivate,
|
|
30
80
|
segments: providedSegments,
|
|
31
81
|
}: RequestAnatomyProps): JSX.Element | null {
|
|
32
|
-
|
|
33
|
-
// LogEntry). When called standalone, fall back to deriving from
|
|
34
|
-
// `parsed` directly using the unknown adapter is not appropriate —
|
|
35
|
-
// the caller is responsible for choosing the right adapter.
|
|
82
|
+
const [viewMode, setViewMode] = useState<ContextViewMode>("role");
|
|
36
83
|
const segments = useMemo(() => providedSegments ?? null, [providedSegments]);
|
|
37
|
-
const total = useMemo(
|
|
84
|
+
const total = useMemo(
|
|
85
|
+
() => (segments ?? []).reduce((sum, segment) => sum + segment.size, 0),
|
|
86
|
+
[segments],
|
|
87
|
+
);
|
|
88
|
+
const roleSegments = useMemo(
|
|
89
|
+
() => (segments === null ? [] : aggregateByRole(segments)),
|
|
90
|
+
[segments],
|
|
91
|
+
);
|
|
92
|
+
const topSegments = useMemo(
|
|
93
|
+
() => (segments === null ? [] : topContributors(segments)),
|
|
94
|
+
[segments],
|
|
95
|
+
);
|
|
38
96
|
|
|
39
|
-
// Show divergence warning when both estimate and server numbers exist.
|
|
40
97
|
const showDivergenceWarning = useMemo(() => {
|
|
41
|
-
if (segments === null
|
|
98
|
+
if (segments === null) return false;
|
|
42
99
|
if (inputTokens === null) return false;
|
|
43
100
|
if (total === 0) return false;
|
|
44
101
|
const ratio = Math.abs(inputTokens - total) / Math.max(inputTokens, total);
|
|
45
102
|
return ratio >= DIVERGENCE_AMBER_THRESHOLD;
|
|
46
103
|
}, [inputTokens, segments, total]);
|
|
47
104
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return "text-muted-foreground";
|
|
52
|
-
}, [inputTokens, showDivergenceWarning]);
|
|
105
|
+
if (segments === null) return null;
|
|
106
|
+
if (segments.length === 0) return null;
|
|
107
|
+
if (parsed === null && providedSegments === undefined) return null;
|
|
53
108
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
109
|
+
const summaryColorClass =
|
|
110
|
+
inputTokens !== null && showDivergenceWarning ? "text-amber-400" : "text-muted-foreground";
|
|
111
|
+
const displayedSegments = viewMode === "role" ? roleSegments : segments;
|
|
112
|
+
const displayedTotal =
|
|
113
|
+
total > 0 ? total : displayedSegments.reduce((sum, item) => sum + item.size, 0);
|
|
114
|
+
const activateSegment = viewMode === "segment" ? onSegmentActivate : undefined;
|
|
115
|
+
const segmentCountLabel = `${String(segments.length)} segment${segments.length === 1 ? "" : "s"}`;
|
|
116
|
+
const providerInputLabel =
|
|
117
|
+
inputTokens === null ? "Provider input unknown" : `Provider input ${formatTokens(inputTokens)}`;
|
|
63
118
|
|
|
64
119
|
return (
|
|
65
120
|
<TooltipProvider delayDuration={150}>
|
|
66
|
-
<div className="px-4 py-3 space-y-
|
|
67
|
-
<div className="flex items-
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
121
|
+
<div className="px-4 py-3 space-y-3" data-testid="anatomy-root">
|
|
122
|
+
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
123
|
+
<div className="min-w-0">
|
|
124
|
+
<div className="text-sm font-semibold text-foreground">Request Context</div>
|
|
125
|
+
<div className={cn("mt-0.5 text-xs font-mono tabular-nums", summaryColorClass)}>
|
|
126
|
+
Estimated ~{formatTokens(total)} tokens | {providerInputLabel} | {segmentCountLabel}
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
<div
|
|
131
|
+
className="inline-flex shrink-0 rounded border border-border bg-muted/20 p-0.5"
|
|
132
|
+
role="group"
|
|
133
|
+
aria-label="Context breakdown mode"
|
|
134
|
+
>
|
|
135
|
+
{VIEW_MODE_OPTIONS.map((option) => (
|
|
136
|
+
<button
|
|
137
|
+
key={option.value}
|
|
138
|
+
type="button"
|
|
139
|
+
aria-pressed={viewMode === option.value}
|
|
140
|
+
onClick={() => setViewMode(option.value)}
|
|
141
|
+
className={cn(
|
|
142
|
+
"h-6 rounded-sm px-2 text-[11px] font-medium transition-colors",
|
|
143
|
+
viewMode === option.value
|
|
144
|
+
? "bg-background text-foreground shadow-sm"
|
|
145
|
+
: "text-muted-foreground hover:text-foreground",
|
|
146
|
+
)}
|
|
147
|
+
>
|
|
148
|
+
{option.label}
|
|
149
|
+
</button>
|
|
150
|
+
))}
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
{showDivergenceWarning && (
|
|
155
|
+
<div className="inline-flex items-center gap-1.5 text-xs text-amber-400">
|
|
77
156
|
<Tooltip>
|
|
78
157
|
<TooltipTrigger asChild>
|
|
79
158
|
<button
|
|
80
159
|
type="button"
|
|
81
|
-
className="inline-flex items-center
|
|
82
|
-
aria-label="Token estimate
|
|
160
|
+
className="inline-flex items-center hover:text-amber-300"
|
|
161
|
+
aria-label="Token estimate differs from provider input"
|
|
83
162
|
>
|
|
84
163
|
<Info className="size-3.5" />
|
|
85
164
|
</button>
|
|
86
165
|
</TooltipTrigger>
|
|
87
166
|
<TooltipContent className="max-w-xs text-xs">
|
|
88
|
-
|
|
89
|
-
|
|
167
|
+
The bar uses a local token estimate. Provider input tokens remain the source of
|
|
168
|
+
truth for billing and context-window usage.
|
|
90
169
|
</TooltipContent>
|
|
91
170
|
</Tooltip>
|
|
92
|
-
|
|
171
|
+
Estimate differs from provider-reported input.
|
|
172
|
+
</div>
|
|
173
|
+
)}
|
|
174
|
+
|
|
175
|
+
<SegmentBar
|
|
176
|
+
segments={displayedSegments}
|
|
177
|
+
totalTokens={displayedTotal}
|
|
178
|
+
showLabels={viewMode === "segment"}
|
|
179
|
+
onActivate={activateSegment}
|
|
180
|
+
/>
|
|
181
|
+
|
|
182
|
+
<div className="flex flex-wrap items-center gap-x-3 gap-y-1.5 text-[11px] text-muted-foreground">
|
|
183
|
+
{roleSegments.map((segment) => {
|
|
184
|
+
const percent = total > 0 ? (segment.size / total) * 100 : 0;
|
|
185
|
+
return (
|
|
186
|
+
<div key={segment.role} className="inline-flex items-center gap-1.5">
|
|
187
|
+
<span
|
|
188
|
+
aria-hidden="true"
|
|
189
|
+
className={cn("size-2.5 rounded-[2px]", ROLE_COLOR_CLASSES[segment.role])}
|
|
190
|
+
/>
|
|
191
|
+
<span>{segment.label}</span>
|
|
192
|
+
<span className="font-mono text-muted-foreground/70">{formatPercent(percent)}</span>
|
|
193
|
+
</div>
|
|
194
|
+
);
|
|
195
|
+
})}
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
<div className="space-y-1.5">
|
|
199
|
+
<div className="text-xs font-medium text-foreground">Top Contributors</div>
|
|
200
|
+
<div className="grid gap-1">
|
|
201
|
+
{topSegments.map((segment, index) => {
|
|
202
|
+
const percent = total > 0 ? (segment.size / total) * 100 : 0;
|
|
203
|
+
const activate = onSegmentActivate;
|
|
204
|
+
const content = (
|
|
205
|
+
<>
|
|
206
|
+
<span className="w-5 shrink-0 text-right font-mono text-muted-foreground/70">
|
|
207
|
+
{String(index + 1)}
|
|
208
|
+
</span>
|
|
209
|
+
<span
|
|
210
|
+
aria-hidden="true"
|
|
211
|
+
className={cn(
|
|
212
|
+
"size-2.5 shrink-0 rounded-[2px]",
|
|
213
|
+
ROLE_COLOR_CLASSES[segment.role],
|
|
214
|
+
)}
|
|
215
|
+
/>
|
|
216
|
+
<span className="min-w-0 flex-1 truncate text-left">{segment.label}</span>
|
|
217
|
+
<span className="shrink-0 font-mono text-muted-foreground">
|
|
218
|
+
{formatPercent(percent)} | ~{formatTokens(segment.size)}
|
|
219
|
+
</span>
|
|
220
|
+
</>
|
|
221
|
+
);
|
|
222
|
+
if (activate !== undefined) {
|
|
223
|
+
return (
|
|
224
|
+
<button
|
|
225
|
+
key={`${segment.path}-${index}`}
|
|
226
|
+
type="button"
|
|
227
|
+
onClick={() => activate(segment)}
|
|
228
|
+
className="flex h-7 items-center gap-2 rounded px-1.5 text-xs text-muted-foreground hover:bg-muted/40 hover:text-foreground"
|
|
229
|
+
title="Jump to this request block"
|
|
230
|
+
>
|
|
231
|
+
{content}
|
|
232
|
+
</button>
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
return (
|
|
236
|
+
<div
|
|
237
|
+
key={`${segment.path}-${index}`}
|
|
238
|
+
className="flex h-7 items-center gap-2 rounded px-1.5 text-xs text-muted-foreground"
|
|
239
|
+
>
|
|
240
|
+
{content}
|
|
241
|
+
</div>
|
|
242
|
+
);
|
|
243
|
+
})}
|
|
244
|
+
</div>
|
|
93
245
|
</div>
|
|
94
|
-
<SegmentBar segments={segments} totalTokens={total} onActivate={onSegmentActivate} />
|
|
95
246
|
</div>
|
|
96
247
|
</TooltipProvider>
|
|
97
248
|
);
|