/** * Unit Tests — tools/tool-registry.js */ import { describe, it, expect, beforeEach } from 'vitest'; const { ToolRegistry } = require('../../src/tools/tool-registry'); describe('ToolRegistry', () => { let registry; beforeEach(() => { registry = new ToolRegistry(); }); describe('register', () => { it('should register a tool', () => { registry.register({ name: 'test_tool', description: 'A test tool', execute: async () => 'ok', }); expect(registry.get('test_tool')).toBeDefined(); }); it('should throw for tool without name', () => { expect(() => registry.register({ execute: async () => {} })).toThrow(); }); it('should throw for tool without execute', () => { expect(() => registry.register({ name: 'broken' })).toThrow(); }); }); describe('registerAll', () => { it('should register multiple tools', () => { registry.registerAll([ { name: 'tool_a', execute: async () => 'a' }, { name: 'tool_b', execute: async () => 'b' }, ]); expect(registry.get('tool_a')).toBeDefined(); expect(registry.get('tool_b')).toBeDefined(); }); }); describe('get', () => { it('should return undefined for unknown tools', () => { expect(registry.get('nonexistent')).toBeUndefined(); }); }); describe('execute', () => { it('should execute a tool and return success', async () => { registry.register({ name: 'greet', execute: async (params) => `Hello ${params.name}`, }); const result = await registry.execute('greet', { name: 'World' }, {}); expect(result.status).toBe('success'); expect(result.result).toBe('Hello World'); }); it('should return error for unknown tool', async () => { const result = await registry.execute('no_tool', {}, {}); expect(result.status).toBe('error'); expect(result.error).toContain('Unknown tool'); }); it('should catch and return tool execution errors', async () => { registry.register({ name: 'failing_tool', execute: async () => { throw new Error('Tool broke'); }, }); const result = await registry.execute('failing_tool', {}, {}); expect(result.status).toBe('error'); expect(result.error).toBe('Tool broke'); }); }); describe('getSchemas', () => { it('should return schemas for all registered tools', () => { registry.register({ name: 'tool_x', description: 'Does X', parameters: { type: 'object', properties: { a: { type: 'string' } } }, execute: async () => {}, }); const schemas = registry.getSchemas(); expect(schemas).toHaveLength(1); expect(schemas[0].name).toBe('tool_x'); expect(schemas[0].description).toBe('Does X'); }); }); describe('generateToolPrompt', () => { it('should return empty string when no tools', () => { expect(registry.generateToolPrompt()).toBe(''); }); it('should generate tool descriptions', () => { registry.register({ name: 'calculator', description: 'Performs math', parameters: { type: 'object', required: ['expression'], properties: { expression: { type: 'string', description: 'Math expression' }, }, }, execute: async () => {}, }); const prompt = registry.generateToolPrompt(); expect(prompt).toContain('calculator'); expect(prompt).toContain('Performs math'); expect(prompt).toContain('expression'); expect(prompt).toContain('TOOL_CALL'); }); }); describe('parseToolCalls (static)', () => { it('should parse tool calls from output', () => { const output = `Let me call a tool. [TOOL_CALL: calculator] {"expression": "2+2"} [/TOOL_CALL] Done.`; const calls = ToolRegistry.parseToolCalls(output); expect(calls).toHaveLength(1); expect(calls[0].tool).toBe('calculator'); expect(calls[0].params.expression).toBe('2+2'); }); it('should parse multiple tool calls', () => { const output = ` [TOOL_CALL: tool_a] {"x": 1} [/TOOL_CALL] Some text [TOOL_CALL: tool_b] {"y": 2} [/TOOL_CALL]`; const calls = ToolRegistry.parseToolCalls(output); expect(calls).toHaveLength(2); }); it('should handle non-JSON params as task text', () => { const output = `[TOOL_CALL: run_agent] Please do this task for me [/TOOL_CALL]`; const calls = ToolRegistry.parseToolCalls(output); expect(calls).toHaveLength(1); expect(calls[0].params.task).toContain('Please do this'); }); it('should return empty array for no tool calls', () => { expect(ToolRegistry.parseToolCalls('No tools here')).toEqual([]); }); }); });