Просмотр исходного кода

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

Aiden Cline 1 месяц назад
Родитель
Сommit
39c6dd1c32
1 измененных файлов с 70 добавлено и 0 удалено
  1. 70 0
      packages/tui/src/routes/session/index.tsx

+ 70 - 0
packages/tui/src/routes/session/index.tsx

@@ -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) {