mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-22 03:53:26 +00:00
fix(tui): streamline generic tool rendering (#43158)
Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com>
This commit is contained in:
parent
5252cefab2
commit
a1eca087d4
2 changed files with 54 additions and 35 deletions
|
|
@ -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 (
|
||||
<BlockTool
|
||||
title={`◆ ${props.tool}`}
|
||||
part={props.part}
|
||||
spinner={props.part.state.status === "streaming" || props.part.state.status === "running"}
|
||||
onClick={expandable() ? () => setExpanded((value) => !value) : undefined}
|
||||
>
|
||||
<>
|
||||
<InlineTool
|
||||
icon={props.part.state.status === "error" ? "✗" : "✓"}
|
||||
complete={props.part.state.status === "completed"}
|
||||
pending={props.tool}
|
||||
spinner={loading()}
|
||||
part={props.part}
|
||||
onClick={expandable() ? () => setExpanded((value) => !value) : undefined}
|
||||
>
|
||||
{genericToolSummary(props.tool, props.input)}
|
||||
</InlineTool>
|
||||
<Show when={expanded()}>
|
||||
<box gap={1} paddingTop={1}>
|
||||
<Show when={Object.keys(props.input).length > 0}>
|
||||
<box gap={1}>
|
||||
<text>
|
||||
<span style={{ bg: theme.raise(theme.background.default), fg: theme.text.subdued }}> Input </span>
|
||||
</text>
|
||||
<box paddingLeft={1}>
|
||||
<code
|
||||
content={args()}
|
||||
filetype="json"
|
||||
syntaxStyle={syntax()}
|
||||
conceal={false}
|
||||
drawUnstyledText={false}
|
||||
fg={theme.text.default}
|
||||
/>
|
||||
<box paddingLeft={3 + INLINE_TOOL_ICON_WIDTH}>
|
||||
<For each={input()}>
|
||||
{([key, value]) => (
|
||||
<box flexDirection="row">
|
||||
<text flexShrink={0} fg={theme.text.subdued}>
|
||||
{key}:{" "}
|
||||
</text>
|
||||
<text flexGrow={1} wrapMode="word" fg={theme.text.default}>
|
||||
{typeof value === "string" ? value : JSON.stringify(value, null, 2)}
|
||||
</text>
|
||||
</box>
|
||||
</box>
|
||||
</Show>
|
||||
)}
|
||||
</For>
|
||||
<Show when={output()}>
|
||||
{(value) => (
|
||||
<box gap={1}>
|
||||
<text>
|
||||
<span style={{ bg: theme.raise(theme.background.default), fg: theme.text.subdued }}> Output </span>
|
||||
<box flexDirection="row">
|
||||
<text flexShrink={0} fg={theme.text.subdued}>
|
||||
output:{" "}
|
||||
</text>
|
||||
<text flexGrow={1} fg={theme.text.default} wrapMode="word">
|
||||
{value()}
|
||||
</text>
|
||||
<box paddingLeft={1}>
|
||||
<text fg={theme.text.default} wrapMode="word">
|
||||
{value()}
|
||||
</text>
|
||||
</box>
|
||||
</box>
|
||||
)}
|
||||
</Show>
|
||||
</box>
|
||||
</Show>
|
||||
</BlockTool>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export function genericToolSummary(tool: string, input: Record<string, unknown>) {
|
||||
const args = primitiveInputSummary(input).replace(/\s+/g, " ")
|
||||
return `${tool}${args ? ` ${args}` : ""}`
|
||||
}
|
||||
|
||||
function useToolPermission(part: () => SessionMessageAssistantTool | undefined) {
|
||||
const ctx = use()
|
||||
const data = useData()
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue