@namzu/sdk 5.1.0 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +361 -0
- package/dist/agents/__tests__/run-agent-forwarding.test.d.ts +2 -0
- package/dist/agents/__tests__/run-agent-forwarding.test.d.ts.map +1 -0
- package/dist/agents/__tests__/run-agent-forwarding.test.js +76 -0
- package/dist/agents/__tests__/run-agent-forwarding.test.js.map +1 -0
- package/dist/agents/__tests__/run-completed-stop-reason.test.d.ts +2 -0
- package/dist/agents/__tests__/run-completed-stop-reason.test.d.ts.map +1 -0
- package/dist/agents/__tests__/run-completed-stop-reason.test.js +50 -0
- package/dist/agents/__tests__/run-completed-stop-reason.test.js.map +1 -0
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +4 -0
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/runAgent.d.ts +34 -0
- package/dist/agents/runAgent.d.ts.map +1 -1
- package/dist/agents/runAgent.js +5 -3
- package/dist/agents/runAgent.js.map +1 -1
- package/dist/config/runtime.d.ts +30 -30
- package/dist/constants/tools/__tests__/dangerous-patterns.test.d.ts +2 -0
- package/dist/constants/tools/__tests__/dangerous-patterns.test.d.ts.map +1 -0
- package/dist/constants/tools/__tests__/dangerous-patterns.test.js +54 -0
- package/dist/constants/tools/__tests__/dangerous-patterns.test.js.map +1 -0
- package/dist/constants/tools/index.d.ts.map +1 -1
- package/dist/constants/tools/index.js +28 -1
- package/dist/constants/tools/index.js.map +1 -1
- package/dist/contracts/a2a.d.ts +44 -44
- package/dist/directory/__tests__/derive.test.d.ts +2 -0
- package/dist/directory/__tests__/derive.test.d.ts.map +1 -0
- package/dist/directory/__tests__/derive.test.js +111 -0
- package/dist/directory/__tests__/derive.test.js.map +1 -0
- package/dist/directory/__tests__/load-diagnostics.test.d.ts +2 -0
- package/dist/directory/__tests__/load-diagnostics.test.d.ts.map +1 -0
- package/dist/directory/__tests__/load-diagnostics.test.js +106 -0
- package/dist/directory/__tests__/load-diagnostics.test.js.map +1 -0
- package/dist/directory/__tests__/load-directory.test.d.ts +2 -0
- package/dist/directory/__tests__/load-directory.test.d.ts.map +1 -0
- package/dist/directory/__tests__/load-directory.test.js +196 -0
- package/dist/directory/__tests__/load-directory.test.js.map +1 -0
- package/dist/directory/__tests__/subagents.test.d.ts +2 -0
- package/dist/directory/__tests__/subagents.test.d.ts.map +1 -0
- package/dist/directory/__tests__/subagents.test.js +117 -0
- package/dist/directory/__tests__/subagents.test.js.map +1 -0
- package/dist/directory/__tests__/supervisor-budget.test.d.ts +2 -0
- package/dist/directory/__tests__/supervisor-budget.test.d.ts.map +1 -0
- package/dist/directory/__tests__/supervisor-budget.test.js +97 -0
- package/dist/directory/__tests__/supervisor-budget.test.js.map +1 -0
- package/dist/directory/derive-supervisor.d.ts +58 -0
- package/dist/directory/derive-supervisor.d.ts.map +1 -0
- package/dist/directory/derive-supervisor.js +88 -0
- package/dist/directory/derive-supervisor.js.map +1 -0
- package/dist/directory/derive.d.ts +12 -0
- package/dist/directory/derive.d.ts.map +1 -0
- package/dist/directory/derive.js +58 -0
- package/dist/directory/derive.js.map +1 -0
- package/dist/directory/index.d.ts +7 -0
- package/dist/directory/index.d.ts.map +1 -0
- package/dist/directory/index.js +5 -0
- package/dist/directory/index.js.map +1 -0
- package/dist/directory/load.d.ts +14 -0
- package/dist/directory/load.d.ts.map +1 -0
- package/dist/directory/load.js +488 -0
- package/dist/directory/load.js.map +1 -0
- package/dist/directory/scan.d.ts +36 -0
- package/dist/directory/scan.d.ts.map +1 -0
- package/dist/directory/scan.js +136 -0
- package/dist/directory/scan.js.map +1 -0
- package/dist/directory/types.d.ts +215 -0
- package/dist/directory/types.d.ts.map +1 -0
- package/dist/directory/types.js +8 -0
- package/dist/directory/types.js.map +1 -0
- package/dist/plugin/__tests__/path-containment.test.d.ts +2 -0
- package/dist/plugin/__tests__/path-containment.test.d.ts.map +1 -0
- package/dist/plugin/__tests__/path-containment.test.js +91 -0
- package/dist/plugin/__tests__/path-containment.test.js.map +1 -0
- package/dist/plugin/lifecycle.d.ts.map +1 -1
- package/dist/plugin/lifecycle.js +3 -3
- package/dist/plugin/lifecycle.js.map +1 -1
- package/dist/plugin/loader.d.ts.map +1 -1
- package/dist/plugin/loader.js +12 -2
- package/dist/plugin/loader.js.map +1 -1
- package/dist/provider/__tests__/model-version.test.d.ts +2 -0
- package/dist/provider/__tests__/model-version.test.d.ts.map +1 -0
- package/dist/provider/__tests__/model-version.test.js +80 -0
- package/dist/provider/__tests__/model-version.test.js.map +1 -0
- package/dist/provider/__tests__/strict-schema.test.d.ts +2 -0
- package/dist/provider/__tests__/strict-schema.test.d.ts.map +1 -0
- package/dist/provider/__tests__/strict-schema.test.js +109 -0
- package/dist/provider/__tests__/strict-schema.test.js.map +1 -0
- package/dist/provider/model-version.d.ts +60 -0
- package/dist/provider/model-version.d.ts.map +1 -0
- package/dist/provider/model-version.js +64 -0
- package/dist/provider/model-version.js.map +1 -0
- package/dist/provider/strict-schema.d.ts +49 -0
- package/dist/provider/strict-schema.d.ts.map +1 -0
- package/dist/provider/strict-schema.js +112 -0
- package/dist/provider/strict-schema.js.map +1 -0
- package/dist/public-runtime.d.ts +6 -1
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +21 -1
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-types.d.ts +2 -0
- package/dist/public-types.d.ts.map +1 -1
- package/dist/registry/tool/__tests__/strict-registration.test.d.ts +2 -0
- package/dist/registry/tool/__tests__/strict-registration.test.d.ts.map +1 -0
- package/dist/registry/tool/__tests__/strict-registration.test.js +82 -0
- package/dist/registry/tool/__tests__/strict-registration.test.js.map +1 -0
- package/dist/registry/tool/execute.d.ts.map +1 -1
- package/dist/registry/tool/execute.js +16 -0
- package/dist/registry/tool/execute.js.map +1 -1
- package/dist/runtime/query/result.d.ts.map +1 -1
- package/dist/runtime/query/result.js +5 -0
- package/dist/runtime/query/result.js.map +1 -1
- package/dist/tools/builtins/__tests__/edit-insert-reachable.test.js +7 -1
- package/dist/tools/builtins/__tests__/edit-insert-reachable.test.js.map +1 -1
- package/dist/tools/builtins/__tests__/edit.test.js +1 -1
- package/dist/tools/builtins/__tests__/edit.test.js.map +1 -1
- package/dist/tools/builtins/edit.d.ts.map +1 -1
- package/dist/tools/builtins/edit.js +20 -2
- package/dist/tools/builtins/edit.js.map +1 -1
- package/dist/types/plugin/index.d.ts +4 -4
- package/dist/types/run/events.d.ts +17 -2
- package/dist/types/run/events.d.ts.map +1 -1
- package/dist/types/run/events.js.map +1 -1
- package/dist/types/verification/index.d.ts +6 -6
- package/package.json +1 -1
- package/src/agents/__tests__/run-agent-forwarding.test.ts +85 -0
- package/src/agents/__tests__/run-completed-stop-reason.test.ts +59 -0
- package/src/agents/index.ts +8 -0
- package/src/agents/runAgent.ts +30 -4
- package/src/constants/tools/__tests__/dangerous-patterns.test.ts +62 -0
- package/src/constants/tools/index.ts +28 -1
- package/src/directory/__tests__/derive.test.ts +135 -0
- package/src/directory/__tests__/load-diagnostics.test.ts +126 -0
- package/src/directory/__tests__/load-directory.test.ts +243 -0
- package/src/directory/__tests__/subagents.test.ts +155 -0
- package/src/directory/__tests__/supervisor-budget.test.ts +117 -0
- package/src/directory/derive-supervisor.ts +149 -0
- package/src/directory/derive.ts +70 -0
- package/src/directory/index.ts +27 -0
- package/src/directory/load.ts +556 -0
- package/src/directory/scan.ts +163 -0
- package/src/directory/types.ts +254 -0
- package/src/plugin/__tests__/path-containment.test.ts +107 -0
- package/src/plugin/lifecycle.ts +3 -3
- package/src/plugin/loader.ts +12 -2
- package/src/provider/__tests__/model-version.test.ts +93 -0
- package/src/provider/__tests__/strict-schema.test.ts +133 -0
- package/src/provider/model-version.ts +98 -0
- package/src/provider/strict-schema.ts +125 -0
- package/src/public-runtime.ts +31 -0
- package/src/public-types.ts +8 -0
- package/src/registry/tool/__tests__/strict-registration.test.ts +115 -0
- package/src/registry/tool/execute.ts +16 -0
- package/src/runtime/query/result.ts +5 -0
- package/src/tools/builtins/__tests__/edit-insert-reachable.test.ts +8 -2
- package/src/tools/builtins/__tests__/edit.test.ts +1 -1
- package/src/tools/builtins/edit.ts +20 -2
- package/src/types/run/events.ts +15 -2
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 @@
|
|
|
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 @@
|
|
|
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"}
|
package/dist/agents/index.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/agents/index.js
CHANGED
|
@@ -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
|
package/dist/agents/index.js.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/agents/runAgent.js
CHANGED
|
@@ -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 };
|