feat(tui): render execute child calls on v2 (#35231)

This commit is contained in:
Aiden Cline 2026-07-03 15:10:25 -05:00 committed by GitHub
parent 438654768c
commit d097cc8065
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1810,6 +1810,9 @@ function ToolPart(props: { part: SessionMessageAssistantTool }) {
<Match when={display() === "subagent"}>
<Subagent {...toolprops} />
</Match>
<Match when={display() === "execute"}>
<Execute {...toolprops} />
</Match>
<Match when={display() === "apply_patch"}>
<ApplyPatch {...toolprops} />
</Match>
@ -2296,6 +2299,65 @@ 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) }]
})
}
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())
const content = createMemo(() => {
const lines = ["execute"]
for (const call of calls()) {
const args = input(call.input ?? {})
lines.push(`${call.tool}${args ? ` ${args}` : ""}${call.status === "error" ? " (failed)" : ""}`)
}
return lines.join("\n")
})
return (
<>
<InlineTool
icon={hasRuntimeError() ? "✗" : props.part.state.status === "completed" ? "✓" : "│"}
color={hasRuntimeError() ? theme.error : undefined}
spinner={isLoading()}
pending="execute"
complete={true}
part={props.part}
>
{content()}
</InlineTool>
<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()
@ -2571,6 +2633,7 @@ const toolDisplays = new Set([
"write",
"edit",
"subagent",
"execute",
"apply_patch",
"todowrite",
"question",