@namzu/sdk 3.3.0 → 5.0.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 +430 -0
- package/dist/agents/SupervisorAgent.d.ts.map +1 -1
- package/dist/agents/SupervisorAgent.js +58 -2
- package/dist/agents/SupervisorAgent.js.map +1 -1
- package/dist/agents/__tests__/run-agent.test.d.ts +2 -0
- package/dist/agents/__tests__/run-agent.test.d.ts.map +1 -0
- package/dist/agents/__tests__/run-agent.test.js +143 -0
- package/dist/agents/__tests__/run-agent.test.js.map +1 -0
- package/dist/agents/__tests__/supervisor-coordinator-registration.test.d.ts +2 -0
- package/dist/agents/__tests__/supervisor-coordinator-registration.test.d.ts.map +1 -0
- package/dist/agents/__tests__/supervisor-coordinator-registration.test.js +122 -0
- package/dist/agents/__tests__/supervisor-coordinator-registration.test.js.map +1 -0
- package/dist/agents/index.d.ts +2 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +1 -0
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/runAgent.d.ts +104 -0
- package/dist/agents/runAgent.d.ts.map +1 -0
- package/dist/agents/runAgent.js +92 -0
- package/dist/agents/runAgent.js.map +1 -0
- package/dist/connector/mcp/__tests__/prompt-as-tool.test.js +1 -1
- package/dist/connector/mcp/__tests__/prompt-as-tool.test.js.map +1 -1
- package/dist/connector/mcp/prompt-adapter.d.ts.map +1 -1
- package/dist/connector/mcp/prompt-adapter.js +16 -9
- package/dist/connector/mcp/prompt-adapter.js.map +1 -1
- package/dist/provider/__tests__/thinking-support.test.d.ts +2 -0
- package/dist/provider/__tests__/thinking-support.test.d.ts.map +1 -0
- package/dist/provider/__tests__/thinking-support.test.js +47 -0
- package/dist/provider/__tests__/thinking-support.test.js.map +1 -0
- package/dist/provider/thinking-support.d.ts +30 -0
- package/dist/provider/thinking-support.d.ts.map +1 -0
- package/dist/provider/thinking-support.js +32 -0
- package/dist/provider/thinking-support.js.map +1 -0
- package/dist/public-runtime.d.ts +5 -2
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +11 -2
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-tools.d.ts +2 -0
- package/dist/public-tools.d.ts.map +1 -1
- package/dist/public-tools.js +3 -0
- package/dist/public-tools.js.map +1 -1
- package/dist/public-types.d.ts +1 -1
- package/dist/public-types.d.ts.map +1 -1
- package/dist/registry/index.d.ts +1 -1
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +1 -1
- package/dist/registry/index.js.map +1 -1
- package/dist/registry/tool/execute.d.ts +15 -0
- package/dist/registry/tool/execute.d.ts.map +1 -1
- package/dist/registry/tool/execute.js +19 -0
- package/dist/registry/tool/execute.js.map +1 -1
- package/dist/runtime/query/__tests__/steering-reaches-the-model.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/steering-reaches-the-model.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/steering-reaches-the-model.test.js +94 -0
- package/dist/runtime/query/__tests__/steering-reaches-the-model.test.js.map +1 -0
- package/dist/runtime/query/__tests__/steering.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/steering.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/steering.test.js +92 -0
- package/dist/runtime/query/__tests__/steering.test.js.map +1 -0
- package/dist/runtime/query/index.d.ts +10 -0
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +1 -0
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context.d.ts +8 -0
- package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/context.js.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.js +7 -1
- package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
- package/dist/runtime/query/steering.d.ts +81 -0
- package/dist/runtime/query/steering.d.ts.map +1 -0
- package/dist/runtime/query/steering.js +77 -0
- package/dist/runtime/query/steering.js.map +1 -0
- package/dist/sandbox/__tests__/exec-cancellation.test.d.ts +2 -0
- package/dist/sandbox/__tests__/exec-cancellation.test.d.ts.map +1 -0
- package/dist/sandbox/__tests__/exec-cancellation.test.js +59 -0
- package/dist/sandbox/__tests__/exec-cancellation.test.js.map +1 -0
- package/dist/sandbox/provider/local.d.ts.map +1 -1
- package/dist/sandbox/provider/local.js +30 -5
- package/dist/sandbox/provider/local.js.map +1 -1
- package/dist/session/workspace/shared-run.d.ts +31 -0
- package/dist/session/workspace/shared-run.d.ts.map +1 -1
- package/dist/session/workspace/shared-run.js +31 -0
- package/dist/session/workspace/shared-run.js.map +1 -1
- package/dist/tools/__tests__/file-tool-containment.test.d.ts +2 -0
- package/dist/tools/__tests__/file-tool-containment.test.d.ts.map +1 -0
- package/dist/tools/__tests__/file-tool-containment.test.js +134 -0
- package/dist/tools/__tests__/file-tool-containment.test.js.map +1 -0
- package/dist/tools/__tests__/sandboxed-search.test.js +51 -0
- package/dist/tools/__tests__/sandboxed-search.test.js.map +1 -1
- package/dist/tools/__tests__/untrusted-envelope.test.d.ts +2 -0
- package/dist/tools/__tests__/untrusted-envelope.test.d.ts.map +1 -0
- package/dist/tools/__tests__/untrusted-envelope.test.js +55 -0
- package/dist/tools/__tests__/untrusted-envelope.test.js.map +1 -0
- package/dist/tools/builtins/__tests__/edit-insert-reachable.test.d.ts +2 -0
- package/dist/tools/builtins/__tests__/edit-insert-reachable.test.d.ts.map +1 -0
- package/dist/tools/builtins/__tests__/edit-insert-reachable.test.js +114 -0
- package/dist/tools/builtins/__tests__/edit-insert-reachable.test.js.map +1 -0
- package/dist/tools/builtins/__tests__/edit.test.js +9 -2
- package/dist/tools/builtins/__tests__/edit.test.js.map +1 -1
- package/dist/tools/builtins/__tests__/write-file.test.js +59 -0
- package/dist/tools/builtins/__tests__/write-file.test.js.map +1 -1
- package/dist/tools/builtins/edit.d.ts.map +1 -1
- package/dist/tools/builtins/edit.js +66 -14
- package/dist/tools/builtins/edit.js.map +1 -1
- package/dist/tools/builtins/ls.d.ts +1 -1
- package/dist/tools/builtins/ls.d.ts.map +1 -1
- package/dist/tools/builtins/ls.js +95 -0
- package/dist/tools/builtins/ls.js.map +1 -1
- package/dist/tools/builtins/read-file.d.ts.map +1 -1
- package/dist/tools/builtins/read-file.js +3 -2
- package/dist/tools/builtins/read-file.js.map +1 -1
- package/dist/tools/builtins/write-file.d.ts.map +1 -1
- package/dist/tools/builtins/write-file.js +26 -12
- package/dist/tools/builtins/write-file.js.map +1 -1
- package/dist/tools/coordinator/__tests__/agent.test.js +6 -1
- package/dist/tools/coordinator/__tests__/agent.test.js.map +1 -1
- package/dist/tools/coordinator/__tests__/ask-user-question.test.js +47 -0
- package/dist/tools/coordinator/__tests__/ask-user-question.test.js.map +1 -1
- package/dist/tools/coordinator/__tests__/empty-roster.test.d.ts +2 -0
- package/dist/tools/coordinator/__tests__/empty-roster.test.d.ts.map +1 -0
- package/dist/tools/coordinator/__tests__/empty-roster.test.js +97 -0
- package/dist/tools/coordinator/__tests__/empty-roster.test.js.map +1 -0
- package/dist/tools/coordinator/agent.d.ts +22 -8
- package/dist/tools/coordinator/agent.d.ts.map +1 -1
- package/dist/tools/coordinator/agent.js +45 -2
- package/dist/tools/coordinator/agent.js.map +1 -1
- package/dist/tools/coordinator/index.d.ts.map +1 -1
- package/dist/tools/coordinator/index.js +80 -3
- package/dist/tools/coordinator/index.js.map +1 -1
- package/dist/tools/paths.d.ts +40 -0
- package/dist/tools/paths.d.ts.map +1 -1
- package/dist/tools/paths.js +70 -1
- package/dist/tools/paths.js.map +1 -1
- package/dist/tools/untrusted-envelope.d.ts +55 -0
- package/dist/tools/untrusted-envelope.d.ts.map +1 -0
- package/dist/tools/untrusted-envelope.js +65 -0
- package/dist/tools/untrusted-envelope.js.map +1 -0
- package/dist/types/agent/manager.d.ts +11 -4
- package/dist/types/agent/manager.d.ts.map +1 -1
- package/dist/types/agent/supervisor.d.ts +9 -0
- package/dist/types/agent/supervisor.d.ts.map +1 -1
- package/dist/types/common/index.d.ts +12 -0
- package/dist/types/common/index.d.ts.map +1 -1
- package/dist/types/common/index.js +7 -0
- package/dist/types/common/index.js.map +1 -1
- package/dist/types/provider/chat.d.ts +57 -5
- package/dist/types/provider/chat.d.ts.map +1 -1
- package/dist/types/provider/index.d.ts +1 -1
- package/dist/types/provider/index.d.ts.map +1 -1
- package/dist/types/sandbox/index.d.ts +10 -0
- package/dist/types/sandbox/index.d.ts.map +1 -1
- package/dist/types/sandbox/index.js.map +1 -1
- package/dist/types/toolset/index.d.ts +0 -24
- package/dist/types/toolset/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/agents/SupervisorAgent.ts +57 -2
- package/src/agents/__tests__/run-agent.test.ts +165 -0
- package/src/agents/__tests__/supervisor-coordinator-registration.test.ts +148 -0
- package/src/agents/index.ts +2 -0
- package/src/agents/runAgent.ts +179 -0
- package/src/connector/mcp/__tests__/prompt-as-tool.test.ts +1 -1
- package/src/connector/mcp/prompt-adapter.ts +19 -9
- package/src/provider/__tests__/thinking-support.test.ts +60 -0
- package/src/provider/thinking-support.ts +37 -0
- package/src/public-runtime.ts +11 -0
- package/src/public-tools.ts +4 -0
- package/src/public-types.ts +7 -1
- package/src/registry/index.ts +1 -1
- package/src/registry/tool/execute.ts +23 -0
- package/src/runtime/query/__tests__/steering-reaches-the-model.test.ts +117 -0
- package/src/runtime/query/__tests__/steering.test.ts +121 -0
- package/src/runtime/query/index.ts +12 -0
- package/src/runtime/query/iteration/phases/context.ts +9 -0
- package/src/runtime/query/iteration/phases/tool-review.ts +7 -1
- package/src/runtime/query/steering.ts +135 -0
- package/src/sandbox/__tests__/exec-cancellation.test.ts +72 -0
- package/src/sandbox/provider/local.ts +30 -4
- package/src/session/workspace/shared-run.ts +31 -0
- package/src/tools/__tests__/file-tool-containment.test.ts +190 -0
- package/src/tools/__tests__/sandboxed-search.test.ts +66 -0
- package/src/tools/__tests__/untrusted-envelope.test.ts +82 -0
- package/src/tools/builtins/__tests__/edit-insert-reachable.test.ts +166 -0
- package/src/tools/builtins/__tests__/edit.test.ts +10 -2
- package/src/tools/builtins/__tests__/write-file.test.ts +80 -0
- package/src/tools/builtins/edit.ts +69 -14
- package/src/tools/builtins/ls.ts +102 -0
- package/src/tools/builtins/read-file.ts +3 -2
- package/src/tools/builtins/write-file.ts +26 -12
- package/src/tools/coordinator/__tests__/agent.test.ts +6 -1
- package/src/tools/coordinator/__tests__/ask-user-question.test.ts +58 -0
- package/src/tools/coordinator/__tests__/empty-roster.test.ts +118 -0
- package/src/tools/coordinator/agent.ts +72 -11
- package/src/tools/coordinator/index.ts +86 -3
- package/src/tools/paths.ts +83 -1
- package/src/tools/untrusted-envelope.ts +78 -0
- package/src/types/agent/manager.ts +11 -4
- package/src/types/agent/supervisor.ts +10 -0
- package/src/types/common/index.ts +20 -0
- package/src/types/provider/chat.ts +61 -5
- package/src/types/provider/index.ts +1 -0
- package/src/types/sandbox/index.ts +10 -0
- package/src/types/toolset/index.ts +0 -25
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,435 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 1cd1094: Thinking is now resolved per model, `effort` is sendable, and thinking tokens
|
|
8
|
+
are reported.
|
|
9
|
+
|
|
10
|
+
**Thinking on a current model was a failed request, not a degraded one.** The
|
|
11
|
+
driver mapped `type: 'enabled'` straight to the wire and everything else to
|
|
12
|
+
`disabled`. The vendor rejects a mismatched mode with a 400 rather than
|
|
13
|
+
falling back: `thinking.type.enabled` is refused from Claude 4.7 onward,
|
|
14
|
+
`adaptive` is refused on 4.5 and earlier, and the always-on models refuse
|
|
15
|
+
`disabled`. One body for every model does not compromise quality, it fails.
|
|
16
|
+
|
|
17
|
+
`ThinkingConfig.type` gains `'adaptive'`, and the Anthropic driver resolves the
|
|
18
|
+
declared intent against the model it is about to call — sending the mode that
|
|
19
|
+
model accepts, dropping a budget where budgets have no meaning, and omitting
|
|
20
|
+
the field entirely rather than asking an always-on model to stop thinking. An
|
|
21
|
+
unrecognised model is treated as manual-only, which is the previous behaviour
|
|
22
|
+
and keeps a gateway serving an older model working.
|
|
23
|
+
|
|
24
|
+
**`ThinkingConfig.display` is narrowed to `'summarized' | 'omitted'`**, and now
|
|
25
|
+
actually reaches the wire. It was `'full' | 'summarized'`: `'full'` is not a
|
|
26
|
+
value any vendor accepts — a declared option that could only ever have been
|
|
27
|
+
rejected — and `'omitted'` was missing. It also was not serialized at all,
|
|
28
|
+
which matters more than it sounds: `display` defaults to `'omitted'` on newer
|
|
29
|
+
models, so a caller wanting to show reasoning received thinking blocks with
|
|
30
|
+
empty text and nothing to explain why.
|
|
31
|
+
|
|
32
|
+
**`effort` is new on `ChatCompletionParams`** — `'low' | 'medium' | 'high' |
|
|
33
|
+
'xhigh' | 'max'`. It goes out as `output_config.effort`, a _sibling_ of
|
|
34
|
+
`thinking` rather than a field inside it, because it shapes the whole response
|
|
35
|
+
and one manual-mode model accepts it alongside a token budget; nesting it would
|
|
36
|
+
have made that combination unsayable. It is dropped on models that do not
|
|
37
|
+
accept it, and refused in the one combination the vendor rejects — thinking
|
|
38
|
+
disabled at `xhigh`/`max`.
|
|
39
|
+
|
|
40
|
+
**`TokenUsage.reasoningTokens`** carries `output_tokens_details.thinking_tokens`
|
|
41
|
+
when the vendor reports it. It is a _subset_ of `completionTokens`, not an
|
|
42
|
+
addition — reasoning is billed as output, so summing it into a total would
|
|
43
|
+
double-count. Absent means not reported, never zero: coercing would claim every
|
|
44
|
+
turn on every silent driver did no thinking, and streamed events carry the
|
|
45
|
+
breakdown only on the final delta.
|
|
46
|
+
|
|
47
|
+
**Migration.** `display: 'full'` no longer compiles — use `'summarized'`, which
|
|
48
|
+
is what it meant. Code passing `thinking: { type: 'enabled', budgetTokens }`
|
|
49
|
+
keeps working and is now translated per model instead of rejected by newer
|
|
50
|
+
ones. `assertThinkingSupported` in `@namzu/openai` refuses `'adaptive'` as it
|
|
51
|
+
already refused `'enabled'`, since that driver implements neither.
|
|
52
|
+
|
|
53
|
+
Not changed: a report accompanying this work claimed `temperature`, `top_p` and
|
|
54
|
+
`top_k` are rejected on 5-series models and should be dropped by the driver.
|
|
55
|
+
The Messages reference, the extended-thinking page and the thinking
|
|
56
|
+
troubleshooting page document no such restriction, so nothing was implemented —
|
|
57
|
+
silently dropping sampling parameters that would have worked is its own defect.
|
|
58
|
+
|
|
59
|
+
### Minor Changes
|
|
60
|
+
|
|
61
|
+
- 19d6a0f: A host can now steer a turn that is already running.
|
|
62
|
+
|
|
63
|
+
`AgentManager.queueMessage` and `drainMessages` have existed for a while and
|
|
64
|
+
nothing in the iteration loop ever read them — the type said so outright. So a
|
|
65
|
+
host watching a run go the wrong way had two options, both worse than they
|
|
66
|
+
sound: cancel and start over, throwing away every tool result already paid
|
|
67
|
+
for; or reject through the review gate, which only works when a call happens
|
|
68
|
+
to be pending approval and says "no" when the host meant "yes, but read this
|
|
69
|
+
first".
|
|
70
|
+
|
|
71
|
+
`SteeringChannel` is the delivery that was missing. A host holds one, passes
|
|
72
|
+
it as `steering` on `drainQuery` params or `SupervisorAgentConfig`, and calls
|
|
73
|
+
`steer(text)` whenever it likes. Anything queued while a tool batch is running
|
|
74
|
+
is appended to that batch's **last tool result**.
|
|
75
|
+
|
|
76
|
+
That slot is not a stylistic choice. A `tool_use` block must be answered by a
|
|
77
|
+
`tool_result` with the same id, so a user message wedged between them is
|
|
78
|
+
rejected by the provider — there is no legal place to insert one mid-batch.
|
|
79
|
+
The tool result is the slot that already exists, and this SDK had already
|
|
80
|
+
reached that conclusion for the neighbouring case: a denied call carries its
|
|
81
|
+
reason inside the `tool_result`, precisely because that is where the model
|
|
82
|
+
looks for tool outcomes. Steering is the same delivery with the refusal taken
|
|
83
|
+
out.
|
|
84
|
+
|
|
85
|
+
It deliberately does not interrupt. The batch in flight finishes and the
|
|
86
|
+
guidance lands where the model reads next; a host that wants the current work
|
|
87
|
+
stopped wants `AbortSignal`, which is a different question. Conflating them is
|
|
88
|
+
how "also check the tests" ends up killing a half-written file.
|
|
89
|
+
|
|
90
|
+
Details worth knowing:
|
|
91
|
+
|
|
92
|
+
- Repeated calls before a drain accumulate in order rather than replacing each
|
|
93
|
+
other — two corrections typed a second apart are two things the model should
|
|
94
|
+
see.
|
|
95
|
+
- Guidance is labelled as coming from the operator. Unlabelled it would read
|
|
96
|
+
as something the tool said, so "stop and ask me first" would look like
|
|
97
|
+
output from `bash`. This is not the untrusted-content envelope: the operator
|
|
98
|
+
is the one party whose words the agent _should_ act on.
|
|
99
|
+
- A turn that called no tools has nothing in flight, so guidance stays queued
|
|
100
|
+
for the next one instead of being dropped.
|
|
101
|
+
|
|
102
|
+
Absent, the loop is byte-identical to before.
|
|
103
|
+
|
|
104
|
+
- 1500973: Every driver that cannot think now says so instead of dropping the request.
|
|
105
|
+
|
|
106
|
+
`thinking` sits on `ChatCompletionParams`, so every driver accepts it. Five of
|
|
107
|
+
them — Bedrock, OpenRouter, HTTP, Ollama, LM Studio — implemented none of it
|
|
108
|
+
and dropped the field: the caller got an ordinary completion with an empty
|
|
109
|
+
`reasoning` array, which is indistinguishable from a model that simply chose
|
|
110
|
+
not to reason. The request looked honoured and the answer looked like an
|
|
111
|
+
answer.
|
|
112
|
+
|
|
113
|
+
The OpenAI driver already refused instead, with the reasoning written out
|
|
114
|
+
beside it. So the rule had been decided once and applied once, while five
|
|
115
|
+
siblings went on being silent. It moves to `@namzu/sdk` as
|
|
116
|
+
`assertThinkingUnsupported(driverName, params)`, and a new driver now inherits
|
|
117
|
+
it rather than re-deciding it.
|
|
118
|
+
|
|
119
|
+
The error names the driver, which in a multi-provider setup is the difference
|
|
120
|
+
between a bug report about the model and a one-line configuration fix.
|
|
121
|
+
|
|
122
|
+
**Turning thinking off stays a no-op** on all of them, because that is the
|
|
123
|
+
state a driver without thinking is already in — a config shared across
|
|
124
|
+
providers saying `{ type: 'disabled' }` should not fail on the ones that were
|
|
125
|
+
never going to think.
|
|
126
|
+
|
|
127
|
+
`assertThinkingSupported` in `@namzu/openai` is unchanged as an export and now
|
|
128
|
+
delegates to the shared helper. Its message changed: it no longer says
|
|
129
|
+
"extended thinking", because `adaptive` is refused too and calling that
|
|
130
|
+
extended would be wrong.
|
|
131
|
+
|
|
132
|
+
**Migration.** If you passed `thinking` to any of the five and relied on it
|
|
133
|
+
being ignored, remove it — you were receiving a non-thinking answer either way,
|
|
134
|
+
and now you find out at the call instead of by inspecting an empty array.
|
|
135
|
+
|
|
136
|
+
Not in this change: implementing thinking natively on Bedrock, which serves the
|
|
137
|
+
same Claude models through a different wire and deserves the per-model
|
|
138
|
+
resolution the Anthropic driver just gained. That needs the Converse request
|
|
139
|
+
and response shapes verified against the reference first, and is not something
|
|
140
|
+
to guess at.
|
|
141
|
+
|
|
142
|
+
- a2cedfd: Adds `runAgent` — a provider, a model and a prompt is now a complete agent run.
|
|
143
|
+
|
|
144
|
+
`drainQuery` is the kernel's entry point and takes eleven required parameters,
|
|
145
|
+
four of which are identity fields that throw when missing. That is the right
|
|
146
|
+
shape for a kernel: a run with no tenant is a run no auditor can attribute. It
|
|
147
|
+
is the wrong shape for the first thing anybody writes, and the proof was
|
|
148
|
+
in-tree — the eval suites, the test files and the CLI each hand-assembled the
|
|
149
|
+
same block, which is what a missing front door looks like from the inside.
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
const { output } = await runAgent({
|
|
153
|
+
provider,
|
|
154
|
+
model,
|
|
155
|
+
prompt: "What is 2 + 2?",
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
It supplies an environment rather than a new engine: it generates the session
|
|
160
|
+
identity a single-tenant local run has no opinion about, defaults the budgets,
|
|
161
|
+
and points the working directory at the process's own. Everything it fills in
|
|
162
|
+
is an ordinary `drainQuery` parameter, so there is no second code path — a
|
|
163
|
+
caller who outgrows it passes more options until they are calling `drainQuery`
|
|
164
|
+
in all but name.
|
|
165
|
+
|
|
166
|
+
The identity comes back on the result, and that pairing is the point.
|
|
167
|
+
Generating one silently would make each call its own session — right for a
|
|
168
|
+
one-shot and wrong for a conversation, where turn two would start with no
|
|
169
|
+
history and nothing would say so. Spread `result.identity` into the next call
|
|
170
|
+
to continue the same session.
|
|
171
|
+
|
|
172
|
+
`model` stays required. `LLMProvider` carries no model — a driver may have been
|
|
173
|
+
constructed with one, but the interface does not expose it, so anything
|
|
174
|
+
inferred here would be a guess billed to the caller.
|
|
175
|
+
|
|
176
|
+
Defaults are safe rather than generous, because nobody reads them before their
|
|
177
|
+
first runaway loop: 16 iterations, a 200k token budget, a 5-minute timeout.
|
|
178
|
+
Each is overridable and named on the option.
|
|
179
|
+
|
|
180
|
+
The README quick start now shows this instead of a bare `provider.chat()` call
|
|
181
|
+
— that example demonstrated an HTTP client, not the kernel.
|
|
182
|
+
|
|
183
|
+
## 4.0.0
|
|
184
|
+
|
|
185
|
+
### Major Changes
|
|
186
|
+
|
|
187
|
+
- c3cb587: `read`, `write` and `edit` are now contained to the working directory.
|
|
188
|
+
|
|
189
|
+
All three called `resolve(workingDirectory, input.path)` bare, so
|
|
190
|
+
`path: "../../.."` reached whatever sits above the working directory and the
|
|
191
|
+
tool used it. No sandbox had to be misconfigured for this — it holds with no
|
|
192
|
+
sandbox at all, which is the common case, so a model that asks for a parent
|
|
193
|
+
directory got one. `resolveWithin` existed the whole time and these three
|
|
194
|
+
never reached it; the search tools (`glob`, `grep`, `ls`) did.
|
|
195
|
+
|
|
196
|
+
A lexical check alone would not have been the fix. `atomicWriteFile` resolves
|
|
197
|
+
its destination and writes _through_ a symlink deliberately, so that editing a
|
|
198
|
+
linked file updates the target rather than replacing the link with a regular
|
|
199
|
+
file. Paired with a lexical check that is check-then-follow: a link inside the
|
|
200
|
+
working directory pointing outside it climbs nothing on paper, and the write
|
|
201
|
+
lands outside anyway (CWE-59). Containment is therefore decided after
|
|
202
|
+
canonicalization, which is the ordering CWE-22 states as the mitigation for
|
|
203
|
+
the family: canonicalize, then validate the canonical form.
|
|
204
|
+
|
|
205
|
+
Two details the new resolver has to get right, because getting either wrong
|
|
206
|
+
breaks ordinary use rather than failing safe:
|
|
207
|
+
|
|
208
|
+
- The root can itself be a symlink — `os.tmpdir()` is one on macOS — so both
|
|
209
|
+
sides are canonicalized. Canonicalizing only the candidate would refuse
|
|
210
|
+
every path under a temp directory.
|
|
211
|
+
- The target may not exist yet, and `realpath` throws on a missing path. The
|
|
212
|
+
deepest existing ancestor is canonicalized and the remainder appended
|
|
213
|
+
lexically; the remainder cannot hide a link because nothing is there to be
|
|
214
|
+
one.
|
|
215
|
+
|
|
216
|
+
This does not claim TOCTOU safety. A component swapped for a symlink between
|
|
217
|
+
the check and the open would still be followed — closing that needs
|
|
218
|
+
per-component `openat`/`O_NOFOLLOW`, which Node does not expose. The threat
|
|
219
|
+
addressed is a link that is already present.
|
|
220
|
+
|
|
221
|
+
**Migration.** If a host relied on these tools reaching outside
|
|
222
|
+
`workingDirectory` — reading a config beside the repo, writing to a sibling
|
|
223
|
+
output directory — those calls now fail with "Path escapes the working
|
|
224
|
+
directory". Point `workingDirectory` at a root that contains everything the
|
|
225
|
+
run legitimately needs. Sandboxed runs are unaffected: the sandbox has its own
|
|
226
|
+
root and its own resolver, and the host-side canonicalization deliberately
|
|
227
|
+
does not run on that branch.
|
|
228
|
+
|
|
229
|
+
- a1f67f3: Two allow-lists in the delegation surface stop failing open, and a host can
|
|
230
|
+
now decline a coordinator tool.
|
|
231
|
+
|
|
232
|
+
## An empty delegate roster means nobody
|
|
233
|
+
|
|
234
|
+
`create_task` derived its `agent_id` parameter from `allowedAgentIds` but
|
|
235
|
+
widened it from the roster enum to a bare string whenever that roster was
|
|
236
|
+
empty — so the one configuration meaning "this run may delegate to nobody" was
|
|
237
|
+
the only one that let the model name anybody. An allow-list _is_ the
|
|
238
|
+
enumeration of what is permitted; an empty one enumerates nothing and admits
|
|
239
|
+
nothing. Degrading it to an open string to keep functioning is failing open
|
|
240
|
+
(CWE-636), and the rule it breaks is fail-safe defaults (Saltzer & Schroeder
|
|
241
|
+
1975, §I.A.3(b)), restated in NIST SP 800-53 Rev. 5 as SC-7(5) "deny by
|
|
242
|
+
default, allow by exception".
|
|
243
|
+
|
|
244
|
+
What that reached is why this is worth a break. The id was not merely rejected
|
|
245
|
+
downstream: it went to the gateway, which resolves against an `AgentManager`
|
|
246
|
+
that is typically **shared**, so an agent the host deliberately left out of
|
|
247
|
+
`agentIds` could still launch if it happened to be registered there. When it
|
|
248
|
+
was not registered, the failure text listed every registered agent id back to
|
|
249
|
+
the model, and the plan row was left stranded at `in_progress` because the
|
|
250
|
+
store write precedes the gateway call while the reconciling update follows it.
|
|
251
|
+
|
|
252
|
+
`create_task` is now **not mounted** when the roster is empty, rather than
|
|
253
|
+
mounted with a schema nothing satisfies — refusing per call reaches the same
|
|
254
|
+
verdict while paying prompt-prefix tokens and an iteration for it (NIST SP
|
|
255
|
+
800-53 CM-7, least functionality). It is the only coordinator tool that reads
|
|
256
|
+
the roster, so `agent_task_list`, `approve_plan` and `ask_user_question` are
|
|
257
|
+
untouched: "no delegates, but still planning and a human channel" remains a
|
|
258
|
+
supported configuration. The schema stays closed underneath as defence in
|
|
259
|
+
depth. If you construct a supervisor with `agentIds: []` and expected
|
|
260
|
+
`create_task` to be callable, populate the roster — there is no flag that
|
|
261
|
+
restores the old shape, because the old shape could not correctly succeed.
|
|
262
|
+
|
|
263
|
+
`buildAgentTool` carried the identical fallback and now throws at construction
|
|
264
|
+
instead: it returns exactly one tool and that tool _is_ the delegation surface,
|
|
265
|
+
so "do not mount it" and "do not build it" are the same statement. It also
|
|
266
|
+
never checked `subagent_type` against the roster inside `execute`, which is
|
|
267
|
+
reachable without going through the registry; it does now.
|
|
268
|
+
|
|
269
|
+
## A host can decline a coordinator tool
|
|
270
|
+
|
|
271
|
+
`runtimeToolOverrides` is this SDK's declared way to decline a kernel-mounted
|
|
272
|
+
tool. It is honoured for the task tools and the advisory tools, and
|
|
273
|
+
`SupervisorAgent` forwards it into its own `drainQuery` call — but it
|
|
274
|
+
registered the coordinator tools before that, unconditionally, so
|
|
275
|
+
`{ create_task: 'disabled' }` was obeyed everywhere except the one surface a
|
|
276
|
+
host would most want to decline. A run that must not delegate had prompt text
|
|
277
|
+
and a gateway refusal as its only defences. This half is pure gap-closure: the
|
|
278
|
+
mechanism, the type and two other call sites already existed, and coordinator
|
|
279
|
+
registration now uses the same idiom.
|
|
280
|
+
|
|
281
|
+
## Collisions refuse instead of overwriting
|
|
282
|
+
|
|
283
|
+
This half is new policy, not a gap-closure. Registration now throws
|
|
284
|
+
`ToolNameCollisionError` (exported, carrying `toolName`) when a coordinator
|
|
285
|
+
tool's name is already registered on the supervisor's `tools`, instead of the
|
|
286
|
+
registry's warn-and-overwrite. The reserved names are `create_task`,
|
|
287
|
+
`agent_task_list`, `approve_plan`, and `ask_user_question` — grep for those
|
|
288
|
+
four.
|
|
289
|
+
|
|
290
|
+
The old behaviour was not "the host's tool quietly loses and the run works".
|
|
291
|
+
`registerOne` ends by setting availability, and the coordinator call passed
|
|
292
|
+
none, so a tool the host registered `deferred` or `suspended` was silently
|
|
293
|
+
promoted to `active` under someone else's implementation; and because the
|
|
294
|
+
backing store is a `Map`, the replacement inherited the host's insertion
|
|
295
|
+
position in the prompt-cache prefix. That is a different authorization surface,
|
|
296
|
+
not a lost registration — detection of an error condition without action
|
|
297
|
+
(CWE-390), where CWE-694's own mitigation is nearly this fix. Complete
|
|
298
|
+
mediation is the principle (§I.A.3(c)): a registry entry is a remembered
|
|
299
|
+
binding of a name to an authority, and rebinding it leaves every decision made
|
|
300
|
+
about the old binding stale.
|
|
301
|
+
|
|
302
|
+
To migrate: rename your tool, or keep your name and decline the coordinator one
|
|
303
|
+
with `runtimeToolOverrides: { "create_task": "disabled" }`. The error names
|
|
304
|
+
both routes.
|
|
305
|
+
|
|
306
|
+
- df07db8: Removes `ToolCatalogSurface` and `ToolsetPolicy.surfaces`.
|
|
307
|
+
|
|
308
|
+
Both were deprecated in 3.2.0 and shipped deprecated again in 3.3.0, so the
|
|
309
|
+
window SemVer asks for — at least one minor release in which working code
|
|
310
|
+
compiles and warns — has been served twice. The deprecation said "slated for
|
|
311
|
+
removal in the next major"; this is that major, and letting it pass would move
|
|
312
|
+
the promise to 5.0.0.
|
|
313
|
+
|
|
314
|
+
Nothing produced or read either one. No code constructed a member of the
|
|
315
|
+
union, and `surfaces` was the only field carrying it and was never consulted,
|
|
316
|
+
so there is no runtime behaviour to change and no working code to migrate:
|
|
317
|
+
setting it did nothing before and the field is gone now. Under this repo's
|
|
318
|
+
release rule that is the case where a removal may go straight to major, and it
|
|
319
|
+
is being said here as that rule asks.
|
|
320
|
+
|
|
321
|
+
It was also the wrong axis. Which tools a run may use is already expressible
|
|
322
|
+
four ways, all per-run and dynamic where this was fixed at definition:
|
|
323
|
+
`allowedTools` on the query, `ToolAvailability` (`active` / `deferred` /
|
|
324
|
+
`suspended`) with mid-run activation, `runtimeToolOverrides`, and capability
|
|
325
|
+
negotiation stripping tools a driver cannot carry. If you set `surfaces`,
|
|
326
|
+
`allowedTools` is the replacement — it says the same thing per run.
|
|
327
|
+
|
|
328
|
+
`SharedRunWorkspace` is unchanged and stays exported without an SDK-side
|
|
329
|
+
caller. That is deliberate and now documented on the class: its config asks for
|
|
330
|
+
a host filesystem root and the path an agent will see, which is a deployment
|
|
331
|
+
shape the kernel does not own. `runtimeRoot` and the paths `refs()` derives
|
|
332
|
+
from it are the contract.
|
|
333
|
+
|
|
334
|
+
- 19f390a: A delegated agent's output is now framed as untrusted material, and the
|
|
335
|
+
framing itself can no longer be forged.
|
|
336
|
+
|
|
337
|
+
**Why the child→parent return.** A delegated worker is the component most
|
|
338
|
+
likely to have consumed something nobody in the run authored: it was handed a
|
|
339
|
+
task like "read these files and report", it ran `read`, `grep`, possibly a
|
|
340
|
+
connector fetch over material the user did not write, and its final text
|
|
341
|
+
landed directly in the parent's context — where the parent typically holds a
|
|
342
|
+
broader tool grant than the child that produced the text. An unlabelled block
|
|
343
|
+
there reads as the parent's own reasoning. Connector-supplied prompts already
|
|
344
|
+
got this treatment; the delegation surface had none.
|
|
345
|
+
|
|
346
|
+
`create_task` and the `Agent` tool now wrap their `output` in a
|
|
347
|
+
`<namzu-untrusted kind="agent-result">` frame naming the agent and task, with
|
|
348
|
+
one line saying the content is material rather than direction. The worker's
|
|
349
|
+
text is unaltered inside it, and `data.result` carries it verbatim, so a host
|
|
350
|
+
reading the result programmatically is unaffected — only the model-facing
|
|
351
|
+
string changed.
|
|
352
|
+
|
|
353
|
+
**The framing was forgeable, and that is fixed.** The existing envelope around
|
|
354
|
+
connector prompts built its tag by hand and interpolated remote text straight
|
|
355
|
+
into the body. A prompt whose content contained `</mcp-prompt>` closed the
|
|
356
|
+
block early, and everything the server wrote after that read as unlabelled —
|
|
357
|
+
which is to say, as this agent's own instructions. The label was the entire
|
|
358
|
+
mitigation and the labelled party could remove it. `wrapUntrusted` now defangs
|
|
359
|
+
the delimiter case-insensitively (a model reads `</NAMZU-UNTRUSTED>` as the
|
|
360
|
+
same tag) and escapes attribute values, so a source name carrying a quote
|
|
361
|
+
cannot rewrite the tag it appears in.
|
|
362
|
+
|
|
363
|
+
Two decisions worth stating because the obvious alternatives are wrong:
|
|
364
|
+
|
|
365
|
+
- **No length threshold.** Skipping short payloads to save tokens leaves the
|
|
366
|
+
cheapest carrier unframed; an instruction fits in a tweet.
|
|
367
|
+
- **No "already wrapped, skip it" fast path.** That check is forgeable —
|
|
368
|
+
content merely beginning with the opening tag would pass through with no
|
|
369
|
+
framing at all. Wrapping twice is harmless; not wrapping once is not.
|
|
370
|
+
|
|
371
|
+
`wrapUntrusted`, `neutralizeEnvelopeDelimiter` and `UntrustedEnvelope` are
|
|
372
|
+
exported, so a host surfacing its own untrusted content to a model can use the
|
|
373
|
+
same framing rather than inventing one.
|
|
374
|
+
|
|
375
|
+
**Migration.** If you assert on `create_task` or `Agent` output text, read
|
|
376
|
+
`data.result` instead — it is the worker's text with nothing added. If you
|
|
377
|
+
call `renderPromptMessages` directly, its output opens with
|
|
378
|
+
`<namzu-untrusted kind="mcp-prompt" …>` rather than `<mcp-prompt …>`.
|
|
379
|
+
|
|
380
|
+
### Minor Changes
|
|
381
|
+
|
|
382
|
+
- 2b9d90e: `edit` can do the thing its own description tells the model to do.
|
|
383
|
+
|
|
384
|
+
The tool description says _"For insertions, pass insertLine … use `insertLine: "end"` to extend a file at the end"_, and `write-file` and `bash` point at the same idiom. But `modelInputSchema` advertised only `path`/`old_string`/`new_string`/`replace_all` with `additionalProperties: false`, and `enforceModelInput: true` — so under constrained decoding the append idiom the prompt recommends was the one idiom a model could not emit. A consuming host measured the result over seven days on one tenant: **94 of 159 tool failures** were `edit` rejecting an `insertLine` whose spelling the model had guessed.
|
|
385
|
+
|
|
386
|
+
`insertLine` is now in the model-facing schema as `oneOf: [integer ≥ 0, "end"]`. Declaring the union that way also removes the synonym problem at its source: for a provider that constrains generation, `"EOF"` is not emittable, because `"end"` is the only string the schema admits.
|
|
387
|
+
|
|
388
|
+
`old_string` leaves `required`, because an insert has no text to match — requiring it is exactly what made the idiom unexpressible. Which of `old_string` / `insertLine` is present is decided by the two refinements the execution schema already carries. That is deliberate over a top-level `oneOf`: strict structured-output modes are least surprising with a flat object, and a discriminated union at the root is the construct most likely to be rejected or quietly ignored. The cost is that an incomplete call is now expressible and caught at execution rather than generation — paid knowingly, since the alternative is a working capability nothing can reach.
|
|
389
|
+
|
|
390
|
+
For providers that do **not** constrain, `insertLine` also accepts `eof`, `append`, `last` and `end_of_file`. Liberal at execution and strict in the schema is the right way round: none of those is ambiguous, and refusing one bought strictness at the price of a full model round trip. The rejection message now names the value it received.
|
|
391
|
+
|
|
392
|
+
Also here, same file family: **`write` refuses a whitespace-only path**, which `edit` has always refused. `.min(1)` admits `" "`, which resolves to the working directory and fails as an unreadable directory-write error. Two mutating tools disagreeing about the same input is the kind of gap a model finds and a reviewer does not.
|
|
393
|
+
|
|
394
|
+
- 4be54ca: Three sandbox and delegation gaps, all of the same kind: something declared,
|
|
395
|
+
threaded through types, and never driven.
|
|
396
|
+
|
|
397
|
+
**`SandboxExecOptions.signal` now works — on the backend where it can.** The
|
|
398
|
+
option was declared, documented and exported, with a docstring stating that
|
|
399
|
+
without it "a Stop could only ever abandon the _wait_ — the sandboxed process
|
|
400
|
+
kept running after the host believed the run had been cancelled". Every
|
|
401
|
+
backend dropped it, so that is exactly what happened. The local sandbox now
|
|
402
|
+
merges the caller's signal with the call's own deadline and hands the result to
|
|
403
|
+
`spawn`, so the child actually dies; a cancelled run is no longer reported as
|
|
404
|
+
`timedOut`, because a run someone stopped did not run too long, and telling the
|
|
405
|
+
model otherwise invites a retry with a bigger budget.
|
|
406
|
+
|
|
407
|
+
The remote backends still ignore it, now explicitly and with the reason in the
|
|
408
|
+
source. Their wire has no cancel op, so aborting the request would abandon the
|
|
409
|
+
wait while the command kept running — the original failure, wearing the
|
|
410
|
+
appearance of a fix. `SandboxExecOptions.signal` documents which backends
|
|
411
|
+
honour it.
|
|
412
|
+
|
|
413
|
+
**`ls` respects the sandbox.** It read the host through `node:fs` and named
|
|
414
|
+
`context.sandbox` nowhere, in the one builtin whose whole job is telling the
|
|
415
|
+
model what exists — so under a container or microVM backend the model's picture
|
|
416
|
+
of the filesystem was the host's. Its paths were host-relative too, while
|
|
417
|
+
`read`, `grep` and `glob` all resolve inside the sandbox, so an ls-to-read
|
|
418
|
+
handoff either failed or opened a different file than the one listed. `glob`
|
|
419
|
+
had the identical defect, was fixed, and its fix notes that "every sibling
|
|
420
|
+
builtin already remembers this branch"; this was the sibling that did not.
|
|
421
|
+
|
|
422
|
+
One behaviour difference worth knowing: inside a sandbox, directories are
|
|
423
|
+
derived from file paths, because `listFiles` reports files. An empty directory
|
|
424
|
+
is invisible there.
|
|
425
|
+
|
|
426
|
+
**The `Agent` tool's header described a design that no longer exists.** It told
|
|
427
|
+
readers to prefer `Agent` because `create_task` was a non-blocking trio driven
|
|
428
|
+
by notification callbacks. `create_task` blocks and returns the worker's output
|
|
429
|
+
as its own result, and `continue_task` / `cancel_task` are not registered at
|
|
430
|
+
all. The two tools are separated by how much of the coordinator surface they
|
|
431
|
+
bring, not by timing.
|
|
432
|
+
|
|
3
433
|
## 3.3.0
|
|
4
434
|
|
|
5
435
|
### Minor Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SupervisorAgent.d.ts","sourceRoot":"","sources":["../../src/agents/SupervisorAgent.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAe,UAAU,EAAE,MAAM,2BAA2B,CAAA;AACxE,OAAO,KAAK,EACX,UAAU,EACV,aAAa,EACb,eAAe,EACf,qBAAqB,EACrB,qBAAqB,EACrB,MAAM,yBAAyB,CAAA;AAEhC,OAAO,KAAK,EAAW,KAAK,EAAU,MAAM,uBAAuB,CAAA;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAG7D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CACpC,WAAW,EAAE,SAAS,UAAU,EAAE,EAClC,KAAK,EAAE,KAAK,EACZ,GAAG,GAAE,MAAmB,GACtB,eAAe,EAAE,CAcnB;AAED,4DAA4D;AAC5D,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,SAAS,eAAe,EAAE,GAAG,MAAM,CAEnF;AAED,qBAAa,eAAgB,SAAQ,aAAa,CAAC,qBAAqB,EAAE,qBAAqB,CAAC;IAC/F,QAAQ,CAAC,IAAI,EAAG,YAAY,CAAS;gBAEzB,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,cAAc,CAAC;IAalE;;;;;;;;OAQG;IACG,GAAG,CACR,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,qBAAqB,EAC7B,QAAQ,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,qBAAqB,CAAC;YAMnB,YAAY;
|
|
1
|
+
{"version":3,"file":"SupervisorAgent.d.ts","sourceRoot":"","sources":["../../src/agents/SupervisorAgent.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAe,UAAU,EAAE,MAAM,2BAA2B,CAAA;AACxE,OAAO,KAAK,EACX,UAAU,EACV,aAAa,EACb,eAAe,EACf,qBAAqB,EACrB,qBAAqB,EACrB,MAAM,yBAAyB,CAAA;AAEhC,OAAO,KAAK,EAAW,KAAK,EAAU,MAAM,uBAAuB,CAAA;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAG7D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CACpC,WAAW,EAAE,SAAS,UAAU,EAAE,EAClC,KAAK,EAAE,KAAK,EACZ,GAAG,GAAE,MAAmB,GACtB,eAAe,EAAE,CAcnB;AAED,4DAA4D;AAC5D,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,SAAS,eAAe,EAAE,GAAG,MAAM,CAEnF;AAED,qBAAa,eAAgB,SAAQ,aAAa,CAAC,qBAAqB,EAAE,qBAAqB,CAAC;IAC/F,QAAQ,CAAC,IAAI,EAAG,YAAY,CAAS;gBAEzB,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,cAAc,CAAC;IAalE;;;;;;;;OAQG;IACG,GAAG,CACR,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,qBAAqB,EAC7B,QAAQ,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,qBAAqB,CAAC;YAMnB,YAAY;CAkP1B"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EMPTY_TOKEN_USAGE } from '../constants/limits.js';
|
|
2
2
|
import { LocalTaskGateway } from '../gateway/local.js';
|
|
3
|
-
import { ToolRegistry } from '../registry/tool/execute.js';
|
|
3
|
+
import { ToolNameCollisionError, ToolRegistry } from '../registry/tool/execute.js';
|
|
4
4
|
import { drainQuery } from '../runtime/query/index.js';
|
|
5
5
|
import { PendingAnswers, QuestionParkBinding } from '../runtime/query/question-park.js';
|
|
6
6
|
import { buildCoordinatorTools } from '../tools/coordinator/index.js';
|
|
@@ -156,8 +156,58 @@ export class SupervisorAgent extends AbstractAgent {
|
|
|
156
156
|
tools.register(tool, config.tools.getAvailability(tool.name));
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
|
+
// Registered the way every other kernel-mounted tool in this SDK is
|
|
160
|
+
// registered: honouring `runtimeToolOverrides`, and refusing to take a
|
|
161
|
+
// name the host already used.
|
|
162
|
+
//
|
|
163
|
+
// Both halves were missing here and nowhere else. `runtimeToolOverrides`
|
|
164
|
+
// is declared on `AgentInput`, is forwarded into this very `drainQuery`
|
|
165
|
+
// call below, and is consulted for the task tools and for the advisory
|
|
166
|
+
// tools — but the coordinator tools were registered before that and
|
|
167
|
+
// unconditionally, so `{ create_task: 'disabled' }` was honoured
|
|
168
|
+
// everywhere except the one surface a host would most want to decline.
|
|
169
|
+
// A run that must not delegate had prompt text and a gateway refusal as
|
|
170
|
+
// its only defences.
|
|
171
|
+
//
|
|
172
|
+
// Collision REFUSES rather than overwrites, and the principle is
|
|
173
|
+
// complete mediation rather than fail-safe defaults: "proposals to gain
|
|
174
|
+
// performance by remembering the result of an authority check [must] be
|
|
175
|
+
// examined skeptically. If a change in authority occurs, such remembered
|
|
176
|
+
// results must be systematically updated" (Saltzer & Schroeder 1975,
|
|
177
|
+
// §I.A.3(c)). A registry entry is a remembered binding of a name to an
|
|
178
|
+
// authority, and a later write that rebinds the name leaves every
|
|
179
|
+
// decision made about the old binding stale.
|
|
180
|
+
//
|
|
181
|
+
// The counter-argument is that today the host's tool merely loses
|
|
182
|
+
// quietly and the run still works, so six reserved names is a real cost
|
|
183
|
+
// on a name a consumer may have chosen long ago. It does not hold,
|
|
184
|
+
// because "loses quietly" is not what happens. `registerOne` ends with
|
|
185
|
+
// `availability.set(id, state)` and this call passes no state, so a tool
|
|
186
|
+
// the host registered `deferred` or `suspended` is silently PROMOTED to
|
|
187
|
+
// active under someone else's implementation; and because the store is a
|
|
188
|
+
// Map, the replacement inherits the host's insertion position in the
|
|
189
|
+
// prompt-cache prefix. That is a different authorization surface, not a
|
|
190
|
+
// lost registration. CWE-390 is the shape `ManagedRegistry` has here —
|
|
191
|
+
// detection of an error condition without action — and CWE-694's own
|
|
192
|
+
// mitigation is nearly this fix: do not operate any resource with a
|
|
193
|
+
// non-unique identifier, and report the error.
|
|
194
|
+
//
|
|
195
|
+
// Refusing is also what the peer set does. One runtime's registry
|
|
196
|
+
// primitive throws on both duplicate and reserved names; another refuses
|
|
197
|
+
// its injected delegation name in a pre-flight that tells the author to
|
|
198
|
+
// rename. Closer to home, `ProviderRegistry.register` already throws
|
|
199
|
+
// unless the caller passes `{ replace: true }` — declared intent is what
|
|
200
|
+
// separates a legitimate replacement from an accidental one, and no such
|
|
201
|
+
// intent is expressible here.
|
|
202
|
+
const overrides = input.runtimeToolOverrides;
|
|
159
203
|
for (const tool of coordinatorToolDefs) {
|
|
160
|
-
|
|
204
|
+
const override = overrides?.[tool.name];
|
|
205
|
+
if (override === 'disabled')
|
|
206
|
+
continue;
|
|
207
|
+
if (config.tools?.has(tool.name)) {
|
|
208
|
+
throw new ToolNameCollisionError(tool.name, 'the supervisor coordinator surface');
|
|
209
|
+
}
|
|
210
|
+
tools.register(tool, override ?? 'active');
|
|
161
211
|
}
|
|
162
212
|
const childInvocationState = deriveChildState(config.invocationState ?? { tenantId }, this.metadata.id);
|
|
163
213
|
const run = await drainQuery({
|
|
@@ -203,6 +253,12 @@ export class SupervisorAgent extends AbstractAgent {
|
|
|
203
253
|
// auto-approve. drainQuery falls back to autoApproveHandler
|
|
204
254
|
// when resumeHandler is omitted (= same behaviour as before).
|
|
205
255
|
...(config.resumeHandler ? { resumeHandler: config.resumeHandler } : {}),
|
|
256
|
+
// Forwarded for the same reason the handler is. A capability the
|
|
257
|
+
// kernel honours in `drainQuery` but that never reaches the
|
|
258
|
+
// surface a host actually constructs is a capability nobody can
|
|
259
|
+
// use — which is the shape of defect this file has already been
|
|
260
|
+
// corrected for twice.
|
|
261
|
+
...(config.steering ? { steering: config.steering } : {}),
|
|
206
262
|
...(config.verificationGate ? { verificationGate: config.verificationGate } : {}),
|
|
207
263
|
...(config.sandboxProvider ? { sandboxProvider: config.sandboxProvider } : {}),
|
|
208
264
|
// Working-memory / compaction seam (optional; absent => unchanged
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SupervisorAgent.js","sourceRoot":"","sources":["../../src/agents/SupervisorAgent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAA;
|
|
1
|
+
{"version":3,"file":"SupervisorAgent.js","sourceRoot":"","sources":["../../src/agents/SupervisorAgent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-agent.test.d.ts","sourceRoot":"","sources":["../../../src/agents/__tests__/run-agent.test.ts"],"names":[],"mappings":""}
|