spb/khaelor Public
KHAELOR — a terminal-native autonomous engineering agent powered by Anthropic.
TypeScript 82.9%
HTML 14.9%
CSS 1.1%
JavaScript 0.7%
1/**2 * KHAELOR3 * File: tests/tools/registry.test.ts4 * Description: Unit tests for the ToolRegistry — registration, schema export, and input validation.5 *6 * Author: Simon-Pierre Boucher7 * Contact: contact@spboucher.ai8 */910import { describe, expect, it } from "vitest";11import {12 ToolRegistry,13 createDefaultToolRegistry,14 createReadTool,15 parseToolInput,16} from "../../src/tools/index.js";1718describe("ToolRegistry", () => {19 it("registers, lists, and gets tools", () => {20 const registry = new ToolRegistry();21 registry.register(createReadTool());22 expect(registry.list().map((t) => t.name)).toEqual(["read"]);23 expect(registry.get("read")?.name).toBe("read");24 expect(registry.get("missing")).toBeUndefined();25 });2627 it("rejects duplicate registration", () => {28 const registry = new ToolRegistry();29 registry.register(createReadTool());30 expect(() => registry.register(createReadTool())).toThrowError(/already registered/);31 });3233 it("registers the seven V1 tools plus the four v2 tools", () => {34 const registry = createDefaultToolRegistry();35 expect(registry.list().map((t) => t.name)).toEqual([36 "read",37 "write",38 "edit",39 "grep",40 "glob",41 "bash",42 "process",43 "design",44 "remember",45 "symbols",46 "refs",47 ]);48 });4950 it("exports valid Anthropic tool params with at most 5 parameters each", () => {51 const params = createDefaultToolRegistry().toAnthropicTools();52 expect(params).toHaveLength(11);53 for (const param of params) {54 expect(typeof param.name).toBe("string");55 expect(param.description.length).toBeGreaterThan(50);56 expect(param.input_schema.type).toBe("object");57 const propNames = Object.keys(param.input_schema.properties);58 expect(propNames.length).toBeGreaterThan(0);59 expect(propNames.length).toBeLessThanOrEqual(5);60 for (const required of param.input_schema.required) {61 expect(propNames).toContain(required);62 }63 for (const prop of Object.values(param.input_schema.properties)) {64 expect(["string", "integer", "boolean"]).toContain(prop.type);65 expect(prop.description.length).toBeGreaterThan(0);66 }67 // Round-trips as plain JSON (what the Anthropic SDK serializes).68 expect(JSON.parse(JSON.stringify(param))).toEqual(param);69 }70 });7172 it("snake_case parameter naming throughout", () => {73 for (const param of createDefaultToolRegistry().toAnthropicTools()) {74 for (const name of Object.keys(param.input_schema.properties)) {75 expect(name).toMatch(/^[a-z][a-z0-9_]*$/);76 }77 }78 });79});8081describe("parseToolInput", () => {82 const read = createReadTool();8384 it("accepts valid input", () => {85 const parsed = parseToolInput(read, { file_path: "a.ts", offset: 2 });86 expect(parsed.ok).toBe(true);87 });8889 it("produces repair prose for a missing required parameter", () => {90 const parsed = parseToolInput(read, { offset: 2 });91 expect(parsed.ok).toBe(false);92 if (!parsed.ok) {93 expect(parsed.error).toBe(94 'Invalid input for tool "read": parameter "file_path" is required. Please rewrite the input so it satisfies the expected schema.',95 );96 }97 });9899 it("rejects wrong types with repair prose", () => {100 const parsed = parseToolInput(read, { file_path: "a.ts", offset: "two" });101 expect(parsed.ok).toBe(false);102 if (!parsed.ok) expect(parsed.error).toContain('parameter "offset" must be an integer');103 });104105 it("rejects non-object input", () => {106 const parsed = parseToolInput(read, "just a string");107 expect(parsed.ok).toBe(false);108 if (!parsed.ok) expect(parsed.error).toContain("must be a JSON object");109 });110111 it("enforces enums (process action)", () => {112 const registry = createDefaultToolRegistry();113 const processTool = registry.get("process");114 expect(processTool).toBeDefined();115 const parsed = parseToolInput(processTool!, { action: "restart" });116 expect(parsed.ok).toBe(false);117 if (!parsed.ok) {118 expect(parsed.error).toContain('parameter "action" must be one of "start", "list", "read", "write", "stop"');119 }120 });121});122