feat(tui): render code-mode execute tool with child calls (#35113)

This commit is contained in:
Aiden Cline
2026-07-03 11:17:21 -05:00
committed by GitHub
parent a09447bc9b
commit 39c6dd1c32
+70
View File
@@ -1758,6 +1758,9 @@ function ToolPart(props: { last: boolean; part: ToolPart; message: AssistantMess
<Match when={display() === "task"}>
<Task {...toolprops} />
</Match>
<Match when={display() === "execute"}>
<Execute {...toolprops} />
</Match>
<Match when={display() === "apply_patch"}>
<ApplyPatch {...toolprops} />
</Match>
@@ -2322,6 +2325,72 @@ export function formatCompletedSubagentDetail(toolcalls: number, duration: strin
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) {
const ctx = use()
const { theme, syntax } = useTheme()
@@ -2578,6 +2647,7 @@ const toolDisplays = new Set([
"todowrite",
"question",
"skill",
"execute",
])
export function toolDisplay(tool: string) {