@namzu/sdk 5.1.0 → 5.2.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/CHANGELOG.md +361 -0
- package/dist/agents/__tests__/run-agent-forwarding.test.d.ts +2 -0
- package/dist/agents/__tests__/run-agent-forwarding.test.d.ts.map +1 -0
- package/dist/agents/__tests__/run-agent-forwarding.test.js +76 -0
- package/dist/agents/__tests__/run-agent-forwarding.test.js.map +1 -0
- package/dist/agents/__tests__/run-completed-stop-reason.test.d.ts +2 -0
- package/dist/agents/__tests__/run-completed-stop-reason.test.d.ts.map +1 -0
- package/dist/agents/__tests__/run-completed-stop-reason.test.js +50 -0
- package/dist/agents/__tests__/run-completed-stop-reason.test.js.map +1 -0
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +4 -0
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/runAgent.d.ts +34 -0
- package/dist/agents/runAgent.d.ts.map +1 -1
- package/dist/agents/runAgent.js +5 -3
- package/dist/agents/runAgent.js.map +1 -1
- package/dist/config/runtime.d.ts +30 -30
- package/dist/constants/tools/__tests__/dangerous-patterns.test.d.ts +2 -0
- package/dist/constants/tools/__tests__/dangerous-patterns.test.d.ts.map +1 -0
- package/dist/constants/tools/__tests__/dangerous-patterns.test.js +54 -0
- package/dist/constants/tools/__tests__/dangerous-patterns.test.js.map +1 -0
- package/dist/constants/tools/index.d.ts.map +1 -1
- package/dist/constants/tools/index.js +28 -1
- package/dist/constants/tools/index.js.map +1 -1
- package/dist/contracts/a2a.d.ts +44 -44
- package/dist/directory/__tests__/derive.test.d.ts +2 -0
- package/dist/directory/__tests__/derive.test.d.ts.map +1 -0
- package/dist/directory/__tests__/derive.test.js +111 -0
- package/dist/directory/__tests__/derive.test.js.map +1 -0
- package/dist/directory/__tests__/load-diagnostics.test.d.ts +2 -0
- package/dist/directory/__tests__/load-diagnostics.test.d.ts.map +1 -0
- package/dist/directory/__tests__/load-diagnostics.test.js +106 -0
- package/dist/directory/__tests__/load-diagnostics.test.js.map +1 -0
- package/dist/directory/__tests__/load-directory.test.d.ts +2 -0
- package/dist/directory/__tests__/load-directory.test.d.ts.map +1 -0
- package/dist/directory/__tests__/load-directory.test.js +196 -0
- package/dist/directory/__tests__/load-directory.test.js.map +1 -0
- package/dist/directory/__tests__/subagents.test.d.ts +2 -0
- package/dist/directory/__tests__/subagents.test.d.ts.map +1 -0
- package/dist/directory/__tests__/subagents.test.js +117 -0
- package/dist/directory/__tests__/subagents.test.js.map +1 -0
- package/dist/directory/__tests__/supervisor-budget.test.d.ts +2 -0
- package/dist/directory/__tests__/supervisor-budget.test.d.ts.map +1 -0
- package/dist/directory/__tests__/supervisor-budget.test.js +97 -0
- package/dist/directory/__tests__/supervisor-budget.test.js.map +1 -0
- package/dist/directory/derive-supervisor.d.ts +58 -0
- package/dist/directory/derive-supervisor.d.ts.map +1 -0
- package/dist/directory/derive-supervisor.js +88 -0
- package/dist/directory/derive-supervisor.js.map +1 -0
- package/dist/directory/derive.d.ts +12 -0
- package/dist/directory/derive.d.ts.map +1 -0
- package/dist/directory/derive.js +58 -0
- package/dist/directory/derive.js.map +1 -0
- package/dist/directory/index.d.ts +7 -0
- package/dist/directory/index.d.ts.map +1 -0
- package/dist/directory/index.js +5 -0
- package/dist/directory/index.js.map +1 -0
- package/dist/directory/load.d.ts +14 -0
- package/dist/directory/load.d.ts.map +1 -0
- package/dist/directory/load.js +488 -0
- package/dist/directory/load.js.map +1 -0
- package/dist/directory/scan.d.ts +36 -0
- package/dist/directory/scan.d.ts.map +1 -0
- package/dist/directory/scan.js +136 -0
- package/dist/directory/scan.js.map +1 -0
- package/dist/directory/types.d.ts +215 -0
- package/dist/directory/types.d.ts.map +1 -0
- package/dist/directory/types.js +8 -0
- package/dist/directory/types.js.map +1 -0
- package/dist/plugin/__tests__/path-containment.test.d.ts +2 -0
- package/dist/plugin/__tests__/path-containment.test.d.ts.map +1 -0
- package/dist/plugin/__tests__/path-containment.test.js +91 -0
- package/dist/plugin/__tests__/path-containment.test.js.map +1 -0
- package/dist/plugin/lifecycle.d.ts.map +1 -1
- package/dist/plugin/lifecycle.js +3 -3
- package/dist/plugin/lifecycle.js.map +1 -1
- package/dist/plugin/loader.d.ts.map +1 -1
- package/dist/plugin/loader.js +12 -2
- package/dist/plugin/loader.js.map +1 -1
- package/dist/provider/__tests__/model-version.test.d.ts +2 -0
- package/dist/provider/__tests__/model-version.test.d.ts.map +1 -0
- package/dist/provider/__tests__/model-version.test.js +80 -0
- package/dist/provider/__tests__/model-version.test.js.map +1 -0
- package/dist/provider/__tests__/strict-schema.test.d.ts +2 -0
- package/dist/provider/__tests__/strict-schema.test.d.ts.map +1 -0
- package/dist/provider/__tests__/strict-schema.test.js +109 -0
- package/dist/provider/__tests__/strict-schema.test.js.map +1 -0
- package/dist/provider/model-version.d.ts +60 -0
- package/dist/provider/model-version.d.ts.map +1 -0
- package/dist/provider/model-version.js +64 -0
- package/dist/provider/model-version.js.map +1 -0
- package/dist/provider/strict-schema.d.ts +49 -0
- package/dist/provider/strict-schema.d.ts.map +1 -0
- package/dist/provider/strict-schema.js +112 -0
- package/dist/provider/strict-schema.js.map +1 -0
- package/dist/public-runtime.d.ts +6 -1
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +21 -1
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-types.d.ts +2 -0
- package/dist/public-types.d.ts.map +1 -1
- package/dist/registry/tool/__tests__/strict-registration.test.d.ts +2 -0
- package/dist/registry/tool/__tests__/strict-registration.test.d.ts.map +1 -0
- package/dist/registry/tool/__tests__/strict-registration.test.js +82 -0
- package/dist/registry/tool/__tests__/strict-registration.test.js.map +1 -0
- package/dist/registry/tool/execute.d.ts.map +1 -1
- package/dist/registry/tool/execute.js +16 -0
- package/dist/registry/tool/execute.js.map +1 -1
- package/dist/runtime/query/result.d.ts.map +1 -1
- package/dist/runtime/query/result.js +5 -0
- package/dist/runtime/query/result.js.map +1 -1
- package/dist/tools/builtins/__tests__/edit-insert-reachable.test.js +7 -1
- package/dist/tools/builtins/__tests__/edit-insert-reachable.test.js.map +1 -1
- package/dist/tools/builtins/__tests__/edit.test.js +1 -1
- package/dist/tools/builtins/__tests__/edit.test.js.map +1 -1
- package/dist/tools/builtins/edit.d.ts.map +1 -1
- package/dist/tools/builtins/edit.js +20 -2
- package/dist/tools/builtins/edit.js.map +1 -1
- package/dist/types/plugin/index.d.ts +4 -4
- package/dist/types/run/events.d.ts +17 -2
- package/dist/types/run/events.d.ts.map +1 -1
- package/dist/types/run/events.js.map +1 -1
- package/dist/types/verification/index.d.ts +6 -6
- package/package.json +1 -1
- package/src/agents/__tests__/run-agent-forwarding.test.ts +85 -0
- package/src/agents/__tests__/run-completed-stop-reason.test.ts +59 -0
- package/src/agents/index.ts +8 -0
- package/src/agents/runAgent.ts +30 -4
- package/src/constants/tools/__tests__/dangerous-patterns.test.ts +62 -0
- package/src/constants/tools/index.ts +28 -1
- package/src/directory/__tests__/derive.test.ts +135 -0
- package/src/directory/__tests__/load-diagnostics.test.ts +126 -0
- package/src/directory/__tests__/load-directory.test.ts +243 -0
- package/src/directory/__tests__/subagents.test.ts +155 -0
- package/src/directory/__tests__/supervisor-budget.test.ts +117 -0
- package/src/directory/derive-supervisor.ts +149 -0
- package/src/directory/derive.ts +70 -0
- package/src/directory/index.ts +27 -0
- package/src/directory/load.ts +556 -0
- package/src/directory/scan.ts +163 -0
- package/src/directory/types.ts +254 -0
- package/src/plugin/__tests__/path-containment.test.ts +107 -0
- package/src/plugin/lifecycle.ts +3 -3
- package/src/plugin/loader.ts +12 -2
- package/src/provider/__tests__/model-version.test.ts +93 -0
- package/src/provider/__tests__/strict-schema.test.ts +133 -0
- package/src/provider/model-version.ts +98 -0
- package/src/provider/strict-schema.ts +125 -0
- package/src/public-runtime.ts +31 -0
- package/src/public-types.ts +8 -0
- package/src/registry/tool/__tests__/strict-registration.test.ts +115 -0
- package/src/registry/tool/execute.ts +16 -0
- package/src/runtime/query/result.ts +5 -0
- package/src/tools/builtins/__tests__/edit-insert-reachable.test.ts +8 -2
- package/src/tools/builtins/__tests__/edit.test.ts +1 -1
- package/src/tools/builtins/edit.ts +20 -2
- package/src/types/run/events.ts +15 -2
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import { deriveRunOptions } from '../derive.js';
|
|
6
|
+
import { loadDirectory } from '../load.js';
|
|
7
|
+
const provider = { id: 'mock', name: 'Mock' };
|
|
8
|
+
function project(files) {
|
|
9
|
+
const root = mkdtempSync(join(tmpdir(), 'namzu-derive-'));
|
|
10
|
+
for (const [relative, body] of Object.entries(files)) {
|
|
11
|
+
const full = join(root, relative);
|
|
12
|
+
mkdirSync(join(full, '..'), { recursive: true });
|
|
13
|
+
writeFileSync(full, body);
|
|
14
|
+
}
|
|
15
|
+
return root;
|
|
16
|
+
}
|
|
17
|
+
const TOOL = (name) => `
|
|
18
|
+
export default {
|
|
19
|
+
name: ${JSON.stringify(name)},
|
|
20
|
+
description: 'a tool',
|
|
21
|
+
inputSchema: { parse: (v) => v, safeParse: (v) => ({ success: true, data: v }) },
|
|
22
|
+
execute: async () => ({ success: true, output: 'ok' }),
|
|
23
|
+
}
|
|
24
|
+
`;
|
|
25
|
+
describe('turning a manifest into run options', () => {
|
|
26
|
+
it('carries instructions, config and tools across', async () => {
|
|
27
|
+
const root = project({
|
|
28
|
+
'instructions.md': 'You are terse.',
|
|
29
|
+
'agent.js': 'export default { model: "m", maxIterations: 3 }',
|
|
30
|
+
'tools/a.js': TOOL('a'),
|
|
31
|
+
});
|
|
32
|
+
const { manifest } = await loadDirectory(root);
|
|
33
|
+
const options = deriveRunOptions(manifest, { provider, prompt: 'hi' });
|
|
34
|
+
expect(options.model).toBe('m');
|
|
35
|
+
expect(options.instructions).toBe('You are terse.');
|
|
36
|
+
expect(options.maxIterations).toBe(3);
|
|
37
|
+
expect(options.tools?.has('a')).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
it('points the working directory at the project, not the host', async () => {
|
|
40
|
+
// Left unset this defaults to the host's cwd, which aims the file
|
|
41
|
+
// tools' containment at the host's own source tree.
|
|
42
|
+
const root = project({
|
|
43
|
+
'instructions.md': 'hi',
|
|
44
|
+
'agent.js': 'export default { model: "m" }',
|
|
45
|
+
});
|
|
46
|
+
const { manifest } = await loadDirectory(root);
|
|
47
|
+
expect(deriveRunOptions(manifest, { provider, prompt: 'hi' }).workingDirectory).toBe(manifest.root);
|
|
48
|
+
});
|
|
49
|
+
it('lets an explicit model win over agent.ts', async () => {
|
|
50
|
+
const root = project({
|
|
51
|
+
'instructions.md': 'hi',
|
|
52
|
+
'agent.js': 'export default { model: "from-file" }',
|
|
53
|
+
});
|
|
54
|
+
const { manifest } = await loadDirectory(root);
|
|
55
|
+
expect(deriveRunOptions(manifest, { provider, prompt: 'hi', model: 'explicit' }).model).toBe('explicit');
|
|
56
|
+
});
|
|
57
|
+
it('refuses when nothing names a model', async () => {
|
|
58
|
+
const root = project({ 'instructions.md': 'hi' });
|
|
59
|
+
const { manifest } = await loadDirectory(root);
|
|
60
|
+
expect(() => deriveRunOptions(manifest, { provider, prompt: 'hi' })).toThrow(/No model/);
|
|
61
|
+
});
|
|
62
|
+
it('forwards a name only when agent.ts declared one', async () => {
|
|
63
|
+
// A name guessed from a directory basename becomes the agent id in
|
|
64
|
+
// traces, where two sibling projects both called `agent` merge into one
|
|
65
|
+
// attribution bucket.
|
|
66
|
+
const declared = project({
|
|
67
|
+
'instructions.md': 'hi',
|
|
68
|
+
'agent.js': 'export default { model: "m", name: "researcher" }',
|
|
69
|
+
});
|
|
70
|
+
const guessed = project({
|
|
71
|
+
'instructions.md': 'hi',
|
|
72
|
+
'agent.js': 'export default { model: "m" }',
|
|
73
|
+
});
|
|
74
|
+
const withName = deriveRunOptions((await loadDirectory(declared)).manifest, {
|
|
75
|
+
provider,
|
|
76
|
+
prompt: 'x',
|
|
77
|
+
});
|
|
78
|
+
const without = deriveRunOptions((await loadDirectory(guessed)).manifest, {
|
|
79
|
+
provider,
|
|
80
|
+
prompt: 'x',
|
|
81
|
+
});
|
|
82
|
+
expect(withName.name).toBe('researcher');
|
|
83
|
+
expect(without.name).toBeUndefined();
|
|
84
|
+
});
|
|
85
|
+
it('refuses a manifest whose modules were never loaded', async () => {
|
|
86
|
+
// `manifest.tools` is empty for a reason that has nothing to do with
|
|
87
|
+
// the project. Running it would produce an agent with no capabilities
|
|
88
|
+
// and no indication why.
|
|
89
|
+
const root = project({
|
|
90
|
+
'instructions.md': 'hi',
|
|
91
|
+
'agent.js': 'export default { model: "m" }',
|
|
92
|
+
'tools/a.js': TOOL('a'),
|
|
93
|
+
});
|
|
94
|
+
const { manifest } = await loadDirectory(root, { modules: 'skip' });
|
|
95
|
+
expect(() => deriveRunOptions(manifest, { provider, prompt: 'hi' })).toThrow(/modules: "skip"/);
|
|
96
|
+
});
|
|
97
|
+
it('lets overrides win over everything', async () => {
|
|
98
|
+
const root = project({
|
|
99
|
+
'instructions.md': 'hi',
|
|
100
|
+
'agent.js': 'export default { model: "m", maxIterations: 3 }',
|
|
101
|
+
});
|
|
102
|
+
const { manifest } = await loadDirectory(root);
|
|
103
|
+
const options = deriveRunOptions(manifest, {
|
|
104
|
+
provider,
|
|
105
|
+
prompt: 'hi',
|
|
106
|
+
overrides: { maxIterations: 99 },
|
|
107
|
+
});
|
|
108
|
+
expect(options.maxIterations).toBe(99);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
//# sourceMappingURL=derive.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive.test.js","sourceRoot":"","sources":["../../../src/directory/__tests__/derive.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-diagnostics.test.d.ts","sourceRoot":"","sources":["../../../src/directory/__tests__/load-diagnostics.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import { loadDirectory } from '../load.js';
|
|
6
|
+
/**
|
|
7
|
+
* Three refusals this loader claimed to make and did not.
|
|
8
|
+
*
|
|
9
|
+
* Each is the same shape: a check that existed, read the wrong thing, and
|
|
10
|
+
* therefore reported the wrong answer while looking correct in review. A
|
|
11
|
+
* loader whose entire job is to say what is wrong with a directory has to be
|
|
12
|
+
* held to the diagnostics it actually emits, not the ones its code appears to
|
|
13
|
+
* emit.
|
|
14
|
+
*/
|
|
15
|
+
function project(files) {
|
|
16
|
+
const root = mkdtempSync(join(tmpdir(), 'namzu-diag-'));
|
|
17
|
+
for (const [relative, body] of Object.entries(files)) {
|
|
18
|
+
const full = join(root, relative);
|
|
19
|
+
mkdirSync(join(full, '..'), { recursive: true });
|
|
20
|
+
writeFileSync(full, body);
|
|
21
|
+
}
|
|
22
|
+
return root;
|
|
23
|
+
}
|
|
24
|
+
describe('a tool that would crash later is refused now', () => {
|
|
25
|
+
it('rejects a default export with no inputSchema', async () => {
|
|
26
|
+
// `name` and `execute` alone used to pass. The object then registered
|
|
27
|
+
// clean and died in `toLLMTools()` on `inputSchema._def` — a TypeError
|
|
28
|
+
// naming neither this file nor this loader.
|
|
29
|
+
const root = project({
|
|
30
|
+
'tools/broken.js': `
|
|
31
|
+
export default {
|
|
32
|
+
name: 'broken',
|
|
33
|
+
description: 'no schema',
|
|
34
|
+
execute: async () => ({ success: true }),
|
|
35
|
+
}
|
|
36
|
+
`,
|
|
37
|
+
});
|
|
38
|
+
const { manifest, diagnostics, ok } = await loadDirectory(root);
|
|
39
|
+
expect(ok).toBe(false);
|
|
40
|
+
expect(diagnostics.map((d) => d.code)).toContain('not_a_tool');
|
|
41
|
+
expect(manifest.tools).toHaveLength(0);
|
|
42
|
+
});
|
|
43
|
+
it('still accepts a hand-written tool that satisfies the published type', async () => {
|
|
44
|
+
// The required set and no more: demanding `defineTool`'s extras would
|
|
45
|
+
// make this loader refuse an object the SDK's own type accepts.
|
|
46
|
+
const root = project({
|
|
47
|
+
'tools/fine.js': `
|
|
48
|
+
export default {
|
|
49
|
+
name: 'fine',
|
|
50
|
+
description: 'a tool',
|
|
51
|
+
inputSchema: { parse: (v) => v },
|
|
52
|
+
execute: async () => ({ success: true }),
|
|
53
|
+
}
|
|
54
|
+
`,
|
|
55
|
+
});
|
|
56
|
+
const { manifest, ok } = await loadDirectory(root);
|
|
57
|
+
expect(ok).toBe(true);
|
|
58
|
+
expect(manifest.tools).toHaveLength(1);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
describe('an import failure explains itself', () => {
|
|
62
|
+
it('gives the extension hint for a module it cannot resolve', async () => {
|
|
63
|
+
// The hint is chosen from Node's error CODE. It used to be matched
|
|
64
|
+
// against the message, which never contains the code, so every hint in
|
|
65
|
+
// the function was unreachable and every author got the bare error.
|
|
66
|
+
const root = project({
|
|
67
|
+
'tools/importer.js': `
|
|
68
|
+
import './nowhere-at-all.js'
|
|
69
|
+
export default { name: 'x', description: 'x', inputSchema: {}, execute: async () => ({}) }
|
|
70
|
+
`,
|
|
71
|
+
});
|
|
72
|
+
const { diagnostics } = await loadDirectory(root);
|
|
73
|
+
const failed = diagnostics.find((d) => d.code === 'module_load_failed');
|
|
74
|
+
expect(failed).toBeDefined();
|
|
75
|
+
expect(failed?.cause).toContain('real extension');
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
describe('agent.ts metadata is checked, not assumed', () => {
|
|
79
|
+
it('refuses metadata values that are not strings', async () => {
|
|
80
|
+
// Typed `Record<string, string>` and admitted on `typeof === 'object'`,
|
|
81
|
+
// so the values were never looked at and the type was a promise this
|
|
82
|
+
// loader did not keep.
|
|
83
|
+
const root = project({
|
|
84
|
+
'agent.js': 'export default { model: "m", metadata: { count: 1 } }',
|
|
85
|
+
});
|
|
86
|
+
const { diagnostics, ok } = await loadDirectory(root);
|
|
87
|
+
expect(ok).toBe(false);
|
|
88
|
+
expect(diagnostics.some((d) => d.code === 'invalid_config')).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
it('refuses an array, which typeof calls an object', async () => {
|
|
91
|
+
const root = project({
|
|
92
|
+
'agent.js': 'export default { model: "m", metadata: ["a", "b"] }',
|
|
93
|
+
});
|
|
94
|
+
const { ok } = await loadDirectory(root);
|
|
95
|
+
expect(ok).toBe(false);
|
|
96
|
+
});
|
|
97
|
+
it('accepts a metadata object of strings', async () => {
|
|
98
|
+
const root = project({
|
|
99
|
+
'agent.js': 'export default { model: "m", metadata: { team: "core" } }',
|
|
100
|
+
});
|
|
101
|
+
const { manifest, ok } = await loadDirectory(root);
|
|
102
|
+
expect(ok).toBe(true);
|
|
103
|
+
expect(manifest.config.metadata).toEqual({ team: 'core' });
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
//# sourceMappingURL=load-diagnostics.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-diagnostics.test.js","sourceRoot":"","sources":["../../../src/directory/__tests__/load-diagnostics.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-directory.test.d.ts","sourceRoot":"","sources":["../../../src/directory/__tests__/load-directory.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, symlinkSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import { loadDirectory } from '../load.js';
|
|
6
|
+
/**
|
|
7
|
+
* Every case builds a real directory and reads it. A fixture object standing
|
|
8
|
+
* in for the filesystem would pass while the scan, the import and the
|
|
9
|
+
* containment check all did the wrong thing — and the whole package is those
|
|
10
|
+
* three things.
|
|
11
|
+
*
|
|
12
|
+
* `.js` is used for tool files rather than `.ts`. Node's type stripping is
|
|
13
|
+
* real and the loader accepts both, but a test that depends on it would be
|
|
14
|
+
* testing Node's version rather than this code.
|
|
15
|
+
*/
|
|
16
|
+
const CAN_SYMLINK = (() => {
|
|
17
|
+
try {
|
|
18
|
+
const probe = mkdtempSync(join(tmpdir(), 'namzu-proj-sym-'));
|
|
19
|
+
symlinkSync(probe, join(probe, 'self'), 'dir');
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
})();
|
|
26
|
+
function project(files) {
|
|
27
|
+
const root = mkdtempSync(join(tmpdir(), 'namzu-proj-'));
|
|
28
|
+
for (const [relative, body] of Object.entries(files)) {
|
|
29
|
+
const full = join(root, relative);
|
|
30
|
+
mkdirSync(join(full, '..'), { recursive: true });
|
|
31
|
+
writeFileSync(full, body);
|
|
32
|
+
}
|
|
33
|
+
return root;
|
|
34
|
+
}
|
|
35
|
+
const TOOL = (name) => `
|
|
36
|
+
export default {
|
|
37
|
+
name: ${JSON.stringify(name)},
|
|
38
|
+
description: 'a tool',
|
|
39
|
+
inputSchema: { parse: (v) => v, safeParse: (v) => ({ success: true, data: v }) },
|
|
40
|
+
execute: async () => ({ success: true, output: 'ok' }),
|
|
41
|
+
}
|
|
42
|
+
`;
|
|
43
|
+
describe('reading a project directory', () => {
|
|
44
|
+
it('loads instructions, config and tools', async () => {
|
|
45
|
+
const root = project({
|
|
46
|
+
'instructions.md': 'You are helpful.\n',
|
|
47
|
+
'agent.js': 'export default { model: "m", temperature: 0.2 }',
|
|
48
|
+
'tools/search.js': TOOL('search'),
|
|
49
|
+
});
|
|
50
|
+
const { manifest, ok, diagnostics } = await loadDirectory(root);
|
|
51
|
+
expect(ok, JSON.stringify(diagnostics)).toBe(true);
|
|
52
|
+
expect(manifest.instructions).toBe('You are helpful.');
|
|
53
|
+
expect(manifest.config).toMatchObject({ model: 'm', temperature: 0.2 });
|
|
54
|
+
expect(manifest.tools.map((t) => t.definition.name)).toEqual(['search']);
|
|
55
|
+
});
|
|
56
|
+
it('reports a broken tool instead of dropping it', async () => {
|
|
57
|
+
const root = project({
|
|
58
|
+
'instructions.md': 'hi',
|
|
59
|
+
'tools/good.js': TOOL('good'),
|
|
60
|
+
'tools/broken.js': 'this is not valid javascript !!!',
|
|
61
|
+
});
|
|
62
|
+
const { manifest, ok, diagnostics } = await loadDirectory(root);
|
|
63
|
+
expect(ok).toBe(false);
|
|
64
|
+
// The good one still loaded — one bad file does not lose the rest.
|
|
65
|
+
expect(manifest.tools.map((t) => t.definition.name)).toEqual(['good']);
|
|
66
|
+
const failure = diagnostics.find((d) => d.code === 'module_load_failed');
|
|
67
|
+
expect(failure?.path).toContain('broken');
|
|
68
|
+
expect(manifest.sources.find((s) => s.id === 'broken')?.outcome).toBe('failed');
|
|
69
|
+
});
|
|
70
|
+
it('refuses both files when two tools claim one name', async () => {
|
|
71
|
+
const root = project({
|
|
72
|
+
'instructions.md': 'hi',
|
|
73
|
+
'tools/a.js': TOOL('search'),
|
|
74
|
+
'tools/b.js': TOOL('search'),
|
|
75
|
+
});
|
|
76
|
+
const { manifest, ok, diagnostics } = await loadDirectory(root);
|
|
77
|
+
expect(ok).toBe(false);
|
|
78
|
+
expect(diagnostics.some((d) => d.code === 'duplicate_tool_name')).toBe(true);
|
|
79
|
+
// Picking a winner silently is what hides the mistake.
|
|
80
|
+
expect(manifest.tools).toHaveLength(1);
|
|
81
|
+
});
|
|
82
|
+
it('rejects a default export that is not a tool', async () => {
|
|
83
|
+
const root = project({
|
|
84
|
+
'instructions.md': 'hi',
|
|
85
|
+
'tools/x.js': 'export default { hello: 1 }',
|
|
86
|
+
});
|
|
87
|
+
const { ok, diagnostics } = await loadDirectory(root);
|
|
88
|
+
expect(ok).toBe(false);
|
|
89
|
+
expect(diagnostics.some((d) => d.code === 'not_a_tool')).toBe(true);
|
|
90
|
+
});
|
|
91
|
+
it('warns rather than errors when instructions are absent', async () => {
|
|
92
|
+
// `runAgent` treats instructions as optional; this package does not get
|
|
93
|
+
// to overrule the kernel about what a valid agent is.
|
|
94
|
+
const root = project({ 'tools/a.js': TOOL('a') });
|
|
95
|
+
const { ok, diagnostics } = await loadDirectory(root);
|
|
96
|
+
expect(ok).toBe(true);
|
|
97
|
+
expect(diagnostics.find((d) => d.code === 'instructions_missing')?.severity).toBe('warning');
|
|
98
|
+
});
|
|
99
|
+
it('errors on an instructions file that says nothing', async () => {
|
|
100
|
+
const root = project({ 'instructions.md': ' \n' });
|
|
101
|
+
const { ok, diagnostics } = await loadDirectory(root);
|
|
102
|
+
expect(ok).toBe(false);
|
|
103
|
+
expect(diagnostics.find((d) => d.code === 'instructions_empty')?.severity).toBe('error');
|
|
104
|
+
});
|
|
105
|
+
it('reports a malformed config field by name', async () => {
|
|
106
|
+
const root = project({
|
|
107
|
+
'instructions.md': 'hi',
|
|
108
|
+
'agent.js': 'export default { model: 42 }',
|
|
109
|
+
});
|
|
110
|
+
const { ok, diagnostics } = await loadDirectory(root);
|
|
111
|
+
expect(ok).toBe(false);
|
|
112
|
+
expect(diagnostics.find((d) => d.code === 'invalid_config')?.message).toContain('"model"');
|
|
113
|
+
});
|
|
114
|
+
it('ignores dot- and underscore-prefixed entries silently', async () => {
|
|
115
|
+
const root = project({
|
|
116
|
+
'instructions.md': 'hi',
|
|
117
|
+
'tools/real.js': TOOL('real'),
|
|
118
|
+
'tools/_helpers/util.js': 'export const x = 1',
|
|
119
|
+
'tools/.hidden.js': TOOL('hidden'),
|
|
120
|
+
});
|
|
121
|
+
const { manifest, ok, diagnostics } = await loadDirectory(root);
|
|
122
|
+
expect(ok).toBe(true);
|
|
123
|
+
expect(manifest.tools.map((t) => t.definition.name)).toEqual(['real']);
|
|
124
|
+
expect(diagnostics.some((d) => d.code === 'unscanned_directory')).toBe(false);
|
|
125
|
+
});
|
|
126
|
+
it('warns about a subdirectory it did not scan', async () => {
|
|
127
|
+
const root = project({
|
|
128
|
+
'instructions.md': 'hi',
|
|
129
|
+
'tools/nested/deep.js': TOOL('deep'),
|
|
130
|
+
});
|
|
131
|
+
const { diagnostics } = await loadDirectory(root);
|
|
132
|
+
expect(diagnostics.find((d) => d.code === 'unscanned_directory')?.message).toContain('nested');
|
|
133
|
+
});
|
|
134
|
+
it('reports a missing directory rather than throwing', async () => {
|
|
135
|
+
const { ok, diagnostics } = await loadDirectory(join(tmpdir(), 'namzu-does-not-exist-xyz'));
|
|
136
|
+
expect(ok).toBe(false);
|
|
137
|
+
expect(diagnostics[0]?.code).toBe('root_missing');
|
|
138
|
+
});
|
|
139
|
+
it('throws only on programmer error', async () => {
|
|
140
|
+
await expect(loadDirectory('')).rejects.toThrow(TypeError);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
describe('modules: skip', () => {
|
|
144
|
+
it('gives full structure without importing anything', async () => {
|
|
145
|
+
// The proof is the side effect: a module that would throw on import is
|
|
146
|
+
// listed, and nothing runs.
|
|
147
|
+
const root = project({
|
|
148
|
+
'instructions.md': 'You are helpful.',
|
|
149
|
+
'agent.js': 'throw new Error("agent.js executed")',
|
|
150
|
+
'tools/a.js': 'throw new Error("tool executed")',
|
|
151
|
+
});
|
|
152
|
+
const { manifest, ok } = await loadDirectory(root, { modules: 'skip' });
|
|
153
|
+
expect(ok).toBe(true);
|
|
154
|
+
expect(manifest.instructions).toBe('You are helpful.');
|
|
155
|
+
expect(manifest.sources.map((s) => s.id).sort()).toEqual(['a', 'agent', 'instructions']);
|
|
156
|
+
expect(manifest.sources
|
|
157
|
+
.filter((s) => s.slot !== 'instructions')
|
|
158
|
+
.every((s) => s.outcome === 'not_loaded')).toBe(true);
|
|
159
|
+
expect(manifest.tools).toHaveLength(0);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
describe('include is an allow-list', () => {
|
|
163
|
+
it('scans only what was asked for', async () => {
|
|
164
|
+
const root = project({ 'instructions.md': 'hi', 'tools/a.js': TOOL('a') });
|
|
165
|
+
const { manifest } = await loadDirectory(root, { include: ['tools'] });
|
|
166
|
+
expect(manifest.included).toEqual(['tools']);
|
|
167
|
+
expect(manifest.instructions).toBe('');
|
|
168
|
+
expect(manifest.tools).toHaveLength(1);
|
|
169
|
+
});
|
|
170
|
+
it('scans nothing when the list is empty', async () => {
|
|
171
|
+
// An allow-list that admits everything when empty is the fail-open
|
|
172
|
+
// shape this estate removed elsewhere.
|
|
173
|
+
const root = project({ 'instructions.md': 'hi', 'tools/a.js': TOOL('a') });
|
|
174
|
+
const { manifest } = await loadDirectory(root, {
|
|
175
|
+
include: [],
|
|
176
|
+
});
|
|
177
|
+
expect(manifest.sources).toHaveLength(0);
|
|
178
|
+
expect(manifest.tools).toHaveLength(0);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
describe('symlinks are refused, not followed', () => {
|
|
182
|
+
it.skipIf(!CAN_SYMLINK)('does not import a linked tool file', async () => {
|
|
183
|
+
const outside = mkdtempSync(join(tmpdir(), 'namzu-outside-'));
|
|
184
|
+
writeFileSync(join(outside, 'evil.js'), TOOL('evil'));
|
|
185
|
+
const root = project({
|
|
186
|
+
'instructions.md': 'hi',
|
|
187
|
+
'tools/real.js': TOOL('real'),
|
|
188
|
+
});
|
|
189
|
+
symlinkSync(join(outside, 'evil.js'), join(root, 'tools', 'linked.js'), 'file');
|
|
190
|
+
const { manifest, diagnostics } = await loadDirectory(root);
|
|
191
|
+
// The file that would be imported is not the file that was listed.
|
|
192
|
+
expect(manifest.tools.map((t) => t.definition.name)).toEqual(['real']);
|
|
193
|
+
expect(diagnostics.some((d) => d.code === 'symlink_refused')).toBe(true);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
//# sourceMappingURL=load-directory.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-directory.test.js","sourceRoot":"","sources":["../../../src/directory/__tests__/load-directory.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagents.test.d.ts","sourceRoot":"","sources":["../../../src/directory/__tests__/subagents.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import { deriveSupervisorOptions } from '../derive-supervisor.js';
|
|
6
|
+
import { loadDirectory } from '../load.js';
|
|
7
|
+
/**
|
|
8
|
+
* `SupervisorAgent` needs an `agentIds` roster and a manager that can spawn
|
|
9
|
+
* them. Nothing led from a directory to either, so a multi-agent system could
|
|
10
|
+
* be described on disk and not run.
|
|
11
|
+
*
|
|
12
|
+
* Delegates are loaded by recursion — a delegate directory has the same shape
|
|
13
|
+
* as its parent — capped at one level, because how deep a system may fan out
|
|
14
|
+
* is a topology decision and a directory layout should not make it by default.
|
|
15
|
+
*/
|
|
16
|
+
const provider = { id: 'mock', name: 'Mock' };
|
|
17
|
+
const agentManager = { sendMessage: async () => ({}) };
|
|
18
|
+
function tree(files) {
|
|
19
|
+
const root = mkdtempSync(join(tmpdir(), 'namzu-sub-'));
|
|
20
|
+
for (const [relative, body] of Object.entries(files)) {
|
|
21
|
+
const full = join(root, relative);
|
|
22
|
+
mkdirSync(join(full, '..'), { recursive: true });
|
|
23
|
+
writeFileSync(full, body);
|
|
24
|
+
}
|
|
25
|
+
return root;
|
|
26
|
+
}
|
|
27
|
+
const TOOL = (name) => `
|
|
28
|
+
export default {
|
|
29
|
+
name: ${JSON.stringify(name)},
|
|
30
|
+
description: 'a tool',
|
|
31
|
+
inputSchema: { parse: (v) => v, safeParse: (v) => ({ success: true, data: v }) },
|
|
32
|
+
execute: async () => ({ success: true, output: 'ok' }),
|
|
33
|
+
}
|
|
34
|
+
`;
|
|
35
|
+
const SYSTEM = {
|
|
36
|
+
'instructions.md': 'You coordinate.',
|
|
37
|
+
'agent.js': 'export default { model: "coordinator-model" }',
|
|
38
|
+
'agents/researcher/instructions.md': 'You research.',
|
|
39
|
+
'agents/researcher/agent.js': 'export default { model: "cheap-model" }',
|
|
40
|
+
'agents/researcher/tools/search.js': TOOL('search'),
|
|
41
|
+
'agents/writer/instructions.md': 'You write.',
|
|
42
|
+
};
|
|
43
|
+
describe('a project that declares delegates', () => {
|
|
44
|
+
it('loads each one as a project in its own right', async () => {
|
|
45
|
+
const { manifest, ok, diagnostics } = await loadDirectory(tree(SYSTEM));
|
|
46
|
+
expect(ok, JSON.stringify(diagnostics)).toBe(true);
|
|
47
|
+
expect(manifest.agents.map((a) => a.id).sort()).toEqual(['researcher', 'writer']);
|
|
48
|
+
const researcher = manifest.agents.find((a) => a.id === 'researcher');
|
|
49
|
+
expect(researcher?.manifest.instructions).toBe('You research.');
|
|
50
|
+
expect(researcher?.manifest.tools.map((t) => t.definition.name)).toEqual(['search']);
|
|
51
|
+
expect(researcher?.manifest.config.model).toBe('cheap-model');
|
|
52
|
+
});
|
|
53
|
+
it('surfaces a delegate failure in the parent list', async () => {
|
|
54
|
+
// A delegate that could not load is a fact about THIS project. A caller
|
|
55
|
+
// reading one list should not have to walk the tree to discover the run
|
|
56
|
+
// will be short a specialist.
|
|
57
|
+
const { manifest, ok, diagnostics } = await loadDirectory(tree({ ...SYSTEM, 'agents/writer/tools/bad.js': 'this is not valid !!!' }));
|
|
58
|
+
expect(ok).toBe(false);
|
|
59
|
+
expect(diagnostics.some((d) => d.message.startsWith('agents/writer:'))).toBe(true);
|
|
60
|
+
// The broken one is not offered as a delegate.
|
|
61
|
+
expect(manifest.agents.map((a) => a.id)).toEqual(['researcher']);
|
|
62
|
+
});
|
|
63
|
+
it('refuses to read a second level of delegates', async () => {
|
|
64
|
+
const { manifest, diagnostics } = await loadDirectory(tree({
|
|
65
|
+
...SYSTEM,
|
|
66
|
+
'agents/researcher/agents/deeper/instructions.md': 'You are too deep.',
|
|
67
|
+
}));
|
|
68
|
+
const researcher = manifest.agents.find((a) => a.id === 'researcher');
|
|
69
|
+
expect(researcher?.manifest.agents).toHaveLength(0);
|
|
70
|
+
expect(diagnostics.some((d) => d.code === 'subagent_too_deep')).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
it('imports nothing under modules: skip, delegates included', async () => {
|
|
73
|
+
const { manifest, ok } = await loadDirectory(tree({
|
|
74
|
+
'instructions.md': 'hi',
|
|
75
|
+
'agents/x/instructions.md': 'hi',
|
|
76
|
+
'agents/x/tools/boom.js': 'throw new Error("executed")',
|
|
77
|
+
}), { modules: 'skip' });
|
|
78
|
+
expect(ok).toBe(true);
|
|
79
|
+
expect(manifest.sources.some((s) => s.slot === 'agents')).toBe(true);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
describe('deriving supervisor options', () => {
|
|
83
|
+
it('builds the roster from the directory', async () => {
|
|
84
|
+
const { manifest } = await loadDirectory(tree(SYSTEM));
|
|
85
|
+
const { config, delegates } = deriveSupervisorOptions(manifest, { provider, agentManager });
|
|
86
|
+
expect(config.agentIds.sort()).toEqual(['researcher', 'writer']);
|
|
87
|
+
expect(config.systemPrompt).toBe('You coordinate.');
|
|
88
|
+
expect(config.model).toBe('coordinator-model');
|
|
89
|
+
expect(delegates).toHaveLength(2);
|
|
90
|
+
});
|
|
91
|
+
it('lets a delegate keep its own model and inherit when it has none', async () => {
|
|
92
|
+
// A cheap model for a narrow job is the common case; inheriting
|
|
93
|
+
// unconditionally would bill every specialist at the coordinator rate.
|
|
94
|
+
const { manifest } = await loadDirectory(tree(SYSTEM));
|
|
95
|
+
const { delegates } = deriveSupervisorOptions(manifest, { provider, agentManager });
|
|
96
|
+
expect(delegates.find((d) => d.id === 'researcher')?.model).toBe('cheap-model');
|
|
97
|
+
expect(delegates.find((d) => d.id === 'writer')?.model).toBe('coordinator-model');
|
|
98
|
+
});
|
|
99
|
+
it('carries each delegate its own instructions and tools', async () => {
|
|
100
|
+
const { manifest } = await loadDirectory(tree(SYSTEM));
|
|
101
|
+
const { delegates } = deriveSupervisorOptions(manifest, { provider, agentManager });
|
|
102
|
+
const researcher = delegates.find((d) => d.id === 'researcher');
|
|
103
|
+
expect(researcher?.systemPrompt).toBe('You research.');
|
|
104
|
+
expect(researcher?.tools.has('search')).toBe(true);
|
|
105
|
+
});
|
|
106
|
+
it('refuses a project with no delegates', async () => {
|
|
107
|
+
// An empty roster makes create_task unmountable, so the result would be
|
|
108
|
+
// a coordinator that cannot coordinate — and the caller asked for one.
|
|
109
|
+
const { manifest } = await loadDirectory(tree({ 'instructions.md': 'hi', 'agent.js': 'export default { model: "m" }' }));
|
|
110
|
+
expect(() => deriveSupervisorOptions(manifest, { provider, agentManager })).toThrow(/declares no delegates/);
|
|
111
|
+
});
|
|
112
|
+
it('refuses a manifest whose modules were never loaded', async () => {
|
|
113
|
+
const { manifest } = await loadDirectory(tree(SYSTEM), { modules: 'skip' });
|
|
114
|
+
expect(() => deriveSupervisorOptions(manifest, { provider, agentManager })).toThrow(/modules: "skip"/);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
//# sourceMappingURL=subagents.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagents.test.js","sourceRoot":"","sources":["../../../src/directory/__tests__/subagents.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supervisor-budget.test.d.ts","sourceRoot":"","sources":["../../../src/directory/__tests__/supervisor-budget.test.ts"],"names":[],"mappings":""}
|