mini: fix shell tool output display (#37711)
This commit is contained in:
parent
cbcf191fdb
commit
cf6e5b3604
4 changed files with 29 additions and 10 deletions
|
|
@ -2,6 +2,7 @@ import type { EventSubscribeOutput, OpenCodeClient } from "@opencode-ai/client/p
|
||||||
import { SessionMessage } from "@opencode-ai/schema/session-message"
|
import { SessionMessage } from "@opencode-ai/schema/session-message"
|
||||||
import { EOL } from "node:os"
|
import { EOL } from "node:os"
|
||||||
import { readFile } from "node:fs/promises"
|
import { readFile } from "node:fs/promises"
|
||||||
|
import { toolOutputText } from "./tool"
|
||||||
import { UI } from "./ui"
|
import { UI } from "./ui"
|
||||||
import type { MiniToolPart } from "./types"
|
import type { MiniToolPart } from "./types"
|
||||||
|
|
||||||
|
|
@ -274,10 +275,7 @@ export async function runNonInteractivePrompt(input: Input) {
|
||||||
state: {
|
state: {
|
||||||
status: "completed",
|
status: "completed",
|
||||||
input: current.input,
|
input: current.input,
|
||||||
output: event.data.content
|
output: toolOutputText(current.tool, event.data.content),
|
||||||
.filter((item) => item.type === "text")
|
|
||||||
.map((item) => item.text)
|
|
||||||
.join("\n"),
|
|
||||||
title: current.tool,
|
title: current.tool,
|
||||||
metadata: {
|
metadata: {
|
||||||
structured: event.data.structured,
|
structured: event.data.structured,
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import type {
|
||||||
} from "@opencode-ai/client/promise"
|
} from "@opencode-ai/client/promise"
|
||||||
import { Locale } from "@opencode-ai/tui/util/locale"
|
import { Locale } from "@opencode-ai/tui/util/locale"
|
||||||
import type { FooterSubagentDetail, FooterSubagentState, FooterSubagentTab, MiniToolPart, StreamCommit } from "./types"
|
import type { FooterSubagentDetail, FooterSubagentState, FooterSubagentTab, MiniToolPart, StreamCommit } from "./types"
|
||||||
|
import { toolOutputText } from "./tool"
|
||||||
|
|
||||||
const CHILD_MESSAGE_LIMIT = 80
|
const CHILD_MESSAGE_LIMIT = 80
|
||||||
const CHILD_FRAME_LIMIT = 80
|
const CHILD_FRAME_LIMIT = 80
|
||||||
|
|
@ -32,10 +33,6 @@ const FALLBACK_LABEL = "Subagent"
|
||||||
|
|
||||||
type V2Event = EventSubscribeOutput
|
type V2Event = EventSubscribeOutput
|
||||||
|
|
||||||
export function outputText(content: ReadonlyArray<{ type: string; text?: string }>) {
|
|
||||||
return content.flatMap((item) => (item.type === "text" && item.text ? [item.text] : [])).join("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
export function miniTool(input: {
|
export function miniTool(input: {
|
||||||
sessionID: string
|
sessionID: string
|
||||||
messageID: string
|
messageID: string
|
||||||
|
|
@ -82,7 +79,7 @@ export function miniTool(input: {
|
||||||
state: {
|
state: {
|
||||||
status: "completed",
|
status: "completed",
|
||||||
input: tool.state.input,
|
input: tool.state.input,
|
||||||
output: outputText(tool.state.content),
|
output: toolOutputText(tool.name, tool.state.content),
|
||||||
title: tool.name,
|
title: tool.name,
|
||||||
metadata: {
|
metadata: {
|
||||||
structured: tool.state.structured,
|
structured: tool.state.structured,
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,12 @@ function text(v: unknown): string {
|
||||||
return typeof v === "string" ? v : ""
|
return typeof v === "string" ? v : ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toolOutputText(name: string, content: ReadonlyArray<{ type: string; text?: string }>) {
|
||||||
|
// V2 shell content appends model-only status after the user-visible command output.
|
||||||
|
if (name === "shell") return content.find((item) => item.type === "text")?.text ?? ""
|
||||||
|
return content.flatMap((item) => (item.type === "text" && item.text ? [item.text] : [])).join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
function num(v: unknown): number | undefined {
|
function num(v: unknown): number | undefined {
|
||||||
if (typeof v !== "number" || !Number.isFinite(v)) {
|
if (typeof v !== "number" || !Number.isFinite(v)) {
|
||||||
return undefined
|
return undefined
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { describe, expect, test } from "bun:test"
|
||||||
import { InstallationVersion } from "@opencode-ai/core/installation/version"
|
import { InstallationVersion } from "@opencode-ai/core/installation/version"
|
||||||
import path from "node:path"
|
import path from "node:path"
|
||||||
import { mergeInteractiveInput, mergeNonInteractiveInput, parseRunModel, pickRunModel } from "../src/mini"
|
import { mergeInteractiveInput, mergeNonInteractiveInput, parseRunModel, pickRunModel } from "../src/mini"
|
||||||
import { toolInlineInfo, toolView } from "../src/mini/tool"
|
import { toolInlineInfo, toolOutputText, toolView } from "../src/mini/tool"
|
||||||
|
|
||||||
async function cli(args: string[]) {
|
async function cli(args: string[]) {
|
||||||
const child = Bun.spawn([process.execPath, "run", "src/index.ts", ...args], {
|
const child = Bun.spawn([process.execPath, "run", "src/index.ts", ...args], {
|
||||||
|
|
@ -36,6 +36,24 @@ describe("mini command", () => {
|
||||||
expect(toolInlineInfo(part)).toMatchObject({ icon: "$", title: "pwd", mode: "block" })
|
expect(toolInlineInfo(part)).toMatchObject({ icon: "$", title: "pwd", mode: "block" })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("uses non-empty V2 shell output without the model-facing status", () => {
|
||||||
|
expect(
|
||||||
|
toolOutputText("shell", [
|
||||||
|
{ type: "text", text: "mini-output\n" },
|
||||||
|
{ type: "text", text: "Command exited with code 0." },
|
||||||
|
]),
|
||||||
|
).toBe("mini-output\n")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("keeps empty V2 shell output empty", () => {
|
||||||
|
expect(
|
||||||
|
toolOutputText("shell", [
|
||||||
|
{ type: "text", text: "" },
|
||||||
|
{ type: "text", text: "Command exited with code 0." },
|
||||||
|
]),
|
||||||
|
).toBe("")
|
||||||
|
})
|
||||||
|
|
||||||
test("uses piped stdin as the initial prompt", () => {
|
test("uses piped stdin as the initial prompt", () => {
|
||||||
expect(mergeInteractiveInput("from stdin", undefined)).toBe("from stdin")
|
expect(mergeInteractiveInput("from stdin", undefined)).toBe("from stdin")
|
||||||
expect(mergeInteractiveInput("from stdin", "from flag")).toBe("from stdin\nfrom flag")
|
expect(mergeInteractiveInput("from stdin", "from flag")).toBe("from stdin\nfrom flag")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue