@tonyclaw/agent-inspector 2.0.23 → 2.0.24

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 (37) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{CompareDrawer-DnYQtd8R.js → CompareDrawer-DrY-gAzy.js} +1 -1
  3. package/.output/public/assets/ProxyViewerContainer-CiLvRNie.js +115 -0
  4. package/.output/public/assets/{ReplayDialog-B-3V95xT.js → ReplayDialog-CFyw6Vu4.js} +1 -1
  5. package/.output/public/assets/{RequestAnatomy-CT8hLGLa.js → RequestAnatomy-DHGJ9py7.js} +1 -1
  6. package/.output/public/assets/{ResponseView-DK3CYom0.js → ResponseView-CB_3yc08.js} +1 -1
  7. package/.output/public/assets/{StreamingChunkSequence-D3jJutjp.js → StreamingChunkSequence-CqhHwgDn.js} +1 -1
  8. package/.output/public/assets/_sessionId-CgG9CQ9r.js +1 -0
  9. package/.output/public/assets/index-CViEXkqa.js +1 -0
  10. package/.output/public/assets/{main-hF_572U6.js → main-CVw7-JyE.js} +2 -2
  11. package/.output/server/{_sessionId-BqhNE2M8.mjs → _sessionId-V33sBWBC.mjs} +2 -2
  12. package/.output/server/_ssr/{CompareDrawer-C4LQW4S1.mjs → CompareDrawer-C_Fk9joM.mjs} +2 -2
  13. package/.output/server/_ssr/{ProxyViewerContainer-BKInvawk.mjs → ProxyViewerContainer-CyFKksQa.mjs} +75 -32
  14. package/.output/server/_ssr/{ReplayDialog-C3ZiRihL.mjs → ReplayDialog-BpQHN7O2.mjs} +3 -3
  15. package/.output/server/_ssr/{RequestAnatomy-DlVAPIQZ.mjs → RequestAnatomy-CuhmKAma.mjs} +2 -2
  16. package/.output/server/_ssr/{ResponseView-nMS0rkxu.mjs → ResponseView-CO6LyBmj.mjs} +2 -2
  17. package/.output/server/_ssr/{StreamingChunkSequence-PDWqrNiO.mjs → StreamingChunkSequence-DLeVetNR.mjs} +2 -2
  18. package/.output/server/_ssr/{index-Cd1zD-lo.mjs → index-DWUKl9Bf.mjs} +2 -2
  19. package/.output/server/_ssr/index.mjs +2 -2
  20. package/.output/server/_ssr/{router-R9gm7_sh.mjs → router-BrK_DcTS.mjs} +191 -14
  21. package/.output/server/{_tanstack-start-manifest_v-BnLVH_EX.mjs → _tanstack-start-manifest_v-BjW2XeWE.mjs} +1 -1
  22. package/.output/server/index.mjs +61 -61
  23. package/package.json +1 -1
  24. package/src/components/ProxyViewer.tsx +11 -1
  25. package/src/components/ProxyViewerContainer.tsx +21 -15
  26. package/src/lib/export-logs.ts +54 -11
  27. package/src/lib/providerTestPrompt.ts +4 -4
  28. package/src/mcp/toolHandlers.ts +58 -8
  29. package/src/proxy/logFinalizer.ts +79 -1
  30. package/src/proxy/logIndex.ts +6 -1
  31. package/src/proxy/schemas.ts +3 -0
  32. package/src/proxy/store.ts +79 -2
  33. package/src/routes/api/logs.stream.ts +5 -2
  34. package/src/routes/api/logs.ts +4 -1
  35. package/.output/public/assets/ProxyViewerContainer-BTYGkg36.js +0 -115
  36. package/.output/public/assets/_sessionId-DpdfAzbo.js +0 -1
  37. package/.output/public/assets/index-BpJNbm9G.js +0 -1
@@ -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-hF_572U6.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-BpJNbm9G.js", "/assets/ProxyViewerContainer-BTYGkg36.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-DpdfAzbo.js", "/assets/ProxyViewerContainer-BTYGkg36.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/model-metadata", "/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/model-metadata": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.$providerId.model-metadata.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-hF_572U6.js" });
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-CVw7-JyE.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-CViEXkqa.js", "/assets/ProxyViewerContainer-CiLvRNie.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-CgG9CQ9r.js", "/assets/ProxyViewerContainer-CiLvRNie.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/model-metadata", "/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/model-metadata": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.$providerId.model-metadata.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-CVw7-JyE.js" });
2
2
  export {
3
3
  tsrStartManifest
4
4
  };
@@ -38,100 +38,100 @@ const assets = {
38
38
  "/assets/alibaba-TTwafVwX.svg": {
39
39
  "type": "image/svg+xml",
40
40
  "etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
41
- "mtime": "2026-06-29T10:57:03.958Z",
41
+ "mtime": "2026-06-29T12:29:42.542Z",
42
42
  "size": 5915,
43
43
  "path": "../public/assets/alibaba-TTwafVwX.svg"
44
44
  },
45
- "/assets/CompareDrawer-DnYQtd8R.js": {
45
+ "/assets/CompareDrawer-DrY-gAzy.js": {
46
46
  "type": "text/javascript; charset=utf-8",
47
- "etag": '"49fe-b7mmBTYljsLKWenrZlAtgJH1LOY"',
48
- "mtime": "2026-06-29T10:57:03.958Z",
47
+ "etag": '"49fe-MpHiIJshHfw4LFDNCsCMDZDrWGg"',
48
+ "mtime": "2026-06-29T12:29:42.542Z",
49
49
  "size": 18942,
50
- "path": "../public/assets/CompareDrawer-DnYQtd8R.js"
50
+ "path": "../public/assets/CompareDrawer-DrY-gAzy.js"
51
51
  },
52
- "/assets/index-BpJNbm9G.js": {
52
+ "/assets/index-CViEXkqa.js": {
53
53
  "type": "text/javascript; charset=utf-8",
54
- "etag": '"74-5ny3SIFXNJjz8mYDJPqwGLMogII"',
55
- "mtime": "2026-06-29T10:57:03.958Z",
54
+ "etag": '"74-U7AFlYRRMX3IzoDVXXko4xBPBvM"',
55
+ "mtime": "2026-06-29T12:29:42.542Z",
56
56
  "size": 116,
57
- "path": "../public/assets/index-BpJNbm9G.js"
57
+ "path": "../public/assets/index-CViEXkqa.js"
58
58
  },
59
- "/assets/index-780zTVwp.css": {
60
- "type": "text/css; charset=utf-8",
61
- "etag": '"1a380-Lz+Shs13XyKSlh9PTaGE50w/BpU"',
62
- "mtime": "2026-06-29T10:57:03.958Z",
63
- "size": 107392,
64
- "path": "../public/assets/index-780zTVwp.css"
59
+ "/assets/ReplayDialog-CFyw6Vu4.js": {
60
+ "type": "text/javascript; charset=utf-8",
61
+ "etag": '"318c-yVT324FTJnGgK/IiiYVI1v6/IEw"',
62
+ "mtime": "2026-06-29T12:29:42.542Z",
63
+ "size": 12684,
64
+ "path": "../public/assets/ReplayDialog-CFyw6Vu4.js"
65
+ },
66
+ "/assets/RequestAnatomy-DHGJ9py7.js": {
67
+ "type": "text/javascript; charset=utf-8",
68
+ "etag": '"4485-2C+vaW+lYZaQ0wLkm/KTOsK3AOY"',
69
+ "mtime": "2026-06-29T12:29:42.542Z",
70
+ "size": 17541,
71
+ "path": "../public/assets/RequestAnatomy-DHGJ9py7.js"
65
72
  },
66
73
  "/assets/minimax-BPMzvuL-.jpeg": {
67
74
  "type": "image/jpeg",
68
75
  "etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
69
- "mtime": "2026-06-29T10:57:03.958Z",
76
+ "mtime": "2026-06-29T12:29:42.542Z",
70
77
  "size": 6918,
71
78
  "path": "../public/assets/minimax-BPMzvuL-.jpeg"
72
79
  },
73
- "/assets/ReplayDialog-B-3V95xT.js": {
74
- "type": "text/javascript; charset=utf-8",
75
- "etag": '"318c-1NLootFaQs7KDJvmrRBmp0zrGoY"',
76
- "mtime": "2026-06-29T10:57:03.958Z",
77
- "size": 12684,
78
- "path": "../public/assets/ReplayDialog-B-3V95xT.js"
79
- },
80
- "/assets/main-hF_572U6.js": {
81
- "type": "text/javascript; charset=utf-8",
82
- "etag": '"51726-eooZ68MhIVAdbT2A97BnHJuW5lM"',
83
- "mtime": "2026-06-29T10:57:03.958Z",
84
- "size": 333606,
85
- "path": "../public/assets/main-hF_572U6.js"
80
+ "/assets/index-780zTVwp.css": {
81
+ "type": "text/css; charset=utf-8",
82
+ "etag": '"1a380-Lz+Shs13XyKSlh9PTaGE50w/BpU"',
83
+ "mtime": "2026-06-29T12:29:42.542Z",
84
+ "size": 107392,
85
+ "path": "../public/assets/index-780zTVwp.css"
86
86
  },
87
- "/assets/ResponseView-DK3CYom0.js": {
87
+ "/assets/ResponseView-CB_3yc08.js": {
88
88
  "type": "text/javascript; charset=utf-8",
89
- "etag": '"30d0-Cy0g09LS9VDwp/DlETvauFmcBFs"',
90
- "mtime": "2026-06-29T10:57:03.958Z",
89
+ "etag": '"30d0-M6AktqEyUeyPg4kcv2fzak6vFlw"',
90
+ "mtime": "2026-06-29T12:29:42.542Z",
91
91
  "size": 12496,
92
- "path": "../public/assets/ResponseView-DK3CYom0.js"
92
+ "path": "../public/assets/ResponseView-CB_3yc08.js"
93
93
  },
94
- "/assets/RequestAnatomy-CT8hLGLa.js": {
94
+ "/assets/StreamingChunkSequence-CqhHwgDn.js": {
95
95
  "type": "text/javascript; charset=utf-8",
96
- "etag": '"4485-oTcemFMGh2ben0T+njg79IE1+H8"',
97
- "mtime": "2026-06-29T10:57:03.958Z",
98
- "size": 17541,
99
- "path": "../public/assets/RequestAnatomy-CT8hLGLa.js"
100
- },
101
- "/assets/StreamingChunkSequence-D3jJutjp.js": {
102
- "type": "text/javascript; charset=utf-8",
103
- "etag": '"d57-SqKRwuSq9h9H7zwcDkj5Lqd+u/Y"',
104
- "mtime": "2026-06-29T10:57:03.958Z",
96
+ "etag": '"d57-C9p9lFGRMu7L/bxJPes/RpOKks0"',
97
+ "mtime": "2026-06-29T12:29:42.542Z",
105
98
  "size": 3415,
106
- "path": "../public/assets/StreamingChunkSequence-D3jJutjp.js"
99
+ "path": "../public/assets/StreamingChunkSequence-CqhHwgDn.js"
107
100
  },
108
- "/assets/_sessionId-DpdfAzbo.js": {
101
+ "/assets/_sessionId-CgG9CQ9r.js": {
109
102
  "type": "text/javascript; charset=utf-8",
110
- "etag": '"d2-tBmz0AuKXPVen+wNzq7oGvD4J44"',
111
- "mtime": "2026-06-29T10:57:03.958Z",
103
+ "etag": '"d2-QqZWnWujfEY0vnXMOs1NyoEJukI"',
104
+ "mtime": "2026-06-29T12:29:42.542Z",
112
105
  "size": 210,
113
- "path": "../public/assets/_sessionId-DpdfAzbo.js"
114
- },
115
- "/assets/qwen-CONDcHqt.png": {
116
- "type": "image/png",
117
- "etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
118
- "mtime": "2026-06-29T10:57:03.958Z",
119
- "size": 357059,
120
- "path": "../public/assets/qwen-CONDcHqt.png"
106
+ "path": "../public/assets/_sessionId-CgG9CQ9r.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-29T10:57:03.958Z",
111
+ "mtime": "2026-06-29T12:29:42.542Z",
126
112
  "size": 11256,
127
113
  "path": "../public/assets/zhipuai-BPNAnxo-.svg"
128
114
  },
129
- "/assets/ProxyViewerContainer-BTYGkg36.js": {
115
+ "/assets/main-CVw7-JyE.js": {
116
+ "type": "text/javascript; charset=utf-8",
117
+ "etag": '"51726-W+9s8t7uIYMEgBdKzOagDvVRdKc"',
118
+ "mtime": "2026-06-29T12:29:42.542Z",
119
+ "size": 333606,
120
+ "path": "../public/assets/main-CVw7-JyE.js"
121
+ },
122
+ "/assets/qwen-CONDcHqt.png": {
123
+ "type": "image/png",
124
+ "etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
125
+ "mtime": "2026-06-29T12:29:42.542Z",
126
+ "size": 357059,
127
+ "path": "../public/assets/qwen-CONDcHqt.png"
128
+ },
129
+ "/assets/ProxyViewerContainer-CiLvRNie.js": {
130
130
  "type": "text/javascript; charset=utf-8",
131
- "etag": '"adfba-Leh4MRDOCIBADBcckDDDPe8s/NM"',
132
- "mtime": "2026-06-29T10:57:03.958Z",
133
- "size": 712634,
134
- "path": "../public/assets/ProxyViewerContainer-BTYGkg36.js"
131
+ "etag": '"ae3c0-Cpzx6KeaKuGDUgS/cMjRV9y+6zQ"',
132
+ "mtime": "2026-06-29T12:29:42.542Z",
133
+ "size": 713664,
134
+ "path": "../public/assets/ProxyViewerContainer-CiLvRNie.js"
135
135
  }
136
136
  };
137
137
  function readAsset(id) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tonyclaw/agent-inspector",
3
- "version": "2.0.23",
3
+ "version": "2.0.24",
4
4
  "type": "module",
5
5
  "description": "Agent observability and knowledge capture layer for AI coding tools.",
6
6
  "license": "MIT",
@@ -637,6 +637,7 @@ export function ProxyViewer({
637
637
  const { totalIn, totalOut } = useMemo(() => computeTokenSummary(logs), [logs]);
638
638
  const { providers } = useProviders();
639
639
  const [exporting, setExporting] = useState<ExportMode | null>(null);
640
+ const [exportError, setExportError] = useState<string | null>(null);
640
641
  const [comparePair, setComparePair] = useState<[CapturedLog, CapturedLog] | null>(null);
641
642
  const [crabEntrancePhase, setCrabEntrancePhase] = useState<"hidden" | "playing" | "done">(
642
643
  "hidden",
@@ -669,8 +670,12 @@ export function ProxyViewer({
669
670
  const handleExport = useCallback(
670
671
  async (mode: ExportMode) => {
671
672
  setExporting(mode);
673
+ setExportError(null);
672
674
  try {
673
- await exportLogsAsZip(logs, mode);
675
+ const result = await exportLogsAsZip(logs, mode);
676
+ if (!result.ok) {
677
+ setExportError(result.message);
678
+ }
674
679
  } finally {
675
680
  setExporting(null);
676
681
  }
@@ -908,6 +913,11 @@ export function ProxyViewer({
908
913
  Clear
909
914
  </button>
910
915
  </div>
916
+ {exportError !== null && (
917
+ <div className="mb-4 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive">
918
+ {exportError}
919
+ </div>
920
+ )}
911
921
  </div>
912
922
 
913
923
  {/* Log list */}
@@ -64,6 +64,7 @@ function filterLogs(
64
64
  const DEBOUNCE_MS = 50;
65
65
  const HASH_SCROLL_ATTEMPTS = 12;
66
66
  const HASH_HIGHLIGHT_MS = 1800;
67
+ const MAX_CLIENT_LOGS = 500;
67
68
 
68
69
  function buildLogsStreamUrl(sessionId: string | undefined): string {
69
70
  if (sessionId === undefined) return "/api/logs/stream";
@@ -71,6 +72,20 @@ function buildLogsStreamUrl(sessionId: string | undefined): string {
71
72
  return `/api/logs/stream?${params.toString()}`;
72
73
  }
73
74
 
75
+ function buildLogIndex(logs: readonly CapturedLog[]): Map<number, number> {
76
+ const idx = new Map<number, number>();
77
+ for (let i = 0; i < logs.length; i++) {
78
+ const log = logs[i];
79
+ if (log !== undefined) idx.set(log.id, i);
80
+ }
81
+ return idx;
82
+ }
83
+
84
+ function trimClientLogs(logs: CapturedLog[]): CapturedLog[] {
85
+ if (logs.length <= MAX_CLIENT_LOGS) return logs;
86
+ return logs.slice(logs.length - MAX_CLIENT_LOGS);
87
+ }
88
+
74
89
  export function ProxyViewerContainer({
75
90
  initialSessionId,
76
91
  }: {
@@ -132,6 +147,8 @@ export function ProxyViewerContainer({
132
147
  next = [...next, log];
133
148
  }
134
149
  }
150
+ next = trimClientLogs(next);
151
+ logIndexRef.current = buildLogIndex(next);
135
152
  return next;
136
153
  });
137
154
  }, []);
@@ -173,14 +190,9 @@ export function ProxyViewerContainer({
173
190
  }
174
191
  pendingUpdatesRef.current = [];
175
192
 
176
- // Build fresh index
177
- const idx = new Map<number, number>();
178
- for (let i = 0; i < update.logs.length; i++) {
179
- const log = update.logs[i];
180
- if (log !== undefined) idx.set(log.id, i);
181
- }
182
- logIndexRef.current = idx;
183
- setAllLogs(update.logs);
193
+ const nextLogs = trimClientLogs(update.logs);
194
+ logIndexRef.current = buildLogIndex(nextLogs);
195
+ setAllLogs(nextLogs);
184
196
  setError(null);
185
197
  } else if (update.type === "update") {
186
198
  scheduleUpdate(update.log);
@@ -317,13 +329,7 @@ export function ProxyViewerContainer({
317
329
  const idSet = new Set(ids);
318
330
  setAllLogs((prev) => {
319
331
  const remaining = prev.filter((l) => !idSet.has(l.id));
320
- // Rebuild index
321
- const idx = new Map<number, number>();
322
- for (let i = 0; i < remaining.length; i++) {
323
- const log = remaining[i];
324
- if (log !== undefined) idx.set(log.id, i);
325
- }
326
- logIndexRef.current = idx;
332
+ logIndexRef.current = buildLogIndex(remaining);
327
333
  return remaining;
328
334
  });
329
335
  setError(null);
@@ -2,6 +2,12 @@ import JSZip from "jszip";
2
2
  import type { CapturedLog } from "../proxy/schemas";
3
3
 
4
4
  export type ExportMode = "redacted" | "raw";
5
+ export type ExportLogsResult =
6
+ | { ok: true }
7
+ | {
8
+ ok: false;
9
+ message: string;
10
+ };
5
11
 
6
12
  const REDACTED = "[REDACTED]";
7
13
  const SECRET_KEY_PATTERN =
@@ -13,6 +19,39 @@ const SECRET_TEXT_PATTERNS: readonly RegExp[] = [
13
19
  /\bghp_[A-Za-z0-9_]{12,}\b/g,
14
20
  /\bglpat-[A-Za-z0-9_-]{12,}\b/g,
15
21
  ];
22
+ const MAX_EXPORT_LOGS = 200;
23
+ const MAX_EXPORT_TEXT_CHARS = 25_000_000;
24
+ const MAX_STREAMING_CHUNK_EXPORTS = 50;
25
+
26
+ function formatApproxSize(chars: number): string {
27
+ if (chars < 1024) return `${chars} chars`;
28
+ if (chars < 1024 * 1024) return `${Math.ceil(chars / 1024)} KB`;
29
+ return `${Math.ceil(chars / (1024 * 1024))} MB`;
30
+ }
31
+
32
+ function estimateExportTextChars(logs: readonly CapturedLog[]): number {
33
+ let total = 0;
34
+ for (const log of logs) {
35
+ total += log.rawRequestBody?.length ?? 0;
36
+ total += log.responseText?.length ?? 0;
37
+ }
38
+ return total;
39
+ }
40
+
41
+ function exportLimitMessage(logs: readonly CapturedLog[]): string | null {
42
+ if (logs.length > MAX_EXPORT_LOGS) {
43
+ return `Export is limited to ${MAX_EXPORT_LOGS} logs at once. Narrow the filter and try again.`;
44
+ }
45
+
46
+ const estimatedChars = estimateExportTextChars(logs);
47
+ if (estimatedChars > MAX_EXPORT_TEXT_CHARS) {
48
+ return `Export is too large (${formatApproxSize(
49
+ estimatedChars,
50
+ )} of text). Narrow the filter and try again.`;
51
+ }
52
+
53
+ return null;
54
+ }
16
55
 
17
56
  async function fetchStreamingChunks(logId: number): Promise<string | null> {
18
57
  try {
@@ -64,9 +103,13 @@ function exportText(text: string, mode: ExportMode): string {
64
103
  export async function exportLogsAsZip(
65
104
  logs: CapturedLog[],
66
105
  mode: ExportMode = "redacted",
67
- ): Promise<void> {
106
+ ): Promise<ExportLogsResult> {
107
+ const limitMessage = exportLimitMessage(logs);
108
+ if (limitMessage !== null) return { ok: false, message: limitMessage };
109
+
68
110
  const zip = new JSZip();
69
111
  const suffix = mode === "redacted" ? "redacted" : "raw";
112
+ const streamingLogs = logs.filter((log) => log.streaming).slice(0, MAX_STREAMING_CHUNK_EXPORTS);
70
113
  zip.file(
71
114
  "manifest.json",
72
115
  JSON.stringify(
@@ -76,6 +119,8 @@ export async function exportLogsAsZip(
76
119
  redacted: mode === "redacted",
77
120
  logCount: logs.length,
78
121
  logIds: logs.map((log) => log.id),
122
+ streamingChunkExportLimit: MAX_STREAMING_CHUNK_EXPORTS,
123
+ streamingChunkLogIds: streamingLogs.map((log) => log.id),
79
124
  },
80
125
  null,
81
126
  2,
@@ -92,16 +137,13 @@ export async function exportLogsAsZip(
92
137
  }
93
138
  }
94
139
 
95
- // Fetch SSE chunks in parallel for streaming logs
96
- const streamingLogs = logs.filter((log) => log.streaming);
97
- await Promise.allSettled(
98
- streamingLogs.map(async (log) => {
99
- const chunks = await fetchStreamingChunks(log.id);
100
- if (chunks !== null) {
101
- zip.file(`#${log.id}.SSE.Response.json`, exportText(chunks, mode));
102
- }
103
- }),
104
- );
140
+ // Fetch SSE chunks sequentially so exports do not spike browser memory.
141
+ for (const log of streamingLogs) {
142
+ const chunks = await fetchStreamingChunks(log.id);
143
+ if (chunks !== null) {
144
+ zip.file(`#${log.id}.SSE.Response.json`, exportText(chunks, mode));
145
+ }
146
+ }
105
147
 
106
148
  // Generate and download ZIP
107
149
  const blob = await zip.generateAsync({ type: "blob" });
@@ -115,4 +157,5 @@ export async function exportLogsAsZip(
115
157
  document.body.removeChild(anchor);
116
158
 
117
159
  URL.revokeObjectURL(url);
160
+ return { ok: true };
118
161
  }
@@ -9,7 +9,7 @@ export type ProviderTestRequestBody = {
9
9
  model: string;
10
10
  messages: ProviderTestMessage[];
11
11
  max_tokens: number;
12
- stream?: true;
12
+ stream: boolean;
13
13
  };
14
14
 
15
15
  const MEMORY_PROBE_FACTS = [
@@ -32,9 +32,9 @@ function modeInstruction(mode: ProviderTestMode): string {
32
32
  function maxTokensForMode(mode: ProviderTestMode): number {
33
33
  switch (mode) {
34
34
  case "non-streaming":
35
- return 1024;
35
+ return 256;
36
36
  case "streaming":
37
- return 384;
37
+ return 256;
38
38
  }
39
39
  }
40
40
 
@@ -71,7 +71,7 @@ export function buildProviderTestRequestBody(
71
71
  };
72
72
  switch (mode) {
73
73
  case "non-streaming":
74
- return base;
74
+ return { ...base, stream: false };
75
75
  case "streaming":
76
76
  return { ...base, stream: true };
77
77
  }
@@ -13,12 +13,13 @@
13
13
  * `isError: true` results from inside the impl.
14
14
  */
15
15
 
16
+ import { Buffer } from "node:buffer";
16
17
  import { z } from "zod";
17
18
  import { LoopbackTimeoutError, type CallApiOptions } from "./loopback";
18
19
  import { extractLastUserMessagePreview, extractResponsePreview } from "./previewExtractor";
19
20
  import { CapturedLogSchema, type CapturedLog } from "../proxy/schemas";
20
21
 
21
- /** Minimal callApi contract same shape as the real `callApi` in loopback.ts. */
22
+ /** Minimal callApi contract: same shape as the real `callApi` in loopback.ts. */
22
23
  export type CallApiFn = (path: string, options?: CallApiOptions) => Promise<Response>;
23
24
 
24
25
  export type ToolResult = {
@@ -26,7 +27,7 @@ export type ToolResult = {
26
27
  isError?: true;
27
28
  };
28
29
 
29
- // Loose shape returned by `GET /api/logs` `logs: CapturedLog[]` and a few
30
+ // Loose shape returned by `GET /api/logs`: `logs: CapturedLog[]` and a few
30
31
  // pagination fields. The CapturedLog items are fully validated downstream.
31
32
  const LogsListResponseSchema = z.object({
32
33
  logs: z.array(CapturedLogSchema).optional(),
@@ -37,6 +38,7 @@ const LogsListResponseSchema = z.object({
37
38
 
38
39
  const PAGINATION_DEFAULTS = { offset: 0, limit: 3 };
39
40
  export const LIMIT_HARD_CAP = 5;
41
+ const LOG_DETAIL_TEXT_LIMIT = 200_000;
40
42
 
41
43
  export function clampLimit(input: number | undefined): number {
42
44
  if (input === undefined) return PAGINATION_DEFAULTS.limit;
@@ -52,10 +54,55 @@ function toolError(message: string): ToolResult {
52
54
  return { content: [{ type: "text", text: message }], isError: true };
53
55
  }
54
56
 
57
+ function textByteLength(value: string | null): number | null {
58
+ if (value === null) return null;
59
+ return Buffer.byteLength(value, "utf8");
60
+ }
61
+
62
+ function hasBodyText(value: string | null, byteLength: number | null | undefined): boolean {
63
+ if (value !== null && value.length > 0) return true;
64
+ return byteLength !== undefined && byteLength !== null && byteLength > 0;
65
+ }
66
+
67
+ function truncateToolText(value: string | null): {
68
+ value: string | null;
69
+ byteLength: number | null;
70
+ truncated: boolean;
71
+ } {
72
+ if (value === null) return { value: null, byteLength: null, truncated: false };
73
+ const byteLength = textByteLength(value);
74
+ if (value.length <= LOG_DETAIL_TEXT_LIMIT) {
75
+ return { value, byteLength, truncated: false };
76
+ }
77
+ const suffix = `\n[truncated by agent-inspector MCP: original ${byteLength ?? 0} bytes]`;
78
+ return {
79
+ value: `${value.slice(0, LOG_DETAIL_TEXT_LIMIT)}${suffix}`,
80
+ byteLength,
81
+ truncated: true,
82
+ };
83
+ }
84
+
85
+ function buildBoundedLogDetail(log: CapturedLog): Record<string, unknown> {
86
+ const { streamingChunks: _chunks, rawRequestBody, responseText, ...rest } = log;
87
+ const boundedRequest = truncateToolText(rawRequestBody);
88
+ const boundedResponse = truncateToolText(responseText);
89
+ return {
90
+ ...rest,
91
+ rawRequestBody: boundedRequest.value,
92
+ responseText: boundedResponse.value,
93
+ rawRequestBodyBytes: boundedRequest.byteLength,
94
+ responseTextBytes: boundedResponse.byteLength,
95
+ rawRequestBodyTruncated: boundedRequest.truncated,
96
+ responseTextTruncated: boundedResponse.truncated,
97
+ };
98
+ }
99
+
55
100
  export function buildLogSummary(log: CapturedLog) {
56
101
  const hasError =
57
102
  (log.error !== null && log.error !== undefined && log.error.length > 0) ||
58
103
  (log.responseStatus !== null && log.responseStatus !== undefined && log.responseStatus >= 400);
104
+ const rawRequestBodyBytes = log.rawRequestBodyBytes ?? textByteLength(log.rawRequestBody);
105
+ const responseTextBytes = log.responseTextBytes ?? textByteLength(log.responseText);
59
106
  return {
60
107
  id: log.id,
61
108
  timestamp: log.timestamp,
@@ -81,7 +128,9 @@ export function buildLogSummary(log: CapturedLog) {
81
128
  hasChunks:
82
129
  (log.streamingChunks !== undefined && log.streamingChunks !== null) ||
83
130
  (log.streamingChunksPath !== null && log.streamingChunksPath !== undefined),
84
- hasRawRequestBody: log.rawRequestBody !== null && log.rawRequestBody !== undefined,
131
+ hasRawRequestBody: hasBodyText(log.rawRequestBody, rawRequestBodyBytes),
132
+ rawRequestBodyBytes,
133
+ responseTextBytes,
85
134
  };
86
135
  }
87
136
 
@@ -99,7 +148,11 @@ export type ListLogsArgs = {
99
148
  export async function listLogsImpl(callApi: CallApiFn, args: ListLogsArgs): Promise<ToolResult> {
100
149
  const offset = args.offset ?? PAGINATION_DEFAULTS.offset;
101
150
  const limit = clampLimit(args.limit);
102
- const params = new URLSearchParams({ offset: String(offset), limit: String(limit) });
151
+ const params = new URLSearchParams({
152
+ offset: String(offset),
153
+ limit: String(limit),
154
+ compact: "1",
155
+ });
103
156
  if (args.sessionId !== undefined && args.sessionId.length > 0) {
104
157
  params.set("sessionId", args.sessionId);
105
158
  }
@@ -123,10 +176,7 @@ export async function getLogImpl(callApi: CallApiFn, id: number): Promise<ToolRe
123
176
  if (!parsed.success) {
124
177
  return toolError(`GET /api/logs/${id} returned an unparseable CapturedLog`);
125
178
  }
126
- // Strip streamingChunks per design D6 — the agent asks for chunks
127
- // explicitly via inspector_get_log_chunks.
128
- const { streamingChunks: _chunks, ...rest } = parsed.data;
129
- return textJson(rest);
179
+ return textJson(buildBoundedLogDetail(parsed.data));
130
180
  }
131
181
 
132
182
  export async function getLogChunksImpl(callApi: CallApiFn, id: number): Promise<ToolResult> {