tool-registry.test.js
4.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/**
* 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([]);
});
});
});