skyloom 1.12.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +36 -36
- package/README.md +142 -46
- package/config/default.yaml +43 -47
- package/config/models.yaml +155 -155
- package/config/providers.yaml +39 -39
- package/config/skills/api_integrator/SKILL.md +15 -15
- package/config/skills/arch_designer/SKILL.md +13 -13
- package/config/skills/ci_cd_manager/SKILL.md +14 -14
- package/config/skills/code_analysis/SKILL.md +13 -13
- package/config/skills/code_generator/SKILL.md +12 -12
- package/config/skills/code_reviewer/SKILL.md +13 -13
- package/config/skills/content_writer/SKILL.md +14 -14
- package/config/skills/data_transformer/SKILL.md +15 -15
- package/config/skills/document_analysis/SKILL.md +13 -13
- package/config/skills/emotional_companion/SKILL.md +15 -15
- package/config/skills/performance_checker/SKILL.md +14 -14
- package/config/skills/security_auditor/SKILL.md +14 -14
- package/config/skills/self_evolve/SKILL.md +13 -13
- package/config/skills/sys_operator/SKILL.md +15 -15
- package/config/skills/task_planner/SKILL.md +14 -14
- package/config/skills/web_research/SKILL.md +14 -14
- package/config/skills/workflow_designer/SKILL.md +13 -13
- package/dist/agents/dew.js +52 -52
- package/dist/agents/fair.js +84 -84
- package/dist/agents/fog.js +30 -30
- package/dist/agents/frost.js +32 -32
- package/dist/agents/rain.js +32 -32
- package/dist/agents/snow.js +68 -68
- package/dist/cli/main.js +103 -51
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/tui.d.ts.map +1 -1
- package/dist/cli/tui.js +8 -1
- package/dist/cli/tui.js.map +1 -1
- package/dist/core/agent/task.d.ts +58 -0
- package/dist/core/agent/task.d.ts.map +1 -0
- package/dist/core/agent/task.js +83 -0
- package/dist/core/agent/task.js.map +1 -0
- package/dist/core/agent.d.ts +2 -45
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js +61 -145
- package/dist/core/agent.js.map +1 -1
- package/dist/core/agent_helpers.d.ts +10 -0
- package/dist/core/agent_helpers.d.ts.map +1 -1
- package/dist/core/agent_helpers.js +39 -0
- package/dist/core/agent_helpers.js.map +1 -1
- package/dist/core/catalog.d.ts +71 -0
- package/dist/core/catalog.d.ts.map +1 -0
- package/dist/core/catalog.js +176 -0
- package/dist/core/catalog.js.map +1 -0
- package/dist/core/config.d.ts +8 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +12 -4
- package/dist/core/config.js.map +1 -1
- package/dist/core/factory.js +16 -16
- package/dist/core/llm.d.ts +7 -0
- package/dist/core/llm.d.ts.map +1 -1
- package/dist/core/llm.js +139 -7
- package/dist/core/llm.js.map +1 -1
- package/dist/core/longdoc.js +5 -5
- package/dist/core/memory.d.ts.map +1 -1
- package/dist/core/memory.js +69 -62
- package/dist/core/memory.js.map +1 -1
- package/dist/core/theme.d.ts +46 -0
- package/dist/core/theme.d.ts.map +1 -0
- package/dist/core/theme.js +42 -0
- package/dist/core/theme.js.map +1 -0
- package/dist/web/server.js +542 -519
- package/dist/web/server.js.map +1 -1
- package/docs/AESTHETIC_DESIGN.md +144 -0
- package/docs/OPTIMIZATION_PLAN.md +178 -0
- package/package.json +60 -60
- package/scripts/install.js +48 -48
- package/scripts/link.js +10 -10
- package/setup.bat +79 -79
- package/skill-test-ty2fOA/test.md +10 -10
- package/src/agents/dew.ts +70 -70
- package/src/agents/fair.ts +102 -102
- package/src/agents/fog.ts +48 -48
- package/src/agents/frost.ts +50 -50
- package/src/agents/rain.ts +50 -50
- package/src/agents/snow.ts +239 -239
- package/src/cli/main.ts +425 -372
- package/src/cli/mode.ts +58 -58
- package/src/cli/tui.ts +272 -269
- package/src/core/agent/task.ts +100 -0
- package/src/core/agent.ts +1446 -1549
- package/src/core/agent_helpers.ts +496 -461
- package/src/core/arbitrate.ts +162 -162
- package/src/core/catalog.ts +178 -0
- package/src/core/checkpoint.ts +94 -94
- package/src/core/config.ts +20 -4
- package/src/core/estimate.ts +104 -104
- package/src/core/evolve.ts +191 -191
- package/src/core/factory.ts +627 -627
- package/src/core/filter.ts +103 -103
- package/src/core/graph.ts +156 -156
- package/src/core/icons.ts +53 -53
- package/src/core/index.ts +37 -37
- package/src/core/learn.ts +146 -146
- package/src/core/llm.ts +108 -5
- package/src/core/longdoc.ts +155 -155
- package/src/core/mcp_server.ts +176 -176
- package/src/core/memory.ts +1178 -1171
- package/src/core/profile.ts +255 -255
- package/src/core/router.ts +124 -124
- package/src/core/sandbox.ts +142 -142
- package/src/core/security.ts +243 -243
- package/src/core/skill.ts +342 -342
- package/src/core/theme.ts +65 -0
- package/src/core/tool_router.ts +193 -193
- package/src/core/vector.ts +152 -152
- package/src/core/workspace.ts +150 -150
- package/src/plugins/loader.ts +66 -66
- package/src/skills/loader.ts +46 -46
- package/src/sql.js.d.ts +29 -29
- package/src/tools/builtin.ts +380 -380
- package/src/tools/computer.ts +269 -269
- package/src/tools/delegate.ts +49 -49
- package/src/web/server.ts +660 -634
- package/src/web/tts.ts +93 -93
- package/tests/agent_helpers.test.ts +48 -0
- package/tests/bus.test.ts +121 -121
- package/tests/catalog.test.ts +86 -0
- package/tests/config.test.ts +41 -0
- package/tests/icons.test.ts +45 -45
- package/tests/memory.test.ts +147 -0
- package/tests/router.test.ts +86 -86
- package/tests/schemas.test.ts +51 -51
- package/tests/semantic.test.ts +83 -83
- package/tests/setup.ts +10 -10
- package/tests/skill.test.ts +172 -172
- package/tests/task.test.ts +60 -0
- package/tests/tool.test.ts +108 -108
- package/tests/tool_router.test.ts +71 -71
- package/vitest.config.ts +17 -17
package/tests/tool.test.ts
CHANGED
|
@@ -1,108 +1,108 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for tool system.
|
|
3
|
-
*/
|
|
4
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
5
|
-
import { ToolRegistry, type ToolDefinition } from '../src/core/tool';
|
|
6
|
-
|
|
7
|
-
function makeTool(overrides: Partial<ToolDefinition> & { name: string }): ToolDefinition {
|
|
8
|
-
return {
|
|
9
|
-
name: overrides.name,
|
|
10
|
-
description: overrides.description ?? 'Test tool',
|
|
11
|
-
parameters: overrides.parameters ?? [],
|
|
12
|
-
handler: overrides.handler ?? vi.fn().mockResolvedValue('ok'),
|
|
13
|
-
dangerous: overrides.dangerous,
|
|
14
|
-
cacheable: overrides.cacheable,
|
|
15
|
-
maxRetries: overrides.maxRetries,
|
|
16
|
-
retryDelay: overrides.retryDelay,
|
|
17
|
-
timeout: overrides.timeout,
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
describe('ToolRegistry', () => {
|
|
22
|
-
let registry: ToolRegistry;
|
|
23
|
-
|
|
24
|
-
beforeEach(() => {
|
|
25
|
-
registry = new ToolRegistry();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('register and get tool', () => {
|
|
29
|
-
const tool = makeTool({ name: 'test_tool' });
|
|
30
|
-
registry.register(tool);
|
|
31
|
-
expect(registry.get('test_tool')).toBe(tool);
|
|
32
|
-
expect(registry.get('nonexistent')).toBeUndefined();
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('list returns all tools', () => {
|
|
36
|
-
registry.register(makeTool({ name: 'a', description: 'A' }));
|
|
37
|
-
registry.register(makeTool({ name: 'b', description: 'B' }));
|
|
38
|
-
expect(registry.list()).toHaveLength(2);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('listNames returns all names', () => {
|
|
42
|
-
registry.register(makeTool({ name: 'alpha', description: 'Alpha' }));
|
|
43
|
-
registry.register(makeTool({ name: 'beta', description: 'Beta' }));
|
|
44
|
-
const names = registry.listNames();
|
|
45
|
-
expect(names).toContain('alpha');
|
|
46
|
-
expect(names).toContain('beta');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('getTools returns all tools', () => {
|
|
50
|
-
registry.register(makeTool({ name: 'x', description: 'X' }));
|
|
51
|
-
expect(registry.getTools()).toHaveLength(1);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('reregister overrides existing', () => {
|
|
55
|
-
const t1 = makeTool({ name: 't', description: 'v1' });
|
|
56
|
-
const t2 = makeTool({ name: 't', description: 'v2' });
|
|
57
|
-
registry.register(t1);
|
|
58
|
-
registry.register(t2);
|
|
59
|
-
expect(registry.get('t')?.description).toBe('v2');
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('unregister removes tool', () => {
|
|
63
|
-
registry.register(makeTool({ name: 'temp', description: 'Temp' }));
|
|
64
|
-
expect(registry.get('temp')).toBeDefined();
|
|
65
|
-
registry.unregister('temp');
|
|
66
|
-
expect(registry.get('temp')).toBeUndefined();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('has checks existence', () => {
|
|
70
|
-
registry.register(makeTool({ name: 'exists' }));
|
|
71
|
-
expect(registry.has('exists')).toBe(true);
|
|
72
|
-
expect(registry.has('missing')).toBe(false);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('merge copies tools', () => {
|
|
76
|
-
const r2 = new ToolRegistry();
|
|
77
|
-
r2.register(makeTool({ name: 't2', description: 'T2' }));
|
|
78
|
-
registry.merge(r2);
|
|
79
|
-
expect(registry.get('t2')).toBeDefined();
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('execute returns result from handler', async () => {
|
|
83
|
-
const handler = vi.fn().mockResolvedValue('hello world');
|
|
84
|
-
registry.register(makeTool({ name: 'greet', handler }));
|
|
85
|
-
const result = await registry.execute('greet', { name: 'world' });
|
|
86
|
-
expect(result.success).toBe(true);
|
|
87
|
-
expect(result.result).toBe('hello world');
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('execute returns error for unknown tool', async () => {
|
|
91
|
-
const result = await registry.execute('unknown', {});
|
|
92
|
-
expect(result.success).toBe(false);
|
|
93
|
-
expect(result.error).toContain('not found');
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('execute validates required parameters', async () => {
|
|
97
|
-
const handler = vi.fn().mockResolvedValue('ok');
|
|
98
|
-
registry.register(makeTool({
|
|
99
|
-
name: 'needs_path',
|
|
100
|
-
parameters: [{ name: 'path', type: 'string', description: 'File path', required: true }],
|
|
101
|
-
handler,
|
|
102
|
-
}));
|
|
103
|
-
const result = await registry.execute('needs_path', {});
|
|
104
|
-
expect(result.success).toBe(false);
|
|
105
|
-
expect(result.error).toContain('required');
|
|
106
|
-
expect(handler).not.toHaveBeenCalled();
|
|
107
|
-
});
|
|
108
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* Tests for tool system.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
5
|
+
import { ToolRegistry, type ToolDefinition } from '../src/core/tool';
|
|
6
|
+
|
|
7
|
+
function makeTool(overrides: Partial<ToolDefinition> & { name: string }): ToolDefinition {
|
|
8
|
+
return {
|
|
9
|
+
name: overrides.name,
|
|
10
|
+
description: overrides.description ?? 'Test tool',
|
|
11
|
+
parameters: overrides.parameters ?? [],
|
|
12
|
+
handler: overrides.handler ?? vi.fn().mockResolvedValue('ok'),
|
|
13
|
+
dangerous: overrides.dangerous,
|
|
14
|
+
cacheable: overrides.cacheable,
|
|
15
|
+
maxRetries: overrides.maxRetries,
|
|
16
|
+
retryDelay: overrides.retryDelay,
|
|
17
|
+
timeout: overrides.timeout,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('ToolRegistry', () => {
|
|
22
|
+
let registry: ToolRegistry;
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
registry = new ToolRegistry();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('register and get tool', () => {
|
|
29
|
+
const tool = makeTool({ name: 'test_tool' });
|
|
30
|
+
registry.register(tool);
|
|
31
|
+
expect(registry.get('test_tool')).toBe(tool);
|
|
32
|
+
expect(registry.get('nonexistent')).toBeUndefined();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('list returns all tools', () => {
|
|
36
|
+
registry.register(makeTool({ name: 'a', description: 'A' }));
|
|
37
|
+
registry.register(makeTool({ name: 'b', description: 'B' }));
|
|
38
|
+
expect(registry.list()).toHaveLength(2);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('listNames returns all names', () => {
|
|
42
|
+
registry.register(makeTool({ name: 'alpha', description: 'Alpha' }));
|
|
43
|
+
registry.register(makeTool({ name: 'beta', description: 'Beta' }));
|
|
44
|
+
const names = registry.listNames();
|
|
45
|
+
expect(names).toContain('alpha');
|
|
46
|
+
expect(names).toContain('beta');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('getTools returns all tools', () => {
|
|
50
|
+
registry.register(makeTool({ name: 'x', description: 'X' }));
|
|
51
|
+
expect(registry.getTools()).toHaveLength(1);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('reregister overrides existing', () => {
|
|
55
|
+
const t1 = makeTool({ name: 't', description: 'v1' });
|
|
56
|
+
const t2 = makeTool({ name: 't', description: 'v2' });
|
|
57
|
+
registry.register(t1);
|
|
58
|
+
registry.register(t2);
|
|
59
|
+
expect(registry.get('t')?.description).toBe('v2');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('unregister removes tool', () => {
|
|
63
|
+
registry.register(makeTool({ name: 'temp', description: 'Temp' }));
|
|
64
|
+
expect(registry.get('temp')).toBeDefined();
|
|
65
|
+
registry.unregister('temp');
|
|
66
|
+
expect(registry.get('temp')).toBeUndefined();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('has checks existence', () => {
|
|
70
|
+
registry.register(makeTool({ name: 'exists' }));
|
|
71
|
+
expect(registry.has('exists')).toBe(true);
|
|
72
|
+
expect(registry.has('missing')).toBe(false);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('merge copies tools', () => {
|
|
76
|
+
const r2 = new ToolRegistry();
|
|
77
|
+
r2.register(makeTool({ name: 't2', description: 'T2' }));
|
|
78
|
+
registry.merge(r2);
|
|
79
|
+
expect(registry.get('t2')).toBeDefined();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('execute returns result from handler', async () => {
|
|
83
|
+
const handler = vi.fn().mockResolvedValue('hello world');
|
|
84
|
+
registry.register(makeTool({ name: 'greet', handler }));
|
|
85
|
+
const result = await registry.execute('greet', { name: 'world' });
|
|
86
|
+
expect(result.success).toBe(true);
|
|
87
|
+
expect(result.result).toBe('hello world');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('execute returns error for unknown tool', async () => {
|
|
91
|
+
const result = await registry.execute('unknown', {});
|
|
92
|
+
expect(result.success).toBe(false);
|
|
93
|
+
expect(result.error).toContain('not found');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('execute validates required parameters', async () => {
|
|
97
|
+
const handler = vi.fn().mockResolvedValue('ok');
|
|
98
|
+
registry.register(makeTool({
|
|
99
|
+
name: 'needs_path',
|
|
100
|
+
parameters: [{ name: 'path', type: 'string', description: 'File path', required: true }],
|
|
101
|
+
handler,
|
|
102
|
+
}));
|
|
103
|
+
const result = await registry.execute('needs_path', {});
|
|
104
|
+
expect(result.success).toBe(false);
|
|
105
|
+
expect(result.error).toContain('required');
|
|
106
|
+
expect(handler).not.toHaveBeenCalled();
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for tool subset routing.
|
|
3
|
-
*/
|
|
4
|
-
import { describe, it, expect } from 'vitest';
|
|
5
|
-
import { selectRelevantTools } from '../src/core/tool_router';
|
|
6
|
-
import { ToolRegistry } from '../src/core/tool';
|
|
7
|
-
|
|
8
|
-
function makeRegistry(toolSpecs: Array<[string, string]>): ToolRegistry {
|
|
9
|
-
const r = new ToolRegistry();
|
|
10
|
-
for (const [name, desc] of toolSpecs) {
|
|
11
|
-
r.register({
|
|
12
|
-
name,
|
|
13
|
-
description: desc,
|
|
14
|
-
parameters: [{ name: 'x', type: 'string', description: 'x' }],
|
|
15
|
-
handler: async () => 'ok',
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
return r;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
describe('selectRelevantTools', () => {
|
|
22
|
-
it('short query returns full set', () => {
|
|
23
|
-
const r = makeRegistry(Array.from({ length: 20 }, (_, i) => [`tool_${i}`, `desc ${i}`]));
|
|
24
|
-
const names = r.listNames();
|
|
25
|
-
const selected = selectRelevantTools(r, names, 'ok', { topK: 5 });
|
|
26
|
-
expect(new Set(selected)).toEqual(new Set(names));
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('small catalog returns full set', () => {
|
|
30
|
-
const r = makeRegistry([['a', 'alpha'], ['b', 'beta']]);
|
|
31
|
-
const names = r.listNames();
|
|
32
|
-
const selected = selectRelevantTools(r, names, 'anything goes here', { topK: 12 });
|
|
33
|
-
expect(new Set(selected)).toEqual(new Set(names));
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('caps at topK for large catalog', () => {
|
|
37
|
-
const r = makeRegistry(Array.from({ length: 50 }, (_, i) => [`tool_${i}`, `desc ${i}`]));
|
|
38
|
-
const names = r.listNames();
|
|
39
|
-
const selected = selectRelevantTools(r, names, 'find weather data', { topK: 10 });
|
|
40
|
-
expect(selected.length).toBeLessThanOrEqual(10);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('relevant tools score higher', () => {
|
|
44
|
-
const r = makeRegistry([
|
|
45
|
-
['read_file', 'read a file from disk'],
|
|
46
|
-
['write_file', 'write content to a file'],
|
|
47
|
-
['send_email', 'send an email message'],
|
|
48
|
-
['fetch_url', 'fetch a web URL'],
|
|
49
|
-
['query_db', 'query the database'],
|
|
50
|
-
]);
|
|
51
|
-
const names = r.listNames();
|
|
52
|
-
const selected = selectRelevantTools(r, names, 'read this config file', { topK: 3 });
|
|
53
|
-
expect(selected).toContain('read_file');
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('mustInclude always present', () => {
|
|
57
|
-
const r = makeRegistry(Array.from({ length: 20 }, (_, i) => [`random_${i}`, `unrelated tool ${i}`]));
|
|
58
|
-
r.register({
|
|
59
|
-
name: 'critical_tool',
|
|
60
|
-
description: 'must always be available',
|
|
61
|
-
parameters: [{ name: 'x', type: 'string', description: 'x' }],
|
|
62
|
-
handler: async () => 'ok',
|
|
63
|
-
});
|
|
64
|
-
const names = r.listNames();
|
|
65
|
-
const selected = selectRelevantTools(r, names, 'totally unrelated query', {
|
|
66
|
-
topK: 3,
|
|
67
|
-
mustInclude: new Set(['critical_tool']),
|
|
68
|
-
});
|
|
69
|
-
expect(selected).toContain('critical_tool');
|
|
70
|
-
});
|
|
71
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* Tests for tool subset routing.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect } from 'vitest';
|
|
5
|
+
import { selectRelevantTools } from '../src/core/tool_router';
|
|
6
|
+
import { ToolRegistry } from '../src/core/tool';
|
|
7
|
+
|
|
8
|
+
function makeRegistry(toolSpecs: Array<[string, string]>): ToolRegistry {
|
|
9
|
+
const r = new ToolRegistry();
|
|
10
|
+
for (const [name, desc] of toolSpecs) {
|
|
11
|
+
r.register({
|
|
12
|
+
name,
|
|
13
|
+
description: desc,
|
|
14
|
+
parameters: [{ name: 'x', type: 'string', description: 'x' }],
|
|
15
|
+
handler: async () => 'ok',
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return r;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('selectRelevantTools', () => {
|
|
22
|
+
it('short query returns full set', () => {
|
|
23
|
+
const r = makeRegistry(Array.from({ length: 20 }, (_, i) => [`tool_${i}`, `desc ${i}`]));
|
|
24
|
+
const names = r.listNames();
|
|
25
|
+
const selected = selectRelevantTools(r, names, 'ok', { topK: 5 });
|
|
26
|
+
expect(new Set(selected)).toEqual(new Set(names));
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('small catalog returns full set', () => {
|
|
30
|
+
const r = makeRegistry([['a', 'alpha'], ['b', 'beta']]);
|
|
31
|
+
const names = r.listNames();
|
|
32
|
+
const selected = selectRelevantTools(r, names, 'anything goes here', { topK: 12 });
|
|
33
|
+
expect(new Set(selected)).toEqual(new Set(names));
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('caps at topK for large catalog', () => {
|
|
37
|
+
const r = makeRegistry(Array.from({ length: 50 }, (_, i) => [`tool_${i}`, `desc ${i}`]));
|
|
38
|
+
const names = r.listNames();
|
|
39
|
+
const selected = selectRelevantTools(r, names, 'find weather data', { topK: 10 });
|
|
40
|
+
expect(selected.length).toBeLessThanOrEqual(10);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('relevant tools score higher', () => {
|
|
44
|
+
const r = makeRegistry([
|
|
45
|
+
['read_file', 'read a file from disk'],
|
|
46
|
+
['write_file', 'write content to a file'],
|
|
47
|
+
['send_email', 'send an email message'],
|
|
48
|
+
['fetch_url', 'fetch a web URL'],
|
|
49
|
+
['query_db', 'query the database'],
|
|
50
|
+
]);
|
|
51
|
+
const names = r.listNames();
|
|
52
|
+
const selected = selectRelevantTools(r, names, 'read this config file', { topK: 3 });
|
|
53
|
+
expect(selected).toContain('read_file');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('mustInclude always present', () => {
|
|
57
|
+
const r = makeRegistry(Array.from({ length: 20 }, (_, i) => [`random_${i}`, `unrelated tool ${i}`]));
|
|
58
|
+
r.register({
|
|
59
|
+
name: 'critical_tool',
|
|
60
|
+
description: 'must always be available',
|
|
61
|
+
parameters: [{ name: 'x', type: 'string', description: 'x' }],
|
|
62
|
+
handler: async () => 'ok',
|
|
63
|
+
});
|
|
64
|
+
const names = r.listNames();
|
|
65
|
+
const selected = selectRelevantTools(r, names, 'totally unrelated query', {
|
|
66
|
+
topK: 3,
|
|
67
|
+
mustInclude: new Set(['critical_tool']),
|
|
68
|
+
});
|
|
69
|
+
expect(selected).toContain('critical_tool');
|
|
70
|
+
});
|
|
71
|
+
});
|
package/vitest.config.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { defineConfig } from 'vitest/config';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
export default defineConfig({
|
|
5
|
-
test: {
|
|
6
|
-
globals: true,
|
|
7
|
-
environment: 'node',
|
|
8
|
-
include: ['tests/**/*.test.ts'],
|
|
9
|
-
setupFiles: ['tests/setup.ts'],
|
|
10
|
-
},
|
|
11
|
-
resolve: {
|
|
12
|
-
alias: {
|
|
13
|
-
'@skyloom': path.resolve(__dirname, 'src'),
|
|
14
|
-
'@': path.resolve(__dirname, 'src'),
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
});
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
test: {
|
|
6
|
+
globals: true,
|
|
7
|
+
environment: 'node',
|
|
8
|
+
include: ['tests/**/*.test.ts'],
|
|
9
|
+
setupFiles: ['tests/setup.ts'],
|
|
10
|
+
},
|
|
11
|
+
resolve: {
|
|
12
|
+
alias: {
|
|
13
|
+
'@skyloom': path.resolve(__dirname, 'src'),
|
|
14
|
+
'@': path.resolve(__dirname, 'src'),
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
});
|