@stigmer/react 0.0.52 → 0.0.54
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/deployment-mode.d.ts +35 -0
- package/deployment-mode.d.ts.map +1 -0
- package/deployment-mode.js +41 -0
- package/deployment-mode.js.map +1 -0
- package/execution/ApprovalCard.d.ts +8 -6
- package/execution/ApprovalCard.d.ts.map +1 -1
- package/execution/ApprovalCard.js +34 -96
- package/execution/ApprovalCard.js.map +1 -1
- package/execution/ArtifactCard.d.ts +11 -1
- package/execution/ArtifactCard.d.ts.map +1 -1
- package/execution/ArtifactCard.js +22 -3
- package/execution/ArtifactCard.js.map +1 -1
- package/execution/ArtifactPreviewModal.d.ts.map +1 -1
- package/execution/ArtifactPreviewModal.js +1 -1
- package/execution/ArtifactPreviewModal.js.map +1 -1
- package/execution/ArtifactsWidget.d.ts +26 -19
- package/execution/ArtifactsWidget.d.ts.map +1 -1
- package/execution/ArtifactsWidget.js +24 -26
- package/execution/ArtifactsWidget.js.map +1 -1
- package/execution/McpToolDetail.d.ts +48 -0
- package/execution/McpToolDetail.d.ts.map +1 -0
- package/execution/McpToolDetail.js +159 -0
- package/execution/McpToolDetail.js.map +1 -0
- package/execution/MessageThread.d.ts +10 -1
- package/execution/MessageThread.d.ts.map +1 -1
- package/execution/MessageThread.js +19 -17
- package/execution/MessageThread.js.map +1 -1
- package/execution/SandboxContext.d.ts +32 -0
- package/execution/SandboxContext.d.ts.map +1 -0
- package/execution/SandboxContext.js +26 -0
- package/execution/SandboxContext.js.map +1 -0
- package/execution/ToolArgsView.d.ts +41 -0
- package/execution/ToolArgsView.d.ts.map +1 -0
- package/execution/ToolArgsView.js +134 -0
- package/execution/ToolArgsView.js.map +1 -0
- package/execution/ToolCallDetail.d.ts +11 -4
- package/execution/ToolCallDetail.d.ts.map +1 -1
- package/execution/ToolCallDetail.js +32 -101
- package/execution/ToolCallDetail.js.map +1 -1
- package/execution/ToolCallGroup.d.ts.map +1 -1
- package/execution/ToolCallGroup.js +3 -2
- package/execution/ToolCallGroup.js.map +1 -1
- package/execution/ToolCallItem.d.ts +2 -0
- package/execution/ToolCallItem.d.ts.map +1 -1
- package/execution/ToolCallItem.js +13 -3
- package/execution/ToolCallItem.js.map +1 -1
- package/execution/WriteBackCard.d.ts +34 -0
- package/execution/WriteBackCard.d.ts.map +1 -0
- package/execution/WriteBackCard.js +75 -0
- package/execution/WriteBackCard.js.map +1 -0
- package/execution/WriteBacksWidget.d.ts +49 -0
- package/execution/WriteBacksWidget.d.ts.map +1 -0
- package/execution/WriteBacksWidget.js +44 -0
- package/execution/WriteBacksWidget.js.map +1 -0
- package/execution/__tests__/file-path-resolver.test.d.ts +2 -0
- package/execution/__tests__/file-path-resolver.test.d.ts.map +1 -0
- package/execution/__tests__/file-path-resolver.test.js +180 -0
- package/execution/__tests__/file-path-resolver.test.js.map +1 -0
- package/execution/file-path-resolver.d.ts +3 -3
- package/execution/file-path-resolver.d.ts.map +1 -1
- package/execution/file-path-resolver.js +23 -12
- package/execution/file-path-resolver.js.map +1 -1
- package/execution/index.d.ts +16 -1
- package/execution/index.d.ts.map +1 -1
- package/execution/index.js +9 -1
- package/execution/index.js.map +1 -1
- package/execution/sandbox-path-normalizer.d.ts +46 -0
- package/execution/sandbox-path-normalizer.d.ts.map +1 -0
- package/execution/sandbox-path-normalizer.js +73 -0
- package/execution/sandbox-path-normalizer.js.map +1 -0
- package/execution/tool-categories.d.ts +35 -8
- package/execution/tool-categories.d.ts.map +1 -1
- package/execution/tool-categories.js +76 -10
- package/execution/tool-categories.js.map +1 -1
- package/execution/tool-rendering-primitives.d.ts +61 -0
- package/execution/tool-rendering-primitives.d.ts.map +1 -0
- package/execution/tool-rendering-primitives.js +106 -0
- package/execution/tool-rendering-primitives.js.map +1 -0
- package/execution/useArtifactContent.d.ts +5 -1
- package/execution/useArtifactContent.d.ts.map +1 -1
- package/execution/useArtifactContent.js +6 -2
- package/execution/useArtifactContent.js.map +1 -1
- package/execution/useWorkspaceWriteBacks.d.ts +40 -0
- package/execution/useWorkspaceWriteBacks.d.ts.map +1 -0
- package/execution/useWorkspaceWriteBacks.js +41 -0
- package/execution/useWorkspaceWriteBacks.js.map +1 -0
- package/github/GitHubRepoPicker.d.ts +5 -2
- package/github/GitHubRepoPicker.d.ts.map +1 -1
- package/github/GitHubRepoPicker.js +133 -36
- package/github/GitHubRepoPicker.js.map +1 -1
- package/github/index.d.ts +1 -0
- package/github/index.d.ts.map +1 -1
- package/github/index.js +1 -0
- package/github/index.js.map +1 -1
- package/github/useGitHubSearch.d.ts +20 -0
- package/github/useGitHubSearch.d.ts.map +1 -0
- package/github/useGitHubSearch.js +127 -0
- package/github/useGitHubSearch.js.map +1 -0
- package/index.d.ts +9 -6
- package/index.d.ts.map +1 -1
- package/index.js +7 -3
- package/index.js.map +1 -1
- package/internal/CloudFeatureNotice.d.ts +19 -0
- package/internal/CloudFeatureNotice.d.ts.map +1 -0
- package/internal/CloudFeatureNotice.js +21 -0
- package/internal/CloudFeatureNotice.js.map +1 -0
- package/mcp-server/McpServerDetailView.d.ts +15 -1
- package/mcp-server/McpServerDetailView.d.ts.map +1 -1
- package/mcp-server/McpServerDetailView.js +11 -3
- package/mcp-server/McpServerDetailView.js.map +1 -1
- package/package.json +4 -4
- package/provider.d.ts +14 -2
- package/provider.d.ts.map +1 -1
- package/provider.js +3 -2
- package/provider.js.map +1 -1
- package/session/index.d.ts +4 -0
- package/session/index.d.ts.map +1 -1
- package/session/index.js +2 -0
- package/session/index.js.map +1 -1
- package/session/useSessionArtifacts.d.ts +73 -0
- package/session/useSessionArtifacts.d.ts.map +1 -0
- package/session/useSessionArtifacts.js +95 -0
- package/session/useSessionArtifacts.js.map +1 -0
- package/session/useSessionWriteBacks.d.ts +56 -0
- package/session/useSessionWriteBacks.d.ts.map +1 -0
- package/session/useSessionWriteBacks.js +56 -0
- package/session/useSessionWriteBacks.js.map +1 -0
- package/src/deployment-mode.ts +46 -0
- package/src/execution/ApprovalCard.tsx +130 -283
- package/src/execution/ArtifactCard.tsx +40 -0
- package/src/execution/ArtifactPreviewModal.tsx +2 -0
- package/src/execution/ArtifactsWidget.tsx +51 -43
- package/src/execution/McpToolDetail.tsx +283 -0
- package/src/execution/MessageThread.tsx +18 -0
- package/src/execution/SandboxContext.ts +47 -0
- package/src/execution/ToolArgsView.tsx +279 -0
- package/src/execution/ToolCallDetail.tsx +54 -220
- package/src/execution/ToolCallGroup.tsx +3 -2
- package/src/execution/ToolCallItem.tsx +21 -3
- package/src/execution/WriteBackCard.tsx +210 -0
- package/src/execution/WriteBacksWidget.tsx +82 -0
- package/src/execution/__tests__/file-path-resolver.test.ts +295 -0
- package/src/execution/file-path-resolver.ts +24 -12
- package/src/execution/index.ts +38 -0
- package/src/execution/sandbox-path-normalizer.ts +80 -0
- package/src/execution/tool-categories.ts +89 -9
- package/src/execution/tool-rendering-primitives.tsx +253 -0
- package/src/execution/useArtifactContent.ts +6 -1
- package/src/execution/useWorkspaceWriteBacks.ts +56 -0
- package/src/github/GitHubRepoPicker.tsx +413 -108
- package/src/github/index.ts +5 -0
- package/src/github/useGitHubSearch.ts +162 -0
- package/src/index.ts +27 -0
- package/src/internal/CloudFeatureNotice.tsx +60 -0
- package/src/mcp-server/McpServerDetailView.tsx +24 -2
- package/src/provider.tsx +18 -2
- package/src/session/index.ts +12 -0
- package/src/session/useSessionArtifacts.ts +143 -0
- package/src/session/useSessionWriteBacks.ts +94 -0
- package/styles.css +1 -1
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
import { cn } from "@stigmer/theme";
|
|
5
|
+
import {
|
|
6
|
+
resolveToolCategory,
|
|
7
|
+
extractWriteContentFromPreview,
|
|
8
|
+
} from "./tool-categories";
|
|
9
|
+
import type { ToolCategory, ToolCategoryInfo } from "./tool-categories";
|
|
10
|
+
import { FilePathLink } from "./FilePathLink";
|
|
11
|
+
import { McpArgsView, McpMetadataRow } from "./McpToolDetail";
|
|
12
|
+
import { useSandboxNormalize } from "./SandboxContext";
|
|
13
|
+
import {
|
|
14
|
+
CollapsibleCode,
|
|
15
|
+
FilePathIcon,
|
|
16
|
+
formatJson,
|
|
17
|
+
} from "./tool-rendering-primitives";
|
|
18
|
+
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Public API
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
export interface ToolArgsViewProps {
|
|
24
|
+
/**
|
|
25
|
+
* Raw tool name as it appears on the ToolCall or PendingApproval.
|
|
26
|
+
* Used for category resolution and MCP metadata display.
|
|
27
|
+
*/
|
|
28
|
+
readonly toolName: string;
|
|
29
|
+
/**
|
|
30
|
+
* Parsed tool arguments — either from `ToolCall.args` or
|
|
31
|
+
* `JSON.parse(PendingApproval.argsPreview)`.
|
|
32
|
+
*/
|
|
33
|
+
readonly args: Record<string, unknown> | null;
|
|
34
|
+
/** MCP server slug for MCP tool classification and metadata. */
|
|
35
|
+
readonly mcpServerSlug?: string;
|
|
36
|
+
readonly className?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Unified tool-arguments renderer used by both {@link ApprovalCard}
|
|
41
|
+
* (pre-execution) and {@link ToolCallDetail} (post-execution).
|
|
42
|
+
*
|
|
43
|
+
* Resolves the tool category from `toolName` + `mcpServerSlug`,
|
|
44
|
+
* extracts the relevant primary argument, and dispatches to the
|
|
45
|
+
* appropriate category-specific view:
|
|
46
|
+
*
|
|
47
|
+
* - **Shell** — terminal-style command block
|
|
48
|
+
* - **File (read/write/edit/delete)** — file icon + path + optional content
|
|
49
|
+
* - **Search / List** — pattern display
|
|
50
|
+
* - **MCP** — metadata row + scalar key-value grid + collapsible JSON
|
|
51
|
+
* - **Generic / Unknown** — formatted JSON args
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```tsx
|
|
55
|
+
* // In approval card (from argsPreview string):
|
|
56
|
+
* const args = JSON.parse(pendingApproval.argsPreview);
|
|
57
|
+
* <ToolArgsView toolName={toolName} args={args} mcpServerSlug={slug} />
|
|
58
|
+
*
|
|
59
|
+
* // In detail view (from ToolCall):
|
|
60
|
+
* <ToolArgsView toolName={tc.name} args={tc.args} mcpServerSlug={tc.mcpServerSlug} />
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export function ToolArgsView({
|
|
64
|
+
toolName,
|
|
65
|
+
args,
|
|
66
|
+
mcpServerSlug,
|
|
67
|
+
className,
|
|
68
|
+
}: ToolArgsViewProps) {
|
|
69
|
+
const categoryInfo = useMemo(
|
|
70
|
+
() => resolveToolCategory(toolName, mcpServerSlug),
|
|
71
|
+
[toolName, mcpServerSlug],
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const primaryArg = useMemo(
|
|
75
|
+
() => extractPrimaryArgValue(args, categoryInfo),
|
|
76
|
+
[args, categoryInfo],
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<div className={cn("text-xs", className)}>
|
|
81
|
+
<CategoryArgsDispatch
|
|
82
|
+
category={categoryInfo.category}
|
|
83
|
+
toolName={toolName}
|
|
84
|
+
args={args}
|
|
85
|
+
primaryArg={primaryArg}
|
|
86
|
+
mcpServerSlug={mcpServerSlug}
|
|
87
|
+
/>
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
// Dispatch
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
|
|
96
|
+
function CategoryArgsDispatch({
|
|
97
|
+
category,
|
|
98
|
+
toolName,
|
|
99
|
+
args,
|
|
100
|
+
primaryArg,
|
|
101
|
+
mcpServerSlug,
|
|
102
|
+
}: {
|
|
103
|
+
category: ToolCategory;
|
|
104
|
+
toolName: string;
|
|
105
|
+
args: Record<string, unknown> | null;
|
|
106
|
+
primaryArg: string | null;
|
|
107
|
+
mcpServerSlug?: string;
|
|
108
|
+
}) {
|
|
109
|
+
switch (category) {
|
|
110
|
+
case "shell":
|
|
111
|
+
return primaryArg ? <ShellArgsView command={primaryArg} /> : null;
|
|
112
|
+
|
|
113
|
+
case "read":
|
|
114
|
+
case "write":
|
|
115
|
+
case "edit":
|
|
116
|
+
case "delete":
|
|
117
|
+
return primaryArg ? (
|
|
118
|
+
<FileArgsView path={primaryArg} category={category} args={args} />
|
|
119
|
+
) : null;
|
|
120
|
+
|
|
121
|
+
case "search":
|
|
122
|
+
case "list":
|
|
123
|
+
return primaryArg ? <SearchArgsView pattern={primaryArg} /> : null;
|
|
124
|
+
|
|
125
|
+
case "mcp":
|
|
126
|
+
return (
|
|
127
|
+
<McpArgsPreview
|
|
128
|
+
toolName={toolName}
|
|
129
|
+
args={args}
|
|
130
|
+
mcpServerSlug={mcpServerSlug ?? ""}
|
|
131
|
+
/>
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
default:
|
|
135
|
+
return args && Object.keys(args).length > 0 ? (
|
|
136
|
+
<GenericArgsView args={args} />
|
|
137
|
+
) : null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
// Category-specific views
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
|
|
145
|
+
function ShellArgsView({ command }: { command: string }) {
|
|
146
|
+
const normalize = useSandboxNormalize();
|
|
147
|
+
return (
|
|
148
|
+
<div className="rounded-md border border-border bg-[var(--stgm-terminal-bg,#1a1a2e)] p-2.5">
|
|
149
|
+
<pre className="whitespace-pre-wrap break-words font-mono text-xs text-[var(--stgm-terminal-fg,#e0e0e0)]">
|
|
150
|
+
<span className="select-none text-[var(--stgm-terminal-prompt,#6b7280)]">
|
|
151
|
+
${" "}
|
|
152
|
+
</span>
|
|
153
|
+
{normalize(command)}
|
|
154
|
+
</pre>
|
|
155
|
+
</div>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function FileArgsView({
|
|
160
|
+
path,
|
|
161
|
+
category,
|
|
162
|
+
args,
|
|
163
|
+
}: {
|
|
164
|
+
path: string;
|
|
165
|
+
category: string;
|
|
166
|
+
args: Record<string, unknown> | null;
|
|
167
|
+
}) {
|
|
168
|
+
const writeContent = useMemo(() => {
|
|
169
|
+
if (category !== "write" && category !== "edit") return null;
|
|
170
|
+
if (!args) return null;
|
|
171
|
+
return extractWriteContentFromArgs(args);
|
|
172
|
+
}, [category, args]);
|
|
173
|
+
|
|
174
|
+
return (
|
|
175
|
+
<div className="space-y-1.5">
|
|
176
|
+
<div className="flex items-center gap-1.5 text-xs">
|
|
177
|
+
<FilePathIcon />
|
|
178
|
+
<FilePathLink path={path} className="text-xs" />
|
|
179
|
+
</div>
|
|
180
|
+
{writeContent && (
|
|
181
|
+
<CollapsibleCode label="Content" content={writeContent} />
|
|
182
|
+
)}
|
|
183
|
+
</div>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function SearchArgsView({ pattern }: { pattern: string }) {
|
|
188
|
+
return (
|
|
189
|
+
<div className="flex items-center gap-1.5 text-xs">
|
|
190
|
+
<span className="text-muted-foreground">Pattern:</span>
|
|
191
|
+
<code className="rounded bg-muted px-1.5 py-0.5 font-mono text-foreground">
|
|
192
|
+
{pattern}
|
|
193
|
+
</code>
|
|
194
|
+
</div>
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function McpArgsPreview({
|
|
199
|
+
toolName,
|
|
200
|
+
args,
|
|
201
|
+
mcpServerSlug,
|
|
202
|
+
}: {
|
|
203
|
+
toolName: string;
|
|
204
|
+
args: Record<string, unknown> | null;
|
|
205
|
+
mcpServerSlug: string;
|
|
206
|
+
}) {
|
|
207
|
+
return (
|
|
208
|
+
<div className="space-y-2">
|
|
209
|
+
<McpMetadataRow
|
|
210
|
+
mcpServerSlug={mcpServerSlug}
|
|
211
|
+
toolName={toolName}
|
|
212
|
+
duration={null}
|
|
213
|
+
/>
|
|
214
|
+
{args && Object.keys(args).length > 0 && <McpArgsView args={args} />}
|
|
215
|
+
</div>
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function GenericArgsView({ args }: { args: Record<string, unknown> }) {
|
|
220
|
+
return (
|
|
221
|
+
<CollapsibleCode label="Arguments" content={formatJson(args)} />
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// ---------------------------------------------------------------------------
|
|
226
|
+
// Utilities
|
|
227
|
+
// ---------------------------------------------------------------------------
|
|
228
|
+
|
|
229
|
+
const WRITE_CONTENT_FIELDS = [
|
|
230
|
+
"contents",
|
|
231
|
+
"content",
|
|
232
|
+
"file_content",
|
|
233
|
+
"new_text",
|
|
234
|
+
"new_string",
|
|
235
|
+
"replacement",
|
|
236
|
+
] as const;
|
|
237
|
+
|
|
238
|
+
function extractWriteContentFromArgs(
|
|
239
|
+
args: Record<string, unknown>,
|
|
240
|
+
): string | null {
|
|
241
|
+
for (const field of WRITE_CONTENT_FIELDS) {
|
|
242
|
+
const val = args[field];
|
|
243
|
+
if (typeof val === "string" && val.length > 0) return val;
|
|
244
|
+
}
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function extractPrimaryArgValue(
|
|
249
|
+
args: Record<string, unknown> | null,
|
|
250
|
+
info: ToolCategoryInfo,
|
|
251
|
+
): string | null {
|
|
252
|
+
if (!args) return null;
|
|
253
|
+
|
|
254
|
+
const tryField = (field: string): string | null => {
|
|
255
|
+
const val = args[field];
|
|
256
|
+
if (typeof val === "string" && val.length > 0) return val;
|
|
257
|
+
return null;
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
if (info.primaryArgField) {
|
|
261
|
+
const v = tryField(info.primaryArgField);
|
|
262
|
+
if (v) return v;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
for (const fb of info.fallbackArgFields) {
|
|
266
|
+
const v = tryField(fb);
|
|
267
|
+
if (v) return v;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (info.category === "unknown" || info.category === "mcp") {
|
|
271
|
+
const keys = Object.keys(args);
|
|
272
|
+
if (keys.length > 0) {
|
|
273
|
+
const val = args[keys[0]];
|
|
274
|
+
if (typeof val === "string") return val;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
@@ -1,28 +1,39 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useState } from "react";
|
|
4
3
|
import type { ToolCall } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
|
|
5
4
|
import { ToolCallStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
6
5
|
import { cn } from "@stigmer/theme";
|
|
7
|
-
import { resolveToolCategory
|
|
8
|
-
import {
|
|
6
|
+
import { resolveToolCategory } from "./tool-categories";
|
|
7
|
+
import { McpToolDetail } from "./McpToolDetail";
|
|
8
|
+
import { useSandboxNormalize } from "./SandboxContext";
|
|
9
|
+
import { ToolArgsView } from "./ToolArgsView";
|
|
10
|
+
import {
|
|
11
|
+
CollapsibleCode,
|
|
12
|
+
CollapsiblePre,
|
|
13
|
+
formatResult,
|
|
14
|
+
} from "./tool-rendering-primitives";
|
|
9
15
|
|
|
10
16
|
export interface ToolCallDetailProps {
|
|
11
17
|
readonly toolCall: ToolCall;
|
|
12
18
|
readonly className?: string;
|
|
13
19
|
}
|
|
14
20
|
|
|
15
|
-
const TRUNCATION_LINE_LIMIT = 10;
|
|
16
|
-
|
|
17
21
|
/**
|
|
18
22
|
* Renders the detail panel for a single tool call with
|
|
19
23
|
* category-specific visual treatments.
|
|
20
24
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
25
|
+
* Arguments are rendered through the shared {@link ToolArgsView}
|
|
26
|
+
* dispatch (same component used by {@link ApprovalCard}), ensuring
|
|
27
|
+
* visual parity between pre-execution approval previews and
|
|
28
|
+
* post-execution detail views. Result/output sections are layered
|
|
29
|
+
* on top by this component.
|
|
30
|
+
*
|
|
31
|
+
* - **Shell tools**: terminal-style command + output
|
|
32
|
+
* - **File tools (read/write/edit/delete)**: file path + content + result
|
|
33
|
+
* - **Search tools (grep/glob)**: pattern + results
|
|
24
34
|
* - **Think**: muted italic thought block
|
|
25
|
-
* - **
|
|
35
|
+
* - **MCP tools**: structured args + parsed result via {@link McpToolDetail}
|
|
36
|
+
* - **Unknown tools**: generic args + result JSON rendering
|
|
26
37
|
*
|
|
27
38
|
* Used inside {@link ToolCallItem} when expanded, but also
|
|
28
39
|
* independently importable by platform builders who compose
|
|
@@ -34,7 +45,7 @@ const TRUNCATION_LINE_LIMIT = 10;
|
|
|
34
45
|
* ```
|
|
35
46
|
*/
|
|
36
47
|
export function ToolCallDetail({ toolCall, className }: ToolCallDetailProps) {
|
|
37
|
-
const category = resolveToolCategory(toolCall.name);
|
|
48
|
+
const category = resolveToolCategory(toolCall.name, toolCall.mcpServerSlug);
|
|
38
49
|
const isFailed = toolCall.status === ToolCallStatus.TOOL_CALL_FAILED;
|
|
39
50
|
|
|
40
51
|
return (
|
|
@@ -55,6 +66,12 @@ export function ToolCallDetail({ toolCall, className }: ToolCallDetailProps) {
|
|
|
55
66
|
|
|
56
67
|
// ---------------------------------------------------------------------------
|
|
57
68
|
// Category-specific renderers
|
|
69
|
+
//
|
|
70
|
+
// Each renderer composes:
|
|
71
|
+
// MetadataRow (duration, slug) + ToolArgsView (shared args) + result section
|
|
72
|
+
//
|
|
73
|
+
// Think and MCP have fully custom rendering that doesn't fit the
|
|
74
|
+
// MetadataRow + ToolArgsView + Result pattern.
|
|
58
75
|
// ---------------------------------------------------------------------------
|
|
59
76
|
|
|
60
77
|
function CategoryRenderer({
|
|
@@ -80,44 +97,33 @@ function CategoryRenderer({
|
|
|
80
97
|
return <SearchToolDetail toolCall={toolCall} />;
|
|
81
98
|
case "think":
|
|
82
99
|
return <ThinkToolDetail toolCall={toolCall} />;
|
|
100
|
+
case "mcp":
|
|
101
|
+
return <McpToolDetail toolCall={toolCall} />;
|
|
83
102
|
default:
|
|
84
103
|
return <GenericToolDetail toolCall={toolCall} />;
|
|
85
104
|
}
|
|
86
105
|
}
|
|
87
106
|
|
|
88
|
-
/**
|
|
89
|
-
* Terminal-style rendering for shell/execute tools.
|
|
90
|
-
* Shows the command in a dark terminal block and output below.
|
|
91
|
-
*/
|
|
92
107
|
function ShellToolDetail({ toolCall }: { toolCall: ToolCall }) {
|
|
93
|
-
const command = extractPrimaryArg(toolCall);
|
|
94
108
|
const duration = formatDuration(toolCall.startedAt, toolCall.completedAt);
|
|
109
|
+
const normalize = useSandboxNormalize();
|
|
95
110
|
|
|
96
111
|
return (
|
|
97
112
|
<>
|
|
98
|
-
{/* Metadata */}
|
|
99
113
|
<MetadataRow toolCall={toolCall} duration={duration} />
|
|
100
114
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
<
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
<pre className="whitespace-pre-wrap break-words font-mono text-[var(--stgm-terminal-fg,#e0e0e0)]">
|
|
107
|
-
<span className="select-none text-[var(--stgm-terminal-prompt,#6b7280)]">$ </span>
|
|
108
|
-
{command}
|
|
109
|
-
</pre>
|
|
110
|
-
</div>
|
|
111
|
-
</div>
|
|
112
|
-
)}
|
|
115
|
+
<ToolArgsView
|
|
116
|
+
toolName={toolCall.name}
|
|
117
|
+
args={toolCall.args as Record<string, unknown> | null}
|
|
118
|
+
mcpServerSlug={toolCall.mcpServerSlug}
|
|
119
|
+
/>
|
|
113
120
|
|
|
114
|
-
{/* Output */}
|
|
115
121
|
{toolCall.result && (
|
|
116
122
|
<div className="space-y-1">
|
|
117
123
|
<span className="font-medium text-muted-foreground">Output</span>
|
|
118
124
|
<div className="rounded-md border border-border bg-[var(--stgm-terminal-bg,#1a1a2e)] p-2.5">
|
|
119
125
|
<CollapsiblePre
|
|
120
|
-
content={toolCall.result}
|
|
126
|
+
content={normalize(toolCall.result)}
|
|
121
127
|
className="text-[var(--stgm-terminal-fg,#e0e0e0)]"
|
|
122
128
|
/>
|
|
123
129
|
</div>
|
|
@@ -128,17 +134,8 @@ function ShellToolDetail({ toolCall }: { toolCall: ToolCall }) {
|
|
|
128
134
|
}
|
|
129
135
|
|
|
130
136
|
/**
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
* For **read** mode: shows only the metadata row and a clickable
|
|
134
|
-
* path. Content is intentionally omitted — the Read tool's purpose
|
|
135
|
-
* is for the *agent* to consume the file, and the content is either
|
|
136
|
-
* truncated, omitted, or simply noise for the user. The clickable
|
|
137
|
-
* path provides direct access to the source file.
|
|
138
|
-
*
|
|
139
|
-
* For **write/edit/delete** modes: shows the clickable path followed
|
|
140
|
-
* by the content block (what was written/edited) and any result
|
|
141
|
-
* confirmation.
|
|
137
|
+
* For **read**: metadata + path only (content is noise for the user).
|
|
138
|
+
* For **write/edit/delete**: metadata + path + content (via ToolArgsView) + result.
|
|
142
139
|
*/
|
|
143
140
|
function FileToolDetail({
|
|
144
141
|
toolCall,
|
|
@@ -147,49 +144,19 @@ function FileToolDetail({
|
|
|
147
144
|
toolCall: ToolCall;
|
|
148
145
|
mode: "read" | "write" | "edit" | "delete";
|
|
149
146
|
}) {
|
|
150
|
-
const filePath = extractPrimaryArg(toolCall);
|
|
151
147
|
const duration = formatDuration(toolCall.startedAt, toolCall.completedAt);
|
|
152
148
|
|
|
153
|
-
if (mode === "read") {
|
|
154
|
-
return (
|
|
155
|
-
<>
|
|
156
|
-
<MetadataRow toolCall={toolCall} duration={duration} />
|
|
157
|
-
{filePath && (
|
|
158
|
-
<div className="flex items-center gap-1.5">
|
|
159
|
-
<FilePathIcon />
|
|
160
|
-
<FilePathLink path={filePath} className="text-xs" />
|
|
161
|
-
</div>
|
|
162
|
-
)}
|
|
163
|
-
</>
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const contentFromArgs =
|
|
168
|
-
mode === "write" || mode === "edit"
|
|
169
|
-
? extractWriteContent(toolCall)
|
|
170
|
-
: null;
|
|
171
|
-
|
|
172
|
-
const displayContent = contentFromArgs || toolCall.result;
|
|
173
|
-
|
|
174
149
|
return (
|
|
175
150
|
<>
|
|
176
151
|
<MetadataRow toolCall={toolCall} duration={duration} />
|
|
177
152
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
)}
|
|
184
|
-
|
|
185
|
-
{displayContent && (
|
|
186
|
-
<CollapsibleCode
|
|
187
|
-
label={mode === "delete" ? "Result" : "Content"}
|
|
188
|
-
content={formatResult(displayContent)}
|
|
189
|
-
/>
|
|
190
|
-
)}
|
|
153
|
+
<ToolArgsView
|
|
154
|
+
toolName={toolCall.name}
|
|
155
|
+
args={toolCall.args as Record<string, unknown> | null}
|
|
156
|
+
mcpServerSlug={toolCall.mcpServerSlug}
|
|
157
|
+
/>
|
|
191
158
|
|
|
192
|
-
{
|
|
159
|
+
{mode !== "read" && toolCall.result && (
|
|
193
160
|
<CollapsibleCode
|
|
194
161
|
label="Result"
|
|
195
162
|
content={formatResult(toolCall.result)}
|
|
@@ -199,24 +166,18 @@ function FileToolDetail({
|
|
|
199
166
|
);
|
|
200
167
|
}
|
|
201
168
|
|
|
202
|
-
/**
|
|
203
|
-
* Search/discovery rendering for grep, glob, list tools.
|
|
204
|
-
* Shows search pattern/path and results.
|
|
205
|
-
*/
|
|
206
169
|
function SearchToolDetail({ toolCall }: { toolCall: ToolCall }) {
|
|
207
|
-
const pattern = extractPrimaryArg(toolCall);
|
|
208
170
|
const duration = formatDuration(toolCall.startedAt, toolCall.completedAt);
|
|
209
171
|
|
|
210
172
|
return (
|
|
211
173
|
<>
|
|
212
174
|
<MetadataRow toolCall={toolCall} duration={duration} />
|
|
213
175
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
)}
|
|
176
|
+
<ToolArgsView
|
|
177
|
+
toolName={toolCall.name}
|
|
178
|
+
args={toolCall.args as Record<string, unknown> | null}
|
|
179
|
+
mcpServerSlug={toolCall.mcpServerSlug}
|
|
180
|
+
/>
|
|
220
181
|
|
|
221
182
|
{toolCall.result && (
|
|
222
183
|
<CollapsibleCode
|
|
@@ -228,10 +189,6 @@ function SearchToolDetail({ toolCall }: { toolCall: ToolCall }) {
|
|
|
228
189
|
);
|
|
229
190
|
}
|
|
230
191
|
|
|
231
|
-
/**
|
|
232
|
-
* Thought rendering. Muted, italic presentation distinct from
|
|
233
|
-
* regular tool output.
|
|
234
|
-
*/
|
|
235
192
|
function ThinkToolDetail({ toolCall }: { toolCall: ToolCall }) {
|
|
236
193
|
const thought =
|
|
237
194
|
(toolCall.args?.["thought"] as string | undefined) || toolCall.result;
|
|
@@ -248,10 +205,6 @@ function ThinkToolDetail({ toolCall }: { toolCall: ToolCall }) {
|
|
|
248
205
|
);
|
|
249
206
|
}
|
|
250
207
|
|
|
251
|
-
/**
|
|
252
|
-
* Fallback rendering for unknown/MCP tools. Preserves the original
|
|
253
|
-
* generic args + result JSON display.
|
|
254
|
-
*/
|
|
255
208
|
function GenericToolDetail({ toolCall }: { toolCall: ToolCall }) {
|
|
256
209
|
const duration = formatDuration(toolCall.startedAt, toolCall.completedAt);
|
|
257
210
|
|
|
@@ -259,12 +212,11 @@ function GenericToolDetail({ toolCall }: { toolCall: ToolCall }) {
|
|
|
259
212
|
<>
|
|
260
213
|
<MetadataRow toolCall={toolCall} duration={duration} />
|
|
261
214
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
)}
|
|
215
|
+
<ToolArgsView
|
|
216
|
+
toolName={toolCall.name}
|
|
217
|
+
args={toolCall.args as Record<string, unknown> | null}
|
|
218
|
+
mcpServerSlug={toolCall.mcpServerSlug}
|
|
219
|
+
/>
|
|
268
220
|
|
|
269
221
|
{toolCall.result && (
|
|
270
222
|
<CollapsibleCode
|
|
@@ -302,128 +254,10 @@ function MetadataRow({
|
|
|
302
254
|
);
|
|
303
255
|
}
|
|
304
256
|
|
|
305
|
-
function CollapsibleCode({
|
|
306
|
-
label,
|
|
307
|
-
content,
|
|
308
|
-
}: {
|
|
309
|
-
label: string;
|
|
310
|
-
content: string;
|
|
311
|
-
}) {
|
|
312
|
-
const lines = content.split("\n");
|
|
313
|
-
const needsTruncation = lines.length > TRUNCATION_LINE_LIMIT;
|
|
314
|
-
const [isExpanded, setIsExpanded] = useState(false);
|
|
315
|
-
|
|
316
|
-
const displayContent =
|
|
317
|
-
needsTruncation && !isExpanded
|
|
318
|
-
? lines.slice(0, TRUNCATION_LINE_LIMIT).join("\n") + "\n\u2026"
|
|
319
|
-
: content;
|
|
320
|
-
|
|
321
|
-
return (
|
|
322
|
-
<div className="space-y-1">
|
|
323
|
-
<span className="font-medium text-muted-foreground">{label}</span>
|
|
324
|
-
<pre className="max-h-80 overflow-auto whitespace-pre-wrap break-words rounded-md border border-border bg-muted/40 p-2 font-mono text-foreground">
|
|
325
|
-
{displayContent}
|
|
326
|
-
</pre>
|
|
327
|
-
{needsTruncation && (
|
|
328
|
-
<button
|
|
329
|
-
type="button"
|
|
330
|
-
onClick={() => setIsExpanded((v) => !v)}
|
|
331
|
-
className="text-primary hover:text-primary/80 text-xs font-medium transition-colors"
|
|
332
|
-
>
|
|
333
|
-
{isExpanded
|
|
334
|
-
? "Show less"
|
|
335
|
-
: `Show all ${lines.length} lines`}
|
|
336
|
-
</button>
|
|
337
|
-
)}
|
|
338
|
-
</div>
|
|
339
|
-
);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
function CollapsiblePre({
|
|
343
|
-
content,
|
|
344
|
-
className,
|
|
345
|
-
}: {
|
|
346
|
-
content: string;
|
|
347
|
-
className?: string;
|
|
348
|
-
}) {
|
|
349
|
-
const lines = content.split("\n");
|
|
350
|
-
const needsTruncation = lines.length > TRUNCATION_LINE_LIMIT;
|
|
351
|
-
const [isExpanded, setIsExpanded] = useState(false);
|
|
352
|
-
|
|
353
|
-
const displayContent =
|
|
354
|
-
needsTruncation && !isExpanded
|
|
355
|
-
? lines.slice(0, TRUNCATION_LINE_LIMIT).join("\n") + "\n\u2026"
|
|
356
|
-
: content;
|
|
357
|
-
|
|
358
|
-
return (
|
|
359
|
-
<>
|
|
360
|
-
<pre className={cn("whitespace-pre-wrap break-words font-mono", className)}>
|
|
361
|
-
{displayContent}
|
|
362
|
-
</pre>
|
|
363
|
-
{needsTruncation && (
|
|
364
|
-
<button
|
|
365
|
-
type="button"
|
|
366
|
-
onClick={() => setIsExpanded((v) => !v)}
|
|
367
|
-
className="mt-1 text-primary hover:text-primary/80 text-xs font-medium transition-colors"
|
|
368
|
-
>
|
|
369
|
-
{isExpanded ? "Show less" : `Show all ${lines.length} lines`}
|
|
370
|
-
</button>
|
|
371
|
-
)}
|
|
372
|
-
</>
|
|
373
|
-
);
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
function FilePathIcon() {
|
|
377
|
-
return (
|
|
378
|
-
<svg
|
|
379
|
-
width="10"
|
|
380
|
-
height="10"
|
|
381
|
-
viewBox="0 0 12 12"
|
|
382
|
-
fill="none"
|
|
383
|
-
stroke="currentColor"
|
|
384
|
-
strokeWidth="1.2"
|
|
385
|
-
strokeLinecap="round"
|
|
386
|
-
strokeLinejoin="round"
|
|
387
|
-
className="shrink-0 text-muted-foreground"
|
|
388
|
-
aria-hidden="true"
|
|
389
|
-
>
|
|
390
|
-
<path d="M7 1H3C2.45 1 2 1.45 2 2V10C2 10.55 2.45 11 3 11H9C9.55 11 10 10.55 10 10V4L7 1Z" />
|
|
391
|
-
<path d="M7 1V4H10" />
|
|
392
|
-
</svg>
|
|
393
|
-
);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
257
|
// ---------------------------------------------------------------------------
|
|
397
258
|
// Utilities
|
|
398
259
|
// ---------------------------------------------------------------------------
|
|
399
260
|
|
|
400
|
-
function extractWriteContent(toolCall: ToolCall): string | null {
|
|
401
|
-
if (!toolCall.args) return null;
|
|
402
|
-
const fields = ["contents", "content", "file_content", "new_text", "new_string", "replacement"];
|
|
403
|
-
for (const field of fields) {
|
|
404
|
-
const val = toolCall.args[field];
|
|
405
|
-
if (typeof val === "string" && val.length > 0) return val;
|
|
406
|
-
}
|
|
407
|
-
return null;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
function formatJson(obj: object): string {
|
|
411
|
-
try {
|
|
412
|
-
return JSON.stringify(obj, null, 2);
|
|
413
|
-
} catch {
|
|
414
|
-
return String(obj);
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
function formatResult(result: string): string {
|
|
419
|
-
try {
|
|
420
|
-
const parsed = JSON.parse(result);
|
|
421
|
-
return JSON.stringify(parsed, null, 2);
|
|
422
|
-
} catch {
|
|
423
|
-
return result;
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
261
|
/**
|
|
428
262
|
* Returns a human-readable duration string from two ISO 8601
|
|
429
263
|
* timestamps. Returns `null` when either timestamp is empty or
|
|
@@ -86,8 +86,9 @@ function defaultFormatSummary(
|
|
|
86
86
|
status: AggregateStatus,
|
|
87
87
|
): string {
|
|
88
88
|
if (toolCalls.length === 1) {
|
|
89
|
-
const
|
|
90
|
-
const
|
|
89
|
+
const tc = toolCalls[0];
|
|
90
|
+
const cat = resolveToolCategory(tc.name, tc.mcpServerSlug);
|
|
91
|
+
const primary = extractPrimaryArg(tc);
|
|
91
92
|
if (primary) {
|
|
92
93
|
const truncated =
|
|
93
94
|
primary.length > 60 ? primary.slice(0, 57) + "\u2026" : primary;
|