@tonyclaw/agent-inspector 2.1.22 → 2.1.23
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-B-I_z_oJ.js → CompareDrawer-Cvgl_Jmi.js} +1 -1
- package/.output/public/assets/ProxyViewerContainer-CNLLZq37.js +106 -0
- package/.output/public/assets/{ReplayDialog-ofqVRdc-.js → ReplayDialog-DeEELx0X.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-lyPjHWzS.js → RequestAnatomy-CrLSqdiA.js} +1 -1
- package/.output/public/assets/ResponseView-CFIqDL5E.js +3 -0
- package/.output/public/assets/{StreamingChunkSequence-CIn2xdVv.js → StreamingChunkSequence-DSRjbgqb.js} +1 -1
- package/.output/public/assets/{_sessionId-KmeAKZJw.js → _sessionId-ZuH6-ZX5.js} +1 -1
- package/.output/public/assets/index-B26q0-ch.js +1 -0
- package/.output/public/assets/{index-M6p8Q0LA.js → index-BZxLBVYd.js} +1 -1
- package/.output/public/assets/index-CxszCIFm.css +1 -0
- package/.output/public/assets/{json-viewer-VR9OOnl8.js → json-viewer-DERQNZRV.js} +1 -1
- package/.output/public/assets/{main-C9gW57P6.js → main-BoshTI0W.js} +2 -2
- package/.output/server/{_sessionId-CBwwWBFg.mjs → _sessionId-BYGtH1pK.mjs} +2 -2
- package/.output/server/_ssr/{CompareDrawer-Dw6CL_qf.mjs → CompareDrawer-OchnKiac.mjs} +2 -2
- package/.output/server/_ssr/{ProxyViewerContainer-BX4RgrZU.mjs → ProxyViewerContainer-C2lwYwDu.mjs} +2645 -2616
- package/.output/server/_ssr/{ReplayDialog-DS9K_cof.mjs → ReplayDialog-BYwaF14u.mjs} +3 -3
- package/.output/server/_ssr/{RequestAnatomy-B2JsAL49.mjs → RequestAnatomy-DTueiqT5.mjs} +2 -2
- package/.output/server/_ssr/{ResponseView-C3LQSg2c.mjs → ResponseView-CqB9NKHB.mjs} +201 -54
- package/.output/server/_ssr/{StreamingChunkSequence-O1Ti-7Pk.mjs → StreamingChunkSequence-DENB9VUj.mjs} +2 -2
- package/.output/server/_ssr/{index-BZ2ijzyu.mjs → index-BR3ea3Zb.mjs} +2 -2
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{json-viewer-BRMmlvXb.mjs → json-viewer-BU9ZUaHK.mjs} +2 -2
- package/.output/server/_ssr/{router-DlGZ0qLz.mjs → router-DT6BcrEg.mjs} +4 -4
- package/.output/server/{_tanstack-start-manifest_v-CYvWDgeN.mjs → _tanstack-start-manifest_v-xQ1BRoZw.mjs} +1 -1
- package/.output/server/index.mjs +68 -68
- package/package.json +1 -1
- package/src/components/proxy-viewer/LogEntry.tsx +10 -0
- package/src/components/proxy-viewer/ResponseView.tsx +5 -1
- package/src/components/proxy-viewer/ToolTraceEvents.tsx +19 -31
- package/src/components/proxy-viewer/TurnGroup.tsx +21 -7
- package/src/components/proxy-viewer/formats/anthropic/ContentBlocks.tsx +37 -4
- package/src/components/proxy-viewer/formats/anthropic/ResponseView.tsx +17 -3
- package/src/components/proxy-viewer/formats/index.tsx +8 -3
- package/src/components/proxy-viewer/formats/openai/ResponseView.tsx +122 -16
- package/src/components/proxy-viewer/logFocus.ts +11 -3
- package/src/components/proxy-viewer/viewerState.ts +22 -7
- package/.output/public/assets/ProxyViewerContainer-ygSGJ4EB.js +0 -106
- package/.output/public/assets/ResponseView-BL263es5.js +0 -3
- package/.output/public/assets/index-DFEiGFKE.js +0 -1
- package/.output/public/assets/index-bXU6y_wh.css +0 -1
package/.output/server/index.mjs
CHANGED
|
@@ -38,114 +38,114 @@ const assets = {
|
|
|
38
38
|
"/assets/alibaba-TTwafVwX.svg": {
|
|
39
39
|
"type": "image/svg+xml",
|
|
40
40
|
"etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
|
|
41
|
-
"mtime": "2026-07-
|
|
41
|
+
"mtime": "2026-07-06T23:30:24.816Z",
|
|
42
42
|
"size": 5915,
|
|
43
43
|
"path": "../public/assets/alibaba-TTwafVwX.svg"
|
|
44
44
|
},
|
|
45
|
-
"/assets/
|
|
45
|
+
"/assets/index-B26q0-ch.js": {
|
|
46
46
|
"type": "text/javascript; charset=utf-8",
|
|
47
|
-
"etag": '"
|
|
48
|
-
"mtime": "2026-07-
|
|
49
|
-
"size": 19391,
|
|
50
|
-
"path": "../public/assets/CompareDrawer-B-I_z_oJ.js"
|
|
51
|
-
},
|
|
52
|
-
"/assets/json-viewer-VR9OOnl8.js": {
|
|
53
|
-
"type": "text/javascript; charset=utf-8",
|
|
54
|
-
"etag": '"1ae6-q2HRnhbr4RmbtnJRlXqA3AA5pn0"',
|
|
55
|
-
"mtime": "2026-07-06T08:42:14.500Z",
|
|
56
|
-
"size": 6886,
|
|
57
|
-
"path": "../public/assets/json-viewer-VR9OOnl8.js"
|
|
58
|
-
},
|
|
59
|
-
"/assets/index-DFEiGFKE.js": {
|
|
60
|
-
"type": "text/javascript; charset=utf-8",
|
|
61
|
-
"etag": '"74-qVbgeAxjdS6pAIAlbzvrFevVSso"',
|
|
62
|
-
"mtime": "2026-07-06T08:42:14.500Z",
|
|
47
|
+
"etag": '"74-AZvnGEhntbiyIDS+wwwbTZjCuCw"',
|
|
48
|
+
"mtime": "2026-07-06T23:30:24.817Z",
|
|
63
49
|
"size": 116,
|
|
64
|
-
"path": "../public/assets/index-
|
|
50
|
+
"path": "../public/assets/index-B26q0-ch.js"
|
|
65
51
|
},
|
|
66
|
-
"/assets/
|
|
52
|
+
"/assets/json-viewer-DERQNZRV.js": {
|
|
67
53
|
"type": "text/javascript; charset=utf-8",
|
|
68
|
-
"etag": '"
|
|
69
|
-
"mtime": "2026-07-
|
|
70
|
-
"size":
|
|
71
|
-
"path": "../public/assets/
|
|
54
|
+
"etag": '"1ae6-A6B2jiKFX+jryATLfM15t7QIsvM"',
|
|
55
|
+
"mtime": "2026-07-06T23:30:24.817Z",
|
|
56
|
+
"size": 6886,
|
|
57
|
+
"path": "../public/assets/json-viewer-DERQNZRV.js"
|
|
72
58
|
},
|
|
73
59
|
"/assets/minimax-BPMzvuL-.jpeg": {
|
|
74
60
|
"type": "image/jpeg",
|
|
75
61
|
"etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
|
|
76
|
-
"mtime": "2026-07-
|
|
62
|
+
"mtime": "2026-07-06T23:30:24.816Z",
|
|
77
63
|
"size": 6918,
|
|
78
64
|
"path": "../public/assets/minimax-BPMzvuL-.jpeg"
|
|
79
65
|
},
|
|
80
|
-
"/assets/
|
|
81
|
-
"type": "text/
|
|
82
|
-
"etag": '"
|
|
83
|
-
"mtime": "2026-07-
|
|
84
|
-
"size":
|
|
85
|
-
"path": "../public/assets/
|
|
66
|
+
"/assets/index-CxszCIFm.css": {
|
|
67
|
+
"type": "text/css; charset=utf-8",
|
|
68
|
+
"etag": '"219d3-hGkO4OXmpghyDnxd7KIL9unRxwQ"',
|
|
69
|
+
"mtime": "2026-07-06T23:30:24.817Z",
|
|
70
|
+
"size": 137683,
|
|
71
|
+
"path": "../public/assets/index-CxszCIFm.css"
|
|
86
72
|
},
|
|
87
|
-
"/assets/
|
|
73
|
+
"/assets/CompareDrawer-Cvgl_Jmi.js": {
|
|
88
74
|
"type": "text/javascript; charset=utf-8",
|
|
89
|
-
"etag": '"
|
|
90
|
-
"mtime": "2026-07-
|
|
91
|
-
"size":
|
|
92
|
-
"path": "../public/assets/
|
|
75
|
+
"etag": '"4bbf-qdrjZBBOyzn/JHMYJ2UAiNDDbFQ"',
|
|
76
|
+
"mtime": "2026-07-06T23:30:24.817Z",
|
|
77
|
+
"size": 19391,
|
|
78
|
+
"path": "../public/assets/CompareDrawer-Cvgl_Jmi.js"
|
|
93
79
|
},
|
|
94
|
-
"/assets/index-
|
|
95
|
-
"type": "text/
|
|
96
|
-
"etag": '"
|
|
97
|
-
"mtime": "2026-07-
|
|
98
|
-
"size":
|
|
99
|
-
"path": "../public/assets/index-
|
|
80
|
+
"/assets/index-BZxLBVYd.js": {
|
|
81
|
+
"type": "text/javascript; charset=utf-8",
|
|
82
|
+
"etag": '"1cd2c-eSvMM8zbdBG02FS4JJNg0vJ028w"',
|
|
83
|
+
"mtime": "2026-07-06T23:30:24.817Z",
|
|
84
|
+
"size": 118060,
|
|
85
|
+
"path": "../public/assets/index-BZxLBVYd.js"
|
|
100
86
|
},
|
|
101
|
-
"/assets/RequestAnatomy-
|
|
87
|
+
"/assets/RequestAnatomy-CrLSqdiA.js": {
|
|
102
88
|
"type": "text/javascript; charset=utf-8",
|
|
103
|
-
"etag": '"43f2-
|
|
104
|
-
"mtime": "2026-07-
|
|
89
|
+
"etag": '"43f2-YwOCt5e63SibXMhWqzHRxd1nNC8"',
|
|
90
|
+
"mtime": "2026-07-06T23:30:24.817Z",
|
|
105
91
|
"size": 17394,
|
|
106
|
-
"path": "../public/assets/RequestAnatomy-
|
|
92
|
+
"path": "../public/assets/RequestAnatomy-CrLSqdiA.js"
|
|
107
93
|
},
|
|
108
|
-
"/assets/
|
|
94
|
+
"/assets/ReplayDialog-DeEELx0X.js": {
|
|
109
95
|
"type": "text/javascript; charset=utf-8",
|
|
110
|
-
"etag": '"
|
|
111
|
-
"mtime": "2026-07-
|
|
112
|
-
"size":
|
|
113
|
-
"path": "../public/assets/
|
|
96
|
+
"etag": '"31d6-hWOAjkfta2prr+9EmQOXzNOAzTU"',
|
|
97
|
+
"mtime": "2026-07-06T23:30:24.817Z",
|
|
98
|
+
"size": 12758,
|
|
99
|
+
"path": "../public/assets/ReplayDialog-DeEELx0X.js"
|
|
114
100
|
},
|
|
115
|
-
"/assets/ResponseView-
|
|
101
|
+
"/assets/ResponseView-CFIqDL5E.js": {
|
|
116
102
|
"type": "text/javascript; charset=utf-8",
|
|
117
|
-
"etag": '"
|
|
118
|
-
"mtime": "2026-07-
|
|
119
|
-
"size":
|
|
120
|
-
"path": "../public/assets/ResponseView-
|
|
103
|
+
"etag": '"47fa-+VN13C6cvB2BYNKPjLEy9ibIswM"',
|
|
104
|
+
"mtime": "2026-07-06T23:30:24.817Z",
|
|
105
|
+
"size": 18426,
|
|
106
|
+
"path": "../public/assets/ResponseView-CFIqDL5E.js"
|
|
121
107
|
},
|
|
122
|
-
"/assets/
|
|
108
|
+
"/assets/main-BoshTI0W.js": {
|
|
123
109
|
"type": "text/javascript; charset=utf-8",
|
|
124
|
-
"etag": '"
|
|
125
|
-
"mtime": "2026-07-
|
|
126
|
-
"size":
|
|
127
|
-
"path": "../public/assets/
|
|
110
|
+
"etag": '"512fd-NlLbmALn+PuYHWA4Dj6BVyzFIuM"',
|
|
111
|
+
"mtime": "2026-07-06T23:30:24.817Z",
|
|
112
|
+
"size": 332541,
|
|
113
|
+
"path": "../public/assets/main-BoshTI0W.js"
|
|
128
114
|
},
|
|
129
115
|
"/assets/zhipuai-BPNAnxo-.svg": {
|
|
130
116
|
"type": "image/svg+xml",
|
|
131
117
|
"etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
|
|
132
|
-
"mtime": "2026-07-
|
|
118
|
+
"mtime": "2026-07-06T23:30:24.816Z",
|
|
133
119
|
"size": 11256,
|
|
134
120
|
"path": "../public/assets/zhipuai-BPNAnxo-.svg"
|
|
135
121
|
},
|
|
122
|
+
"/assets/_sessionId-ZuH6-ZX5.js": {
|
|
123
|
+
"type": "text/javascript; charset=utf-8",
|
|
124
|
+
"etag": '"36c-yfRDDJm0mM1r+nbDh5oXBDpciWQ"',
|
|
125
|
+
"mtime": "2026-07-06T23:30:24.817Z",
|
|
126
|
+
"size": 876,
|
|
127
|
+
"path": "../public/assets/_sessionId-ZuH6-ZX5.js"
|
|
128
|
+
},
|
|
129
|
+
"/assets/StreamingChunkSequence-DSRjbgqb.js": {
|
|
130
|
+
"type": "text/javascript; charset=utf-8",
|
|
131
|
+
"etag": '"dd6-phWzlhQq/JJk54G5Z2rU0kzp2as"',
|
|
132
|
+
"mtime": "2026-07-06T23:30:24.817Z",
|
|
133
|
+
"size": 3542,
|
|
134
|
+
"path": "../public/assets/StreamingChunkSequence-DSRjbgqb.js"
|
|
135
|
+
},
|
|
136
136
|
"/assets/qwen-CONDcHqt.png": {
|
|
137
137
|
"type": "image/png",
|
|
138
138
|
"etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
|
|
139
|
-
"mtime": "2026-07-
|
|
139
|
+
"mtime": "2026-07-06T23:30:24.816Z",
|
|
140
140
|
"size": 357059,
|
|
141
141
|
"path": "../public/assets/qwen-CONDcHqt.png"
|
|
142
142
|
},
|
|
143
|
-
"/assets/ProxyViewerContainer-
|
|
143
|
+
"/assets/ProxyViewerContainer-CNLLZq37.js": {
|
|
144
144
|
"type": "text/javascript; charset=utf-8",
|
|
145
|
-
"etag": '"
|
|
146
|
-
"mtime": "2026-07-
|
|
147
|
-
"size":
|
|
148
|
-
"path": "../public/assets/ProxyViewerContainer-
|
|
145
|
+
"etag": '"aece0-rsojOMYS6lexxfh1G0dXZ/InUpE"',
|
|
146
|
+
"mtime": "2026-07-06T23:30:24.817Z",
|
|
147
|
+
"size": 716e3,
|
|
148
|
+
"path": "../public/assets/ProxyViewerContainer-CNLLZq37.js"
|
|
149
149
|
}
|
|
150
150
|
};
|
|
151
151
|
function readAsset(id) {
|
package/package.json
CHANGED
|
@@ -60,6 +60,8 @@ function resolveFocusedTab(tab: LogFocusTab, anatomySegments: AnatomySegment[] |
|
|
|
60
60
|
return anatomySegments === null ? "request" : "anatomy";
|
|
61
61
|
case "request":
|
|
62
62
|
return "request";
|
|
63
|
+
case "response":
|
|
64
|
+
return "parsed";
|
|
63
65
|
}
|
|
64
66
|
}
|
|
65
67
|
|
|
@@ -429,6 +431,8 @@ export const LogEntry = memo(function ({
|
|
|
429
431
|
const [headersDiff, setHeadersDiff] = useState<boolean>(false);
|
|
430
432
|
const [requestDiff, setRequestDiff] = useState<boolean>(false);
|
|
431
433
|
const [activeTab, setActiveTab] = useState("request");
|
|
434
|
+
const [focusedToolIndex, setFocusedToolIndex] = useState<number | null>(null);
|
|
435
|
+
const [toolFocusNonce, setToolFocusNonce] = useState(0);
|
|
432
436
|
const [expandToPath, setExpandToPath] = useState<string | null>(null);
|
|
433
437
|
const [hydratedLog, setHydratedLog] = useState<CapturedLog | null>(null);
|
|
434
438
|
const [bodyHydrationStatus, setBodyHydrationStatus] = useState<BodyHydrationStatus>("idle");
|
|
@@ -779,6 +783,10 @@ export const LogEntry = memo(function ({
|
|
|
779
783
|
if (request.logId !== log.id) return;
|
|
780
784
|
setExpanded(true);
|
|
781
785
|
setActiveTab(resolveFocusedTab(request.tab, anatomySegments));
|
|
786
|
+
if (request.tab === "response" && request.toolCallIndex !== undefined) {
|
|
787
|
+
setFocusedToolIndex(request.toolCallIndex);
|
|
788
|
+
setToolFocusNonce((current) => current + 1);
|
|
789
|
+
}
|
|
782
790
|
};
|
|
783
791
|
|
|
784
792
|
window.addEventListener(LOG_FOCUS_REQUEST_EVENT, handleLogFocusRequest);
|
|
@@ -1120,6 +1128,8 @@ export const LogEntry = memo(function ({
|
|
|
1120
1128
|
cacheReadInputTokens={displayLog.cacheReadInputTokens}
|
|
1121
1129
|
apiFormat={resolvedFormat}
|
|
1122
1130
|
error={displayLog.error}
|
|
1131
|
+
focusedToolIndex={focusedToolIndex}
|
|
1132
|
+
toolFocusNonce={toolFocusNonce}
|
|
1123
1133
|
/>
|
|
1124
1134
|
</Suspense>
|
|
1125
1135
|
)}
|
|
@@ -19,6 +19,8 @@ export type ResponseViewProps = {
|
|
|
19
19
|
apiFormat?: ApiFormat;
|
|
20
20
|
/** SSE error message from streaming response */
|
|
21
21
|
error?: string | null;
|
|
22
|
+
focusedToolIndex?: number | null;
|
|
23
|
+
toolFocusNonce?: number;
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
function getStatusClasses(category: StatusCategory): string {
|
|
@@ -74,6 +76,8 @@ export const ResponseView = memo(function ResponseView({
|
|
|
74
76
|
cacheReadInputTokens,
|
|
75
77
|
apiFormat,
|
|
76
78
|
error,
|
|
79
|
+
focusedToolIndex = null,
|
|
80
|
+
toolFocusNonce = 0,
|
|
77
81
|
}: ResponseViewProps): JSX.Element {
|
|
78
82
|
const resolvedFormat = apiFormat ?? "unknown";
|
|
79
83
|
const parsed = useMemo(
|
|
@@ -128,7 +132,7 @@ export const ResponseView = memo(function ResponseView({
|
|
|
128
132
|
return (
|
|
129
133
|
<div className="space-y-2">
|
|
130
134
|
<StatusIndicator status={responseStatus} />
|
|
131
|
-
{formatViewFor(resolvedFormat, parsed)}
|
|
135
|
+
{formatViewFor(resolvedFormat, parsed, { focusedToolIndex, toolFocusNonce })}
|
|
132
136
|
</div>
|
|
133
137
|
);
|
|
134
138
|
}
|
|
@@ -1,52 +1,40 @@
|
|
|
1
1
|
import { type JSX } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { Wrench } from "lucide-react";
|
|
3
3
|
import type { ToolTraceEvent } from "./viewerState";
|
|
4
|
-
import {
|
|
4
|
+
import { dispatchLogFocusRequest } from "./logFocus";
|
|
5
5
|
|
|
6
6
|
type ToolTraceEventsProps = {
|
|
7
7
|
events: ToolTraceEvent[];
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
function
|
|
11
|
-
const argumentCopy = useCopyFeedback(event.argumentsText);
|
|
12
|
-
const canCopyArguments = event.argumentsText !== null;
|
|
13
|
-
|
|
10
|
+
function ToolTraceEventChip({ event }: { event: ToolTraceEvent }): JSX.Element {
|
|
14
11
|
return (
|
|
15
|
-
<
|
|
12
|
+
<button
|
|
13
|
+
type="button"
|
|
16
14
|
key={event.id}
|
|
17
|
-
className="
|
|
15
|
+
className="inline-flex min-w-0 items-center gap-1.5 rounded-md bg-white/[0.035] px-2 py-1 text-xs text-muted-foreground transition-colors hover:bg-sky-400/[0.08] hover:text-sky-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
16
|
+
onClick={() =>
|
|
17
|
+
dispatchLogFocusRequest({
|
|
18
|
+
logId: event.logId,
|
|
19
|
+
tab: "response",
|
|
20
|
+
toolCallIndex: event.index,
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
aria-label={`Open response tool call ${event.name}`}
|
|
24
|
+
title={`Open ${event.name} in Response`}
|
|
18
25
|
>
|
|
19
26
|
<Wrench className="size-3.5 shrink-0 text-sky-400/70" />
|
|
20
|
-
<span className="font-mono font-semibold
|
|
21
|
-
|
|
22
|
-
<>
|
|
23
|
-
<ChevronRight className="size-3 shrink-0 text-muted-foreground/60" />
|
|
24
|
-
<span className="min-w-0 truncate font-mono text-muted-foreground">
|
|
25
|
-
{event.argumentsPreview}
|
|
26
|
-
</span>
|
|
27
|
-
</>
|
|
28
|
-
)}
|
|
29
|
-
{canCopyArguments && (
|
|
30
|
-
<button
|
|
31
|
-
type="button"
|
|
32
|
-
className="ml-auto inline-flex size-6 shrink-0 items-center justify-center rounded text-muted-foreground opacity-0 transition-opacity hover:bg-background/80 hover:text-foreground focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring group-hover/tool-trace:opacity-100 group-focus-within/tool-trace:opacity-100"
|
|
33
|
-
onClick={argumentCopy.copy}
|
|
34
|
-
aria-label={argumentCopy.copied ? "Copied tool arguments" : "Copy tool arguments"}
|
|
35
|
-
title={argumentCopy.copied ? "Copied tool arguments" : "Copy tool arguments"}
|
|
36
|
-
>
|
|
37
|
-
{argumentCopy.copied ? <Check className="size-3.5" /> : <Copy className="size-3.5" />}
|
|
38
|
-
</button>
|
|
39
|
-
)}
|
|
40
|
-
</div>
|
|
27
|
+
<span className="min-w-0 truncate font-mono font-semibold">{event.name}</span>
|
|
28
|
+
</button>
|
|
41
29
|
);
|
|
42
30
|
}
|
|
43
31
|
|
|
44
32
|
export function ToolTraceEvents({ events }: ToolTraceEventsProps): JSX.Element | null {
|
|
45
33
|
if (events.length === 0) return null;
|
|
46
34
|
return (
|
|
47
|
-
<div className="mx-3 mb-2
|
|
35
|
+
<div className="mx-3 mb-2 flex flex-wrap gap-1.5">
|
|
48
36
|
{events.map((event) => (
|
|
49
|
-
<
|
|
37
|
+
<ToolTraceEventChip key={event.id} event={event} />
|
|
50
38
|
))}
|
|
51
39
|
</div>
|
|
52
40
|
);
|
|
@@ -14,6 +14,7 @@ import type { TimeDisplayFormat } from "../../lib/runtimeConfig";
|
|
|
14
14
|
import { cn, formatTokens } from "../../lib/utils";
|
|
15
15
|
import type { CapturedLog } from "../../contracts";
|
|
16
16
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip";
|
|
17
|
+
import { getCrabVariant } from "../ui/crab-variants";
|
|
17
18
|
import type { CacheTrendEntry } from "./cacheTrend";
|
|
18
19
|
import { LogEntry } from "./LogEntry";
|
|
19
20
|
import {
|
|
@@ -177,6 +178,7 @@ export const TurnGroup = memo(function TurnGroup({
|
|
|
177
178
|
|
|
178
179
|
const firstLogId = entries[0]?.log.id ?? turnIndex;
|
|
179
180
|
const turnLabel = `Turn ${String(turnIndex + 1)}`;
|
|
181
|
+
const CollapsedCrab = useMemo(() => getCrabVariant(firstLogId % 12), [firstLogId]);
|
|
180
182
|
const containmentStyle = useMemo<CSSProperties>(
|
|
181
183
|
() => ({
|
|
182
184
|
contentVisibility: "auto",
|
|
@@ -224,16 +226,28 @@ export const TurnGroup = memo(function TurnGroup({
|
|
|
224
226
|
|
|
225
227
|
<div className="w-6 shrink-0 flex flex-col items-center pt-1.5 pb-1.5">
|
|
226
228
|
<div className="flex justify-center h-[calc(0.75rem-8px)]" />
|
|
227
|
-
<
|
|
228
|
-
<div className="flex-1 flex justify-center min-h-0">
|
|
229
|
-
<div className="w-px bg-muted-foreground/14 h-full" />
|
|
230
|
-
</div>
|
|
231
|
-
<span
|
|
229
|
+
<CollapsedCrab
|
|
232
230
|
className={cn(
|
|
233
|
-
"size-
|
|
234
|
-
|
|
231
|
+
"size-3.5",
|
|
232
|
+
isPending
|
|
233
|
+
? "animate-crab-crawl text-amber-300/80"
|
|
234
|
+
: "animate-crab-appear text-emerald-400",
|
|
235
|
+
isPending
|
|
236
|
+
? "drop-shadow-[0_0_4px_rgba(252,211,77,0.42)]"
|
|
237
|
+
: "drop-shadow-[0_0_4px_rgba(52,211,153,0.45)]",
|
|
235
238
|
)}
|
|
236
239
|
/>
|
|
240
|
+
<div className="flex-1 flex justify-center min-h-0">
|
|
241
|
+
<div className="w-px bg-muted-foreground/14 h-full" />
|
|
242
|
+
</div>
|
|
243
|
+
{isComplete && (
|
|
244
|
+
<CollapsedCrab
|
|
245
|
+
className={cn(
|
|
246
|
+
"size-3.5 animate-crab-settle text-amber-400",
|
|
247
|
+
"drop-shadow-[0_0_4px_rgba(251,191,36,0.45)]",
|
|
248
|
+
)}
|
|
249
|
+
/>
|
|
250
|
+
)}
|
|
237
251
|
</div>
|
|
238
252
|
|
|
239
253
|
{/* Summary content - hidden for single-log turns. */}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Brain, ChevronDown, ChevronRight, Terminal } from "lucide-react";
|
|
2
|
-
import { type JSX, memo, Suspense, useState } from "react";
|
|
2
|
+
import { type JSX, memo, Suspense, useEffect, useRef, useState } from "react";
|
|
3
3
|
import type { ResponseContentBlockType } from "../../../../contracts/anthropic";
|
|
4
|
+
import type { ResponseToolFocus } from "../index";
|
|
4
5
|
import { AnswerMarkdown } from "../../AnswerMarkdown";
|
|
5
6
|
import { Badge } from "../../../ui/badge";
|
|
6
7
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../../../ui/collapsible";
|
|
@@ -99,16 +100,37 @@ export const ThinkingBlock = memo(function ThinkingBlock({
|
|
|
99
100
|
export const ToolUseBlock = memo(function ToolUseBlock({
|
|
100
101
|
name,
|
|
101
102
|
input,
|
|
103
|
+
toolIndex,
|
|
104
|
+
toolFocus,
|
|
102
105
|
}: {
|
|
103
106
|
name: string;
|
|
104
107
|
input: Record<string, unknown>;
|
|
108
|
+
toolIndex: number;
|
|
109
|
+
toolFocus?: ResponseToolFocus;
|
|
105
110
|
}): JSX.Element {
|
|
106
111
|
const [open, setOpen] = useState(false);
|
|
112
|
+
const triggerRef = useRef<HTMLButtonElement | null>(null);
|
|
113
|
+
const shouldFocus = toolFocus?.focusedToolIndex === toolIndex;
|
|
114
|
+
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
if (!shouldFocus || toolFocus === undefined || toolFocus.toolFocusNonce <= 0) return undefined;
|
|
117
|
+
setOpen(true);
|
|
118
|
+
const timer = window.setTimeout(() => {
|
|
119
|
+
const trigger = triggerRef.current;
|
|
120
|
+
if (trigger === null) return;
|
|
121
|
+
trigger.scrollIntoView({ block: "center", behavior: "smooth" });
|
|
122
|
+
trigger.focus({ preventScroll: true });
|
|
123
|
+
}, 0);
|
|
124
|
+
return () => window.clearTimeout(timer);
|
|
125
|
+
}, [shouldFocus, toolFocus, toolFocus?.toolFocusNonce]);
|
|
107
126
|
|
|
108
127
|
return (
|
|
109
128
|
<Collapsible open={open} onOpenChange={setOpen}>
|
|
110
|
-
<div className="border-l-2 border-sky-400/25 my-1">
|
|
111
|
-
<CollapsibleTrigger
|
|
129
|
+
<div className="border-l-2 border-sky-400/25 my-1" data-response-tool-index={toolIndex}>
|
|
130
|
+
<CollapsibleTrigger
|
|
131
|
+
ref={triggerRef}
|
|
132
|
+
className="flex items-center gap-1.5 px-3 py-1 w-full text-left cursor-pointer hover:bg-sky-400/[0.04] transition-colors rounded-r-sm group focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
133
|
+
>
|
|
112
134
|
<Terminal className="size-3.5 text-sky-400/70 shrink-0" />
|
|
113
135
|
<Badge variant="outline" className="text-[10px] font-mono px-1.5 py-0 h-4">
|
|
114
136
|
{name}
|
|
@@ -140,8 +162,12 @@ export const ToolUseBlock = memo(function ToolUseBlock({
|
|
|
140
162
|
|
|
141
163
|
export const ResponseContentBlockRenderer = memo(function ResponseContentBlockRenderer({
|
|
142
164
|
block,
|
|
165
|
+
toolIndex,
|
|
166
|
+
toolFocus,
|
|
143
167
|
}: {
|
|
144
168
|
block: ResponseContentBlockType;
|
|
169
|
+
toolIndex?: number;
|
|
170
|
+
toolFocus?: ResponseToolFocus;
|
|
145
171
|
}): JSX.Element {
|
|
146
172
|
switch (block.type) {
|
|
147
173
|
case "text":
|
|
@@ -150,7 +176,14 @@ export const ResponseContentBlockRenderer = memo(function ResponseContentBlockRe
|
|
|
150
176
|
case "think":
|
|
151
177
|
return <ThinkingBlock thinking={block.thinking} />;
|
|
152
178
|
case "tool_use":
|
|
153
|
-
return
|
|
179
|
+
return (
|
|
180
|
+
<ToolUseBlock
|
|
181
|
+
name={block.name}
|
|
182
|
+
input={block.input}
|
|
183
|
+
toolIndex={toolIndex ?? 0}
|
|
184
|
+
toolFocus={toolFocus}
|
|
185
|
+
/>
|
|
186
|
+
);
|
|
154
187
|
default:
|
|
155
188
|
return assertNever(block);
|
|
156
189
|
}
|
|
@@ -4,13 +4,18 @@ import type { AnthropicResponse } from "../../../../contracts/anthropic";
|
|
|
4
4
|
import { formatTokens } from "../../../../lib/utils";
|
|
5
5
|
import { Badge } from "../../../ui/badge";
|
|
6
6
|
import { Separator } from "../../../ui/separator";
|
|
7
|
+
import type { ResponseToolFocus } from "../index";
|
|
7
8
|
import { ResponseContentBlockRenderer } from "./ContentBlocks";
|
|
8
9
|
|
|
9
10
|
export const StructuredResponseViewAnthropic = memo(function StructuredResponseViewAnthropic({
|
|
10
11
|
response,
|
|
12
|
+
toolFocus,
|
|
11
13
|
}: {
|
|
12
14
|
response: AnthropicResponse;
|
|
15
|
+
toolFocus?: ResponseToolFocus;
|
|
13
16
|
}): JSX.Element {
|
|
17
|
+
let toolIndex = 0;
|
|
18
|
+
|
|
14
19
|
return (
|
|
15
20
|
<div className="space-y-3">
|
|
16
21
|
<div className="flex items-center gap-2 flex-wrap">
|
|
@@ -54,9 +59,18 @@ export const StructuredResponseViewAnthropic = memo(function StructuredResponseV
|
|
|
54
59
|
<Separator className="opacity-50" />
|
|
55
60
|
|
|
56
61
|
<div className="space-y-2">
|
|
57
|
-
{response.content.map((block, i) =>
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
{response.content.map((block, i) => {
|
|
63
|
+
const currentToolIndex = block.type === "tool_use" ? toolIndex : undefined;
|
|
64
|
+
if (block.type === "tool_use") toolIndex += 1;
|
|
65
|
+
return (
|
|
66
|
+
<ResponseContentBlockRenderer
|
|
67
|
+
key={i}
|
|
68
|
+
block={block}
|
|
69
|
+
toolIndex={currentToolIndex}
|
|
70
|
+
toolFocus={toolFocus}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
})}
|
|
60
74
|
{response.content.length === 0 && (
|
|
61
75
|
<p className="text-xs text-muted-foreground italic">Empty response content</p>
|
|
62
76
|
)}
|
|
@@ -28,15 +28,20 @@ function isAnthropicResponse(response: unknown): response is AnthropicResponse {
|
|
|
28
28
|
export function formatViewFor(
|
|
29
29
|
apiFormat: ApiFormat | undefined,
|
|
30
30
|
response: unknown,
|
|
31
|
+
toolFocus?: ResponseToolFocus,
|
|
31
32
|
): JSX.Element | null {
|
|
32
33
|
if (apiFormat === "openai" && isOpenAIResponse(response)) {
|
|
33
|
-
return <OpenAIResponseView response={response} />;
|
|
34
|
+
return <OpenAIResponseView response={response} toolFocus={toolFocus} />;
|
|
34
35
|
}
|
|
35
36
|
if (apiFormat === "openai" && isOpenAIResponsesResponse(response)) {
|
|
36
|
-
return <OpenAIResponsesResponseView response={response} />;
|
|
37
|
+
return <OpenAIResponsesResponseView response={response} toolFocus={toolFocus} />;
|
|
37
38
|
}
|
|
38
39
|
if (apiFormat === "anthropic" && isAnthropicResponse(response)) {
|
|
39
|
-
return <StructuredResponseViewAnthropic response={response} />;
|
|
40
|
+
return <StructuredResponseViewAnthropic response={response} toolFocus={toolFocus} />;
|
|
40
41
|
}
|
|
41
42
|
return null;
|
|
42
43
|
}
|
|
44
|
+
export type ResponseToolFocus = {
|
|
45
|
+
focusedToolIndex: number | null;
|
|
46
|
+
toolFocusNonce: number;
|
|
47
|
+
};
|