Parcourir la source

show combined output of bash tool progressively

Dax Raad il y a 6 mois
Parent
commit
061ba65d20

+ 39 - 8
packages/opencode/src/tool/bash.ts

@@ -1,6 +1,6 @@
 import { z } from "zod"
 import { exec } from "child_process"
-import { text } from "stream/consumers"
+
 import { Tool } from "./tool"
 import DESCRIPTION from "./bash.txt"
 import { App } from "../app/app"
@@ -130,8 +130,35 @@ export const BashTool = Tool.define("bash", {
       timeout,
     })
 
-    const stdoutPromise = text(process.stdout!)
-    const stderrPromise = text(process.stderr!)
+    let output = ""
+
+    // Initialize metadata with empty output
+    ctx.metadata({
+      metadata: {
+        output: "",
+        description: params.description,
+      },
+    })
+
+    process.stdout?.on("data", (chunk) => {
+      output += chunk.toString()
+      ctx.metadata({
+        metadata: {
+          output: output,
+          description: params.description,
+        },
+      })
+    })
+
+    process.stderr?.on("data", (chunk) => {
+      output += chunk.toString()
+      ctx.metadata({
+        metadata: {
+          output: output,
+          description: params.description,
+        },
+      })
+    })
 
     await new Promise<void>((resolve) => {
       process.on("close", () => {
@@ -139,18 +166,22 @@ export const BashTool = Tool.define("bash", {
       })
     })
 
-    const stdout = await stdoutPromise
-    const stderr = await stderrPromise
+    ctx.metadata({
+      metadata: {
+        output: output,
+        exit: process.exitCode,
+        description: params.description,
+      },
+    })
 
     return {
       title: params.command,
       metadata: {
-        stderr,
-        stdout,
+        output,
         exit: process.exitCode,
         description: params.description,
       },
-      output: [`<stdout>`, stdout ?? "", `</stdout>`, `<stderr>`, stderr ?? "", `</stderr>`].join("\n"),
+      output,
     }
   },
 })

+ 1 - 1
packages/opencode/test/tool/bash.test.ts

@@ -27,7 +27,7 @@ describe("tool.bash", () => {
         ctx,
       )
       expect(result.metadata.exit).toBe(0)
-      expect(result.metadata.stdout).toContain("test")
+      expect(result.metadata.output).toContain("test")
     })
   })
 

+ 3 - 7
packages/tui/internal/components/chat/message.go

@@ -569,13 +569,9 @@ func renderToolDetails(
 		case "bash":
 			command := toolInputMap["command"].(string)
 			body = fmt.Sprintf("```console\n$ %s\n", command)
-			stdout := metadata["stdout"]
-			if stdout != nil {
-				body += ansi.Strip(fmt.Sprintf("%s", stdout))
-			}
-			stderr := metadata["stderr"]
-			if stderr != nil {
-				body += ansi.Strip(fmt.Sprintf("%s", stderr))
+			output := metadata["output"]
+			if output != nil {
+				body += ansi.Strip(fmt.Sprintf("%s", output))
 			}
 			body += "```"
 			body = util.ToMarkdown(body, width, backgroundColor)

+ 1 - 1
packages/web/src/components/share/part.tsx

@@ -605,7 +605,7 @@ export function BashTool(props: ToolProps) {
   return (
     <ContentBash
       command={props.state.input.command}
-      output={props.state.metadata?.stdout || ""}
+      output={props.state.metadata.output ?? props.state.metadata?.stdout}
       description={props.state.metadata.description}
     />
   )