|
@@ -1758,6 +1758,9 @@ function ToolPart(props: { last: boolean; part: ToolPart; message: AssistantMess
|
|
|
<Match when={display() === "task"}>
|
|
<Match when={display() === "task"}>
|
|
|
<Task {...toolprops} />
|
|
<Task {...toolprops} />
|
|
|
</Match>
|
|
</Match>
|
|
|
|
|
+ <Match when={display() === "execute"}>
|
|
|
|
|
+ <Execute {...toolprops} />
|
|
|
|
|
+ </Match>
|
|
|
<Match when={display() === "apply_patch"}>
|
|
<Match when={display() === "apply_patch"}>
|
|
|
<ApplyPatch {...toolprops} />
|
|
<ApplyPatch {...toolprops} />
|
|
|
</Match>
|
|
</Match>
|
|
@@ -2322,6 +2325,72 @@ export function formatCompletedSubagentDetail(toolcalls: number, duration: strin
|
|
|
return `${formatSubagentToolcalls(toolcalls)} · ${duration}`
|
|
return `${formatSubagentToolcalls(toolcalls)} · ${duration}`
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+type ExecuteCall = { tool: string; status: "running" | "completed" | "error"; input?: Record<string, unknown> }
|
|
|
|
|
+
|
|
|
|
|
+function executeCalls(value: unknown): ExecuteCall[] {
|
|
|
|
|
+ if (!Array.isArray(value)) return []
|
|
|
|
|
+ return value.flatMap((call) => {
|
|
|
|
|
+ const item = recordValue(call)
|
|
|
|
|
+ const tool = stringValue(item?.tool)
|
|
|
|
|
+ const status = stringValue(item?.status)
|
|
|
|
|
+ if (!tool || !status || !["running", "completed", "error"].includes(status)) return []
|
|
|
|
|
+ return [{ tool, status: status as ExecuteCall["status"], input: recordValue(item?.input) }]
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// The `execute` tool streams child tool calls through metadata, not a child session like Task.
|
|
|
|
|
+function Execute(props: ToolProps) {
|
|
|
|
|
+ const ctx = use()
|
|
|
|
|
+ const { theme } = useTheme()
|
|
|
|
|
+ const isLoading = createMemo(() => props.part.state.status === "pending" || props.part.state.status === "running")
|
|
|
|
|
+ const calls = createMemo(() => executeCalls(props.metadata.toolCalls))
|
|
|
|
|
+ const output = createMemo(() => stripAnsi(props.output?.trim() ?? ""))
|
|
|
|
|
+ const hasRuntimeError = createMemo(() => props.metadata.error === true)
|
|
|
|
|
+ const outputPreview = createMemo(() => collapseToolOutput(output(), 4, 4 * Math.max(20, ctx.width - 6)).output)
|
|
|
|
|
+ const showOutput = createMemo(() => output() && hasRuntimeError())
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <>
|
|
|
|
|
+ <InlineTool
|
|
|
|
|
+ icon={hasRuntimeError() ? "✗" : props.part.state.status === "completed" ? "✓" : "│"}
|
|
|
|
|
+ color={hasRuntimeError() ? theme.error : undefined}
|
|
|
|
|
+ spinner={isLoading()}
|
|
|
|
|
+ pending="execute"
|
|
|
|
|
+ complete={true}
|
|
|
|
|
+ part={props.part}
|
|
|
|
|
+ >
|
|
|
|
|
+ execute
|
|
|
|
|
+ </InlineTool>
|
|
|
|
|
+ <For each={calls()}>
|
|
|
|
|
+ {(call) => {
|
|
|
|
|
+ const args = input(call.input ?? {})
|
|
|
|
|
+ return (
|
|
|
|
|
+ <box paddingLeft={3}>
|
|
|
|
|
+ <text paddingLeft={3} fg={call.status === "error" ? theme.error : theme.textMuted}>
|
|
|
|
|
+ ↳ {call.tool}
|
|
|
|
|
+ {args ? ` ${args}` : ""}
|
|
|
|
|
+ {call.status === "error" ? " (failed)" : ""}
|
|
|
|
|
+ </text>
|
|
|
|
|
+ </box>
|
|
|
|
|
+ )
|
|
|
|
|
+ }}
|
|
|
|
|
+ </For>
|
|
|
|
|
+ <Show when={showOutput()}>
|
|
|
|
|
+ <box paddingLeft={3}>
|
|
|
|
|
+ <For each={outputPreview().split("\n")}>
|
|
|
|
|
+ {(line, index) => (
|
|
|
|
|
+ <text paddingLeft={3} fg={theme.error}>
|
|
|
|
|
+ {index() === 0 ? "↳ " : " "}
|
|
|
|
|
+ {line}
|
|
|
|
|
+ </text>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </For>
|
|
|
|
|
+ </box>
|
|
|
|
|
+ </Show>
|
|
|
|
|
+ </>
|
|
|
|
|
+ )
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
function Edit(props: ToolProps) {
|
|
function Edit(props: ToolProps) {
|
|
|
const ctx = use()
|
|
const ctx = use()
|
|
|
const { theme, syntax } = useTheme()
|
|
const { theme, syntax } = useTheme()
|
|
@@ -2578,6 +2647,7 @@ const toolDisplays = new Set([
|
|
|
"todowrite",
|
|
"todowrite",
|
|
|
"question",
|
|
"question",
|
|
|
"skill",
|
|
"skill",
|
|
|
|
|
+ "execute",
|
|
|
])
|
|
])
|
|
|
|
|
|
|
|
export function toolDisplay(tool: string) {
|
|
export function toolDisplay(tool: string) {
|