diff --git a/packages/tui/src/routes/session/index.tsx b/packages/tui/src/routes/session/index.tsx index ed2fb307b2d..2b75cb11cbc 100644 --- a/packages/tui/src/routes/session/index.tsx +++ b/packages/tui/src/routes/session/index.tsx @@ -2595,58 +2595,61 @@ type ToolProps = { } function GenericTool(props: ToolProps) { const theme = useTheme() - const { currentSyntax: syntax } = useThemes() const output = createMemo(() => props.output?.trim() ?? "") - const args = createMemo(() => JSON.stringify(props.input, null, 2)) + const input = createMemo(() => Object.entries(props.input)) const [expanded, setExpanded] = createSignal(false) - const expandable = createMemo(() => Object.keys(props.input).length > 0 || output().length > 0) + const expandable = createMemo(() => input().length > 0 || output().length > 0) + const loading = createMemo(() => props.part.state.status === "streaming" || props.part.state.status === "running") return ( - setExpanded((value) => !value) : undefined} - > + <> + setExpanded((value) => !value) : undefined} + > + {genericToolSummary(props.tool, props.input)} + - - 0}> - - - Input - - - + + + {([key, value]) => ( + + + {key}:{" "} + + + {typeof value === "string" ? value : JSON.stringify(value, null, 2)} + - - + )} + {(value) => ( - - - Output + + + output:{" "} + + + {value()} - - - {value()} - - )} - + ) } +export function genericToolSummary(tool: string, input: Record) { + const args = primitiveInputSummary(input).replace(/\s+/g, " ") + return `${tool}${args ? ` ${args}` : ""}` +} + function useToolPermission(part: () => SessionMessageAssistantTool | undefined) { const ctx = use() const data = useData() diff --git a/packages/tui/test/cli/tui/inline-tool-wrap-snapshot.test.tsx b/packages/tui/test/cli/tui/inline-tool-wrap-snapshot.test.tsx index e6958334c92..997c627ac0e 100644 --- a/packages/tui/test/cli/tui/inline-tool-wrap-snapshot.test.tsx +++ b/packages/tui/test/cli/tui/inline-tool-wrap-snapshot.test.tsx @@ -4,6 +4,7 @@ import { testRender, type JSX } from "@opentui/solid" import { InlineToolRow, executeCallSummary, + genericToolSummary, isBackgroundSubagent, parseApplyPatchFiles, parseDiagnostics, @@ -199,6 +200,21 @@ describe("TUI inline tool wrapping", () => { ).toBe("↳ session.prompt [text=first line second line]") }) + test("summarizes generic tool arguments on one line", () => { + expect( + genericToolSummary("demo_search_catalog", { + query: "wireless keyboard", + limit: 8, + includeArchived: false, + filters: { category: "accessories" }, + }), + ).toBe("demo_search_catalog [query=wireless keyboard, limit=8, includeArchived=false]") + expect(genericToolSummary("demo_get_weather", { city: "Tokyo", units: "celsius" })).toBe( + "demo_get_weather [city=Tokyo, units=celsius]", + ) + expect(genericToolSummary("demo_refresh", {})).toBe("demo_refresh") + }) + test("ignores diagnostics with malformed nested ranges", () => { expect( parseDiagnostics(