返回 DeepSeek-Reasonix
chat-tool-presentation.test.ts
根目录 / desktop / frontend / src / __tests__ / chat-tool-presentation.test.ts
1 import assert from "node:assert/strict";
2 import { classifyTool, shellDisplayName, type ToolItem } from "../lib/chatToolPresentation";
3 import { deriveTurnFiles, fileIdentity } from "../lib/turnFiles";
4 import { fileResourceCapabilities, type FileResourceRef } from "../lib/fileResource";
5 import { subjectOf, summarize } from "../lib/tools";
6 import { historyMessagesToItems } from "../lib/historyItems";
7
8 const tool = (overrides: Partial<ToolItem>): ToolItem => ({
9 kind: "tool", id: "call", name: "unknown", args: "{}", readOnly: true, status: "done", ...overrides,
10 });
11
12 assert.equal(classifyTool(tool({ name: "bash", isShell: true, execution: { shell: "pwsh" } })), "shell");
13 for (const name of ["pwsh", "PWSH", "PowerShell", "powershell", "bash", "BASH", "shell"]) {
14 const args = JSON.stringify({ command: "Write-Output example" });
15 assert.equal(classifyTool(tool({ name })), "shell", `live ${name} has a terminal renderer before metadata arrives`);
16 assert.equal(subjectOf(name, args), "Write-Output example");
17 assert.equal(summarize(name, args, "one\ntwo\n"), summarize("bash", args, "one\ntwo\n"));
18 const history = historyMessagesToItems([
19 { role: "assistant", content: "", toolCalls: [{ id: "call", name, arguments: args }] },
20 { role: "tool", content: "example", toolName: name, toolCallId: "call" },
21 ], "test");
22 const call = history.items.find(item => item.kind === "tool");
23 assert.ok(call?.kind === "tool" && call.isShell, `restored ${name} remains a shell`);
24 }
25 assert.equal(shellDisplayName(tool({ name: "pwsh" })), "PowerShell");
26 assert.equal(classifyTool(tool({ name: "mcp_pwsh" })), "tool");
27 assert.equal(shellDisplayName(tool({ name: "bash", isShell: true, execution: { shell: "pwsh" } })), "PowerShell");
28 assert.equal(shellDisplayName(tool({ name: "bash", isShell: true, execution: { shell: "zsh" } })), "Zsh");
29 assert.equal(shellDisplayName(tool({ name: "bash", isShell: true })), "Terminal");
30 assert.equal(classifyTool(tool({ name: "write_file" })), "file");
31 assert.equal(classifyTool(tool({ name: "plugin_write_report", capabilityId: "mcp-tool:plugin:write" })), "tool",
32 "untrusted names containing write do not acquire the native file renderer");
33
34 const calls: ToolItem[] = [
35 tool({ id: "write", name: "write_file", args: '{"path":"./docs/guide.md","content":"hi"}', readOnly: false }),
36 tool({ id: "edit", name: "edit_file", args: '{"path":"docs/./guide.md"}', readOnly: false }),
37 tool({ id: "noop", name: "write_file", args: '{"path":"noop.txt"}', output: "noop.txt already contains the exact content; no changes made", readOnly: false }),
38 tool({ id: "failed", name: "edit_file", args: '{"path":"failed.txt"}', error: "not found", status: "error", readOnly: false }),
39 tool({ id: "shell", name: "bash", args: '{"command":"touch guessed.txt"}', readOnly: false, isShell: true }),
40 tool({ id: "read", name: "read_file", args: '{"path":"read.txt"}', readOnly: true }),
41 tool({ id: "move", name: "move_file", args: '{"source_path":"old.txt","destination_path":"new.txt"}', readOnly: false }),
42 ];
43 assert.deepEqual(deriveTurnFiles(calls), [
44 { path: "./docs/guide.md", toolCallId: "edit", operation: "modified" },
45 { path: "new.txt", toolCallId: "move", operation: "written" },
46 ]);
47 assert.equal(fileIdentity("a/./b/../c.txt"), "a/c.txt");
48 // Capabilities answer for a caller-shaped reference, and read only its host and
49 // name: the origin and the tool call never change what the row may offer.
50 const remoteReportRef: FileResourceRef = { source: "workspace", hostId: "remote-a", tabId: "tab", toolCallId: "write", path: "report.md" };
51 assert.deepEqual(fileResourceCapabilities(remoteReportRef), {
52 preview: true, source: true, browser: false, revealTree: true, copyPath: true, openNative: false, revealNative: false, saveCopy: true,
53 });
54 const localPresentedRef: FileResourceRef = { source: "presented", hostId: "local", tabId: "tab", toolCallId: "present", path: "app.html" };
55 assert.equal(fileResourceCapabilities(localPresentedRef).browser, true);
56
57 console.log("chat tool presentation: trusted renderer matching, shell labels and file facts passed");
58
59 const { historyToolStatus } = await import("../lib/historyToolStatus");
60 const { toolPresentation } = await import("../lib/chatToolPresentation");
61 assert.equal(historyToolStatus(undefined), "unknown", "unloaded results must not become stopped");
62 assert.equal(historyToolStatus(undefined, { id: "call", name: "bash", arguments: "{}", resultObservation: { state: "completed", messageId: "result", version: 1 } }), "done");
63 assert.equal(toolPresentation(tool({ status: "unknown", resultMissing: true })).state, "unknown");
64 assert.equal(historyToolStatus({ role: "tool", content: "", execution: { state: "cancelled" } }), "stopped");
65
65 lines TYPESCRIPT