web: pretty tool cards — args rendered as the real command/path (priority keys, label-less single field), output label; 276 tests green
This commit is contained in:
@@ -6,6 +6,7 @@ import ChatStream, {
|
||||
Bubble,
|
||||
TypingIndicator,
|
||||
renderMarkdown,
|
||||
toolArgsEntries,
|
||||
} from "./ChatStream";
|
||||
|
||||
function msg(partial: Partial<ChatMessage>): ChatMessage {
|
||||
@@ -761,3 +762,46 @@ describe("copy button", () => {
|
||||
expect(screen.queryByRole("button", { name: "Copy message" })).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("pretty tool args", () => {
|
||||
const tool = (args: string): ToolState => ({
|
||||
id: "t1", name: "bash", args, running: false, isError: false, preview: "out",
|
||||
});
|
||||
|
||||
it("bash command renders as the bare command, no JSON braces", () => {
|
||||
render(<Bubble msg={{ key: "k", role: "assistant", text: "", thinking: null,
|
||||
toolCalls: [{ id: "t1", name: "bash", argsJson: "{}" }], toolCallId: null, streaming: false, ts: 0 }}
|
||||
tools={new Map([["t1", tool('{"command":"ls -la","foo":1}')]])} />);
|
||||
expect(screen.getByText("ls -la")).toBeInTheDocument();
|
||||
expect(document.querySelector(".tool-args")?.textContent).not.toContain('"command"');
|
||||
});
|
||||
|
||||
it("priority ordering puts command first even when not first in JSON", () => {
|
||||
const entries = toolArgsEntries('{"path":"a.go","command":"go build ./..."}');
|
||||
expect(entries[0]?.v).toBe("go build ./...");
|
||||
expect(entries[1]?.k).toBe("path");
|
||||
});
|
||||
|
||||
it("single string arg renders label-less; multi-field keeps labels", () => {
|
||||
render(<Bubble msg={{ key: "k", role: "assistant", text: "", thinking: null,
|
||||
toolCalls: [{ id: "t1", name: "read", argsJson: "{}" }], toolCallId: null, streaming: false, ts: 0 }}
|
||||
tools={new Map([["t1", tool('{"path":"src/main.ts"}')]])} />);
|
||||
expect(screen.getByText("src/main.ts")).toBeInTheDocument();
|
||||
expect(document.querySelector(".tool-args .arg-k")).toBeNull();
|
||||
});
|
||||
|
||||
it("non-JSON args pass through raw", () => {
|
||||
const entries = toolArgsEntries("just text");
|
||||
expect(entries).toEqual([{ k: null, v: "just text" }]);
|
||||
});
|
||||
|
||||
it("JSON string arg unwraps", () => {
|
||||
const entries = toolArgsEntries('"plain string"');
|
||||
expect(entries).toEqual([{ k: null, v: "plain string" }]);
|
||||
});
|
||||
|
||||
it("non-string values are pretty JSON", () => {
|
||||
const entries = toolArgsEntries('{"offset":1}');
|
||||
expect(entries[0]?.v).toBe("1");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user