@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.
Files changed (158) hide show
  1. package/CHANGELOG.md +361 -0
  2. package/dist/agents/__tests__/run-agent-forwarding.test.d.ts +2 -0
  3. package/dist/agents/__tests__/run-agent-forwarding.test.d.ts.map +1 -0
  4. package/dist/agents/__tests__/run-agent-forwarding.test.js +76 -0
  5. package/dist/agents/__tests__/run-agent-forwarding.test.js.map +1 -0
  6. package/dist/agents/__tests__/run-completed-stop-reason.test.d.ts +2 -0
  7. package/dist/agents/__tests__/run-completed-stop-reason.test.d.ts.map +1 -0
  8. package/dist/agents/__tests__/run-completed-stop-reason.test.js +50 -0
  9. package/dist/agents/__tests__/run-completed-stop-reason.test.js.map +1 -0
  10. package/dist/agents/index.d.ts +1 -0
  11. package/dist/agents/index.d.ts.map +1 -1
  12. package/dist/agents/index.js +4 -0
  13. package/dist/agents/index.js.map +1 -1
  14. package/dist/agents/runAgent.d.ts +34 -0
  15. package/dist/agents/runAgent.d.ts.map +1 -1
  16. package/dist/agents/runAgent.js +5 -3
  17. package/dist/agents/runAgent.js.map +1 -1
  18. package/dist/config/runtime.d.ts +30 -30
  19. package/dist/constants/tools/__tests__/dangerous-patterns.test.d.ts +2 -0
  20. package/dist/constants/tools/__tests__/dangerous-patterns.test.d.ts.map +1 -0
  21. package/dist/constants/tools/__tests__/dangerous-patterns.test.js +54 -0
  22. package/dist/constants/tools/__tests__/dangerous-patterns.test.js.map +1 -0
  23. package/dist/constants/tools/index.d.ts.map +1 -1
  24. package/dist/constants/tools/index.js +28 -1
  25. package/dist/constants/tools/index.js.map +1 -1
  26. package/dist/contracts/a2a.d.ts +44 -44
  27. package/dist/directory/__tests__/derive.test.d.ts +2 -0
  28. package/dist/directory/__tests__/derive.test.d.ts.map +1 -0
  29. package/dist/directory/__tests__/derive.test.js +111 -0
  30. package/dist/directory/__tests__/derive.test.js.map +1 -0
  31. package/dist/directory/__tests__/load-diagnostics.test.d.ts +2 -0
  32. package/dist/directory/__tests__/load-diagnostics.test.d.ts.map +1 -0
  33. package/dist/directory/__tests__/load-diagnostics.test.js +106 -0
  34. package/dist/directory/__tests__/load-diagnostics.test.js.map +1 -0
  35. package/dist/directory/__tests__/load-directory.test.d.ts +2 -0
  36. package/dist/directory/__tests__/load-directory.test.d.ts.map +1 -0
  37. package/dist/directory/__tests__/load-directory.test.js +196 -0
  38. package/dist/directory/__tests__/load-directory.test.js.map +1 -0
  39. package/dist/directory/__tests__/subagents.test.d.ts +2 -0
  40. package/dist/directory/__tests__/subagents.test.d.ts.map +1 -0
  41. package/dist/directory/__tests__/subagents.test.js +117 -0
  42. package/dist/directory/__tests__/subagents.test.js.map +1 -0
  43. package/dist/directory/__tests__/supervisor-budget.test.d.ts +2 -0
  44. package/dist/directory/__tests__/supervisor-budget.test.d.ts.map +1 -0
  45. package/dist/directory/__tests__/supervisor-budget.test.js +97 -0
  46. package/dist/directory/__tests__/supervisor-budget.test.js.map +1 -0
  47. package/dist/directory/derive-supervisor.d.ts +58 -0
  48. package/dist/directory/derive-supervisor.d.ts.map +1 -0
  49. package/dist/directory/derive-supervisor.js +88 -0
  50. package/dist/directory/derive-supervisor.js.map +1 -0
  51. package/dist/directory/derive.d.ts +12 -0
  52. package/dist/directory/derive.d.ts.map +1 -0
  53. package/dist/directory/derive.js +58 -0
  54. package/dist/directory/derive.js.map +1 -0
  55. package/dist/directory/index.d.ts +7 -0
  56. package/dist/directory/index.d.ts.map +1 -0
  57. package/dist/directory/index.js +5 -0
  58. package/dist/directory/index.js.map +1 -0
  59. package/dist/directory/load.d.ts +14 -0
  60. package/dist/directory/load.d.ts.map +1 -0
  61. package/dist/directory/load.js +488 -0
  62. package/dist/directory/load.js.map +1 -0
  63. package/dist/directory/scan.d.ts +36 -0
  64. package/dist/directory/scan.d.ts.map +1 -0
  65. package/dist/directory/scan.js +136 -0
  66. package/dist/directory/scan.js.map +1 -0
  67. package/dist/directory/types.d.ts +215 -0
  68. package/dist/directory/types.d.ts.map +1 -0
  69. package/dist/directory/types.js +8 -0
  70. package/dist/directory/types.js.map +1 -0
  71. package/dist/plugin/__tests__/path-containment.test.d.ts +2 -0
  72. package/dist/plugin/__tests__/path-containment.test.d.ts.map +1 -0
  73. package/dist/plugin/__tests__/path-containment.test.js +91 -0
  74. package/dist/plugin/__tests__/path-containment.test.js.map +1 -0
  75. package/dist/plugin/lifecycle.d.ts.map +1 -1
  76. package/dist/plugin/lifecycle.js +3 -3
  77. package/dist/plugin/lifecycle.js.map +1 -1
  78. package/dist/plugin/loader.d.ts.map +1 -1
  79. package/dist/plugin/loader.js +12 -2
  80. package/dist/plugin/loader.js.map +1 -1
  81. package/dist/provider/__tests__/model-version.test.d.ts +2 -0
  82. package/dist/provider/__tests__/model-version.test.d.ts.map +1 -0
  83. package/dist/provider/__tests__/model-version.test.js +80 -0
  84. package/dist/provider/__tests__/model-version.test.js.map +1 -0
  85. package/dist/provider/__tests__/strict-schema.test.d.ts +2 -0
  86. package/dist/provider/__tests__/strict-schema.test.d.ts.map +1 -0
  87. package/dist/provider/__tests__/strict-schema.test.js +109 -0
  88. package/dist/provider/__tests__/strict-schema.test.js.map +1 -0
  89. package/dist/provider/model-version.d.ts +60 -0
  90. package/dist/provider/model-version.d.ts.map +1 -0
  91. package/dist/provider/model-version.js +64 -0
  92. package/dist/provider/model-version.js.map +1 -0
  93. package/dist/provider/strict-schema.d.ts +49 -0
  94. package/dist/provider/strict-schema.d.ts.map +1 -0
  95. package/dist/provider/strict-schema.js +112 -0
  96. package/dist/provider/strict-schema.js.map +1 -0
  97. package/dist/public-runtime.d.ts +6 -1
  98. package/dist/public-runtime.d.ts.map +1 -1
  99. package/dist/public-runtime.js +21 -1
  100. package/dist/public-runtime.js.map +1 -1
  101. package/dist/public-types.d.ts +2 -0
  102. package/dist/public-types.d.ts.map +1 -1
  103. package/dist/registry/tool/__tests__/strict-registration.test.d.ts +2 -0
  104. package/dist/registry/tool/__tests__/strict-registration.test.d.ts.map +1 -0
  105. package/dist/registry/tool/__tests__/strict-registration.test.js +82 -0
  106. package/dist/registry/tool/__tests__/strict-registration.test.js.map +1 -0
  107. package/dist/registry/tool/execute.d.ts.map +1 -1
  108. package/dist/registry/tool/execute.js +16 -0
  109. package/dist/registry/tool/execute.js.map +1 -1
  110. package/dist/runtime/query/result.d.ts.map +1 -1
  111. package/dist/runtime/query/result.js +5 -0
  112. package/dist/runtime/query/result.js.map +1 -1
  113. package/dist/tools/builtins/__tests__/edit-insert-reachable.test.js +7 -1
  114. package/dist/tools/builtins/__tests__/edit-insert-reachable.test.js.map +1 -1
  115. package/dist/tools/builtins/__tests__/edit.test.js +1 -1
  116. package/dist/tools/builtins/__tests__/edit.test.js.map +1 -1
  117. package/dist/tools/builtins/edit.d.ts.map +1 -1
  118. package/dist/tools/builtins/edit.js +20 -2
  119. package/dist/tools/builtins/edit.js.map +1 -1
  120. package/dist/types/plugin/index.d.ts +4 -4
  121. package/dist/types/run/events.d.ts +17 -2
  122. package/dist/types/run/events.d.ts.map +1 -1
  123. package/dist/types/run/events.js.map +1 -1
  124. package/dist/types/verification/index.d.ts +6 -6
  125. package/package.json +1 -1
  126. package/src/agents/__tests__/run-agent-forwarding.test.ts +85 -0
  127. package/src/agents/__tests__/run-completed-stop-reason.test.ts +59 -0
  128. package/src/agents/index.ts +8 -0
  129. package/src/agents/runAgent.ts +30 -4
  130. package/src/constants/tools/__tests__/dangerous-patterns.test.ts +62 -0
  131. package/src/constants/tools/index.ts +28 -1
  132. package/src/directory/__tests__/derive.test.ts +135 -0
  133. package/src/directory/__tests__/load-diagnostics.test.ts +126 -0
  134. package/src/directory/__tests__/load-directory.test.ts +243 -0
  135. package/src/directory/__tests__/subagents.test.ts +155 -0
  136. package/src/directory/__tests__/supervisor-budget.test.ts +117 -0
  137. package/src/directory/derive-supervisor.ts +149 -0
  138. package/src/directory/derive.ts +70 -0
  139. package/src/directory/index.ts +27 -0
  140. package/src/directory/load.ts +556 -0
  141. package/src/directory/scan.ts +163 -0
  142. package/src/directory/types.ts +254 -0
  143. package/src/plugin/__tests__/path-containment.test.ts +107 -0
  144. package/src/plugin/lifecycle.ts +3 -3
  145. package/src/plugin/loader.ts +12 -2
  146. package/src/provider/__tests__/model-version.test.ts +93 -0
  147. package/src/provider/__tests__/strict-schema.test.ts +133 -0
  148. package/src/provider/model-version.ts +98 -0
  149. package/src/provider/strict-schema.ts +125 -0
  150. package/src/public-runtime.ts +31 -0
  151. package/src/public-types.ts +8 -0
  152. package/src/registry/tool/__tests__/strict-registration.test.ts +115 -0
  153. package/src/registry/tool/execute.ts +16 -0
  154. package/src/runtime/query/result.ts +5 -0
  155. package/src/tools/builtins/__tests__/edit-insert-reachable.test.ts +8 -2
  156. package/src/tools/builtins/__tests__/edit.test.ts +1 -1
  157. package/src/tools/builtins/edit.ts +20 -2
  158. package/src/types/run/events.ts +15 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,366 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 604a56a: completed is not succeeded — run_completed says why it stopped, and namzu run exits accordingly
8
+
9
+ `run_failed` is emitted from exactly one place in the kernel: the throw path.
10
+ Every other way a run can end badly arrives as `run_completed` — the token
11
+ budget, the timeout, the iteration cap, a cancellation, a rejected plan, a
12
+ refused structured output, and both guardrails.
13
+
14
+ Measured: a `max_iterations` stop reports `status: 'completed'`, and the event
15
+ carried nothing that distinguished it from an answered question.
16
+
17
+ **SDK.** `run_completed` now carries `stopReason`. It is optional and additive,
18
+ so nothing breaks; a consumer that wants to tell "answered" from "ran out of
19
+ budget" no longer has to hold the `Run` alongside the event stream.
20
+
21
+ **CLI — read this before upgrading if you script `namzu run`.** The command
22
+ exited `0` for all of those. The sharp case is the output guardrail: an answer
23
+ that was _refused_ exited `0` with empty text, so
24
+
25
+ ```sh
26
+ namzu run "write the release notes" > notes.md && publish notes.md
27
+ ```
28
+
29
+ published an empty file and reported success. `namzu run` now exits `1` when
30
+ the run did not finish normally, and names the reason on stderr. The text still
31
+ prints — partial output is real output, and a caller who piped it wants what
32
+ there is — but `$?` can now say it is partial.
33
+
34
+ If you have a script that depends on `namzu run` exiting 0 for a truncated run,
35
+ it was depending on not being told. Check `$?` and read the stderr line.
36
+
37
+ Also in the CLI, internally: the `done` agent event's `finishReason?: string`
38
+ had no producer and no reader anywhere in the package, and the name belonged to
39
+ a different concept — a "finish reason" here is `MessageStopReason`, reported
40
+ per model message, not the run-level `StopReason` a caller asks about at the end
41
+ of a turn. Replaced by `stopReason`. The type is not exported from the package
42
+ entry, so this is internal.
43
+
44
+ - f25ebce: a model id's date suffix is no longer read as its minor version
45
+
46
+ Three copies of one regular expression matched Claude model ids — the capability
47
+ table plus two drivers — and all three had the same defect: the minor-version
48
+ group was `(\d+)`, which swallowed the 8-digit date suffix.
49
+
50
+ Measured against the shipped pattern:
51
+
52
+ ```
53
+ claude-sonnet-4-20250514 -> major=4 minor=20250514
54
+ claude-opus-4-1-20250805 -> major=4 minor=1
55
+ ```
56
+
57
+ So a dated id naming no minor version compared as enormously _newer_ than one
58
+ that does, and every capability gate keyed on `minor >= n` inverted for exactly
59
+ those ids. `claude-sonnet-4-20250514` was classified as a 4.7+ model: the driver
60
+ sent it `thinking: {type: 'adaptive'}`, silently discarding a caller's
61
+ `budgetTokens`, and cleared the 4.5 gate that enables strict tool inputs.
62
+
63
+ `parseClaudeModelVersion` and `claudeVersionAtLeast` are now exported from
64
+ `@namzu/sdk` and used by both drivers and the capability table. A real minor
65
+ version is one to three digits; a date is eight, and the group is bounded
66
+ accordingly. An id the parser does not recognise makes `claudeVersionAtLeast`
67
+ return `false` — a capability gate must not open for a name it does not
68
+ understand.
69
+
70
+ The comment above the old parser warned that "a second, subtly different model
71
+ matcher is how two capability decisions drift apart on the same model name."
72
+ There were three.
73
+
74
+ - 5496fb2: the agent-directory loader is part of the SDK
75
+
76
+ It shipped briefly as a separate package. The name was the tell: nothing fit.
77
+ `project` collided with `ProjectId`, the tenancy bucket every run already
78
+ carries, and it described a scope that no longer existed once `channels/` and
79
+ `schedules/` were cut. `agent-dir` was a hyphenated abbreviation, out of family
80
+ with `skills`, `plugin`, `registry`, `sandbox`.
81
+
82
+ A directory reader that needs the kernel to be useful is a function of the
83
+ kernel, not a product beside it. So it is one now:
84
+
85
+ ```ts
86
+ import { loadDirectory, deriveRunOptions, runAgent } from "@namzu/sdk";
87
+
88
+ const { manifest, ok, diagnostics } = await loadDirectory("./agent");
89
+ if (!ok) console.error(diagnostics);
90
+
91
+ const { output } = await runAgent(
92
+ deriveRunOptions(manifest, { provider, prompt: "What is the weather?" })
93
+ );
94
+ ```
95
+
96
+ Nothing about the convention changed — the same `agent.ts`, `instructions.md`,
97
+ `tools/`, `skills/`, `agents/` layout, the same `modules: 'skip'` mode, the same
98
+ diagnostics, the same `deriveSupervisorOptions` for a directory that declares
99
+ delegates. Only the import path and the names.
100
+
101
+ **Nobody has to migrate.** The package was never published — a `@namzu/project`
102
+ install has always 404'd — so there is no consumer to move and no deprecation
103
+ window owed. The rename that would have cost a major after publishing cost
104
+ nothing before it.
105
+
106
+ Renames, if you were following the source: `loadProject` → `loadDirectory`,
107
+ `ProjectManifest` → `DirectoryManifest`, `ProjectConfig` → `DirectoryConfig`,
108
+ `ProjectSlot` → `DirectorySlot`, `ProjectLoadResult` → `DirectoryLoadResult`,
109
+ `ProjectDiagnostic` → `DirectoryDiagnostic`, `LoadProjectOptions` →
110
+ `LoadDirectoryOptions`. `DiagnosticCode` and `DiagnosticSeverity` gained a
111
+ `Directory` prefix as well — bare, in a shared namespace, they read as the
112
+ SDK's own diagnostic vocabulary rather than one loader's.
113
+
114
+ A side effect worth naming: `@namzu/project` was the one package the release
115
+ pipeline could not publish, so every release since `#102` ended red on its
116
+ `E404`. That failure goes with it.
117
+
118
+ - ca64062: runAgent forwards skills and the verification gate
119
+
120
+ `runAgent` built its `drainQuery` call with an `as never` cast. The cast was
121
+ not load-bearing — removing it typechecks clean — but while it was there the
122
+ kernel seam was unchecked in both directions, and two options the kernel
123
+ accepts were never forwarded.
124
+
125
+ **`skills`** is the one with a caller. `@namzu/sdk` reads a whole `skills/`
126
+ directory, puts them on the options, and every one was dropped: the run was
127
+ assembled without them and nothing reported it. If you passed `skills` to
128
+ `runAgent` and wondered why the model behaved as though it had never seen them,
129
+ this is why. No change needed on your side — the field now arrives.
130
+
131
+ **`verificationGate`** is the safety one. The kernel builds a `VerificationGate`
132
+ from it and consults it on every tool call; the front door had no way to supply
133
+ one, so a `runAgent` run was strictly less mediated than a `drainQuery` run. A
134
+ host that hands `runAgent` an agent directory it did not write should now set
135
+ it.
136
+
137
+ Both are optional and default to today's behaviour, so nothing breaks.
138
+
139
+ Three fixes in `@namzu/sdk`, each a check that existed and read the wrong
140
+ thing:
141
+
142
+ - **A tool with no `inputSchema` is refused.** It used to pass `isToolDefinition`
143
+ — which checked only `name` and `execute` — register clean, then die inside
144
+ `toLLMTools()` on `inputSchema._def`, in a `TypeError` naming neither the tool
145
+ file nor the loader. The check is now the four fields `ToolDefinition`
146
+ declares as required, and no more: demanding `defineTool`'s extras would make
147
+ the loader refuse an object the SDK's own published type accepts. A directory
148
+ that previously loaded with `ok: true` and crashed on first use now loads with
149
+ `ok: false` and a `not_a_tool` diagnostic naming the file.
150
+ - **Import failures explain themselves again.** `explainImportFailure` chose its
151
+ hint by matching Node's error code against `err.message`, and Node does not
152
+ put the code in the message — probed: `ERR_MODULE_NOT_FOUND` arrives as
153
+ "Cannot find module …". Every hint in the function was unreachable. It reads
154
+ `err.code` now, and a Node too old for type stripping gets a hint of its own.
155
+ - **`metadata` values are checked.** Typed `Record<string, string>` and admitted
156
+ on `typeof === 'object'` alone, which an array also satisfies and which says
157
+ nothing about the values, so `{ count: 1 }` and `["a"]` both reached a
158
+ consumer that had been promised strings.
159
+
160
+ - 61ca851: a tool whose schema cannot carry the guarantee it asks for is refused at registration
161
+
162
+ The previous release fixed the `edit` tool's schema and added a check in the
163
+ Anthropic driver. That caught the bug, but in the wrong place: per request, in
164
+ one of the **two** drivers that mark tools strict, and only once something
165
+ actually ran.
166
+
167
+ `ToolRegistry` already refused `enforceModelInput` without a
168
+ `modelInputSchema`, and the comment above that check states the principle
169
+ exactly — _"Refusing at registration puts the error where the author can fix it
170
+ rather than at the first request."_ The rule was written down; the new check was
171
+ somewhere else.
172
+
173
+ It is now beside its sibling. One asks whether a model schema **exists**; the
174
+ other asks whether it can **carry the guarantee the tool just requested**. A
175
+ tool that asks for constrained generation and supplies a schema the constrained
176
+ dialect cannot express is wrong at the moment it is declared, whichever model it
177
+ later meets — so it never registers, and can never reach a request.
178
+
179
+ ```
180
+ Tool "edit" is marked for strict input validation, but its model-facing schema
181
+ uses 1 construct(s) the strict subset does not accept…
182
+ edit.properties.insertLine.oneOf — use `anyOf` — for disjoint branches the two are equivalent
183
+ ```
184
+
185
+ This is the only path that matters in practice: the kernel builds its tool list
186
+ with `ToolRegistry.toLLMTools()`, so every tool reaching a driver through the
187
+ normal loop passed the gate.
188
+
189
+ **A tool that never asked for the guarantee is untouched.** Without
190
+ `enforceModelInput` nothing is marked strict, the schema is sent as ordinary
191
+ JSON Schema, and `oneOf` is perfectly legal there. Refusing it would break
192
+ working setups for no reason.
193
+
194
+ `@namzu/http` also marks tools strict and had no check at all — the same bug
195
+ was reachable through it. It now has the driver-level check the Anthropic driver
196
+ already carried. Both remain as a second boundary for a host that hand-builds
197
+ `ChatCompletionParams` and calls a provider directly, bypassing the registry.
198
+
199
+ **If you author a tool with `enforceModelInput: true`,** a schema using `oneOf`,
200
+ `not`, `if`/`then`/`else`, numeric or length bounds, `patternProperties`, or an
201
+ `additionalProperties` other than `false` now throws at registration instead of
202
+ failing the first request that carries it. The message names the path and the
203
+ replacement.
204
+
205
+ - f25ebce: the edit tool's schema could not be sent under strict validation
206
+
207
+ Strict tool input is not "JSON Schema, enforced" — it is a **subset** of JSON
208
+ Schema, and a keyword outside that subset is not degraded. The vendor rejects
209
+ the whole request, so one unexpressible field in one tool takes every other
210
+ tool down with it and the turn dies before producing a token.
211
+
212
+ The `edit` tool declared its integer-or-`"end"` field with `oneOf`, which is
213
+ outside the subset while the equivalent `anyOf` is inside it. Measured against
214
+ the live API:
215
+
216
+ | body | result |
217
+ | ------------------------- | ------------------------------------------------ |
218
+ | `strict: true` + `oneOf` | **400** — `Schema type 'oneOf' is not supported` |
219
+ | `strict: false` + `oneOf` | accepted |
220
+ | `strict: true` + `anyOf` | accepted |
221
+
222
+ The middle row is why nothing caught it. Neither half is wrong on its own — the
223
+ schema is valid JSON Schema, and marking the tool strict is correct policy — so
224
+ no test of either one failed. Only the pairing did, and the pairing had no
225
+ owner. Every agent using the built-in `edit` tool on a model at or above the
226
+ strict gate lost its first tool-carrying turn to a 400.
227
+
228
+ `oneOf` is now `anyOf` (equivalent here — the branches are disjoint), and
229
+ `minimum` is gone from the model-facing schema for the same reason: numeric
230
+ bounds are outside the subset too. The bound is not lost, the execution schema
231
+ still enforces it.
232
+
233
+ **The general fix is the second half.** `assertStrictSchema` and
234
+ `findStrictSchemaViolations` are exported from `@namzu/sdk`, and the driver now
235
+ checks every schema it is about to mark strict — refusing with the exact path
236
+ and the remedy rather than letting the request go and getting back an error
237
+ that names the keyword but not where it lives:
238
+
239
+ ```
240
+ Tool "edit" is marked for strict input validation, but its model-facing schema
241
+ uses 1 construct(s) the strict subset does not accept…
242
+ edit.properties.insertLine.oneOf — use `anyOf` — for disjoint branches the two are equivalent
243
+ ```
244
+
245
+ A test sweeps every built-in tool that asks for strict validation, so the next
246
+ one is caught in the suite rather than in production.
247
+
248
+ - f25ebce: a directory-derived supervisor now has a token budget, a wall clock, and its skills
249
+
250
+ `BaseAgentConfig` declares `tokenBudget` and `timeoutMs` as **required**.
251
+ `deriveSupervisorOptions` supplied them only when `agent.ts` happened to name
252
+ them — the uncommon case — and an `as SupervisorAgentConfig` made that compile.
253
+ The returned object was therefore typed `tokenBudget: number` while holding
254
+ `undefined`.
255
+
256
+ That is not a type-level nicety. `buildLimitConfig` defaults only
257
+ `maxIterations`, so an undefined budget and timeout disable **both** hard stops:
258
+ a supervisor derived from a directory ran with no token cap and no wall clock.
259
+ And the child-spawn guard computes a delegate's allocation from the parent
260
+ budget, so `undefined` became `NaN` — and `NaN <= 0` is `false`, meaning the
261
+ refusal that exists to stop an unfunded child let it through with a `NaN`
262
+ budget.
263
+
264
+ Both now default to the same numbers `runAgent` uses, which are exported as
265
+ `DEFAULT_TOKEN_BUDGET`, `DEFAULT_TIMEOUT_MS` and `DEFAULT_MAX_ITERATIONS` so the
266
+ two front doors cannot drift. Anything `agent.ts` declares still wins, and
267
+ `overrides` still wins over that.
268
+
269
+ The cast is now `satisfies`, so the next missing required field is a compile
270
+ error rather than a run with its limits quietly switched off.
271
+
272
+ Same file, same cast: `skills` were loaded from the project's `skills/`
273
+ directory, put on the manifest, and then left out of the config the supervisor
274
+ actually ran with. `SupervisorAgentConfig` accepts them and the kernel drives
275
+ them; they are now supplied.
276
+
277
+ - c6b8aa8: An agent directory can declare delegates, and `deriveSupervisorOptions` turns them into
278
+ a `SupervisorAgent` configuration.
279
+
280
+ `SupervisorAgent` needs an `agentIds` roster and a manager that can spawn them.
281
+ Nothing led from a directory to either, so a multi-agent system could be
282
+ described on disk and not run.
283
+
284
+ A directory under `agents/` is read by the same loader that read the root — a
285
+ delegate has the same shape as its parent, so this is recursion rather than a
286
+ new concept.
287
+
288
+ ```
289
+ agent/
290
+ ├── instructions.md
291
+ └── agents/
292
+ ├── researcher/ ← its own agent.ts, instructions.md, tools/
293
+ └── writer/
294
+ ```
295
+
296
+ `deriveSupervisorOptions` supplies the roster and leaves the manager to the
297
+ host, the same contract `deriveRunOptions` follows: it converts, it does not
298
+ run. Delegates come back as plans rather than registered agents, because
299
+ registration mutates the host's manager and a function that quietly mutates an
300
+ object it was handed for reference is the surprise this package avoids.
301
+
302
+ A delegate may name its own model and inherits the coordinator's only when it
303
+ does not — a cheap model for a narrow job is the common case, and inheriting
304
+ unconditionally would bill every specialist at the coordinator's rate.
305
+
306
+ **One level only.** A delegate may not declare delegates of its own. How deep a
307
+ system fans out is a topology decision that belongs to whoever composes it, and
308
+ answering it by default is how a directory layout ends up deciding a system's
309
+ shape. It also removes the cycle: `agents/a/agents/b/agents/a` cannot be built
310
+ if the second level is never read.
311
+
312
+ A delegate that fails to load is reported in the parent's diagnostics, prefixed
313
+ with its path, and is not offered in the roster. A caller reading one list
314
+ should not have to walk the tree to find out the run will be short a specialist.
315
+
316
+ ### Patch Changes
317
+
318
+ - f25ebce: the fork-bomb entry in the dangerous-command list could not match a fork bomb
319
+
320
+ `DANGEROUS_PATTERNS` is what the `deny_dangerous_patterns` verification rule
321
+ consults, and what `namzu run`'s own docstring means when it promises that in a
322
+ non-interactive run "the safety gate still hard-denies catastrophic commands".
323
+
324
+ The fork-bomb entry was written `/:(){ :\|:& };:/`. In a regular expression
325
+ `()` is an empty capture group, not two literal parentheses — so that pattern
326
+ described the string `:{ :|:& };:`, which is not valid shell and which nobody
327
+ would ever type. Probed: it returned `false` for `:(){ :|:& };:` and for every
328
+ other spelling of it.
329
+
330
+ The replacement matches on **self-reference** rather than on one literal
331
+ spelling — a fork bomb is a function whose own name appears on both sides of a
332
+ pipe, is backgrounded, and is then invoked. So `bomb(){ bomb|bomb& }; bomb` is
333
+ denied along with the `:` form, while `watch(){ tail -f log | grep E & }` — a
334
+ function that merely contains a pipe and a background job — is not.
335
+
336
+ No test named a fork bomb before this change, which is how it survived. There
337
+ are now sixteen.
338
+
339
+ - c8672ed: The plugin subsystem contains its paths. It had none, and it is the part of
340
+ this SDK that loads third-party code.
341
+
342
+ **A manifest could name any file on disk.** `PluginLifecycleManager` built its
343
+ import path with `join(plugin.rootDir, toolPath)`, and `toolPath` comes out of
344
+ the plugin's own manifest — a file the plugin author writes. A manifest reading
345
+ `"tools": ["../../../../somewhere/evil.js"]` left the plugin directory entirely
346
+ and was imported, which is to say executed, in-process. The same held for
347
+ `hooks`. Both now resolve through `resolveWithinReal`, so a path that escapes
348
+ the plugin root is refused before anything is imported.
349
+
350
+ **Discovery followed symlinks.** `discoverPlugins` used `stat`, which reports
351
+ on a link's _target_, so a symlinked entry pointing anywhere on disk was
352
+ admitted as a plugin directory and its manifest read from there — the directory
353
+ listed was not the directory loaded (CWE-59). It now uses `lstat` and refuses a
354
+ link with a warning naming the path.
355
+
356
+ Found by comparing the plugin loader against `@namzu/sdk`'s scanner, which
357
+ was written this week with both protections. The subsystem that had them was
358
+ the one loading code the repo's own reviewers wrote; the one without them was
359
+ the one loading code from a home directory those reviewers never see.
360
+
361
+ If you ship a plugin whose manifest points outside its own directory, it now
362
+ fails at enable with a message naming the path. Move the file inside the plugin.
363
+
3
364
  ## 5.1.0
4
365
 
5
366
  ### Minor Changes
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=run-agent-forwarding.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-agent-forwarding.test.d.ts","sourceRoot":"","sources":["../../../src/agents/__tests__/run-agent-forwarding.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,76 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { z } from 'zod';
3
+ import { MockLLMProvider, registerMock } from '../../provider/index.js';
4
+ import { ToolRegistry } from '../../registry/index.js';
5
+ import { runAgent } from '../runAgent.js';
6
+ /**
7
+ * The `drainQuery` call in `runAgent` was written `as never`.
8
+ *
9
+ * That cast was not load-bearing — removing it typechecks clean — but while it
10
+ * was there the kernel seam was unchecked in both directions: a field the
11
+ * kernel accepts and this door forgot to forward produced no error, and neither
12
+ * did a field spelled wrong. Two were already missing when it was removed.
13
+ *
14
+ * `skills` is the one with a caller in this repo. `@namzu/project` reads a
15
+ * whole `skills/` directory, put them on the options, and every one was dropped
16
+ * on the floor — the run was assembled without them and said nothing. These
17
+ * pin the forwarding rather than the cast, because the cast can come back and
18
+ * a test that only asserted its absence would not notice.
19
+ */
20
+ registerMock();
21
+ describe('runAgent forwards what the kernel takes', () => {
22
+ it('puts skills in front of the model', async () => {
23
+ const provider = new MockLLMProvider({ turns: [{ text: 'ok' }] });
24
+ await runAgent({
25
+ provider,
26
+ model: 'mock-model',
27
+ prompt: 'plan something',
28
+ skills: [
29
+ {
30
+ metadata: { name: 'plan-a-trip', description: 'Plan a trip end to end' },
31
+ body: 'Ask for dates first.',
32
+ dirPath: '/tmp/skills/plan-a-trip',
33
+ },
34
+ ],
35
+ });
36
+ // Serialized rather than reached into: the prompt builder decides where a
37
+ // skill lands, and pinning that path here would make this test fail on a
38
+ // refactor that kept the behaviour. What matters is that it arrived.
39
+ expect(JSON.stringify(provider.requests[0])).toContain('plan-a-trip');
40
+ });
41
+ it('forwards the verification gate, so a denied tool does not run', async () => {
42
+ // The first version of this test asserted `run.status === 'completed'`
43
+ // with the gate set. It passed with the forwarding deleted — a run with
44
+ // no gate completes too — so it proved nothing. A gate is only observable
45
+ // through a call it stops, which means the assertion has to be about
46
+ // whether the tool body ran.
47
+ let ran = false;
48
+ const tools = new ToolRegistry();
49
+ tools.register({
50
+ name: 'delete_everything',
51
+ description: 'Deletes everything.',
52
+ inputSchema: z.object({}),
53
+ execute: async () => {
54
+ ran = true;
55
+ return { success: true, output: 'deleted' };
56
+ },
57
+ });
58
+ await runAgent({
59
+ provider: new MockLLMProvider({
60
+ turns: [{ toolCalls: [{ name: 'delete_everything', args: {} }] }, { text: 'done' }],
61
+ }),
62
+ model: 'mock-model',
63
+ prompt: 'clean up',
64
+ tools,
65
+ verificationGate: {
66
+ enabled: true,
67
+ rules: [{ type: 'deny_by_name', toolNames: ['delete_everything'] }],
68
+ allowReadOnlyTools: false,
69
+ denyDangerousPatterns: false,
70
+ logDecisions: false,
71
+ },
72
+ });
73
+ expect(ran).toBe(false);
74
+ });
75
+ });
76
+ //# sourceMappingURL=run-agent-forwarding.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-agent-forwarding.test.js","sourceRoot":"","sources":["../../../src/agents/__tests__/run-agent-forwarding.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC;;;;;;;;;;;;;GAaG;AAEH,YAAY,EAAE,CAAA;AAEd,QAAQ,CAAC,yCAAyC,EAAE,GAAG,EAAE;IACxD,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAA;QAEjE,MAAM,QAAQ,CAAC;YACd,QAAQ;YACR,KAAK,EAAE,YAAY;YACnB,MAAM,EAAE,gBAAgB;YACxB,MAAM,EAAE;gBACP;oBACC,QAAQ,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,WAAW,EAAE,wBAAwB,EAAE;oBACxE,IAAI,EAAE,sBAAsB;oBAC5B,OAAO,EAAE,yBAAyB;iBAClC;aACD;SACD,CAAC,CAAA;QAEF,0EAA0E;QAC1E,yEAAyE;QACzE,qEAAqE;QACrE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAA;IACtE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC9E,uEAAuE;QACvE,wEAAwE;QACxE,0EAA0E;QAC1E,qEAAqE;QACrE,6BAA6B;QAC7B,IAAI,GAAG,GAAG,KAAK,CAAA;QAEf,MAAM,KAAK,GAAG,IAAI,YAAY,EAAE,CAAA;QAChC,KAAK,CAAC,QAAQ,CAAC;YACd,IAAI,EAAE,mBAAmB;YACzB,WAAW,EAAE,qBAAqB;YAClC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;YACzB,OAAO,EAAE,KAAK,IAAI,EAAE;gBACnB,GAAG,GAAG,IAAI,CAAA;gBACV,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;YAC5C,CAAC;SACD,CAAC,CAAA;QAEF,MAAM,QAAQ,CAAC;YACd,QAAQ,EAAE,IAAI,eAAe,CAAC;gBAC7B,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;aACnF,CAAC;YACF,KAAK,EAAE,YAAY;YACnB,MAAM,EAAE,UAAU;YAClB,KAAK;YACL,gBAAgB,EAAE;gBACjB,OAAO,EAAE,IAAI;gBACb,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,CAAC,mBAAmB,CAAC,EAAE,CAAC;gBACnE,kBAAkB,EAAE,KAAK;gBACzB,qBAAqB,EAAE,KAAK;gBAC5B,YAAY,EAAE,KAAK;aACnB;SACD,CAAC,CAAA;QAEF,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACxB,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=run-completed-stop-reason.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-completed-stop-reason.test.d.ts","sourceRoot":"","sources":["../../../src/agents/__tests__/run-completed-stop-reason.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,50 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { MockLLMProvider, registerMock } from '../../provider/index.js';
3
+ import { runAgent } from '../runAgent.js';
4
+ /**
5
+ * `completed` is not `succeeded`.
6
+ *
7
+ * `run_failed` is emitted from exactly one place — the throw path in
8
+ * `result.ts` — so every other way a run can end badly arrives as
9
+ * `run_completed`: the token budget, the timeout, the iteration cap, a
10
+ * cancellation, and a blocking output guardrail. A consumer reading that event
11
+ * as success reported one for a run whose answer was refused, and the CLI did:
12
+ * it mapped `run_completed` to a bare `done` and exited 0.
13
+ *
14
+ * Measured before the fix: a `max_iterations` stop reports
15
+ * `status: 'completed'`, and the event carried nothing to distinguish it.
16
+ */
17
+ registerMock();
18
+ async function eventsOf(options) {
19
+ const events = [];
20
+ await runAgent({ ...options, listener: (e) => void events.push(e) });
21
+ return events;
22
+ }
23
+ function completion(events) {
24
+ return events.find((e) => e.type === 'run_completed');
25
+ }
26
+ describe('run_completed says why the run stopped', () => {
27
+ it('reports end_turn when the model finished its answer', async () => {
28
+ const events = await eventsOf({
29
+ provider: new MockLLMProvider({ turns: [{ text: 'done' }] }),
30
+ model: 'mock-model',
31
+ prompt: 'x',
32
+ });
33
+ expect(completion(events)?.stopReason).toBe('end_turn');
34
+ });
35
+ it('reports max_iterations when the loop was cut short', async () => {
36
+ const events = await eventsOf({
37
+ provider: new MockLLMProvider({ turns: [{ toolCalls: [{ name: 'absent', args: {} }] }] }),
38
+ model: 'mock-model',
39
+ prompt: 'x',
40
+ maxIterations: 1,
41
+ });
42
+ const done = completion(events);
43
+ // The event that a consumer treats as "the run ended" — and the field
44
+ // that stops it being read as "the run succeeded".
45
+ expect(done).toBeDefined();
46
+ expect(done?.stopReason).toBe('max_iterations');
47
+ expect(events.some((e) => e.type === 'run_failed')).toBe(false);
48
+ });
49
+ });
50
+ //# sourceMappingURL=run-completed-stop-reason.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-completed-stop-reason.test.js","sourceRoot":"","sources":["../../../src/agents/__tests__/run-completed-stop-reason.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAEvE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC;;;;;;;;;;;;GAYG;AAEH,YAAY,EAAE,CAAA;AAEd,KAAK,UAAU,QAAQ,CAAC,OAAuC;IAC9D,MAAM,MAAM,GAAe,EAAE,CAAA;IAC7B,MAAM,QAAQ,CAAC,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IACpE,OAAO,MAAM,CAAA;AACd,CAAC;AAED,SAAS,UAAU,CAAC,MAAkB;IACrC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe,CAAU,CAAA;AAC/D,CAAC;AAED,QAAQ,CAAC,wCAAwC,EAAE,GAAG,EAAE;IACvD,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC;YAC7B,QAAQ,EAAE,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;YAC5D,KAAK,EAAE,YAAY;YACnB,MAAM,EAAE,GAAG;SACX,CAAC,CAAA;QAEF,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IACxD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QACnE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC;YAC7B,QAAQ,EAAE,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;YACzF,KAAK,EAAE,YAAY;YACnB,MAAM,EAAE,GAAG;YACX,aAAa,EAAE,CAAC;SAChB,CAAC,CAAA;QAEF,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAA;QAC/B,sEAAsE;QACtE,mDAAmD;QACnD,MAAM,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAA;QAC1B,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;QAC/C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAChE,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -8,5 +8,6 @@ export type { DefineAgentOptions } from './defineAgent.js';
8
8
  export { InvocationLock, ConcurrentInvocationError } from './lock.js';
9
9
  export type { Disposable } from './lock.js';
10
10
  export { runAgent } from './runAgent.js';
11
+ export { DEFAULT_MAX_ITERATIONS, DEFAULT_TIMEOUT_MS, DEFAULT_TOKEN_BUDGET, } from './runAgent.js';
11
12
  export type { AgentIdentity, RunAgentOptions, RunAgentResult } from './runAgent.js';
12
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAA;AACrE,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAA;AACrE,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAIxC,OAAO,EACN,sBAAsB,EACtB,kBAAkB,EAClB,oBAAoB,GACpB,MAAM,eAAe,CAAA;AACtB,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA"}
@@ -6,4 +6,8 @@ export { SupervisorAgent } from './SupervisorAgent.js';
6
6
  export { defineAgent } from './defineAgent.js';
7
7
  export { InvocationLock, ConcurrentInvocationError } from './lock.js';
8
8
  export { runAgent } from './runAgent.js';
9
+ // The budgets the front door applies when a caller names none. Exported so a
10
+ // deriver that builds a config by hand lands on the SAME numbers rather than
11
+ // inventing its own or, as `@namzu/project` did, supplying none at all.
12
+ export { DEFAULT_MAX_ITERATIONS, DEFAULT_TIMEOUT_MS, DEFAULT_TOKEN_BUDGET, } from './runAgent.js';
9
13
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9C,OAAO,EAAE,cAAc,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAA;AAErE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9C,OAAO,EAAE,cAAc,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAA;AAErE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,6EAA6E;AAC7E,6EAA6E;AAC7E,wEAAwE;AACxE,OAAO,EACN,sBAAsB,EACtB,kBAAkB,EAClB,oBAAoB,GACpB,MAAM,eAAe,CAAA"}
@@ -2,7 +2,9 @@ import type { ProjectId, SessionId, TenantId, ThreadId } from '../types/ids/inde
2
2
  import type { Message } from '../types/message/index.js';
3
3
  import type { LLMProvider } from '../types/provider/index.js';
4
4
  import type { Run, RunEventListener } from '../types/run/index.js';
5
+ import type { Skill } from '../types/skills/index.js';
5
6
  import type { ToolRegistryContract } from '../types/tool/index.js';
7
+ import type { VerificationGateConfig } from '../types/verification/index.js';
6
8
  /**
7
9
  * The session a run belongs to.
8
10
  *
@@ -36,6 +38,26 @@ export interface RunAgentOptions extends AgentIdentity {
36
38
  */
37
39
  model: string;
38
40
  tools?: ToolRegistryContract;
41
+ /**
42
+ * Skills to put in front of the model.
43
+ *
44
+ * The kernel has taken these since it had a prompt builder; this door did
45
+ * not forward them, so a caller who assembled skills — `@namzu/project`
46
+ * reads a whole `skills/` directory — handed them over and got a run that
47
+ * had never heard of them. Silent, because the `drainQuery` call below was
48
+ * cast, and a cast seam reports nothing when a field goes missing.
49
+ */
50
+ skills?: Skill[];
51
+ /**
52
+ * Operator policy for tool calls: which ones need review before they run.
53
+ *
54
+ * Absent means every tool runs unreviewed, which is the right default for a
55
+ * library front door and the wrong one for a host that hands this an agent
56
+ * directory it did not write. The kernel builds a `VerificationGate` from
57
+ * this and consults it on every call; without it there is nothing to
58
+ * consult, so a front-door run is strictly less mediated than a kernel one.
59
+ */
60
+ verificationGate?: VerificationGateConfig;
39
61
  /** Defaults to the current working directory. */
40
62
  workingDirectory?: string;
41
63
  maxIterations?: number;
@@ -59,6 +81,18 @@ export interface RunAgentResult {
59
81
  */
60
82
  readonly identity: Required<AgentIdentity>;
61
83
  }
84
+ /**
85
+ * Defaults chosen to be safe rather than generous.
86
+ *
87
+ * A front door exists so a first run works without a decision, and the cost of
88
+ * that convenience is that nobody reads these numbers before their first
89
+ * runaway loop. So: a budget that ends a stuck run in seconds rather than
90
+ * dollars, and an iteration cap that stops a tool-calling loop well before a
91
+ * context window does. Every one is overridable and named on the option.
92
+ */
93
+ export declare const DEFAULT_MAX_ITERATIONS = 16;
94
+ export declare const DEFAULT_TOKEN_BUDGET = 200000;
95
+ export declare const DEFAULT_TIMEOUT_MS = 300000;
62
96
  /**
63
97
  * Run an agent, without assembling a kernel by hand.
64
98
  *
@@ -1 +1 @@
1
- {"version":3,"file":"runAgent.d.ts","sourceRoot":"","sources":["../../src/agents/runAgent.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AACrF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAC7D,OAAO,KAAK,EAAE,GAAG,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAClE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAQlE;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC7B,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAA;CACnB;AAED,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACrD,gEAAgE;IAChE,QAAQ,EAAE,WAAW,CAAA;IAErB,kEAAkE;IAClE,MAAM,EAAE,MAAM,GAAG,OAAO,EAAE,CAAA;IAE1B,yBAAyB;IACzB,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;;;;;;;;OAQG;IACH,KAAK,EAAE,MAAM,CAAA;IAEb,KAAK,CAAC,EAAE,oBAAoB,CAAA;IAE5B,iDAAiD;IACjD,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAEzB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IAEpB,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAA;IAEb,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,QAAQ,CAAC,EAAE,gBAAgB,CAAA;CAC3B;AAED,MAAM,WAAW,cAAc;IAC9B,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAEnC,qEAAqE;IACrE,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAA;IAEjB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAA;CAC1C;AAeD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAyChF"}
1
+ {"version":3,"file":"runAgent.d.ts","sourceRoot":"","sources":["../../src/agents/runAgent.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AACrF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAC7D,OAAO,KAAK,EAAE,GAAG,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAClE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAA;AACrD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAClE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAA;AAQ5E;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC7B,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAA;CACnB;AAED,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACrD,gEAAgE;IAChE,QAAQ,EAAE,WAAW,CAAA;IAErB,kEAAkE;IAClE,MAAM,EAAE,MAAM,GAAG,OAAO,EAAE,CAAA;IAE1B,yBAAyB;IACzB,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;;;;;;;;OAQG;IACH,KAAK,EAAE,MAAM,CAAA;IAEb,KAAK,CAAC,EAAE,oBAAoB,CAAA;IAE5B;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,KAAK,EAAE,CAAA;IAEhB;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,sBAAsB,CAAA;IAEzC,iDAAiD;IACjD,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAEzB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IAEpB,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAA;IAEb,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,QAAQ,CAAC,EAAE,gBAAgB,CAAA;CAC3B;AAED,MAAM,WAAW,cAAc;IAC9B,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAEnC,qEAAqE;IACrE,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAA;IAEjB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAA;CAC1C;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,KAAK,CAAA;AACxC,eAAO,MAAM,oBAAoB,SAAU,CAAA;AAC3C,eAAO,MAAM,kBAAkB,SAAU,CAAA;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CA2ChF"}
@@ -10,9 +10,9 @@ import { generateProjectId, generateSessionId, generateTenantId, generateThreadI
10
10
  * dollars, and an iteration cap that stops a tool-calling loop well before a
11
11
  * context window does. Every one is overridable and named on the option.
12
12
  */
13
- const DEFAULT_MAX_ITERATIONS = 16;
14
- const DEFAULT_TOKEN_BUDGET = 200_000;
15
- const DEFAULT_TIMEOUT_MS = 300_000;
13
+ export const DEFAULT_MAX_ITERATIONS = 16;
14
+ export const DEFAULT_TOKEN_BUDGET = 200_000;
15
+ export const DEFAULT_TIMEOUT_MS = 300_000;
16
16
  /**
17
17
  * Run an agent, without assembling a kernel by hand.
18
18
  *
@@ -85,6 +85,8 @@ export async function runAgent(options) {
85
85
  agentName: options.name ?? 'Agent',
86
86
  ...(options.instructions ? { systemPrompt: options.instructions } : {}),
87
87
  ...(options.signal ? { signal: options.signal } : {}),
88
+ ...(options.skills ? { skills: options.skills } : {}),
89
+ ...(options.verificationGate ? { verificationGate: options.verificationGate } : {}),
88
90
  ...identity,
89
91
  }, options.listener);
90
92
  return { output: run.result, run, identity };