@namzu/sdk 46.0.0 → 48.1.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 +351 -8
- package/README.md +7 -8
- package/dist/advisory/history.d.ts.map +1 -1
- package/dist/advisory/history.js +21 -1
- package/dist/advisory/history.js.map +1 -1
- package/dist/advisory/index.d.ts +1 -1
- package/dist/advisory/index.d.ts.map +1 -1
- package/dist/advisory/index.js +1 -1
- package/dist/advisory/index.js.map +1 -1
- package/dist/advisory/registry.d.ts +17 -0
- package/dist/advisory/registry.d.ts.map +1 -1
- package/dist/advisory/registry.js +26 -0
- package/dist/advisory/registry.js.map +1 -1
- package/dist/agents/PipelineAgent.d.ts +2 -46
- package/dist/agents/PipelineAgent.d.ts.map +1 -1
- package/dist/agents/PipelineAgent.js +2 -242
- package/dist/agents/PipelineAgent.js.map +1 -1
- package/dist/agents/QueryAgent.d.ts +21 -0
- package/dist/agents/QueryAgent.d.ts.map +1 -0
- package/dist/agents/QueryAgent.js +214 -0
- package/dist/agents/QueryAgent.js.map +1 -0
- package/dist/agents/ReactiveAgent.d.ts +4 -16
- package/dist/agents/ReactiveAgent.d.ts.map +1 -1
- package/dist/agents/ReactiveAgent.js +4 -183
- package/dist/agents/ReactiveAgent.js.map +1 -1
- package/dist/agents/RouterAgent.d.ts +2 -20
- package/dist/agents/RouterAgent.d.ts.map +1 -1
- package/dist/agents/RouterAgent.js +2 -266
- package/dist/agents/RouterAgent.js.map +1 -1
- package/dist/agents/SupervisorAgent.d.ts +3 -43
- package/dist/agents/SupervisorAgent.d.ts.map +1 -1
- package/dist/agents/SupervisorAgent.js +3 -418
- package/dist/agents/SupervisorAgent.js.map +1 -1
- package/dist/agents/defineAgent.d.ts +2 -1
- package/dist/agents/defineAgent.d.ts.map +1 -1
- package/dist/agents/defineAgent.js +6 -1
- package/dist/agents/defineAgent.js.map +1 -1
- package/dist/agents/examples/PipelineAgent.d.ts +46 -0
- package/dist/agents/examples/PipelineAgent.d.ts.map +1 -0
- package/dist/agents/examples/PipelineAgent.js +242 -0
- package/dist/agents/examples/PipelineAgent.js.map +1 -0
- package/dist/agents/examples/RouterAgent.d.ts +22 -0
- package/dist/agents/examples/RouterAgent.d.ts.map +1 -0
- package/dist/agents/examples/RouterAgent.js +268 -0
- package/dist/agents/examples/RouterAgent.js.map +1 -0
- package/dist/agents/examples/SupervisorAgent.d.ts +45 -0
- package/dist/agents/examples/SupervisorAgent.d.ts.map +1 -0
- package/dist/agents/examples/SupervisorAgent.js +406 -0
- package/dist/agents/examples/SupervisorAgent.js.map +1 -0
- package/dist/agents/explore.d.ts +6 -3
- package/dist/agents/explore.d.ts.map +1 -1
- package/dist/agents/explore.js +6 -3
- package/dist/agents/explore.js.map +1 -1
- package/dist/agents/forward-options.d.ts +11 -0
- package/dist/agents/forward-options.d.ts.map +1 -0
- package/dist/agents/forward-options.js +15 -0
- package/dist/agents/forward-options.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 +2 -0
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/runAgent.d.ts +19 -8
- package/dist/agents/runAgent.d.ts.map +1 -1
- package/dist/agents/runAgent.js +99 -29
- package/dist/agents/runAgent.js.map +1 -1
- package/dist/authorization/command-line.d.ts +2 -0
- package/dist/authorization/command-line.d.ts.map +1 -1
- package/dist/authorization/command-line.js +2 -2
- package/dist/authorization/command-line.js.map +1 -1
- package/dist/authorization/gate.d.ts +8 -0
- package/dist/authorization/gate.d.ts.map +1 -1
- package/dist/authorization/gate.js +12 -1
- package/dist/authorization/gate.js.map +1 -1
- package/dist/authorization/program.d.ts +151 -0
- package/dist/authorization/program.d.ts.map +1 -0
- package/dist/authorization/program.js +713 -0
- package/dist/authorization/program.js.map +1 -0
- package/dist/authorization/reexec-wrapper.d.ts +106 -0
- package/dist/authorization/reexec-wrapper.d.ts.map +1 -0
- package/dist/authorization/reexec-wrapper.js +532 -0
- package/dist/authorization/reexec-wrapper.js.map +1 -0
- package/dist/authorization/rules.d.ts +9 -0
- package/dist/authorization/rules.d.ts.map +1 -1
- package/dist/authorization/rules.js +8 -1
- package/dist/authorization/rules.js.map +1 -1
- package/dist/authorization/shell-lexer.d.ts +19 -4
- package/dist/authorization/shell-lexer.d.ts.map +1 -1
- package/dist/authorization/shell-lexer.js +91 -65
- package/dist/authorization/shell-lexer.js.map +1 -1
- package/dist/bridge/sse/mapper.d.ts.map +1 -1
- package/dist/bridge/sse/mapper.js +6 -0
- package/dist/bridge/sse/mapper.js.map +1 -1
- package/dist/capabilities/index.d.ts +54 -0
- package/dist/capabilities/index.d.ts.map +1 -0
- package/dist/capabilities/index.js +92 -0
- package/dist/capabilities/index.js.map +1 -0
- package/dist/config/registry.d.ts +2 -1
- package/dist/config/registry.d.ts.map +1 -1
- package/dist/config/registry.js +3 -2
- package/dist/config/registry.js.map +1 -1
- package/dist/connector/index.d.ts +4 -4
- package/dist/connector/index.d.ts.map +1 -1
- package/dist/connector/index.js +3 -3
- package/dist/connector/index.js.map +1 -1
- package/dist/connector/mcp/adapter.d.ts +16 -1
- package/dist/connector/mcp/adapter.d.ts.map +1 -1
- package/dist/connector/mcp/adapter.js +71 -4
- package/dist/connector/mcp/adapter.js.map +1 -1
- package/dist/connector/mcp/client.d.ts +32 -4
- package/dist/connector/mcp/client.d.ts.map +1 -1
- package/dist/connector/mcp/client.js +383 -5
- package/dist/connector/mcp/client.js.map +1 -1
- package/dist/connector/mcp/discovery.d.ts +24 -1
- package/dist/connector/mcp/discovery.d.ts.map +1 -1
- package/dist/connector/mcp/discovery.js +44 -0
- package/dist/connector/mcp/discovery.js.map +1 -1
- package/dist/connector/mcp/era.d.ts.map +1 -1
- package/dist/connector/mcp/era.js +7 -0
- package/dist/connector/mcp/era.js.map +1 -1
- package/dist/connector/mcp/index.d.ts +2 -0
- package/dist/connector/mcp/index.d.ts.map +1 -1
- package/dist/connector/mcp/index.js +11 -0
- package/dist/connector/mcp/index.js.map +1 -1
- package/dist/connector/mcp/mcp-toolset.d.ts +133 -0
- package/dist/connector/mcp/mcp-toolset.d.ts.map +1 -0
- package/dist/connector/mcp/mcp-toolset.js +399 -0
- package/dist/connector/mcp/mcp-toolset.js.map +1 -0
- package/dist/connector/mcp/streamable-http.d.ts +15 -0
- package/dist/connector/mcp/streamable-http.d.ts.map +1 -1
- package/dist/connector/mcp/streamable-http.js +281 -6
- package/dist/connector/mcp/streamable-http.js.map +1 -1
- package/dist/connector/tools/index.d.ts +2 -2
- package/dist/connector/tools/index.d.ts.map +1 -1
- package/dist/connector/tools/index.js +1 -1
- package/dist/connector/tools/index.js.map +1 -1
- package/dist/connector/tools/router.d.ts +15 -13
- package/dist/connector/tools/router.d.ts.map +1 -1
- package/dist/connector/tools/router.js +30 -51
- package/dist/connector/tools/router.js.map +1 -1
- package/dist/contracts/a2a.d.ts +2 -2
- package/dist/directory/derive-supervisor.d.ts +2 -2
- package/dist/directory/derive-supervisor.d.ts.map +1 -1
- package/dist/directory/derive-supervisor.js +6 -7
- package/dist/directory/derive-supervisor.js.map +1 -1
- package/dist/directory/derive.d.ts.map +1 -1
- package/dist/directory/derive.js +5 -5
- package/dist/directory/derive.js.map +1 -1
- package/dist/execution/code-runtime/types.d.ts +2 -2
- package/dist/execution/code-runtime/types.js +1 -1
- package/dist/invariants/index.d.ts +2 -1
- package/dist/invariants/index.d.ts.map +1 -1
- package/dist/invariants/index.js +3 -2
- package/dist/invariants/index.js.map +1 -1
- package/dist/manager/agent/lifecycle.d.ts +1 -0
- package/dist/manager/agent/lifecycle.d.ts.map +1 -1
- package/dist/manager/agent/lifecycle.js +146 -18
- package/dist/manager/agent/lifecycle.js.map +1 -1
- package/dist/manager/connector/environment.d.ts +6 -0
- package/dist/manager/connector/environment.d.ts.map +1 -1
- package/dist/manager/connector/environment.js +11 -4
- package/dist/manager/connector/environment.js.map +1 -1
- package/dist/manager/connector/index.d.ts +2 -2
- package/dist/manager/connector/index.d.ts.map +1 -1
- package/dist/manager/connector/index.js +2 -2
- package/dist/manager/connector/index.js.map +1 -1
- package/dist/manager/connector/tenant.d.ts +6 -0
- package/dist/manager/connector/tenant.d.ts.map +1 -1
- package/dist/manager/connector/tenant.js +11 -4
- package/dist/manager/connector/tenant.js.map +1 -1
- package/dist/manager/index.d.ts +2 -2
- package/dist/manager/index.d.ts.map +1 -1
- package/dist/manager/index.js +2 -2
- package/dist/manager/index.js.map +1 -1
- package/dist/manager/resident/initiative.d.ts +6 -6
- package/dist/manager/resident/learning-observation.d.ts +4 -4
- package/dist/manager/resident/learning.d.ts +36 -36
- package/dist/manager/resident/outbox.d.ts +4 -4
- package/dist/manager/session/attribution.d.ts +22 -0
- package/dist/manager/session/attribution.d.ts.map +1 -0
- package/dist/manager/session/attribution.js +64 -0
- package/dist/manager/session/attribution.js.map +1 -0
- package/dist/manager/session/turn-recorder.d.ts +14 -0
- package/dist/manager/session/turn-recorder.d.ts.map +1 -1
- package/dist/manager/session/turn-recorder.js +208 -55
- package/dist/manager/session/turn-recorder.js.map +1 -1
- package/dist/peers/address.d.ts +36 -0
- package/dist/peers/address.d.ts.map +1 -0
- package/dist/peers/address.js +52 -0
- package/dist/peers/address.js.map +1 -0
- package/dist/peers/client.d.ts +47 -0
- package/dist/peers/client.d.ts.map +1 -0
- package/dist/peers/client.js +132 -0
- package/dist/peers/client.js.map +1 -0
- package/dist/peers/dir.d.ts +88 -0
- package/dist/peers/dir.d.ts.map +1 -0
- package/dist/peers/dir.js +139 -0
- package/dist/peers/dir.js.map +1 -0
- package/dist/peers/endpoint.d.ts +144 -0
- package/dist/peers/endpoint.d.ts.map +1 -0
- package/dist/peers/endpoint.js +420 -0
- package/dist/peers/endpoint.js.map +1 -0
- package/dist/peers/envelope.d.ts +42 -0
- package/dist/peers/envelope.d.ts.map +1 -0
- package/dist/peers/envelope.js +110 -0
- package/dist/peers/envelope.js.map +1 -0
- package/dist/peers/index.d.ts +30 -0
- package/dist/peers/index.d.ts.map +1 -0
- package/dist/peers/index.js +22 -0
- package/dist/peers/index.js.map +1 -0
- package/dist/peers/protocol.d.ts +645 -0
- package/dist/peers/protocol.d.ts.map +1 -0
- package/dist/peers/protocol.js +151 -0
- package/dist/peers/protocol.js.map +1 -0
- package/dist/peers/record.d.ts +71 -0
- package/dist/peers/record.d.ts.map +1 -0
- package/dist/peers/record.js +45 -0
- package/dist/peers/record.js.map +1 -0
- package/dist/peers/registry.d.ts +54 -0
- package/dist/peers/registry.d.ts.map +1 -0
- package/dist/peers/registry.js +213 -0
- package/dist/peers/registry.js.map +1 -0
- package/dist/plugin/define.d.ts +24 -0
- package/dist/plugin/define.d.ts.map +1 -0
- package/dist/plugin/define.js +42 -0
- package/dist/plugin/define.js.map +1 -0
- package/dist/plugin/index.d.ts +2 -0
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +1 -0
- package/dist/plugin/index.js.map +1 -1
- package/dist/plugin/lifecycle.d.ts +27 -3
- package/dist/plugin/lifecycle.d.ts.map +1 -1
- package/dist/plugin/lifecycle.js +242 -92
- package/dist/plugin/lifecycle.js.map +1 -1
- package/dist/plugin/resolver.d.ts +2 -2
- package/dist/plugin/resolver.d.ts.map +1 -1
- package/dist/plugin/resolver.js.map +1 -1
- package/dist/plugin/shell-hook.d.ts.map +1 -1
- package/dist/plugin/shell-hook.js +17 -3
- package/dist/plugin/shell-hook.js.map +1 -1
- package/dist/probe/errors.d.ts +2 -1
- package/dist/probe/errors.d.ts.map +1 -1
- package/dist/probe/errors.js +3 -2
- package/dist/probe/errors.js.map +1 -1
- package/dist/prompt/coding-agent-doctrine.d.ts +18 -7
- package/dist/prompt/coding-agent-doctrine.d.ts.map +1 -1
- package/dist/prompt/coding-agent-doctrine.js +11 -6
- package/dist/prompt/coding-agent-doctrine.js.map +1 -1
- package/dist/prompt/contributions.d.ts +4 -1
- package/dist/prompt/contributions.d.ts.map +1 -1
- package/dist/prompt/contributions.js +7 -2
- package/dist/prompt/contributions.js.map +1 -1
- package/dist/prompt/index.d.ts +1 -1
- package/dist/prompt/index.d.ts.map +1 -1
- package/dist/prompt/index.js +1 -1
- package/dist/prompt/index.js.map +1 -1
- package/dist/provider/collect-chat-completion.d.ts +6 -1
- package/dist/provider/collect-chat-completion.d.ts.map +1 -1
- package/dist/provider/collect-chat-completion.js +88 -10
- package/dist/provider/collect-chat-completion.js.map +1 -1
- package/dist/provider/mock.d.ts.map +1 -1
- package/dist/provider/mock.js +23 -6
- package/dist/provider/mock.js.map +1 -1
- package/dist/provider/registry.d.ts +2 -1
- package/dist/provider/registry.d.ts.map +1 -1
- package/dist/provider/registry.js +3 -2
- package/dist/provider/registry.js.map +1 -1
- package/dist/provider/tool-call-framing.d.ts +164 -0
- package/dist/provider/tool-call-framing.d.ts.map +1 -0
- package/dist/provider/tool-call-framing.js +163 -0
- package/dist/provider/tool-call-framing.js.map +1 -0
- package/dist/public-runtime.d.ts +24 -11
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +45 -9
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-tools.d.ts +6 -4
- package/dist/public-tools.d.ts.map +1 -1
- package/dist/public-tools.js +8 -3
- package/dist/public-tools.js.map +1 -1
- package/dist/public-types.d.ts +13 -2
- package/dist/public-types.d.ts.map +1 -1
- package/dist/read-model/registry.d.ts +2 -1
- package/dist/read-model/registry.d.ts.map +1 -1
- package/dist/read-model/registry.js +3 -2
- package/dist/read-model/registry.js.map +1 -1
- package/dist/registry/ManagedRegistry.d.ts +30 -0
- package/dist/registry/ManagedRegistry.d.ts.map +1 -1
- package/dist/registry/ManagedRegistry.js +45 -6
- package/dist/registry/ManagedRegistry.js.map +1 -1
- package/dist/registry/collision.d.ts +57 -0
- package/dist/registry/collision.d.ts.map +1 -0
- package/dist/registry/collision.js +41 -0
- package/dist/registry/collision.js.map +1 -0
- package/dist/registry/command/index.d.ts +5 -3
- package/dist/registry/command/index.d.ts.map +1 -1
- package/dist/registry/command/index.js +6 -4
- package/dist/registry/command/index.js.map +1 -1
- package/dist/registry/index.d.ts +3 -4
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +2 -2
- package/dist/registry/index.js.map +1 -1
- package/dist/registry/plugin/index.d.ts.map +1 -1
- package/dist/registry/plugin/index.js +14 -1
- package/dist/registry/plugin/index.js.map +1 -1
- package/dist/registry/tool/callable.d.ts +7 -7
- package/dist/registry/tool/callable.d.ts.map +1 -1
- package/dist/registry/tool/callable.js +6 -7
- package/dist/registry/tool/callable.js.map +1 -1
- package/dist/registry/tool/execute.d.ts +14 -77
- package/dist/registry/tool/execute.d.ts.map +1 -1
- package/dist/registry/tool/execute.js +15 -727
- package/dist/registry/tool/execute.js.map +1 -1
- package/dist/registry/tool/portable.d.ts +25 -0
- package/dist/registry/tool/portable.d.ts.map +1 -1
- package/dist/registry/tool/portable.js +50 -0
- package/dist/registry/tool/portable.js.map +1 -1
- package/dist/registry/tool/presentation.d.ts +6 -5
- package/dist/registry/tool/presentation.d.ts.map +1 -1
- package/dist/registry/tool/presentation.js +3 -3
- package/dist/registry/tool/presentation.js.map +1 -1
- package/dist/runtime/bidi/session.d.ts +5 -4
- package/dist/runtime/bidi/session.d.ts.map +1 -1
- package/dist/runtime/bidi/session.js +18 -1
- package/dist/runtime/bidi/session.js.map +1 -1
- package/dist/runtime/query/executor/tool-call-admission.d.ts +45 -2
- package/dist/runtime/query/executor/tool-call-admission.d.ts.map +1 -1
- package/dist/runtime/query/executor/tool-call-admission.js +189 -5
- package/dist/runtime/query/executor/tool-call-admission.js.map +1 -1
- package/dist/runtime/query/executor.d.ts +33 -3
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +86 -10
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/file-evidence-replay.d.ts +1 -1
- package/dist/runtime/query/file-evidence-replay.d.ts.map +1 -1
- package/dist/runtime/query/file-evidence-replay.js +8 -7
- package/dist/runtime/query/file-evidence-replay.js.map +1 -1
- package/dist/runtime/query/fork/prepare.d.ts +4 -1
- package/dist/runtime/query/fork/prepare.d.ts.map +1 -1
- package/dist/runtime/query/fork/prepare.js +4 -0
- package/dist/runtime/query/fork/prepare.js.map +1 -1
- package/dist/runtime/query/guardrail-presets.d.ts +4 -3
- package/dist/runtime/query/guardrail-presets.d.ts.map +1 -1
- package/dist/runtime/query/guardrail-presets.js +4 -3
- package/dist/runtime/query/guardrail-presets.js.map +1 -1
- package/dist/runtime/query/index.d.ts +23 -10
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +149 -70
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +8 -1
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.js +1 -1
- package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context.d.ts +2 -2
- package/dist/runtime/query/iteration/phases/context.d.ts.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 +55 -2
- package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.js +342 -116
- package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
- package/dist/runtime/query/iteration/tool-input.d.ts +79 -0
- package/dist/runtime/query/iteration/tool-input.d.ts.map +1 -0
- package/dist/runtime/query/iteration/tool-input.js +291 -0
- package/dist/runtime/query/iteration/tool-input.js.map +1 -0
- package/dist/runtime/query/observation-context.d.ts +2 -2
- package/dist/runtime/query/observation-context.d.ts.map +1 -1
- package/dist/runtime/query/observation-context.js.map +1 -1
- package/dist/runtime/query/prelude-lease.d.ts +18 -0
- package/dist/runtime/query/prelude-lease.d.ts.map +1 -0
- package/dist/runtime/query/prelude-lease.js +121 -0
- package/dist/runtime/query/prelude-lease.js.map +1 -0
- package/dist/runtime/query/prepare-turn.d.ts.map +1 -1
- package/dist/runtime/query/prepare-turn.js +386 -187
- package/dist/runtime/query/prepare-turn.js.map +1 -1
- package/dist/runtime/query/prompt-cache.d.ts +2 -2
- package/dist/runtime/query/prompt-cache.d.ts.map +1 -1
- package/dist/runtime/query/prompt.d.ts +2 -2
- package/dist/runtime/query/prompt.d.ts.map +1 -1
- package/dist/runtime/query/prompt.js +1 -1
- package/dist/runtime/query/prompt.js.map +1 -1
- package/dist/runtime/query/resume-session.d.ts.map +1 -1
- package/dist/runtime/query/resume-session.js +37 -2
- package/dist/runtime/query/resume-session.js.map +1 -1
- package/dist/runtime/query/review-policy.d.ts +22 -3
- package/dist/runtime/query/review-policy.d.ts.map +1 -1
- package/dist/runtime/query/review-policy.js +84 -6
- package/dist/runtime/query/review-policy.js.map +1 -1
- package/dist/runtime/query/tooling.d.ts +3 -2
- package/dist/runtime/query/tooling.d.ts.map +1 -1
- package/dist/runtime/query/tooling.js.map +1 -1
- package/dist/runtime/query/turn-state.d.ts.map +1 -1
- package/dist/runtime/query/turn-state.js +5 -0
- package/dist/runtime/query/turn-state.js.map +1 -1
- package/dist/runtime/system-events.d.ts +112 -0
- package/dist/runtime/system-events.d.ts.map +1 -0
- package/dist/runtime/system-events.js +183 -0
- package/dist/runtime/system-events.js.map +1 -0
- package/dist/scheduler/delegating.d.ts +2 -1
- package/dist/scheduler/delegating.d.ts.map +1 -1
- package/dist/scheduler/delegating.js +3 -2
- package/dist/scheduler/delegating.js.map +1 -1
- package/dist/scheduler/local.d.ts.map +1 -1
- package/dist/scheduler/local.js +2 -0
- package/dist/scheduler/local.js.map +1 -1
- package/dist/session/retention/archive.js +1 -1
- package/dist/session/retention/archive.js.map +1 -1
- package/dist/skills/index.d.ts +1 -1
- package/dist/skills/index.d.ts.map +1 -1
- package/dist/skills/index.js +1 -1
- package/dist/skills/index.js.map +1 -1
- package/dist/skills/registry.d.ts +12 -0
- package/dist/skills/registry.d.ts.map +1 -1
- package/dist/skills/registry.js +19 -0
- package/dist/skills/registry.js.map +1 -1
- package/dist/store/evidence/index-page.d.ts +2 -2
- package/dist/store/session/disk.d.ts.map +1 -1
- package/dist/store/session/disk.js +2 -0
- package/dist/store/session/disk.js.map +1 -1
- package/dist/store/session-log/conformance.d.ts +1 -1
- package/dist/store/session-log/conformance.d.ts.map +1 -1
- package/dist/store/session-log/conformance.js +49 -8
- package/dist/store/session-log/conformance.js.map +1 -1
- package/dist/store/session-log/core.d.ts +8 -3
- package/dist/store/session-log/core.d.ts.map +1 -1
- package/dist/store/session-log/core.js +2 -1
- package/dist/store/session-log/core.js.map +1 -1
- package/dist/store/session-log/fold.d.ts +12 -0
- package/dist/store/session-log/fold.d.ts.map +1 -1
- package/dist/store/session-log/fold.js +57 -7
- package/dist/store/session-log/fold.js.map +1 -1
- package/dist/store/session-log/index.d.ts +2 -2
- package/dist/store/session-log/index.d.ts.map +1 -1
- package/dist/store/session-log/index.js +1 -1
- package/dist/store/session-log/index.js.map +1 -1
- package/dist/test-support/toolset.d.ts +19 -0
- package/dist/test-support/toolset.d.ts.map +1 -0
- package/dist/test-support/toolset.js +20 -0
- package/dist/test-support/toolset.js.map +1 -0
- package/dist/tools/builtins/bash.d.ts +29 -0
- package/dist/tools/builtins/bash.d.ts.map +1 -1
- package/dist/tools/builtins/bash.js +19 -9
- package/dist/tools/builtins/bash.js.map +1 -1
- package/dist/tools/builtins/browser-url.d.ts +1 -1
- package/dist/tools/builtins/browser-url.js +1 -1
- package/dist/tools/builtins/browser.d.ts +6 -6
- package/dist/tools/builtins/browser.js +2 -2
- package/dist/tools/builtins/browser.js.map +1 -1
- package/dist/tools/builtins/computer-use.d.ts.map +1 -1
- package/dist/tools/builtins/computer-use.js +19 -11
- package/dist/tools/builtins/computer-use.js.map +1 -1
- package/dist/tools/builtins/edit.d.ts.map +1 -1
- package/dist/tools/builtins/edit.js +9 -1
- package/dist/tools/builtins/edit.js.map +1 -1
- package/dist/tools/builtins/json-string-hint.d.ts +15 -0
- package/dist/tools/builtins/json-string-hint.d.ts.map +1 -0
- package/dist/tools/builtins/json-string-hint.js +17 -0
- package/dist/tools/builtins/json-string-hint.js.map +1 -0
- package/dist/tools/builtins/search-tools.d.ts.map +1 -1
- package/dist/tools/builtins/search-tools.js +7 -15
- package/dist/tools/builtins/search-tools.js.map +1 -1
- package/dist/tools/builtins/write-file.d.ts.map +1 -1
- package/dist/tools/builtins/write-file.js +11 -0
- package/dist/tools/builtins/write-file.js.map +1 -1
- package/dist/tools/command-shell.d.ts +10 -0
- package/dist/tools/command-shell.d.ts.map +1 -1
- package/dist/tools/command-shell.js +45 -1
- package/dist/tools/command-shell.js.map +1 -1
- package/dist/tools/coordinator/agent.d.ts.map +1 -1
- package/dist/tools/coordinator/agent.js +5 -0
- package/dist/tools/coordinator/agent.js.map +1 -1
- package/dist/tools/coordinator/ask-user-question.d.ts.map +1 -1
- package/dist/tools/coordinator/ask-user-question.js +26 -13
- package/dist/tools/coordinator/ask-user-question.js.map +1 -1
- package/dist/tools/coordinator/index.d.ts.map +1 -1
- package/dist/tools/coordinator/index.js +5 -0
- package/dist/tools/coordinator/index.js.map +1 -1
- package/dist/tools/coordinator/question-options.d.ts +78 -0
- package/dist/tools/coordinator/question-options.d.ts.map +1 -0
- package/dist/tools/coordinator/question-options.js +153 -0
- package/dist/tools/coordinator/question-options.js.map +1 -0
- package/dist/tools/defineTool.d.ts +10 -0
- package/dist/tools/defineTool.d.ts.map +1 -1
- package/dist/tools/defineTool.js +17 -0
- package/dist/tools/defineTool.js.map +1 -1
- package/dist/tools/memory/search.d.ts.map +1 -1
- package/dist/tools/memory/search.js +4 -1
- package/dist/tools/memory/search.js.map +1 -1
- package/dist/tools/memory/update.d.ts.map +1 -1
- package/dist/tools/memory/update.js +8 -5
- package/dist/tools/memory/update.js.map +1 -1
- package/dist/tools/render-nonce.d.ts +47 -0
- package/dist/tools/render-nonce.d.ts.map +1 -0
- package/dist/tools/render-nonce.js +63 -0
- package/dist/tools/render-nonce.js.map +1 -0
- package/dist/tools/roster.d.ts +46 -19
- package/dist/tools/roster.d.ts.map +1 -1
- package/dist/tools/roster.js +63 -33
- package/dist/tools/roster.js.map +1 -1
- package/dist/tools/schedules/schedule-tool.d.ts.map +1 -1
- package/dist/tools/schedules/schedule-tool.js +94 -14
- package/dist/tools/schedules/schedule-tool.js.map +1 -1
- package/dist/tools/schedules/types.d.ts +52 -6
- package/dist/tools/schedules/types.d.ts.map +1 -1
- package/dist/tools/trusted-read-only.d.ts +9 -5
- package/dist/tools/trusted-read-only.d.ts.map +1 -1
- package/dist/tools/trusted-read-only.js +14 -10
- package/dist/tools/trusted-read-only.js.map +1 -1
- package/dist/tools/untrusted-envelope.d.ts +67 -28
- package/dist/tools/untrusted-envelope.d.ts.map +1 -1
- package/dist/tools/untrusted-envelope.js +108 -59
- package/dist/tools/untrusted-envelope.js.map +1 -1
- package/dist/toolsets/combine.d.ts +44 -0
- package/dist/toolsets/combine.d.ts.map +1 -0
- package/dist/toolsets/combine.js +153 -0
- package/dist/toolsets/combine.js.map +1 -0
- package/dist/toolsets/manager.d.ts +201 -0
- package/dist/toolsets/manager.d.ts.map +1 -0
- package/dist/toolsets/manager.js +837 -0
- package/dist/toolsets/manager.js.map +1 -0
- package/dist/toolsets/source-glob.d.ts +15 -0
- package/dist/toolsets/source-glob.d.ts.map +1 -0
- package/dist/toolsets/source-glob.js +23 -0
- package/dist/toolsets/source-glob.js.map +1 -0
- package/dist/toolsets/toolset.d.ts +20 -0
- package/dist/toolsets/toolset.d.ts.map +1 -0
- package/dist/toolsets/toolset.js +28 -0
- package/dist/toolsets/toolset.js.map +1 -0
- package/dist/toolsets/types.d.ts +128 -0
- package/dist/toolsets/types.d.ts.map +1 -0
- package/dist/toolsets/types.js +33 -0
- package/dist/toolsets/types.js.map +1 -0
- package/dist/toolsets/wrappers.d.ts +59 -0
- package/dist/toolsets/wrappers.d.ts.map +1 -0
- package/dist/toolsets/wrappers.js +165 -0
- package/dist/toolsets/wrappers.js.map +1 -0
- package/dist/types/agent/base.d.ts +27 -16
- package/dist/types/agent/base.d.ts.map +1 -1
- package/dist/types/agent/index.d.ts +1 -0
- package/dist/types/agent/index.d.ts.map +1 -1
- package/dist/types/agent/index.js +1 -0
- package/dist/types/agent/index.js.map +1 -1
- package/dist/types/agent/pipeline.d.ts +2 -0
- package/dist/types/agent/pipeline.d.ts.map +1 -1
- package/dist/types/agent/query.d.ts +117 -0
- package/dist/types/agent/query.d.ts.map +1 -0
- package/dist/types/agent/query.js +2 -0
- package/dist/types/agent/query.js.map +1 -0
- package/dist/types/agent/reactive.d.ts +2 -129
- package/dist/types/agent/reactive.d.ts.map +1 -1
- package/dist/types/agent/router.d.ts +2 -0
- package/dist/types/agent/router.d.ts.map +1 -1
- package/dist/types/agent/scheduler.d.ts +6 -1
- package/dist/types/agent/scheduler.d.ts.map +1 -1
- package/dist/types/agent/supervisor.d.ts +5 -2
- package/dist/types/agent/supervisor.d.ts.map +1 -1
- package/dist/types/agent/task.d.ts +19 -1
- package/dist/types/agent/task.d.ts.map +1 -1
- package/dist/types/agent/task.js.map +1 -1
- package/dist/types/authorization/index.d.ts +49 -12
- package/dist/types/authorization/index.d.ts.map +1 -1
- package/dist/types/authorization/index.js +6 -0
- package/dist/types/authorization/index.js.map +1 -1
- package/dist/types/connector/mcp.d.ts +45 -0
- package/dist/types/connector/mcp.d.ts.map +1 -1
- package/dist/types/errors/index.d.ts +15 -0
- package/dist/types/errors/index.d.ts.map +1 -1
- package/dist/types/errors/index.js.map +1 -1
- package/dist/types/hitl/index.d.ts +57 -0
- package/dist/types/hitl/index.d.ts.map +1 -1
- package/dist/types/hitl/index.js.map +1 -1
- package/dist/types/message/index.d.ts +130 -9
- package/dist/types/message/index.d.ts.map +1 -1
- package/dist/types/message/index.js +4 -1
- package/dist/types/message/index.js.map +1 -1
- package/dist/types/plugin/index.d.ts +22 -4
- package/dist/types/plugin/index.d.ts.map +1 -1
- package/dist/types/plugin/index.js +1 -0
- package/dist/types/plugin/index.js.map +1 -1
- package/dist/types/provider/chat.d.ts +5 -0
- package/dist/types/provider/chat.d.ts.map +1 -1
- package/dist/types/provider/config.d.ts +8 -3
- package/dist/types/provider/config.d.ts.map +1 -1
- package/dist/types/provider/stream.d.ts +39 -0
- package/dist/types/provider/stream.d.ts.map +1 -1
- package/dist/types/sandbox/index.d.ts +1 -1
- package/dist/types/session/events.d.ts +14 -3
- package/dist/types/session/events.d.ts.map +1 -1
- package/dist/types/session/events.js.map +1 -1
- package/dist/types/session/sub-session.d.ts +2 -0
- package/dist/types/session/sub-session.d.ts.map +1 -1
- package/dist/types/tool/index.d.ts +152 -91
- package/dist/types/tool/index.d.ts.map +1 -1
- package/dist/types/tool/index.js.map +1 -1
- package/dist/types/toolset/index.d.ts +10 -40
- package/dist/types/toolset/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/advisory/history.ts +27 -2
- package/src/advisory/index.ts +1 -1
- package/src/advisory/registry.ts +33 -0
- package/src/agents/AGENTS.md +14 -7
- package/src/agents/PipelineAgent.ts +2 -303
- package/src/agents/QueryAgent.ts +269 -0
- package/src/agents/ReactiveAgent.ts +6 -216
- package/src/agents/RouterAgent.ts +2 -337
- package/src/agents/SupervisorAgent.ts +3 -476
- package/src/agents/defineAgent.ts +13 -2
- package/src/agents/examples/PipelineAgent.ts +302 -0
- package/src/agents/examples/RouterAgent.ts +338 -0
- package/src/agents/examples/SupervisorAgent.ts +472 -0
- package/src/agents/explore.ts +6 -3
- package/src/agents/forward-options.ts +37 -0
- package/src/agents/index.ts +2 -0
- package/src/agents/runAgent.ts +144 -37
- package/src/authorization/command-line.ts +2 -2
- package/src/authorization/gate.ts +21 -1
- package/src/authorization/program.ts +773 -0
- package/src/authorization/reexec-wrapper.ts +589 -0
- package/src/authorization/rules.ts +18 -1
- package/src/authorization/shell-lexer.ts +104 -59
- package/src/bridge/sse/mapper.ts +6 -0
- package/src/capabilities/index.ts +157 -0
- package/src/config/registry.ts +4 -1
- package/src/connector/index.ts +9 -2
- package/src/connector/mcp/adapter.ts +73 -3
- package/src/connector/mcp/client.ts +425 -6
- package/src/connector/mcp/discovery.ts +60 -0
- package/src/connector/mcp/era.ts +7 -0
- package/src/connector/mcp/index.ts +13 -0
- package/src/connector/mcp/mcp-toolset.ts +515 -0
- package/src/connector/mcp/streamable-http.ts +302 -5
- package/src/connector/tools/index.ts +2 -2
- package/src/connector/tools/router.ts +35 -58
- package/src/directory/derive-supervisor.ts +12 -8
- package/src/directory/derive.ts +8 -5
- package/src/execution/code-runtime/types.ts +2 -2
- package/src/invariants/index.ts +4 -1
- package/src/manager/agent/lifecycle.ts +167 -19
- package/src/manager/connector/environment.ts +17 -4
- package/src/manager/connector/index.ts +2 -2
- package/src/manager/connector/tenant.ts +17 -4
- package/src/manager/index.ts +2 -2
- package/src/manager/session/attribution.ts +79 -0
- package/src/manager/session/turn-recorder.ts +211 -55
- package/src/peers/address.ts +58 -0
- package/src/peers/client.ts +202 -0
- package/src/peers/dir.ts +176 -0
- package/src/peers/endpoint.ts +564 -0
- package/src/peers/envelope.ts +121 -0
- package/src/peers/index.ts +96 -0
- package/src/peers/protocol.ts +196 -0
- package/src/peers/record.ts +56 -0
- package/src/peers/registry.ts +241 -0
- package/src/plugin/define.ts +68 -0
- package/src/plugin/index.ts +2 -0
- package/src/plugin/lifecycle.ts +286 -106
- package/src/plugin/resolver.ts +6 -3
- package/src/plugin/shell-hook.ts +21 -5
- package/src/probe/errors.ts +4 -1
- package/src/prompt/coding-agent-doctrine.ts +22 -10
- package/src/prompt/contributions.ts +12 -2
- package/src/prompt/index.ts +1 -0
- package/src/provider/collect-chat-completion.ts +96 -11
- package/src/provider/mock.ts +24 -6
- package/src/provider/registry.ts +4 -1
- package/src/provider/tool-call-framing.ts +226 -0
- package/src/public-runtime.ts +136 -7
- package/src/public-tools.ts +24 -4
- package/src/public-types.ts +60 -6
- package/src/read-model/registry.ts +7 -2
- package/src/registry/ManagedRegistry.ts +57 -6
- package/src/registry/collision.ts +64 -0
- package/src/registry/command/index.ts +7 -3
- package/src/registry/index.ts +3 -9
- package/src/registry/plugin/index.ts +14 -1
- package/src/registry/tool/callable.ts +8 -9
- package/src/registry/tool/execute.ts +16 -846
- package/src/registry/tool/portable.ts +59 -0
- package/src/registry/tool/presentation.ts +6 -5
- package/src/runtime/bidi/session.ts +24 -5
- package/src/runtime/query/executor/tool-call-admission.ts +228 -6
- package/src/runtime/query/executor.ts +110 -12
- package/src/runtime/query/file-evidence-replay.ts +8 -7
- package/src/runtime/query/fork/prepare.ts +6 -1
- package/src/runtime/query/guardrail-presets.ts +4 -3
- package/src/runtime/query/index.ts +199 -101
- package/src/runtime/query/iteration/index.ts +13 -3
- package/src/runtime/query/iteration/phases/compaction.ts +1 -1
- package/src/runtime/query/iteration/phases/context.ts +2 -2
- package/src/runtime/query/iteration/phases/tool-review.ts +59 -2
- package/src/runtime/query/iteration/stream-turn.ts +390 -136
- package/src/runtime/query/iteration/tool-input.ts +284 -0
- package/src/runtime/query/observation-context.ts +2 -2
- package/src/runtime/query/prelude-lease.ts +132 -0
- package/src/runtime/query/prepare-turn.ts +477 -198
- package/src/runtime/query/prompt-cache.ts +2 -2
- package/src/runtime/query/prompt.ts +4 -4
- package/src/runtime/query/resume-session.ts +42 -3
- package/src/runtime/query/review-policy.ts +87 -9
- package/src/runtime/query/tooling.ts +3 -6
- package/src/runtime/query/turn-state.ts +4 -0
- package/src/runtime/system-events.ts +246 -0
- package/src/scheduler/delegating.ts +7 -2
- package/src/scheduler/local.ts +2 -0
- package/src/session/retention/archive.ts +1 -1
- package/src/skills/index.ts +1 -1
- package/src/skills/registry.ts +25 -0
- package/src/store/session/disk.ts +3 -0
- package/src/store/session-log/conformance.ts +51 -8
- package/src/store/session-log/core.ts +10 -4
- package/src/store/session-log/fold.ts +33 -7
- package/src/store/session-log/index.ts +2 -0
- package/src/test-support/toolset.ts +23 -0
- package/src/tools/builtins/bash.ts +27 -10
- package/src/tools/builtins/browser-url.ts +1 -1
- package/src/tools/builtins/browser.ts +2 -2
- package/src/tools/builtins/computer-use.ts +21 -11
- package/src/tools/builtins/edit.ts +12 -2
- package/src/tools/builtins/json-string-hint.ts +16 -0
- package/src/tools/builtins/search-tools.ts +7 -20
- package/src/tools/builtins/write-file.ts +12 -0
- package/src/tools/command-shell.ts +46 -1
- package/src/tools/coordinator/agent.ts +6 -0
- package/src/tools/coordinator/ask-user-question.ts +29 -15
- package/src/tools/coordinator/index.ts +6 -0
- package/src/tools/coordinator/question-options.ts +195 -0
- package/src/tools/defineTool.ts +28 -0
- package/src/tools/memory/search.ts +4 -1
- package/src/tools/memory/update.ts +8 -5
- package/src/tools/render-nonce.ts +69 -0
- package/src/tools/roster.ts +84 -33
- package/src/tools/schedules/schedule-tool.ts +107 -14
- package/src/tools/schedules/types.ts +52 -6
- package/src/tools/trusted-read-only.ts +19 -10
- package/src/tools/untrusted-envelope.ts +121 -57
- package/src/toolsets/combine.ts +181 -0
- package/src/toolsets/manager.ts +996 -0
- package/src/toolsets/source-glob.ts +22 -0
- package/src/toolsets/toolset.ts +31 -0
- package/src/toolsets/types.ts +154 -0
- package/src/toolsets/wrappers.ts +191 -0
- package/src/types/agent/base.ts +29 -16
- package/src/types/agent/index.ts +1 -0
- package/src/types/agent/pipeline.ts +2 -0
- package/src/types/agent/query.ts +129 -0
- package/src/types/agent/reactive.ts +5 -142
- package/src/types/agent/router.ts +2 -0
- package/src/types/agent/scheduler.ts +6 -1
- package/src/types/agent/supervisor.ts +5 -2
- package/src/types/agent/task.ts +21 -1
- package/src/types/authorization/index.ts +12 -0
- package/src/types/connector/mcp.ts +46 -0
- package/src/types/errors/index.ts +15 -0
- package/src/types/hitl/index.ts +57 -0
- package/src/types/message/index.ts +135 -7
- package/src/types/plugin/index.ts +44 -21
- package/src/types/provider/chat.ts +5 -0
- package/src/types/provider/config.ts +8 -3
- package/src/types/provider/stream.ts +39 -0
- package/src/types/sandbox/index.ts +1 -1
- package/src/types/session/events.ts +14 -3
- package/src/types/session/sub-session.ts +2 -0
- package/src/types/tool/index.ts +154 -105
- package/src/types/toolset/index.ts +10 -47
- package/dist/registry/toolset/catalog.d.ts +0 -42
- package/dist/registry/toolset/catalog.d.ts.map +0 -1
- package/dist/registry/toolset/catalog.js +0 -234
- package/dist/registry/toolset/catalog.js.map +0 -1
- package/src/registry/toolset/catalog.ts +0 -308
|
@@ -0,0 +1,996 @@
|
|
|
1
|
+
import { SpanStatusCode, context as otelContext, trace } from '@opentelemetry/api'
|
|
2
|
+
import { isCompactionMessage } from '../compaction/summary.js'
|
|
3
|
+
import { assertStrictSchema } from '../provider/strict-schema.js'
|
|
4
|
+
import { callableToolNames, formatToolNames } from '../registry/tool/callable.js'
|
|
5
|
+
import { assertToolName, describeWithOutput, toolDiscoveryHint } from '../registry/tool/execute.js'
|
|
6
|
+
import { renderToolSchema, toolWireSchema } from '../registry/tool/schema.js'
|
|
7
|
+
import { ToolResultHalted, screenToolResult } from '../registry/tool/screen.js'
|
|
8
|
+
import { GENAI, NAMZU, toolSpanName } from '../telemetry/attributes.js'
|
|
9
|
+
import { recordToolCall } from '../telemetry/metrics.js'
|
|
10
|
+
import { getTracer } from '../telemetry/runtime-accessors.js'
|
|
11
|
+
import { isTrustedReadOnly } from '../tools/trusted-read-only.js'
|
|
12
|
+
import type { ToolResultGuardrailSpec } from '../types/guardrail/index.js'
|
|
13
|
+
import type { Message, ToolRevealReceipt } from '../types/message/index.js'
|
|
14
|
+
import { PLAN_MODE_REFUSAL } from '../types/permission/index.js'
|
|
15
|
+
import type {
|
|
16
|
+
LLMToolSchema,
|
|
17
|
+
PreparedToolExecution,
|
|
18
|
+
ToolAvailability,
|
|
19
|
+
ToolContext,
|
|
20
|
+
ToolDefinition,
|
|
21
|
+
ToolExecutionResult,
|
|
22
|
+
ToolPreparationResult,
|
|
23
|
+
ToolProvenance,
|
|
24
|
+
ToolTierConfig,
|
|
25
|
+
ToolsView,
|
|
26
|
+
} from '../types/tool/index.js'
|
|
27
|
+
import { toErrorMessage } from '../utils/error.js'
|
|
28
|
+
import { cloneJsonValue as clonePreparedInput } from '../utils/json-snapshot.js'
|
|
29
|
+
import { SCOPE_ATTRIBUTE } from '../utils/log/types.js'
|
|
30
|
+
import { type Logger, resolveLogger } from '../utils/logger.js'
|
|
31
|
+
import { ToolsetConflictError } from './combine.js'
|
|
32
|
+
import type { ToolSourceRef, Toolset, ToolsetAvailability } from './types.js'
|
|
33
|
+
import { toToolSourceRef, toolsetIsReady } from './types.js'
|
|
34
|
+
|
|
35
|
+
export type { ToolExecutionResult }
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* What `refresh()` reports after re-resolving a live toolset's change.
|
|
39
|
+
*
|
|
40
|
+
* `refused` is a newly-contributed name that would have collided with a name
|
|
41
|
+
* already served by another toolset — the incumbent keeps serving and the
|
|
42
|
+
* newcomer never reaches the manager, unlike a construction-time collision,
|
|
43
|
+
* which throws instead (nothing was serving anyone yet, so there is nothing
|
|
44
|
+
* to protect by continuing).
|
|
45
|
+
*/
|
|
46
|
+
export interface ToolsetChangeReport {
|
|
47
|
+
/** Names a toolset started contributing that nobody else already served. */
|
|
48
|
+
readonly added: readonly string[]
|
|
49
|
+
/** Names whose owning toolset stopped contributing them, with no other toolset picking them up. */
|
|
50
|
+
readonly removed: readonly string[]
|
|
51
|
+
/**
|
|
52
|
+
* Names whose OWNING toolset now returns a different `ToolDefinition`
|
|
53
|
+
* object under the same name. The previously admitted definition keeps
|
|
54
|
+
* serving — see the class doc on why identity, not content, is what
|
|
55
|
+
* `toLLMTools`'s prompt-cache stability depends on.
|
|
56
|
+
*/
|
|
57
|
+
readonly drifted: readonly string[]
|
|
58
|
+
/** A new contributor for a name some other toolset already serves. Refused, not applied. */
|
|
59
|
+
readonly refused: readonly {
|
|
60
|
+
readonly name: string
|
|
61
|
+
readonly reason: string
|
|
62
|
+
}[]
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface ToolManagerConfig {
|
|
66
|
+
readonly toolsets: readonly Toolset[]
|
|
67
|
+
/**
|
|
68
|
+
* Screens run against every tool result before anything downstream reads
|
|
69
|
+
* it. Wins over whatever the turn's own `ToolContext.toolResultGuardrails`
|
|
70
|
+
* supplies when this is present — including `[]`, which means none —
|
|
71
|
+
* because a manager built with an explicit policy has stated it. See
|
|
72
|
+
* `executeRetained` below.
|
|
73
|
+
*/
|
|
74
|
+
readonly resultGuardrails?: readonly ToolResultGuardrailSpec[]
|
|
75
|
+
readonly tierConfig?: ToolTierConfig
|
|
76
|
+
/**
|
|
77
|
+
* The turn's own message history, read fresh on every `availability`
|
|
78
|
+
* call rather than captured once — see {@link ToolManager.availability}.
|
|
79
|
+
*/
|
|
80
|
+
readonly messages: () => readonly Message[]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Tokens too generic to identify a tool by name — ignored when matching a
|
|
84
|
+
// batched `search_tools` query so they can't activate the whole catalog.
|
|
85
|
+
// Copied from `registry/tool/execute.ts`'s `ToolRegistry.searchByAvailability`
|
|
86
|
+
// (same weights, same stop list); consolidate once that class is removed.
|
|
87
|
+
const SEARCH_STOP_TOKENS = new Set([
|
|
88
|
+
'clawtool',
|
|
89
|
+
'tool',
|
|
90
|
+
'tools',
|
|
91
|
+
'mcp',
|
|
92
|
+
'the',
|
|
93
|
+
'and',
|
|
94
|
+
'for',
|
|
95
|
+
'use',
|
|
96
|
+
'list',
|
|
97
|
+
'read',
|
|
98
|
+
'create',
|
|
99
|
+
'update',
|
|
100
|
+
'get',
|
|
101
|
+
'find',
|
|
102
|
+
'delete',
|
|
103
|
+
'search',
|
|
104
|
+
])
|
|
105
|
+
|
|
106
|
+
const SEARCH_WEIGHT_NAME_EXACT = 12
|
|
107
|
+
const SEARCH_WEIGHT_NAME_PARTIAL = 8
|
|
108
|
+
const SEARCH_WEIGHT_DESCRIPTION = 5
|
|
109
|
+
const SEARCH_WEIGHT_ARGUMENT = 3
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* The runtime-owned resolver of {@link Toolset}s.
|
|
113
|
+
*
|
|
114
|
+
* It is built once from a fixed list of toolsets and never mutates its own
|
|
115
|
+
* membership: a toolset changing live (`onChange`) is only adopted when the caller calls
|
|
116
|
+
* {@link refresh}, at an iteration boundary the caller chooses — never
|
|
117
|
+
* mid-call. This is what keeps `toLLMTools`'s wire rendering byte-stable
|
|
118
|
+
* between refreshes: `toolWireSchema` (`registry/tool/schema.ts`) memoizes a
|
|
119
|
+
* tool's rendered schema by the object identity of `ToolDefinition.inputSchema`,
|
|
120
|
+
* not by anything owned by whichever object resolved the tool, so returning
|
|
121
|
+
* the SAME `ToolDefinition` object for the same name across calls — which a
|
|
122
|
+
* fixed, never-mutated resolution trivially does — is what keeps the cache
|
|
123
|
+
* hit.
|
|
124
|
+
*
|
|
125
|
+
* Availability has no stored, mutable map (unlike `ToolRegistry.availability`).
|
|
126
|
+
* It is DERIVED: an unready source is suspended; otherwise a tool is
|
|
127
|
+
* deferred iff its owner declared `deferred()` and no source-bound receipt
|
|
128
|
+
* in the turn's post-compaction history has loaded its schema. See
|
|
129
|
+
* {@link ToolManager.availability}.
|
|
130
|
+
*
|
|
131
|
+
* The execution pipeline below (`prepareExecution`/`executePrepared`/
|
|
132
|
+
* `execute`/`executeRetained`) is copied from `ToolRegistry`'s, per plan.md
|
|
133
|
+
* §2: "Diff it line by line; the only permitted changes are where it read
|
|
134
|
+
* `this.availability`, `tool.provenance` or registry identity." Those three
|
|
135
|
+
* substitutions are exactly: `this.availability(name)` (derived, above) for
|
|
136
|
+
* `this.getAvailability(name)`; `this.sourceOf(name)` for `tool.provenance`;
|
|
137
|
+
* and `this.toolsByName` for `this.items`. Every check, in the same order,
|
|
138
|
+
* with the same messages, is unchanged.
|
|
139
|
+
*/
|
|
140
|
+
export class ToolManager {
|
|
141
|
+
private readonly toolsets: readonly Toolset[]
|
|
142
|
+
private readonly resultGuardrails?: readonly ToolResultGuardrailSpec[]
|
|
143
|
+
private readonly tierConfig?: ToolTierConfig
|
|
144
|
+
private readonly messagesAccessor: () => readonly Message[]
|
|
145
|
+
private readonly log: Logger
|
|
146
|
+
|
|
147
|
+
private toolsByName = new Map<string, ToolDefinition>()
|
|
148
|
+
private ownerToolsetByName = new Map<string, Toolset>()
|
|
149
|
+
private defaultAvailabilityByName = new Map<string, ToolsetAvailability>()
|
|
150
|
+
/**
|
|
151
|
+
* The object each name's owning toolset returned the LAST time `refresh()`
|
|
152
|
+
* (or construction) observed it — distinct from `toolsByName`, which holds
|
|
153
|
+
* whatever was first admitted under that name and never changes on drift.
|
|
154
|
+
* `refresh()` diffs against this map, not `toolsByName`, so a name that
|
|
155
|
+
* drifted once and has been stable ever since is not reported as drifted
|
|
156
|
+
* again just because some unrelated toolset's change forced a re-walk.
|
|
157
|
+
*/
|
|
158
|
+
private lastObservedByName = new Map<string, ToolDefinition>()
|
|
159
|
+
private dirty = false
|
|
160
|
+
private readonly unsubscribeToolsetChanges: (() => void)[] = []
|
|
161
|
+
private disposed = false
|
|
162
|
+
|
|
163
|
+
private readonly preparations = new WeakMap<
|
|
164
|
+
PreparedToolExecution,
|
|
165
|
+
{ readonly tool: ToolDefinition; readonly input: unknown }
|
|
166
|
+
>()
|
|
167
|
+
|
|
168
|
+
constructor(config: ToolManagerConfig) {
|
|
169
|
+
this.toolsets = config.toolsets
|
|
170
|
+
this.resultGuardrails = config.resultGuardrails
|
|
171
|
+
this.tierConfig = config.tierConfig
|
|
172
|
+
this.messagesAccessor = config.messages
|
|
173
|
+
this.log = resolveLogger(undefined).child({
|
|
174
|
+
[SCOPE_ATTRIBUTE]: 'registry',
|
|
175
|
+
[NAMZU.REGISTRY_NAME]: 'ToolManager',
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
this.resolveInitial()
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
for (const toolset of this.toolsets) {
|
|
182
|
+
const unsubscribe = toolset.onChange?.(() => {
|
|
183
|
+
if (!this.disposed) this.dirty = true
|
|
184
|
+
})
|
|
185
|
+
if (unsubscribe) this.unsubscribeToolsetChanges.push(unsubscribe)
|
|
186
|
+
}
|
|
187
|
+
} catch (error) {
|
|
188
|
+
// A later subscription can fail after earlier live toolsets subscribed.
|
|
189
|
+
this.dispose()
|
|
190
|
+
throw error
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** Stop observing live toolsets when this manager's owner finishes; the host owns their connections. */
|
|
195
|
+
dispose(): void {
|
|
196
|
+
if (this.disposed) return
|
|
197
|
+
this.disposed = true
|
|
198
|
+
for (const unsubscribe of this.unsubscribeToolsetChanges.splice(0).reverse()) {
|
|
199
|
+
try {
|
|
200
|
+
unsubscribe()
|
|
201
|
+
} catch (error) {
|
|
202
|
+
// A broken source must not prevent the other listeners (or the
|
|
203
|
+
// turn's recorder) from being released.
|
|
204
|
+
this.log.warn('Toolset change listener cleanup failed', {
|
|
205
|
+
'exception.message': toErrorMessage(error),
|
|
206
|
+
})
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// ---- Composition / membership ----------------------------------------
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* First resolution, at construction. Toolset order, then tool order,
|
|
215
|
+
* matching `combineToolsets` (`./combine.ts`) — a name contributed by two
|
|
216
|
+
* sources throws {@link ToolsetConflictError} naming both, because
|
|
217
|
+
* nothing has served anyone yet: unlike {@link refresh}, there is no
|
|
218
|
+
* incumbent to protect by refusing the newcomer instead.
|
|
219
|
+
*/
|
|
220
|
+
/**
|
|
221
|
+
* The checks `ToolRegistry.registerOne` used to run before admitting a
|
|
222
|
+
* tool, copied verbatim: a legal name; `enforceModelInput` requires a
|
|
223
|
+
* `modelInputSchema` (nothing to constrain generation against
|
|
224
|
+
* otherwise) and that schema must itself fit the strict-decoding subset
|
|
225
|
+
* `assertStrictSchema` checks (existing is not enough — it also has to
|
|
226
|
+
* be sendable); a declared `tier` must be one `this.tierConfig` lists.
|
|
227
|
+
*/
|
|
228
|
+
private assertAdmissible(tool: ToolDefinition): void {
|
|
229
|
+
assertToolName(tool.name)
|
|
230
|
+
if (tool.enforceModelInput && !tool.modelInputSchema) {
|
|
231
|
+
throw new Error(
|
|
232
|
+
`Tool "${tool.name}" enables enforceModelInput but does not define modelInputSchema. Constrained input generation requires an explicit provider-safe model schema.`,
|
|
233
|
+
)
|
|
234
|
+
}
|
|
235
|
+
if (tool.enforceModelInput) {
|
|
236
|
+
assertStrictSchema(tool.name, tool.modelInputSchema)
|
|
237
|
+
}
|
|
238
|
+
if (tool.tier && this.tierConfig) {
|
|
239
|
+
const validIds = this.tierConfig.tiers.map((t) => t.id)
|
|
240
|
+
if (!validIds.includes(tool.tier)) {
|
|
241
|
+
throw new Error(
|
|
242
|
+
`Tool "${tool.name}" has tier "${tool.tier}" which is not defined. Valid tiers: ${validIds.join(', ')}`,
|
|
243
|
+
)
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private resolveInitial(): void {
|
|
249
|
+
const toolsByName = new Map<string, ToolDefinition>()
|
|
250
|
+
const ownerToolsetByName = new Map<string, Toolset>()
|
|
251
|
+
const defaultAvailabilityByName = new Map<string, ToolsetAvailability>()
|
|
252
|
+
|
|
253
|
+
for (const toolset of this.toolsets) {
|
|
254
|
+
for (const tool of toolset.tools()) {
|
|
255
|
+
// The same admission checks `ToolRegistry.register` used to run
|
|
256
|
+
// (name legality, `enforceModelInput`'s two schema
|
|
257
|
+
// requirements, a declared tier's existence) — moved here
|
|
258
|
+
// rather than dropped when that class went away. "Fail where
|
|
259
|
+
// it can still be attributed" (at construction) instead of at
|
|
260
|
+
// the first request.
|
|
261
|
+
this.assertAdmissible(tool)
|
|
262
|
+
const existingOwner = ownerToolsetByName.get(tool.name)
|
|
263
|
+
if (existingOwner) {
|
|
264
|
+
throw new ToolsetConflictError(tool.name, existingOwner.source, toolset.source)
|
|
265
|
+
}
|
|
266
|
+
toolsByName.set(tool.name, tool)
|
|
267
|
+
ownerToolsetByName.set(tool.name, toolset)
|
|
268
|
+
defaultAvailabilityByName.set(tool.name, toolset.availability ?? 'active')
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
this.toolsByName = toolsByName
|
|
273
|
+
this.ownerToolsetByName = ownerToolsetByName
|
|
274
|
+
this.defaultAvailabilityByName = defaultAvailabilityByName
|
|
275
|
+
this.lastObservedByName = new Map(toolsByName)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Re-resolve iff a toolset signalled change (`onChange`) since
|
|
280
|
+
* construction or the last `refresh()` — otherwise returns `undefined`
|
|
281
|
+
* without re-walking anything, so a caller that refreshes every
|
|
282
|
+
* iteration boundary pays nothing on the common case where nothing
|
|
283
|
+
* changed.
|
|
284
|
+
*
|
|
285
|
+
* Three outcomes per name, matching plan.md §2:
|
|
286
|
+
* - A name only ONE current toolset contributes, that nobody served
|
|
287
|
+
* before: `added`.
|
|
288
|
+
* - A name a toolset served before and stopped, with no other toolset
|
|
289
|
+
* now contributing it: `removed`.
|
|
290
|
+
* - A name still contributed by its ORIGINAL owning toolset, under a
|
|
291
|
+
* `ToolDefinition` object different from the one that toolset returned
|
|
292
|
+
* the LAST time it was observed (construction, or the previous
|
|
293
|
+
* `refresh()`): `drifted` — the previously admitted definition keeps
|
|
294
|
+
* serving; the new object is held, not adopted, so `toolWireSchema`'s
|
|
295
|
+
* identity-keyed cache (see the class doc) survives a live toolset's
|
|
296
|
+
* own internal change. Comparing against the last OBSERVATION, not
|
|
297
|
+
* the served object, means a name that drifted once and has been
|
|
298
|
+
* stable since is reported only on the refresh where it actually
|
|
299
|
+
* changed, not again on every later refresh some unrelated toolset's
|
|
300
|
+
* change happens to trigger.
|
|
301
|
+
* - A name some OTHER toolset starts contributing while its incumbent
|
|
302
|
+
* owner still serves it: `refused` — the incumbent wins regardless of
|
|
303
|
+
* toolset order; the newcomer is reported, never applied.
|
|
304
|
+
*/
|
|
305
|
+
refresh(): ToolsetChangeReport | undefined {
|
|
306
|
+
if (!this.dirty) return undefined
|
|
307
|
+
this.dirty = false
|
|
308
|
+
|
|
309
|
+
const current = this.toolsets.map((toolset) => ({
|
|
310
|
+
toolset,
|
|
311
|
+
tools: toolset.tools(),
|
|
312
|
+
}))
|
|
313
|
+
const nextToolsByName = new Map<string, ToolDefinition>()
|
|
314
|
+
const nextOwnerByName = new Map<string, Toolset>()
|
|
315
|
+
const nextDefaultAvailabilityByName = new Map<string, ToolsetAvailability>()
|
|
316
|
+
const nextLastObservedByName = new Map<string, ToolDefinition>()
|
|
317
|
+
const added: string[] = []
|
|
318
|
+
const drifted: string[] = []
|
|
319
|
+
const refused: { name: string; reason: string }[] = []
|
|
320
|
+
|
|
321
|
+
// Pass 1: every incumbent whose OWN owning toolset still offers it
|
|
322
|
+
// keeps its slot — held at its OLD object identity even if the fresh
|
|
323
|
+
// one differs (drift), so a live toolset's own change never bumps an
|
|
324
|
+
// unrelated newcomer ahead of it, and never busts the wire-schema
|
|
325
|
+
// identity cache mid-turn. Drift is judged against the last fresh
|
|
326
|
+
// observation, not the held object, and that observation is updated
|
|
327
|
+
// unconditionally so a name that just drifted is not drifted again
|
|
328
|
+
// next time nothing about it has changed.
|
|
329
|
+
for (const [name, ownerToolset] of this.ownerToolsetByName) {
|
|
330
|
+
const ownerEntry = current.find((entry) => entry.toolset === ownerToolset)
|
|
331
|
+
const freshTool = ownerEntry?.tools.find((tool) => tool.name === name)
|
|
332
|
+
if (!freshTool) continue // handled as `removed` below, unless re-added by pass 2
|
|
333
|
+
const oldTool = this.toolsByName.get(name)
|
|
334
|
+
const lastObserved = this.lastObservedByName.get(name)
|
|
335
|
+
if (lastObserved && freshTool !== lastObserved) drifted.push(name)
|
|
336
|
+
nextToolsByName.set(name, oldTool ?? freshTool)
|
|
337
|
+
nextOwnerByName.set(name, ownerToolset)
|
|
338
|
+
nextDefaultAvailabilityByName.set(name, ownerToolset.availability ?? 'active')
|
|
339
|
+
nextLastObservedByName.set(name, freshTool)
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Pass 2: walk every toolset, in order, for names no incumbent
|
|
343
|
+
// claimed above. First writer among the CURRENTLY offered names wins;
|
|
344
|
+
// anything already claimed here was necessarily claimed by pass 1
|
|
345
|
+
// (an incumbent), so this can only ever refuse a newcomer, never an
|
|
346
|
+
// incumbent.
|
|
347
|
+
for (const { toolset, tools } of current) {
|
|
348
|
+
for (const tool of tools) {
|
|
349
|
+
const claimedBy = nextOwnerByName.get(tool.name)
|
|
350
|
+
if (claimedBy) {
|
|
351
|
+
if (claimedBy !== toolset) {
|
|
352
|
+
refused.push({
|
|
353
|
+
name: tool.name,
|
|
354
|
+
reason: `tool "${tool.name}" is already served by "${claimedBy.source.id}"; "${toolset.source.id}" was refused. Rename it, or wrap the newcomer with prefixed(toolset, prefix).`,
|
|
355
|
+
})
|
|
356
|
+
}
|
|
357
|
+
continue
|
|
358
|
+
}
|
|
359
|
+
nextToolsByName.set(tool.name, tool)
|
|
360
|
+
nextOwnerByName.set(tool.name, toolset)
|
|
361
|
+
nextDefaultAvailabilityByName.set(tool.name, toolset.availability ?? 'active')
|
|
362
|
+
nextLastObservedByName.set(tool.name, tool)
|
|
363
|
+
added.push(tool.name)
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const removed = [...this.toolsByName.keys()].filter((name) => !nextToolsByName.has(name))
|
|
368
|
+
|
|
369
|
+
this.toolsByName = nextToolsByName
|
|
370
|
+
this.ownerToolsetByName = nextOwnerByName
|
|
371
|
+
this.defaultAvailabilityByName = nextDefaultAvailabilityByName
|
|
372
|
+
this.lastObservedByName = nextLastObservedByName
|
|
373
|
+
|
|
374
|
+
return { added, removed, drifted, refused }
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
has(name: string): boolean {
|
|
378
|
+
return this.toolsByName.has(name)
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
get(name: string): ToolDefinition | undefined {
|
|
382
|
+
return this.toolsByName.get(name)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
listNames(): string[] {
|
|
386
|
+
return [...this.toolsByName.keys()]
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/** Where `name` came from. Throws for an unknown name, like {@link getOrThrow}. */
|
|
390
|
+
sourceOf(name: string): ToolSourceRef {
|
|
391
|
+
const ownerToolset = this.ownerToolsetByName.get(name)
|
|
392
|
+
if (!ownerToolset) {
|
|
393
|
+
throw new Error(`Not found: "${name}". Available: ${this.listNames().join(', ')}`)
|
|
394
|
+
}
|
|
395
|
+
return toToolSourceRef(ownerToolset.source)
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
private getOrThrow(name: string): ToolDefinition {
|
|
399
|
+
const tool = this.toolsByName.get(name)
|
|
400
|
+
if (!tool) {
|
|
401
|
+
throw new Error(`Not found: "${name}". Available: ${this.listNames().join(', ')}`)
|
|
402
|
+
}
|
|
403
|
+
return tool
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// ---- Availability (derived) -------------------------------------------
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* `'suspended'` when the owning toolset is unready; otherwise `'deferred'`
|
|
410
|
+
* when it declared deferred and no matching receipt exists in the
|
|
411
|
+
* post-compaction history; otherwise `'active'`.
|
|
412
|
+
*
|
|
413
|
+
* Nothing here is stored: this is a pure read of the toolset's own
|
|
414
|
+
* declaration plus a scan of `messages()`, recomputed on every call — the
|
|
415
|
+
* same "safe to call repeatedly, byte-identical between calls" property
|
|
416
|
+
* `toLLMTools` already has. The scan is bounded to the window AFTER the
|
|
417
|
+
* last compaction summary (`compaction/summary.ts`'s
|
|
418
|
+
* `isCompactionMessage` — the one marker a compacted history carries, a
|
|
419
|
+
* system message whose content starts with `COMPACTION_HEADER`):
|
|
420
|
+
* compaction is the one deliberate "forget" boundary a derivation like
|
|
421
|
+
* this one needs, the same way it is the one boundary namzu's own
|
|
422
|
+
* summarisation treats as a reset. A tool message's own `revealedTools`
|
|
423
|
+
* (`types/message/index.ts`) is written by the executor from
|
|
424
|
+
* `ToolResult.reveals`, persisted like any other message field — there is
|
|
425
|
+
* no separate store to keep in sync, restore on resume, or lose across a
|
|
426
|
+
* fork.
|
|
427
|
+
*/
|
|
428
|
+
availability(name: string): ToolAvailability {
|
|
429
|
+
const owner = this.ownerToolsetByName.get(name)
|
|
430
|
+
if (owner && !toolsetIsReady(owner)) return 'suspended'
|
|
431
|
+
const declared = this.defaultAvailabilityByName.get(name) ?? 'active'
|
|
432
|
+
if (declared === 'active') return 'active'
|
|
433
|
+
return this.wasRevealed(name) ? 'active' : 'deferred'
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
private wasRevealed(name: string): boolean {
|
|
437
|
+
const owner = this.ownerToolsetByName.get(name)
|
|
438
|
+
if (!owner) return false
|
|
439
|
+
const window = postCompactionWindow(this.messagesAccessor())
|
|
440
|
+
for (const message of window) {
|
|
441
|
+
if (
|
|
442
|
+
message.role === 'tool' &&
|
|
443
|
+
!message.isError &&
|
|
444
|
+
message.revealedTools?.some(
|
|
445
|
+
(receipt) =>
|
|
446
|
+
receipt.name === name &&
|
|
447
|
+
receipt.sourceId === owner.source.id &&
|
|
448
|
+
receipt.sourceKind === owner.source.kind,
|
|
449
|
+
)
|
|
450
|
+
)
|
|
451
|
+
return true
|
|
452
|
+
}
|
|
453
|
+
return false
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/** Bind a reveal to the source currently serving the named tool. */
|
|
457
|
+
revealReceipt(name: string): ToolRevealReceipt {
|
|
458
|
+
const source = this.sourceOf(name)
|
|
459
|
+
return { name, sourceId: source.id, sourceKind: source.kind }
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
private getByAvailability(
|
|
463
|
+
states: readonly ToolAvailability[],
|
|
464
|
+
filter?: readonly string[],
|
|
465
|
+
): ToolDefinition[] {
|
|
466
|
+
const candidates = filter
|
|
467
|
+
? filter.map((name) => this.getOrThrow(name))
|
|
468
|
+
: [...this.toolsByName.values()]
|
|
469
|
+
return candidates.filter((tool) => states.includes(this.availability(tool.name)))
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// ---- Discovery ----------------------------------------------------------
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Ranked lexical search over deferred tools — same scoring
|
|
476
|
+
* `ToolRegistry.searchDeferred` used (exact name 12 / name-substring 8 /
|
|
477
|
+
* description 5 / argument-name 3, generic tokens stopped), extended
|
|
478
|
+
* with an optional cap so a caller does not have to slice the result
|
|
479
|
+
* itself.
|
|
480
|
+
*/
|
|
481
|
+
searchDeferred(query: string, limit?: number): readonly ToolDefinition[] {
|
|
482
|
+
const results = this.searchByAvailability(query, 'deferred')
|
|
483
|
+
return limit === undefined ? results : results.slice(0, limit)
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
private searchByAvailability(query: string, state: ToolsetAvailability): ToolDefinition[] {
|
|
487
|
+
const q = query.toLowerCase().trim()
|
|
488
|
+
if (q.length === 0) return []
|
|
489
|
+
const terms = q.split(/\s+/).filter((tok) => tok.length >= 3 && !SEARCH_STOP_TOKENS.has(tok))
|
|
490
|
+
|
|
491
|
+
const scored: Array<{ tool: ToolDefinition; score: number }> = []
|
|
492
|
+
for (const tool of this.toolsByName.values()) {
|
|
493
|
+
if (this.availability(tool.name) !== state) continue
|
|
494
|
+
const name = tool.name.toLowerCase()
|
|
495
|
+
const description = tool.description.toLowerCase()
|
|
496
|
+
const argumentNames = listArgumentNames(tool)
|
|
497
|
+
let score = terms.length === 0 && name === q ? SEARCH_WEIGHT_NAME_EXACT : 0
|
|
498
|
+
for (const term of terms) {
|
|
499
|
+
if (name === term) {
|
|
500
|
+
score += SEARCH_WEIGHT_NAME_EXACT
|
|
501
|
+
} else if (name.includes(term)) {
|
|
502
|
+
score += SEARCH_WEIGHT_NAME_PARTIAL
|
|
503
|
+
}
|
|
504
|
+
if (description.includes(term)) {
|
|
505
|
+
score += SEARCH_WEIGHT_DESCRIPTION
|
|
506
|
+
}
|
|
507
|
+
if (argumentNames.some((arg) => arg.includes(term))) {
|
|
508
|
+
score += SEARCH_WEIGHT_ARGUMENT
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
if (score > 0) scored.push({ tool, score })
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
scored.sort((a, b) => b.score - a.score || a.tool.name.localeCompare(b.tool.name))
|
|
515
|
+
return scored.map((entry) => entry.tool)
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// ---- Rendering to the model ----------------------------------------------
|
|
519
|
+
|
|
520
|
+
toLLMTools(names?: readonly string[]): LLMToolSchema[] {
|
|
521
|
+
const tools = this.getByAvailability(['active'], names)
|
|
522
|
+
return tools.map((tool) => {
|
|
523
|
+
let description = tool.description
|
|
524
|
+
if (this.tierConfig?.labelInDescription && tool.tier) {
|
|
525
|
+
const tierDef = this.tierConfig.tiers.find((t) => t.id === tool.tier)
|
|
526
|
+
if (tierDef) description = `[${tierDef.label}] ${description}`
|
|
527
|
+
}
|
|
528
|
+
return {
|
|
529
|
+
type: 'function' as const,
|
|
530
|
+
function: {
|
|
531
|
+
name: tool.name,
|
|
532
|
+
description: describeWithOutput(description, tool.outputSchema),
|
|
533
|
+
parameters: toolWireSchema(tool),
|
|
534
|
+
},
|
|
535
|
+
}
|
|
536
|
+
})
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
toPromptSection(names?: readonly string[]): string {
|
|
540
|
+
const active = this.getByAvailability(['active'], names)
|
|
541
|
+
const deferred = this.getByAvailability(['deferred'], names)
|
|
542
|
+
|
|
543
|
+
const parts: string[] = []
|
|
544
|
+
const contractNote = `<tool_runtime_contract>
|
|
545
|
+
Executable tool names, descriptions, and JSON input schemas are attached through the runtime tools parameter. Treat that runtime schema as authoritative; this prompt section is a discoverability summary only.
|
|
546
|
+
</tool_runtime_contract>`
|
|
547
|
+
|
|
548
|
+
if (active.length > 0) {
|
|
549
|
+
const entries = active.map((t) => `- ${t.name}`).join('\n')
|
|
550
|
+
parts.push(`<available_tools>\n${entries}\n</available_tools>`)
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
if (deferred.length > 0) {
|
|
554
|
+
const entries = deferred
|
|
555
|
+
.map((t) => {
|
|
556
|
+
const hint = toolDiscoveryHint(t.description)
|
|
557
|
+
return hint.length > 0 ? `- ${t.name}: ${hint}` : `- ${t.name}`
|
|
558
|
+
})
|
|
559
|
+
.join('\n')
|
|
560
|
+
const deferredIntro =
|
|
561
|
+
this.has('search_tools') &&
|
|
562
|
+
this.availability('search_tools') === 'active' &&
|
|
563
|
+
(!names || names.includes('search_tools'))
|
|
564
|
+
? 'Use search_tools to load these before use:'
|
|
565
|
+
: 'Deferred tools are discoverable but not executable until the runtime activates them:'
|
|
566
|
+
parts.push(`<deferred_tools>\n${deferredIntro}\n${entries}\n</deferred_tools>`)
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
if (parts.length === 0) return ''
|
|
570
|
+
return [contractNote, ...parts].join('\n\n')
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
toTierGuidance(): string | null {
|
|
574
|
+
if (!this.tierConfig?.guidanceTemplate) return null
|
|
575
|
+
return this.tierConfig.guidanceTemplate(this.tierConfig.tiers)
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// ---- Narrow live view for a running tool's own `execute()` --------------
|
|
579
|
+
|
|
580
|
+
/** What `ToolContext` gives a running tool: read-only, no mutation. */
|
|
581
|
+
view(): ToolsView {
|
|
582
|
+
return {
|
|
583
|
+
has: (name) => this.has(name),
|
|
584
|
+
availability: (name) => this.availability(name),
|
|
585
|
+
searchDeferred: (query, limit) => this.searchDeferred(query, limit),
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// ---- Execution pipeline ---------------------------------------------
|
|
590
|
+
//
|
|
591
|
+
// Copied from `ToolRegistry` (`registry/tool/execute.ts:475-791`) per
|
|
592
|
+
// plan.md §2. See the class doc for the three permitted substitutions;
|
|
593
|
+
// everything else — order of checks, messages, the WeakMap ownership and
|
|
594
|
+
// staleness re-check, the halt/fail distinction, the explicit parent
|
|
595
|
+
// span — is unchanged.
|
|
596
|
+
|
|
597
|
+
prepareExecution(toolName: string, rawInput: unknown): ToolPreparationResult {
|
|
598
|
+
const tool = this.getOrThrow(toolName)
|
|
599
|
+
const parseResult = tool.inputSchema.safeParse(rawInput)
|
|
600
|
+
if (!parseResult.success) {
|
|
601
|
+
return {
|
|
602
|
+
success: false,
|
|
603
|
+
result: this.validationFailure(tool, rawInput, parseResult.error),
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
let retainedInput: unknown
|
|
608
|
+
let reviewInput: unknown
|
|
609
|
+
try {
|
|
610
|
+
retainedInput = clonePreparedInput(parseResult.data, false)
|
|
611
|
+
reviewInput = clonePreparedInput(retainedInput, true)
|
|
612
|
+
} catch (err) {
|
|
613
|
+
const message = `Tool "${toolName}" produced an input that cannot be safely prepared for review and execution: ${toErrorMessage(err)}`
|
|
614
|
+
this.log.error('Prepared tool input could not be detached for review and execution', {
|
|
615
|
+
'namzu.tool.name': toolName,
|
|
616
|
+
'exception.message': toErrorMessage(err),
|
|
617
|
+
})
|
|
618
|
+
return {
|
|
619
|
+
success: false,
|
|
620
|
+
result: { success: false, output: '', error: message },
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
const prepared = Object.freeze({ toolName, input: reviewInput })
|
|
625
|
+
this.preparations.set(prepared, { tool, input: retainedInput })
|
|
626
|
+
return { success: true, prepared }
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
async executePrepared(
|
|
630
|
+
prepared: PreparedToolExecution,
|
|
631
|
+
context: ToolContext,
|
|
632
|
+
): Promise<ToolExecutionResult> {
|
|
633
|
+
const retained = this.preparations.get(prepared)
|
|
634
|
+
if (!retained) {
|
|
635
|
+
return {
|
|
636
|
+
success: false,
|
|
637
|
+
output: '',
|
|
638
|
+
error: `Tool "${prepared.toolName}" preparation is not owned by this registry or is no longer valid.`,
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
if (this.toolsByName.get(prepared.toolName) !== retained.tool) {
|
|
642
|
+
return {
|
|
643
|
+
success: false,
|
|
644
|
+
output: '',
|
|
645
|
+
error: `Tool "${prepared.toolName}" changed after its input was reviewed; prepare the call again.`,
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
return this.executeRetained(prepared.toolName, retained.tool, retained.input, context)
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
async execute(
|
|
652
|
+
toolName: string,
|
|
653
|
+
rawInput: unknown,
|
|
654
|
+
context: ToolContext,
|
|
655
|
+
): Promise<ToolExecutionResult> {
|
|
656
|
+
let preparation: ToolPreparationResult
|
|
657
|
+
try {
|
|
658
|
+
preparation = this.prepareExecution(toolName, rawInput)
|
|
659
|
+
} catch (err) {
|
|
660
|
+
return this.rejectPreparationWithClosedSpan(toolName, context, err)
|
|
661
|
+
}
|
|
662
|
+
if (!preparation.success) return preparation.result
|
|
663
|
+
return this.executePrepared(preparation.prepared, context)
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
private rejectPreparationWithClosedSpan(
|
|
667
|
+
toolName: string,
|
|
668
|
+
context: ToolContext,
|
|
669
|
+
err: unknown,
|
|
670
|
+
): Promise<never> {
|
|
671
|
+
const tracer = getTracer()
|
|
672
|
+
const parentCtx = context.parentSpan
|
|
673
|
+
? trace.setSpan(otelContext.active(), context.parentSpan)
|
|
674
|
+
: otelContext.active()
|
|
675
|
+
return tracer.startActiveSpan(toolSpanName(toolName), {}, parentCtx, async (span) => {
|
|
676
|
+
try {
|
|
677
|
+
span.setAttributes({
|
|
678
|
+
[GENAI.TOOL_NAME]: toolName,
|
|
679
|
+
[GENAI.TOOL_TYPE]: 'function',
|
|
680
|
+
...(context.toolUseId !== undefined ? { [GENAI.TOOL_CALL_ID]: context.toolUseId } : {}),
|
|
681
|
+
...toolSpanIdentity(context),
|
|
682
|
+
[NAMZU.TOOL_SUCCESS]: false,
|
|
683
|
+
[NAMZU.TOOL_ERROR]: toErrorMessage(err),
|
|
684
|
+
})
|
|
685
|
+
span.setStatus({
|
|
686
|
+
code: SpanStatusCode.ERROR,
|
|
687
|
+
message: toErrorMessage(err),
|
|
688
|
+
})
|
|
689
|
+
throw err
|
|
690
|
+
} finally {
|
|
691
|
+
span.end()
|
|
692
|
+
}
|
|
693
|
+
})
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
private async executeRetained(
|
|
697
|
+
toolName: string,
|
|
698
|
+
tool: ToolDefinition,
|
|
699
|
+
finalInput: unknown,
|
|
700
|
+
context: ToolContext,
|
|
701
|
+
): Promise<ToolExecutionResult> {
|
|
702
|
+
const tracer = getTracer()
|
|
703
|
+
// The permitted `tool.provenance` substitution: a lean per-tool source
|
|
704
|
+
// pointer from the OWNING toolset, computed once per call, rather than
|
|
705
|
+
// something stamped onto the shared `ToolDefinition` object.
|
|
706
|
+
const source = this.sourceOf(toolName)
|
|
707
|
+
|
|
708
|
+
const parentCtx = context.parentSpan
|
|
709
|
+
? trace.setSpan(otelContext.active(), context.parentSpan)
|
|
710
|
+
: otelContext.active()
|
|
711
|
+
|
|
712
|
+
return tracer.startActiveSpan(toolSpanName(toolName), {}, parentCtx, async (span) => {
|
|
713
|
+
try {
|
|
714
|
+
span.setAttributes({
|
|
715
|
+
[GENAI.TOOL_NAME]: toolName,
|
|
716
|
+
[GENAI.TOOL_TYPE]: 'function',
|
|
717
|
+
...(context.toolUseId !== undefined ? { [GENAI.TOOL_CALL_ID]: context.toolUseId } : {}),
|
|
718
|
+
...toolSpanIdentity(context),
|
|
719
|
+
})
|
|
720
|
+
|
|
721
|
+
// The permitted `this.getAvailability` substitution: derived,
|
|
722
|
+
// not read off a stored map. See `availability` above.
|
|
723
|
+
const availability = this.availability(toolName)
|
|
724
|
+
if (availability !== 'active') {
|
|
725
|
+
const msg = `Tool "${toolName}" is ${availability} and cannot be executed`
|
|
726
|
+
this.log.warn(msg)
|
|
727
|
+
span.setAttributes({
|
|
728
|
+
[NAMZU.TOOL_SUCCESS]: false,
|
|
729
|
+
[NAMZU.TOOL_ERROR]: msg,
|
|
730
|
+
})
|
|
731
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: msg })
|
|
732
|
+
return {
|
|
733
|
+
success: false,
|
|
734
|
+
output: '',
|
|
735
|
+
error: msg,
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
const allowed = context.allowedTools
|
|
740
|
+
if (allowed !== undefined && !allowed.includes(toolName)) {
|
|
741
|
+
const msg = `Tool "${toolName}" is not available on this step. Available: ${formatToolNames(callableToolNames(this, allowed))}`
|
|
742
|
+
this.log.warn('Blocked a tool outside the step allow-list', {
|
|
743
|
+
[GENAI.TOOL_NAME]: toolName,
|
|
744
|
+
'namzu.registry.allowed': allowed.length,
|
|
745
|
+
})
|
|
746
|
+
span.setAttributes({
|
|
747
|
+
[NAMZU.TOOL_SUCCESS]: false,
|
|
748
|
+
[NAMZU.TOOL_ERROR]: msg,
|
|
749
|
+
})
|
|
750
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: msg })
|
|
751
|
+
return {
|
|
752
|
+
success: false,
|
|
753
|
+
output: '',
|
|
754
|
+
error: msg,
|
|
755
|
+
permissionDenied: true,
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
const mode = context.permissionContext?.mode ?? 'auto'
|
|
760
|
+
if (mode === 'plan') {
|
|
761
|
+
const isReadOnly = isTrustedReadOnly(tool, finalInput, source)
|
|
762
|
+
if (!isReadOnly) {
|
|
763
|
+
const msg = `plan mode: non-read-only tool "${toolName}" blocked. ${PLAN_MODE_REFUSAL}`
|
|
764
|
+
span.setAttributes({
|
|
765
|
+
[NAMZU.TOOL_SUCCESS]: false,
|
|
766
|
+
[NAMZU.TOOL_ERROR]: msg,
|
|
767
|
+
})
|
|
768
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: msg })
|
|
769
|
+
return {
|
|
770
|
+
success: false,
|
|
771
|
+
output: '',
|
|
772
|
+
error: msg,
|
|
773
|
+
permissionDenied: true,
|
|
774
|
+
permissionMessage: msg,
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
try {
|
|
780
|
+
this.log.debug('Executing tool', { 'namzu.tool.name': toolName })
|
|
781
|
+
const startedAt = Date.now()
|
|
782
|
+
const runResultGuardrails = context.toolResultGuardrails
|
|
783
|
+
const produced = await tool.execute(finalInput, context)
|
|
784
|
+
const provenance = sourceToProvenance(source)
|
|
785
|
+
const result = await screenToolResult(
|
|
786
|
+
this.resultGuardrails ?? runResultGuardrails,
|
|
787
|
+
produced,
|
|
788
|
+
{
|
|
789
|
+
toolName,
|
|
790
|
+
input: finalInput,
|
|
791
|
+
...(provenance ? { provenance } : {}),
|
|
792
|
+
},
|
|
793
|
+
this.log,
|
|
794
|
+
)
|
|
795
|
+
const durationMs = Date.now() - startedAt
|
|
796
|
+
this.log.debug('Tool completed', {
|
|
797
|
+
'namzu.tool.name': toolName,
|
|
798
|
+
'namzu.registry.success': result.success,
|
|
799
|
+
})
|
|
800
|
+
|
|
801
|
+
span.setAttribute(NAMZU.TOOL_SUCCESS, result.success)
|
|
802
|
+
recordToolCall(
|
|
803
|
+
toolName,
|
|
804
|
+
result.success,
|
|
805
|
+
result.success ? undefined : result.error,
|
|
806
|
+
durationMs,
|
|
807
|
+
)
|
|
808
|
+
if (!result.success && result.error) {
|
|
809
|
+
span.setAttribute(NAMZU.TOOL_ERROR, result.error)
|
|
810
|
+
span.setStatus({
|
|
811
|
+
code: SpanStatusCode.ERROR,
|
|
812
|
+
message: result.error,
|
|
813
|
+
})
|
|
814
|
+
} else {
|
|
815
|
+
span.setStatus({ code: SpanStatusCode.OK })
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
return result
|
|
819
|
+
} catch (err) {
|
|
820
|
+
if (err instanceof ToolResultHalted) {
|
|
821
|
+
span.setAttributes({
|
|
822
|
+
[NAMZU.TOOL_SUCCESS]: false,
|
|
823
|
+
[NAMZU.TOOL_ERROR]: err.message,
|
|
824
|
+
})
|
|
825
|
+
span.setStatus({
|
|
826
|
+
code: SpanStatusCode.ERROR,
|
|
827
|
+
message: err.message,
|
|
828
|
+
})
|
|
829
|
+
throw err
|
|
830
|
+
}
|
|
831
|
+
const errorMessage = toErrorMessage(err)
|
|
832
|
+
this.log.error('Tool execution error', {
|
|
833
|
+
'namzu.tool.name': toolName,
|
|
834
|
+
'exception.message': errorMessage,
|
|
835
|
+
})
|
|
836
|
+
|
|
837
|
+
span.setAttributes({
|
|
838
|
+
[NAMZU.TOOL_SUCCESS]: false,
|
|
839
|
+
[NAMZU.TOOL_ERROR]: errorMessage,
|
|
840
|
+
})
|
|
841
|
+
span.setStatus({
|
|
842
|
+
code: SpanStatusCode.ERROR,
|
|
843
|
+
message: errorMessage,
|
|
844
|
+
})
|
|
845
|
+
span.recordException(err instanceof Error ? err : new Error(errorMessage))
|
|
846
|
+
|
|
847
|
+
return {
|
|
848
|
+
success: false,
|
|
849
|
+
output: '',
|
|
850
|
+
error: `Tool "${toolName}" execution failed: ${errorMessage}`,
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
} finally {
|
|
854
|
+
span.end()
|
|
855
|
+
}
|
|
856
|
+
})
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
private validationFailure(
|
|
860
|
+
tool: ToolDefinition,
|
|
861
|
+
rawInput: unknown,
|
|
862
|
+
error: {
|
|
863
|
+
readonly issues: readonly {
|
|
864
|
+
readonly path: readonly PropertyKey[]
|
|
865
|
+
readonly message: string
|
|
866
|
+
}[]
|
|
867
|
+
},
|
|
868
|
+
): ToolExecutionResult {
|
|
869
|
+
const errorMessage = error.issues
|
|
870
|
+
.map((issue) => `${issue.path.join('.')}: ${issue.message}`)
|
|
871
|
+
.join('; ')
|
|
872
|
+
const isEmptyInput =
|
|
873
|
+
rawInput === null ||
|
|
874
|
+
rawInput === undefined ||
|
|
875
|
+
(typeof rawInput === 'object' &&
|
|
876
|
+
!Array.isArray(rawInput) &&
|
|
877
|
+
Object.keys(rawInput as Record<string, unknown>).length === 0)
|
|
878
|
+
const requiredHint = describeRequiredInput(tool.inputSchema)
|
|
879
|
+
const recoveryHint = tool.validationErrorHint?.trim()
|
|
880
|
+
? ` ${tool.validationErrorHint.trim()}`
|
|
881
|
+
: ''
|
|
882
|
+
const enrichedMessage = isEmptyInput
|
|
883
|
+
? `Tool "${tool.name}" was called with no arguments. ${requiredHint}${recoveryHint} Retry the call with the required parameters populated.`
|
|
884
|
+
: `Validation failed for "${tool.name}": ${errorMessage}. ${requiredHint}${recoveryHint}`
|
|
885
|
+
this.log.error('Tool input validation failed', {
|
|
886
|
+
'namzu.tool.name': tool.name,
|
|
887
|
+
'namzu.registry.errors': errorMessage,
|
|
888
|
+
'namzu.registry.empty': isEmptyInput,
|
|
889
|
+
})
|
|
890
|
+
return { success: false, output: '', error: enrichedMessage }
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
/**
|
|
895
|
+
* The session and turn a tool span belongs to, copied from
|
|
896
|
+
* `registry/tool/execute.ts`'s identically named private function.
|
|
897
|
+
*/
|
|
898
|
+
function toolSpanIdentity(context: ToolContext): Record<string, string> {
|
|
899
|
+
return {
|
|
900
|
+
...(context.sessionId ? { [GENAI.CONVERSATION_ID]: context.sessionId } : {}),
|
|
901
|
+
...(context.turnId ? { [NAMZU.TURN_ID]: context.turnId } : {}),
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/** Project a `ToolSourceRef` to the `ToolProvenance` shape `screenToolResult` reads, for MCP-kind sources only. */
|
|
906
|
+
function sourceToProvenance(source: ToolSourceRef): ToolProvenance | undefined {
|
|
907
|
+
if (source.kind !== 'mcp_server') return undefined
|
|
908
|
+
return {
|
|
909
|
+
server: source.server ?? source.id,
|
|
910
|
+
readOnlyHintTrusted: source.readOnlyHintTrusted ?? false,
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* Every message after the last compaction summary. `isCompactionMessage`
|
|
916
|
+
* (`compaction/summary.ts`) is the one marker a compacted history carries: a
|
|
917
|
+
* system message whose content starts with `COMPACTION_HEADER`. No such
|
|
918
|
+
* message means nothing has been compacted yet, so the whole history is the
|
|
919
|
+
* window.
|
|
920
|
+
*/
|
|
921
|
+
function postCompactionWindow(messages: readonly Message[]): readonly Message[] {
|
|
922
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
923
|
+
const message = messages[i]
|
|
924
|
+
if (message?.role === 'system' && isCompactionMessage(message.content)) {
|
|
925
|
+
return messages.slice(i + 1)
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
return messages
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
/**
|
|
932
|
+
* Lower-cased argument (property) names of a tool's input schema, copied
|
|
933
|
+
* from `registry/tool/execute.ts`'s identically named private function
|
|
934
|
+
* (used by `searchByAvailability`'s ranking).
|
|
935
|
+
*/
|
|
936
|
+
function listArgumentNames(tool: ToolDefinition): string[] {
|
|
937
|
+
try {
|
|
938
|
+
const json = tool.modelInputSchema ?? renderToolSchema(tool.inputSchema)
|
|
939
|
+
return [...collectSchemaPropertyNames(json)].map((key) => key.toLowerCase())
|
|
940
|
+
} catch {
|
|
941
|
+
return []
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
/**
|
|
946
|
+
* Every property name a schema can accept, including ones that only appear
|
|
947
|
+
* inside a branch. Copied from `registry/tool/execute.ts`'s identically
|
|
948
|
+
* named private function.
|
|
949
|
+
*/
|
|
950
|
+
function collectSchemaPropertyNames(
|
|
951
|
+
schema: unknown,
|
|
952
|
+
names: Set<string> = new Set(),
|
|
953
|
+
seen: Set<object> = new Set(),
|
|
954
|
+
): Set<string> {
|
|
955
|
+
if (!schema || typeof schema !== 'object' || Array.isArray(schema)) return names
|
|
956
|
+
if (seen.has(schema)) return names
|
|
957
|
+
seen.add(schema)
|
|
958
|
+
|
|
959
|
+
const record = schema as Record<string, unknown>
|
|
960
|
+
const properties = record.properties
|
|
961
|
+
if (properties && typeof properties === 'object' && !Array.isArray(properties)) {
|
|
962
|
+
for (const name of Object.keys(properties)) names.add(name)
|
|
963
|
+
}
|
|
964
|
+
for (const keyword of ['anyOf', 'oneOf', 'allOf'] as const) {
|
|
965
|
+
const branches = record[keyword]
|
|
966
|
+
if (!Array.isArray(branches)) continue
|
|
967
|
+
for (const branch of branches) collectSchemaPropertyNames(branch, names, seen)
|
|
968
|
+
}
|
|
969
|
+
return names
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
/**
|
|
973
|
+
* Build a one-sentence "Required: <field>: <type>, …" validation hint.
|
|
974
|
+
* Copied from `registry/tool/execute.ts`'s identically named private
|
|
975
|
+
* function.
|
|
976
|
+
*/
|
|
977
|
+
function describeRequiredInput(schema: { _def?: unknown }): string {
|
|
978
|
+
try {
|
|
979
|
+
const json = renderToolSchema(schema as never) as {
|
|
980
|
+
properties?: Record<string, { type?: string; description?: string }>
|
|
981
|
+
required?: string[]
|
|
982
|
+
}
|
|
983
|
+
const required = json.required ?? []
|
|
984
|
+
if (required.length === 0) return 'No required parameters known.'
|
|
985
|
+
const props = json.properties ?? {}
|
|
986
|
+
const lines = required.map((name) => {
|
|
987
|
+
const def = props[name] ?? {}
|
|
988
|
+
const type = def.type ?? 'value'
|
|
989
|
+
const desc = def.description ? ` — ${def.description}` : ''
|
|
990
|
+
return `${name}: ${type}${desc}`
|
|
991
|
+
})
|
|
992
|
+
return `Required: ${lines.join(', ')}.`
|
|
993
|
+
} catch {
|
|
994
|
+
return 'Could not introspect required parameters.'
|
|
995
|
+
}
|
|
996
|
+
}
|