| 1 | // Tests for the sidecar's tool_use -> action-chip mapping. node test/actions.test.mjs |
| 2 | import assert from "node:assert/strict"; |
| 3 | import { actionsFromToolUse, CHIP_TOOLS } from "../agent/actions.mjs"; |
| 4 | import { sanitizeActions } from "../web/static/ui.js"; |
| 5 | |
| 6 | let failures = 0; |
| 7 | async function test(name, fn) { |
| 8 | try { |
| 9 | await fn(); |
| 10 | console.log(`PASS ${name}`); |
| 11 | } catch (e) { |
| 12 | failures++; |
| 13 | console.log(`FAIL ${name} — ${e.message.split("\n")[0]}`); |
| 14 | } |
| 15 | } |
| 16 | |
| 17 | await test("maps tool_use blocks to actions, dropping junk", () => { |
| 18 | const actions = actionsFromToolUse([ |
| 19 | { type: "text", text: "Here you go —" }, |
| 20 | { type: "tool_use", name: "set_theme", input: { theme: "plum" } }, |
| 21 | { type: "tool_use", name: "set_theme", input: { theme: "neon" } }, // invalid theme |
| 22 | { type: "tool_use", name: "set_appearance", input: { appearance: "dark" } }, |
| 23 | { type: "tool_use", name: "rm_rf", input: {} }, // not a tool we offer |
| 24 | { type: "tool_use", name: "open_profile", input: {} }, |
| 25 | ]); |
| 26 | assert.deepEqual(actions, [ |
| 27 | { type: "set_theme", theme: "plum" }, |
| 28 | { type: "set_appearance", appearance: "dark" }, |
| 29 | { type: "open_profile" }, |
| 30 | ]); |
| 31 | }); |
| 32 | |
| 33 | await test("every action the sidecar can emit survives the client whitelist", () => { |
| 34 | // The two whitelists (agent/actions.mjs and ui.js) must stay in step: a chip |
| 35 | // Eleven proposes that the client would drop is a silent no-op button. |
| 36 | const emitted = actionsFromToolUse([ |
| 37 | { type: "tool_use", name: "set_theme", input: { theme: "litroom" } }, |
| 38 | { type: "tool_use", name: "set_appearance", input: { appearance: "system" } }, |
| 39 | { type: "tool_use", name: "open_theme_picker", input: {} }, |
| 40 | { type: "tool_use", name: "open_profile", input: {} }, |
| 41 | ]); |
| 42 | assert.equal(emitted.length, CHIP_TOOLS.length); |
| 43 | assert.equal(sanitizeActions(emitted).length, emitted.length); |
| 44 | }); |
| 45 | |
| 46 | console.log(failures === 0 ? "\nALL PASSED" : `\n${failures} FAILED`); |
| 47 | process.exit(failures === 0 ? 0 : 1); |
| 48 | |