@namzu/sdk 5.0.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.
Files changed (181) hide show
  1. package/CHANGELOG.md +463 -0
  2. package/README.md +2 -2
  3. package/dist/agents/__tests__/run-agent-forwarding.test.d.ts +2 -0
  4. package/dist/agents/__tests__/run-agent-forwarding.test.d.ts.map +1 -0
  5. package/dist/agents/__tests__/run-agent-forwarding.test.js +76 -0
  6. package/dist/agents/__tests__/run-agent-forwarding.test.js.map +1 -0
  7. package/dist/agents/__tests__/run-completed-stop-reason.test.d.ts +2 -0
  8. package/dist/agents/__tests__/run-completed-stop-reason.test.d.ts.map +1 -0
  9. package/dist/agents/__tests__/run-completed-stop-reason.test.js +50 -0
  10. package/dist/agents/__tests__/run-completed-stop-reason.test.js.map +1 -0
  11. package/dist/agents/index.d.ts +1 -0
  12. package/dist/agents/index.d.ts.map +1 -1
  13. package/dist/agents/index.js +4 -0
  14. package/dist/agents/index.js.map +1 -1
  15. package/dist/agents/runAgent.d.ts +34 -0
  16. package/dist/agents/runAgent.d.ts.map +1 -1
  17. package/dist/agents/runAgent.js +5 -3
  18. package/dist/agents/runAgent.js.map +1 -1
  19. package/dist/config/runtime.d.ts +30 -30
  20. package/dist/constants/tools/__tests__/dangerous-patterns.test.d.ts +2 -0
  21. package/dist/constants/tools/__tests__/dangerous-patterns.test.d.ts.map +1 -0
  22. package/dist/constants/tools/__tests__/dangerous-patterns.test.js +54 -0
  23. package/dist/constants/tools/__tests__/dangerous-patterns.test.js.map +1 -0
  24. package/dist/constants/tools/index.d.ts.map +1 -1
  25. package/dist/constants/tools/index.js +28 -1
  26. package/dist/constants/tools/index.js.map +1 -1
  27. package/dist/contracts/a2a.d.ts +44 -44
  28. package/dist/directory/__tests__/derive.test.d.ts +2 -0
  29. package/dist/directory/__tests__/derive.test.d.ts.map +1 -0
  30. package/dist/directory/__tests__/derive.test.js +111 -0
  31. package/dist/directory/__tests__/derive.test.js.map +1 -0
  32. package/dist/directory/__tests__/load-diagnostics.test.d.ts +2 -0
  33. package/dist/directory/__tests__/load-diagnostics.test.d.ts.map +1 -0
  34. package/dist/directory/__tests__/load-diagnostics.test.js +106 -0
  35. package/dist/directory/__tests__/load-diagnostics.test.js.map +1 -0
  36. package/dist/directory/__tests__/load-directory.test.d.ts +2 -0
  37. package/dist/directory/__tests__/load-directory.test.d.ts.map +1 -0
  38. package/dist/directory/__tests__/load-directory.test.js +196 -0
  39. package/dist/directory/__tests__/load-directory.test.js.map +1 -0
  40. package/dist/directory/__tests__/subagents.test.d.ts +2 -0
  41. package/dist/directory/__tests__/subagents.test.d.ts.map +1 -0
  42. package/dist/directory/__tests__/subagents.test.js +117 -0
  43. package/dist/directory/__tests__/subagents.test.js.map +1 -0
  44. package/dist/directory/__tests__/supervisor-budget.test.d.ts +2 -0
  45. package/dist/directory/__tests__/supervisor-budget.test.d.ts.map +1 -0
  46. package/dist/directory/__tests__/supervisor-budget.test.js +97 -0
  47. package/dist/directory/__tests__/supervisor-budget.test.js.map +1 -0
  48. package/dist/directory/derive-supervisor.d.ts +58 -0
  49. package/dist/directory/derive-supervisor.d.ts.map +1 -0
  50. package/dist/directory/derive-supervisor.js +88 -0
  51. package/dist/directory/derive-supervisor.js.map +1 -0
  52. package/dist/directory/derive.d.ts +12 -0
  53. package/dist/directory/derive.d.ts.map +1 -0
  54. package/dist/directory/derive.js +58 -0
  55. package/dist/directory/derive.js.map +1 -0
  56. package/dist/directory/index.d.ts +7 -0
  57. package/dist/directory/index.d.ts.map +1 -0
  58. package/dist/directory/index.js +5 -0
  59. package/dist/directory/index.js.map +1 -0
  60. package/dist/directory/load.d.ts +14 -0
  61. package/dist/directory/load.d.ts.map +1 -0
  62. package/dist/directory/load.js +488 -0
  63. package/dist/directory/load.js.map +1 -0
  64. package/dist/directory/scan.d.ts +36 -0
  65. package/dist/directory/scan.d.ts.map +1 -0
  66. package/dist/directory/scan.js +136 -0
  67. package/dist/directory/scan.js.map +1 -0
  68. package/dist/directory/types.d.ts +215 -0
  69. package/dist/directory/types.d.ts.map +1 -0
  70. package/dist/directory/types.js +8 -0
  71. package/dist/directory/types.js.map +1 -0
  72. package/dist/plugin/__tests__/path-containment.test.d.ts +2 -0
  73. package/dist/plugin/__tests__/path-containment.test.d.ts.map +1 -0
  74. package/dist/plugin/__tests__/path-containment.test.js +91 -0
  75. package/dist/plugin/__tests__/path-containment.test.js.map +1 -0
  76. package/dist/plugin/lifecycle.d.ts.map +1 -1
  77. package/dist/plugin/lifecycle.js +3 -3
  78. package/dist/plugin/lifecycle.js.map +1 -1
  79. package/dist/plugin/loader.d.ts.map +1 -1
  80. package/dist/plugin/loader.js +12 -2
  81. package/dist/plugin/loader.js.map +1 -1
  82. package/dist/provider/__tests__/model-version.test.d.ts +2 -0
  83. package/dist/provider/__tests__/model-version.test.d.ts.map +1 -0
  84. package/dist/provider/__tests__/model-version.test.js +80 -0
  85. package/dist/provider/__tests__/model-version.test.js.map +1 -0
  86. package/dist/provider/__tests__/strict-schema.test.d.ts +2 -0
  87. package/dist/provider/__tests__/strict-schema.test.d.ts.map +1 -0
  88. package/dist/provider/__tests__/strict-schema.test.js +109 -0
  89. package/dist/provider/__tests__/strict-schema.test.js.map +1 -0
  90. package/dist/provider/__tests__/typed-error-classification.test.d.ts +2 -0
  91. package/dist/provider/__tests__/typed-error-classification.test.d.ts.map +1 -0
  92. package/dist/provider/__tests__/typed-error-classification.test.js +123 -0
  93. package/dist/provider/__tests__/typed-error-classification.test.js.map +1 -0
  94. package/dist/provider/model-version.d.ts +60 -0
  95. package/dist/provider/model-version.d.ts.map +1 -0
  96. package/dist/provider/model-version.js +64 -0
  97. package/dist/provider/model-version.js.map +1 -0
  98. package/dist/provider/retry.d.ts.map +1 -1
  99. package/dist/provider/retry.js +23 -7
  100. package/dist/provider/retry.js.map +1 -1
  101. package/dist/provider/strict-schema.d.ts +49 -0
  102. package/dist/provider/strict-schema.d.ts.map +1 -0
  103. package/dist/provider/strict-schema.js +112 -0
  104. package/dist/provider/strict-schema.js.map +1 -0
  105. package/dist/public-runtime.d.ts +6 -1
  106. package/dist/public-runtime.d.ts.map +1 -1
  107. package/dist/public-runtime.js +21 -1
  108. package/dist/public-runtime.js.map +1 -1
  109. package/dist/public-tools.d.ts +1 -0
  110. package/dist/public-tools.d.ts.map +1 -1
  111. package/dist/public-tools.js +4 -0
  112. package/dist/public-tools.js.map +1 -1
  113. package/dist/public-types.d.ts +2 -0
  114. package/dist/public-types.d.ts.map +1 -1
  115. package/dist/registry/tool/__tests__/strict-registration.test.d.ts +2 -0
  116. package/dist/registry/tool/__tests__/strict-registration.test.d.ts.map +1 -0
  117. package/dist/registry/tool/__tests__/strict-registration.test.js +82 -0
  118. package/dist/registry/tool/__tests__/strict-registration.test.js.map +1 -0
  119. package/dist/registry/tool/execute.d.ts.map +1 -1
  120. package/dist/registry/tool/execute.js +16 -0
  121. package/dist/registry/tool/execute.js.map +1 -1
  122. package/dist/runtime/query/__tests__/stream-recovery.test.js +5 -0
  123. package/dist/runtime/query/__tests__/stream-recovery.test.js.map +1 -1
  124. package/dist/runtime/query/result.d.ts.map +1 -1
  125. package/dist/runtime/query/result.js +5 -0
  126. package/dist/runtime/query/result.js.map +1 -1
  127. package/dist/tools/builtins/__tests__/edit-insert-reachable.test.js +7 -1
  128. package/dist/tools/builtins/__tests__/edit-insert-reachable.test.js.map +1 -1
  129. package/dist/tools/builtins/__tests__/edit.test.js +1 -1
  130. package/dist/tools/builtins/__tests__/edit.test.js.map +1 -1
  131. package/dist/tools/builtins/edit.d.ts.map +1 -1
  132. package/dist/tools/builtins/edit.js +20 -2
  133. package/dist/tools/builtins/edit.js.map +1 -1
  134. package/dist/types/plugin/index.d.ts +4 -4
  135. package/dist/types/provider/errors.d.ts +0 -17
  136. package/dist/types/provider/errors.d.ts.map +1 -1
  137. package/dist/types/provider/errors.js +60 -0
  138. package/dist/types/provider/errors.js.map +1 -1
  139. package/dist/types/run/events.d.ts +17 -2
  140. package/dist/types/run/events.d.ts.map +1 -1
  141. package/dist/types/run/events.js.map +1 -1
  142. package/dist/types/verification/index.d.ts +6 -6
  143. package/package.json +1 -1
  144. package/src/agents/__tests__/run-agent-forwarding.test.ts +85 -0
  145. package/src/agents/__tests__/run-completed-stop-reason.test.ts +59 -0
  146. package/src/agents/index.ts +8 -0
  147. package/src/agents/runAgent.ts +30 -4
  148. package/src/constants/tools/__tests__/dangerous-patterns.test.ts +62 -0
  149. package/src/constants/tools/index.ts +28 -1
  150. package/src/directory/__tests__/derive.test.ts +135 -0
  151. package/src/directory/__tests__/load-diagnostics.test.ts +126 -0
  152. package/src/directory/__tests__/load-directory.test.ts +243 -0
  153. package/src/directory/__tests__/subagents.test.ts +155 -0
  154. package/src/directory/__tests__/supervisor-budget.test.ts +117 -0
  155. package/src/directory/derive-supervisor.ts +149 -0
  156. package/src/directory/derive.ts +70 -0
  157. package/src/directory/index.ts +27 -0
  158. package/src/directory/load.ts +556 -0
  159. package/src/directory/scan.ts +163 -0
  160. package/src/directory/types.ts +254 -0
  161. package/src/plugin/__tests__/path-containment.test.ts +107 -0
  162. package/src/plugin/lifecycle.ts +3 -3
  163. package/src/plugin/loader.ts +12 -2
  164. package/src/provider/__tests__/model-version.test.ts +93 -0
  165. package/src/provider/__tests__/strict-schema.test.ts +133 -0
  166. package/src/provider/__tests__/typed-error-classification.test.ts +143 -0
  167. package/src/provider/model-version.ts +98 -0
  168. package/src/provider/retry.ts +23 -7
  169. package/src/provider/strict-schema.ts +125 -0
  170. package/src/public-runtime.ts +31 -0
  171. package/src/public-tools.ts +4 -0
  172. package/src/public-types.ts +8 -0
  173. package/src/registry/tool/__tests__/strict-registration.test.ts +115 -0
  174. package/src/registry/tool/execute.ts +16 -0
  175. package/src/runtime/query/__tests__/stream-recovery.test.ts +5 -0
  176. package/src/runtime/query/result.ts +5 -0
  177. package/src/tools/builtins/__tests__/edit-insert-reachable.test.ts +8 -2
  178. package/src/tools/builtins/__tests__/edit.test.ts +1 -1
  179. package/src/tools/builtins/edit.ts +20 -2
  180. package/src/types/provider/errors.ts +71 -0
  181. package/src/types/run/events.ts +15 -2
@@ -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":"AAAA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C;;;;;;;;;GASG;AAEH,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE;IACzB,IAAI,CAAC;QACJ,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAA;QAC5D,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC,CAAA;QAC9C,OAAO,IAAI,CAAA;IACZ,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAA;IACb,CAAC;AACF,CAAC,CAAC,EAAE,CAAA;AAEJ,SAAS,OAAO,CAAC,KAA6B;IAC7C,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,aAAa,CAAC,CAAC,CAAA;IACvD,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;QACjC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAChD,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAC1B,CAAC;IACD,OAAO,IAAI,CAAA;AACZ,CAAC;AAED,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC;;UAErB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;;;;;CAK7B,CAAA;AAED,QAAQ,CAAC,6BAA6B,EAAE,GAAG,EAAE;IAC5C,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,IAAI,GAAG,OAAO,CAAC;YACpB,iBAAiB,EAAE,oBAAoB;YACvC,UAAU,EAAE,iDAAiD;YAC7D,iBAAiB,EAAE,IAAI,CAAC,QAAQ,CAAC;SACjC,CAAC,CAAA;QAEF,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAA;QAE/D,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClD,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;QACtD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAA;QACvE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;IACzE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,IAAI,GAAG,OAAO,CAAC;YACpB,iBAAiB,EAAE,IAAI;YACvB,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC;YAC7B,iBAAiB,EAAE,kCAAkC;SACrD,CAAC,CAAA;QAEF,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAA;QAE/D,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACtB,mEAAmE;QACnE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;QACtE,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,oBAAoB,CAAC,CAAA;QACxE,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;QACzC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAChF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,IAAI,GAAG,OAAO,CAAC;YACpB,iBAAiB,EAAE,IAAI;YACvB,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC;YAC5B,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC;SAC5B,CAAC,CAAA;QAEF,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAA;QAE/D,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACtB,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC5E,uDAAuD;QACvD,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,IAAI,GAAG,OAAO,CAAC;YACpB,iBAAiB,EAAE,IAAI;YACvB,YAAY,EAAE,6BAA6B;SAC3C,CAAC,CAAA;QAEF,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAA;QAErD,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACtB,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACpE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACtE,wEAAwE;QACxE,sDAAsD;QACtD,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAEjD,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAA;QAErD,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACrB,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,sBAAsB,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IAC7F,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,iBAAiB,EAAE,OAAO,EAAE,CAAC,CAAA;QAEpD,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAA;QAErD,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACtB,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,oBAAoB,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACzF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,IAAI,GAAG,OAAO,CAAC;YACpB,iBAAiB,EAAE,IAAI;YACvB,UAAU,EAAE,8BAA8B;SAC1C,CAAC,CAAA;QAEF,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAA;QAErD,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACtB,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,gBAAgB,CAAC,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAA;IAC3F,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACtE,MAAM,IAAI,GAAG,OAAO,CAAC;YACpB,iBAAiB,EAAE,IAAI;YACvB,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC;YAC7B,wBAAwB,EAAE,oBAAoB;YAC9C,kBAAkB,EAAE,IAAI,CAAC,QAAQ,CAAC;SAClC,CAAC,CAAA;QAEF,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAA;QAE/D,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACrB,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;QACtE,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC9E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,IAAI,GAAG,OAAO,CAAC;YACpB,iBAAiB,EAAE,IAAI;YACvB,sBAAsB,EAAE,IAAI,CAAC,MAAM,CAAC;SACpC,CAAC,CAAA;QAEF,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAA;QAEjD,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,qBAAqB,CAAC,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;IAC/F,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,0BAA0B,CAAC,CAAC,CAAA;QAE3F,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACtB,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;IAClD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,MAAM,CAAC,aAAa,CAAC,EAAY,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IACrE,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAChE,uEAAuE;QACvE,4BAA4B;QAC5B,MAAM,IAAI,GAAG,OAAO,CAAC;YACpB,iBAAiB,EAAE,kBAAkB;YACrC,UAAU,EAAE,sCAAsC;YAClD,YAAY,EAAE,kCAAkC;SAChD,CAAC,CAAA;QAEF,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAA;QAEvE,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACrB,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;QACtD,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC,CAAA;QACxF,MAAM,CACL,QAAQ,CAAC,OAAO;aACd,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC;aACxC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,YAAY,CAAC,CAC1C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACZ,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACzC,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,iBAAiB,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAE1E,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QAEtE,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAA;QAC5C,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACtC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACrD,mEAAmE;QACnE,uCAAuC;QACvC,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,iBAAiB,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAE1E,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE;YAC9C,OAAO,EAAE,EAA0B;SACnC,CAAC,CAAA;QAEF,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QACxC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;IACnD,EAAE,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAA;QAC7D,aAAa,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;QACrD,MAAM,IAAI,GAAG,OAAO,CAAC;YACpB,iBAAiB,EAAE,IAAI;YACvB,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC;SAC7B,CAAC,CAAA;QACF,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,CAAA;QAE/E,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAA;QAE3D,mEAAmE;QACnE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;QACtE,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACzE,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=subagents.test.d.ts.map
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=supervisor-budget.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supervisor-budget.test.d.ts","sourceRoot":"","sources":["../../../src/directory/__tests__/supervisor-budget.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,97 @@
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
+ * `BaseAgentConfig` declares `tokenBudget` and `timeoutMs` as REQUIRED, and
9
+ * `deriveSupervisorOptions` supplied them only when `agent.ts` happened to
10
+ * name them — which is the uncommon case. An `as SupervisorAgentConfig` made
11
+ * that compile, so the returned object was typed `tokenBudget: number` while
12
+ * holding `undefined`.
13
+ *
14
+ * The consequence is not a type-level nicety. `buildLimitConfig` defaults only
15
+ * `maxIterations`, so an undefined budget and timeout disable BOTH hard stops
16
+ * — a project-derived supervisor ran with no token cap and no wall clock. And
17
+ * the child-spawn guard computes a delegate's allocation from the parent
18
+ * budget, so `undefined` became `NaN`, and `NaN <= 0` is false: the refusal
19
+ * that exists to stop an unfunded child let it through.
20
+ *
21
+ * The cast is now `satisfies`, which is what keeps this from recurring — but
22
+ * a type check is not a test, so the values are asserted here too.
23
+ */
24
+ const provider = { id: 'mock', name: 'Mock' };
25
+ const agentManager = { sendMessage: async () => ({}) };
26
+ function tree(files) {
27
+ const root = mkdtempSync(join(tmpdir(), 'namzu-budget-'));
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 MINIMAL = {
36
+ 'agent.js': 'export default { model: "m" }',
37
+ 'agents/researcher/agent.js': 'export default { model: "m2" }',
38
+ 'agents/researcher/instructions.md': 'Research things.',
39
+ };
40
+ describe('a derived supervisor always has a budget and a clock', () => {
41
+ it('defaults both when agent.ts names neither', async () => {
42
+ const { manifest } = await loadDirectory(tree(MINIMAL));
43
+ const { config } = deriveSupervisorOptions(manifest, { provider, agentManager });
44
+ // The exact numbers matter less than that they are finite: a NaN or an
45
+ // undefined here is what silently disabled the limits.
46
+ expect(Number.isFinite(config.tokenBudget)).toBe(true);
47
+ expect(Number.isFinite(config.timeoutMs)).toBe(true);
48
+ expect(config.tokenBudget).toBeGreaterThan(0);
49
+ expect(config.timeoutMs).toBeGreaterThan(0);
50
+ });
51
+ it('uses the same defaults the SDK front door uses', async () => {
52
+ // Imported from the module that owns them rather than through the
53
+ // package entry: this file now lives inside that package, and a
54
+ // self-import resolves to the built `dist`, not to the source under
55
+ // test — which is how a stale build reads as a passing test.
56
+ const { DEFAULT_TIMEOUT_MS, DEFAULT_TOKEN_BUDGET } = await import('../../agents/runAgent.js');
57
+ const { manifest } = await loadDirectory(tree(MINIMAL));
58
+ const { config } = deriveSupervisorOptions(manifest, { provider, agentManager });
59
+ // Two front doors that default differently is a difference nobody would
60
+ // find until a run behaved unlike its sibling.
61
+ expect(config.tokenBudget).toBe(DEFAULT_TOKEN_BUDGET);
62
+ expect(config.timeoutMs).toBe(DEFAULT_TIMEOUT_MS);
63
+ });
64
+ it('still honours what agent.ts declares', async () => {
65
+ const { manifest } = await loadDirectory(tree({
66
+ ...MINIMAL,
67
+ 'agent.js': 'export default { model: "m", tokenBudget: 1234, timeoutMs: 5678 }',
68
+ }));
69
+ const { config } = deriveSupervisorOptions(manifest, { provider, agentManager });
70
+ expect(config.tokenBudget).toBe(1234);
71
+ expect(config.timeoutMs).toBe(5678);
72
+ });
73
+ it('lets an override win over both', async () => {
74
+ const { manifest } = await loadDirectory(tree(MINIMAL));
75
+ const { config } = deriveSupervisorOptions(manifest, {
76
+ provider,
77
+ agentManager,
78
+ overrides: { tokenBudget: 42 },
79
+ });
80
+ expect(config.tokenBudget).toBe(42);
81
+ });
82
+ });
83
+ describe('a derived supervisor carries the skills it loaded', () => {
84
+ it('passes skills through instead of dropping them', async () => {
85
+ const { manifest } = await loadDirectory(tree({
86
+ ...MINIMAL,
87
+ 'skills/plan-a-trip/SKILL.md': '---\nname: plan-a-trip\ndescription: Plan a trip\n---\n\nAsk for dates.',
88
+ }));
89
+ expect(manifest.skills).toHaveLength(1);
90
+ const { config } = deriveSupervisorOptions(manifest, { provider, agentManager });
91
+ // Loaded from disk, put on the manifest, and then — before this — left
92
+ // out of the config the supervisor actually runs with.
93
+ expect(config.skills).toHaveLength(1);
94
+ expect(config.skills?.[0]?.metadata.name).toBe('plan-a-trip');
95
+ });
96
+ });
97
+ //# sourceMappingURL=supervisor-budget.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supervisor-budget.test.js","sourceRoot":"","sources":["../../../src/directory/__tests__/supervisor-budget.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import type { AgentIdentity } from '../agents/runAgent.js';
2
+ import { ToolRegistry } from '../registry/tool/execute.js';
3
+ import type { SupervisorAgentConfig } from '../types/agent/supervisor.js';
4
+ import type { LLMProvider } from '../types/provider/index.js';
5
+ import type { DirectoryManifest } from './types.js';
6
+ export interface DeriveSupervisorInput {
7
+ readonly provider: LLMProvider;
8
+ /** Wins over `agent.ts`. Required when `agent.ts` names no model. */
9
+ readonly model?: string;
10
+ readonly identity?: Required<AgentIdentity>;
11
+ /**
12
+ * The lifecycle object that actually spawns delegates.
13
+ *
14
+ * Supplied by the host and never built here. An `AgentManager` owns
15
+ * running processes, budgets and cancellation — it is a thing with a
16
+ * lifetime, not a description of one, and this package's whole boundary is
17
+ * that it describes and does not run. Handing back options that carry a
18
+ * manager we constructed would make it a runner wearing a loader's name.
19
+ */
20
+ readonly agentManager: SupervisorAgentConfig['agentManager'];
21
+ readonly overrides?: Partial<SupervisorAgentConfig>;
22
+ }
23
+ export interface SupervisorPlan {
24
+ /** Ready for `new SupervisorAgent(...).run(input, config)`. */
25
+ readonly config: SupervisorAgentConfig;
26
+ /**
27
+ * What the host must register with its `AgentManager` before running,
28
+ * one per delegate, keyed by the id the supervisor will name.
29
+ *
30
+ * Returned rather than registered: registration is a mutation of the
31
+ * host's manager, and a function that quietly mutates an object it was
32
+ * handed for reference is the kind of surprise this package exists to
33
+ * avoid. The host does it, in one loop it can see.
34
+ */
35
+ readonly delegates: readonly DelegatePlan[];
36
+ }
37
+ export interface DelegatePlan {
38
+ readonly id: string;
39
+ readonly manifest: DirectoryManifest;
40
+ /** The delegate's own instructions, tools and model, already assembled. */
41
+ readonly systemPrompt: string;
42
+ readonly tools: ToolRegistry;
43
+ readonly model: string;
44
+ }
45
+ /**
46
+ * Turn a project that declares delegates into a supervisor configuration.
47
+ *
48
+ * The counterpart to `deriveRunOptions` for the multi-agent shape, and the
49
+ * same contract: it converts, it does not run. `SupervisorAgent` needs an
50
+ * `agentIds` roster and a manager that can spawn them; this supplies the
51
+ * roster from the directory and leaves the manager to the host.
52
+ *
53
+ * The delegates come back as plans rather than registered agents because
54
+ * registration mutates the host's manager. Two lines in the host, and the host
55
+ * can see exactly what it just gained.
56
+ */
57
+ export declare function deriveSupervisorOptions(manifest: DirectoryManifest, input: DeriveSupervisorInput): SupervisorPlan;
58
+ //# sourceMappingURL=derive-supervisor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive-supervisor.d.ts","sourceRoot":"","sources":["../../src/directory/derive-supervisor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAC1D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAE7D,OAAO,KAAK,EAAE,iBAAiB,EAAiB,MAAM,YAAY,CAAA;AAElE,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAA;IAC9B,qEAAqE;IACrE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAA;IAC3C;;;;;;;;OAQG;IACH,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC,cAAc,CAAC,CAAA;IAC5D,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAA;CACnD;AAED,MAAM,WAAW,cAAc;IAC9B,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAA;IACtC;;;;;;;;OAQG;IACH,QAAQ,CAAC,SAAS,EAAE,SAAS,YAAY,EAAE,CAAA;CAC3C;AAED,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAA;IACpC,2EAA2E;IAC3E,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAA;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACtB;AAsBD;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACtC,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,EAAE,qBAAqB,GAC1B,cAAc,CA+DhB"}
@@ -0,0 +1,88 @@
1
+ import { DEFAULT_TIMEOUT_MS, DEFAULT_TOKEN_BUDGET } from '../agents/runAgent.js';
2
+ import { ToolRegistry } from '../registry/tool/execute.js';
3
+ function toolsOf(manifest) {
4
+ const tools = new ToolRegistry();
5
+ for (const entry of manifest.tools)
6
+ tools.register(entry.definition);
7
+ return tools;
8
+ }
9
+ function delegatePlan(entry, fallbackModel) {
10
+ return {
11
+ id: entry.id,
12
+ manifest: entry.manifest,
13
+ systemPrompt: entry.manifest.instructions,
14
+ tools: toolsOf(entry.manifest),
15
+ // A delegate may name its own model — a cheap one for a narrow job is
16
+ // the common case — and inherits the supervisor's only when it does
17
+ // not. Inheriting unconditionally would silently bill every specialist
18
+ // at the coordinator's rate.
19
+ model: entry.manifest.config.model ?? fallbackModel,
20
+ };
21
+ }
22
+ /**
23
+ * Turn a project that declares delegates into a supervisor configuration.
24
+ *
25
+ * The counterpart to `deriveRunOptions` for the multi-agent shape, and the
26
+ * same contract: it converts, it does not run. `SupervisorAgent` needs an
27
+ * `agentIds` roster and a manager that can spawn them; this supplies the
28
+ * roster from the directory and leaves the manager to the host.
29
+ *
30
+ * The delegates come back as plans rather than registered agents because
31
+ * registration mutates the host's manager. Two lines in the host, and the host
32
+ * can see exactly what it just gained.
33
+ */
34
+ export function deriveSupervisorOptions(manifest, input) {
35
+ if (manifest.modules === 'skip') {
36
+ throw new Error('This manifest was loaded with modules: "skip", so no tool was imported and no delegate was evaluated. Load with modules: "evaluate" before deriving supervisor options.');
37
+ }
38
+ if (manifest.agents.length === 0) {
39
+ // Not a warning that degrades into a supervisor with nobody to call.
40
+ // An empty roster makes `create_task` unmountable by design, so the
41
+ // result would be a coordinator that cannot coordinate — and the
42
+ // caller asked for a supervisor, which means they expected delegates.
43
+ throw new Error(`${manifest.root} declares no delegates, so there is nothing for a supervisor to coordinate. Add directories under agents/, or use deriveRunOptions for a single agent.`);
44
+ }
45
+ const model = input.model ?? manifest.config.model;
46
+ if (!model) {
47
+ throw new Error(`No model. Declare one in ${manifest.root}/agent.ts as \`export default { model: "…" }\`, or pass \`model\` here.`);
48
+ }
49
+ const delegates = manifest.agents.map((entry) => delegatePlan(entry, model));
50
+ const config = {
51
+ provider: input.provider,
52
+ model,
53
+ agentManager: input.agentManager,
54
+ agentIds: delegates.map((d) => d.id),
55
+ systemPrompt: manifest.instructions,
56
+ tools: toolsOf(manifest),
57
+ // Skills were loaded and then dropped. The manifest reads a whole
58
+ // `skills/` directory and `SupervisorAgentConfig` takes them, and the
59
+ // cast that used to close this object meant nobody was told the field
60
+ // had never been supplied.
61
+ ...(manifest.skills.length > 0 ? { skills: manifest.skills.map((s) => s.skill) } : {}),
62
+ // `tokenBudget` and `timeoutMs` are REQUIRED by `BaseAgentConfig`, and
63
+ // this object supplied them only when `agent.ts` happened to declare
64
+ // them — which is the uncommon case. The `as SupervisorAgentConfig`
65
+ // below made that compile, so a directory that named no budget produced
66
+ // a config typed `tokenBudget: number` holding `undefined`, and
67
+ // `buildLimitConfig` then disabled BOTH hard stops: no token cap, no
68
+ // wall clock. Worse, the child-spawn refusal computes its allocation
69
+ // from the parent budget, so `undefined` became `NaN`, and `NaN <= 0`
70
+ // is false — the guard that exists to refuse an unfunded child let it
71
+ // through with a NaN budget.
72
+ //
73
+ // Defaulted to the same numbers `runAgent` uses rather than to a local
74
+ // guess, so the two front doors cannot drift.
75
+ tokenBudget: manifest.config.tokenBudget ?? DEFAULT_TOKEN_BUDGET,
76
+ timeoutMs: manifest.config.timeoutMs ?? DEFAULT_TIMEOUT_MS,
77
+ ...(manifest.config.temperature !== undefined
78
+ ? { temperature: manifest.config.temperature }
79
+ : {}),
80
+ ...(manifest.config.maxIterations !== undefined
81
+ ? { maxIterations: manifest.config.maxIterations }
82
+ : {}),
83
+ ...(input.identity ?? {}),
84
+ ...(input.overrides ?? {}),
85
+ };
86
+ return { config, delegates };
87
+ }
88
+ //# sourceMappingURL=derive-supervisor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive-supervisor.js","sourceRoot":"","sources":["../../src/directory/derive-supervisor.ts"],"names":[],"mappings":"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"}