@namzu/sdk 0.6.0 → 1.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 +529 -0
- package/dist/advisory/executor.d.ts.map +1 -1
- package/dist/advisory/executor.js +9 -2
- package/dist/advisory/executor.js.map +1 -1
- package/dist/advisory/executor.test.d.ts +2 -1
- package/dist/advisory/executor.test.d.ts.map +1 -1
- package/dist/advisory/executor.test.js +7 -4
- package/dist/advisory/executor.test.js.map +1 -1
- package/dist/agents/ReactiveAgent.d.ts.map +1 -1
- package/dist/agents/ReactiveAgent.js +7 -0
- package/dist/agents/ReactiveAgent.js.map +1 -1
- package/dist/agents/SupervisorAgent.d.ts +22 -1
- package/dist/agents/SupervisorAgent.d.ts.map +1 -1
- package/dist/agents/SupervisorAgent.js +54 -14
- package/dist/agents/SupervisorAgent.js.map +1 -1
- package/dist/agents/__tests__/supervisor-ledger.test.d.ts +2 -0
- package/dist/agents/__tests__/supervisor-ledger.test.d.ts.map +1 -0
- package/dist/agents/__tests__/supervisor-ledger.test.js +131 -0
- package/dist/agents/__tests__/supervisor-ledger.test.js.map +1 -0
- package/dist/bridge/sse/mapper.test.js +2 -2
- package/dist/config/runtime.d.ts +24 -0
- package/dist/config/runtime.d.ts.map +1 -1
- package/dist/config/runtime.js +9 -0
- package/dist/config/runtime.js.map +1 -1
- package/dist/connector/builtins/webhook.test.js +17 -0
- package/dist/connector/builtins/webhook.test.js.map +1 -1
- package/dist/connector/index.d.ts +1 -0
- package/dist/connector/index.d.ts.map +1 -1
- package/dist/connector/index.js +1 -0
- package/dist/connector/index.js.map +1 -1
- package/dist/connector/mcp/client.d.ts.map +1 -1
- package/dist/connector/mcp/client.js +4 -0
- package/dist/connector/mcp/client.js.map +1 -1
- package/dist/connector/mcp/index.d.ts +1 -0
- package/dist/connector/mcp/index.d.ts.map +1 -1
- package/dist/connector/mcp/index.js +1 -0
- package/dist/connector/mcp/index.js.map +1 -1
- package/dist/connector/mcp/streamable-http.d.ts +22 -0
- package/dist/connector/mcp/streamable-http.d.ts.map +1 -0
- package/dist/connector/mcp/streamable-http.js +128 -0
- package/dist/connector/mcp/streamable-http.js.map +1 -0
- package/dist/connector/mcp/streamable-http.test.d.ts +2 -0
- package/dist/connector/mcp/streamable-http.test.d.ts.map +1 -0
- package/dist/connector/mcp/streamable-http.test.js +132 -0
- package/dist/connector/mcp/streamable-http.test.js.map +1 -0
- package/dist/constants/compaction/index.d.ts.map +1 -1
- package/dist/constants/compaction/index.js +8 -3
- package/dist/constants/compaction/index.js.map +1 -1
- package/dist/constants/sandbox/index.d.ts +21 -0
- package/dist/constants/sandbox/index.d.ts.map +1 -1
- package/dist/constants/sandbox/index.js +30 -0
- package/dist/constants/sandbox/index.js.map +1 -1
- package/dist/constants/tools/index.d.ts.map +1 -1
- package/dist/constants/tools/index.js +33 -2
- package/dist/constants/tools/index.js.map +1 -1
- package/dist/manager/run/persistence.d.ts.map +1 -1
- package/dist/manager/run/persistence.js +35 -5
- package/dist/manager/run/persistence.js.map +1 -1
- package/dist/persona/assembler.d.ts +1 -0
- package/dist/persona/assembler.d.ts.map +1 -1
- package/dist/persona/assembler.js +37 -6
- package/dist/persona/assembler.js.map +1 -1
- package/dist/provider/collect.d.ts.map +1 -1
- package/dist/provider/collect.js +4 -1
- package/dist/provider/collect.js.map +1 -1
- package/dist/provider/collect.test.js +2 -2
- package/dist/public-runtime.d.ts +6 -5
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +6 -5
- 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 +2 -0
- package/dist/public-tools.js.map +1 -1
- package/dist/public-types.d.ts +3 -0
- package/dist/public-types.d.ts.map +1 -1
- package/dist/registry/index.d.ts +2 -0
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +1 -0
- package/dist/registry/index.js.map +1 -1
- package/dist/registry/tool/execute.d.ts +27 -0
- package/dist/registry/tool/execute.d.ts.map +1 -1
- package/dist/registry/tool/execute.js +192 -7
- package/dist/registry/tool/execute.js.map +1 -1
- package/dist/registry/tool/execute.test.d.ts +9 -4
- package/dist/registry/tool/execute.test.d.ts.map +1 -1
- package/dist/registry/tool/execute.test.js +178 -7
- package/dist/registry/tool/execute.test.js.map +1 -1
- package/dist/registry/toolset/catalog.d.ts +42 -0
- package/dist/registry/toolset/catalog.d.ts.map +1 -0
- package/dist/registry/toolset/catalog.js +217 -0
- package/dist/registry/toolset/catalog.js.map +1 -0
- package/dist/registry/toolset/catalog.test.d.ts +2 -0
- package/dist/registry/toolset/catalog.test.d.ts.map +1 -0
- package/dist/registry/toolset/catalog.test.js +147 -0
- package/dist/registry/toolset/catalog.test.js.map +1 -0
- package/dist/runtime/query/__tests__/deferred-tools.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/deferred-tools.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/deferred-tools.test.js +185 -0
- package/dist/runtime/query/__tests__/deferred-tools.test.js.map +1 -0
- package/dist/runtime/query/__tests__/executor-concurrency.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/executor-concurrency.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/executor-concurrency.test.js +98 -0
- package/dist/runtime/query/__tests__/executor-concurrency.test.js.map +1 -0
- package/dist/runtime/query/__tests__/executor-plugin-hooks.test.js +38 -3
- package/dist/runtime/query/__tests__/executor-plugin-hooks.test.js.map +1 -1
- package/dist/runtime/query/__tests__/long-document-flow.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/long-document-flow.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/long-document-flow.test.js +154 -0
- package/dist/runtime/query/__tests__/long-document-flow.test.js.map +1 -0
- package/dist/runtime/query/__tests__/prompt.test.js +51 -2
- package/dist/runtime/query/__tests__/prompt.test.js.map +1 -1
- package/dist/runtime/query/__tests__/stream-recovery.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/stream-recovery.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/stream-recovery.test.js +126 -0
- package/dist/runtime/query/__tests__/stream-recovery.test.js.map +1 -0
- package/dist/runtime/query/continuation.d.ts +16 -0
- package/dist/runtime/query/continuation.d.ts.map +1 -0
- package/dist/runtime/query/continuation.js +16 -0
- package/dist/runtime/query/continuation.js.map +1 -0
- package/dist/runtime/query/executor.d.ts +3 -0
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +71 -3
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/index.d.ts +9 -0
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +42 -5
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +24 -0
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +326 -66
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/phases/checkpoint.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/checkpoint.js +2 -2
- package/dist/runtime/query/iteration/phases/checkpoint.js.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.d.ts +8 -0
- package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.js +84 -3
- package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context.d.ts +22 -0
- package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/context.js +53 -0
- package/dist/runtime/query/iteration/phases/context.js.map +1 -1
- package/dist/runtime/query/iteration/phases/hitl-abort-race.test.d.ts +2 -0
- package/dist/runtime/query/iteration/phases/hitl-abort-race.test.d.ts.map +1 -0
- package/dist/runtime/query/iteration/phases/hitl-abort-race.test.js +73 -0
- package/dist/runtime/query/iteration/phases/hitl-abort-race.test.js.map +1 -0
- package/dist/runtime/query/iteration/phases/hitl-answer-question.test.d.ts +2 -0
- package/dist/runtime/query/iteration/phases/hitl-answer-question.test.d.ts.map +1 -0
- package/dist/runtime/query/iteration/phases/hitl-answer-question.test.js +120 -0
- package/dist/runtime/query/iteration/phases/hitl-answer-question.test.js.map +1 -0
- package/dist/runtime/query/iteration/phases/tool-review.d.ts +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 -2
- package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
- package/dist/runtime/query/iteration/phases/working-memory-compaction.test.d.ts +19 -0
- package/dist/runtime/query/iteration/phases/working-memory-compaction.test.d.ts.map +1 -0
- package/dist/runtime/query/iteration/phases/working-memory-compaction.test.js +177 -0
- package/dist/runtime/query/iteration/phases/working-memory-compaction.test.js.map +1 -0
- package/dist/runtime/query/iteration/phases/working-memory.d.ts +31 -0
- package/dist/runtime/query/iteration/phases/working-memory.d.ts.map +1 -0
- package/dist/runtime/query/iteration/phases/working-memory.js +81 -0
- package/dist/runtime/query/iteration/phases/working-memory.js.map +1 -0
- package/dist/runtime/query/prompt.d.ts.map +1 -1
- package/dist/runtime/query/prompt.js +21 -1
- package/dist/runtime/query/prompt.js.map +1 -1
- package/dist/runtime/query/tooling.d.ts +1 -0
- package/dist/runtime/query/tooling.d.ts.map +1 -1
- package/dist/runtime/query/tooling.js +1 -0
- package/dist/runtime/query/tooling.js.map +1 -1
- package/dist/sandbox/provider/local.d.ts.map +1 -1
- package/dist/sandbox/provider/local.js +32 -1
- package/dist/sandbox/provider/local.js.map +1 -1
- package/dist/session/workspace/__tests__/shared-run.test.d.ts +2 -0
- package/dist/session/workspace/__tests__/shared-run.test.d.ts.map +1 -0
- package/dist/session/workspace/__tests__/shared-run.test.js +147 -0
- package/dist/session/workspace/__tests__/shared-run.test.js.map +1 -0
- package/dist/session/workspace/index.d.ts +2 -0
- package/dist/session/workspace/index.d.ts.map +1 -1
- package/dist/session/workspace/index.js +1 -0
- package/dist/session/workspace/index.js.map +1 -1
- package/dist/session/workspace/shared-run.d.ts +81 -0
- package/dist/session/workspace/shared-run.d.ts.map +1 -0
- package/dist/session/workspace/shared-run.js +252 -0
- package/dist/session/workspace/shared-run.js.map +1 -0
- package/dist/skills/loader.d.ts.map +1 -1
- package/dist/skills/loader.js +36 -6
- package/dist/skills/loader.js.map +1 -1
- package/dist/skills/loader.test.d.ts +2 -0
- package/dist/skills/loader.test.d.ts.map +1 -0
- package/dist/skills/loader.test.js +65 -0
- package/dist/skills/loader.test.js.map +1 -0
- package/dist/streaming/coalesce.test.js +1 -1
- package/dist/streaming/coalesce.test.js.map +1 -1
- package/dist/tools/builtins/__tests__/edit.test.d.ts +2 -0
- package/dist/tools/builtins/__tests__/edit.test.d.ts.map +1 -0
- package/dist/tools/builtins/__tests__/edit.test.js +38 -0
- package/dist/tools/builtins/__tests__/edit.test.js.map +1 -0
- package/dist/tools/builtins/__tests__/payload-budget.test.d.ts +2 -0
- package/dist/tools/builtins/__tests__/payload-budget.test.d.ts.map +1 -0
- package/dist/tools/builtins/__tests__/payload-budget.test.js +70 -0
- package/dist/tools/builtins/__tests__/payload-budget.test.js.map +1 -0
- package/dist/tools/builtins/__tests__/read-file.test.d.ts +2 -0
- package/dist/tools/builtins/__tests__/read-file.test.d.ts.map +1 -0
- package/dist/tools/builtins/__tests__/read-file.test.js +33 -0
- package/dist/tools/builtins/__tests__/read-file.test.js.map +1 -0
- package/dist/tools/builtins/__tests__/verify-outputs.test.d.ts +2 -0
- package/dist/tools/builtins/__tests__/verify-outputs.test.d.ts.map +1 -0
- package/dist/tools/builtins/__tests__/verify-outputs.test.js +52 -0
- package/dist/tools/builtins/__tests__/verify-outputs.test.js.map +1 -0
- package/dist/tools/builtins/__tests__/write-file.test.d.ts +2 -0
- package/dist/tools/builtins/__tests__/write-file.test.d.ts.map +1 -0
- package/dist/tools/builtins/__tests__/write-file.test.js +74 -0
- package/dist/tools/builtins/__tests__/write-file.test.js.map +1 -0
- package/dist/tools/builtins/bash.d.ts.map +1 -1
- package/dist/tools/builtins/bash.js +40 -7
- package/dist/tools/builtins/bash.js.map +1 -1
- package/dist/tools/builtins/edit.d.ts +5 -2
- package/dist/tools/builtins/edit.d.ts.map +1 -1
- package/dist/tools/builtins/edit.js +114 -18
- package/dist/tools/builtins/edit.js.map +1 -1
- package/dist/tools/builtins/index.d.ts +1 -0
- package/dist/tools/builtins/index.d.ts.map +1 -1
- package/dist/tools/builtins/index.js +13 -13
- package/dist/tools/builtins/index.js.map +1 -1
- package/dist/tools/builtins/read-file.d.ts +1 -0
- package/dist/tools/builtins/read-file.d.ts.map +1 -1
- package/dist/tools/builtins/read-file.js +73 -10
- package/dist/tools/builtins/read-file.js.map +1 -1
- package/dist/tools/builtins/search-tools.d.ts.map +1 -1
- package/dist/tools/builtins/search-tools.js +35 -7
- package/dist/tools/builtins/search-tools.js.map +1 -1
- package/dist/tools/builtins/verify-outputs.d.ts +5 -0
- package/dist/tools/builtins/verify-outputs.d.ts.map +1 -0
- package/dist/tools/builtins/verify-outputs.js +103 -0
- package/dist/tools/builtins/verify-outputs.js.map +1 -0
- package/dist/tools/builtins/write-file.d.ts +3 -2
- package/dist/tools/builtins/write-file.d.ts.map +1 -1
- package/dist/tools/builtins/write-file.js +72 -12
- package/dist/tools/builtins/write-file.js.map +1 -1
- package/dist/tools/coordinator/__tests__/agent.test.d.ts +15 -0
- package/dist/tools/coordinator/__tests__/agent.test.d.ts.map +1 -0
- package/dist/tools/coordinator/__tests__/agent.test.js +142 -0
- package/dist/tools/coordinator/__tests__/agent.test.js.map +1 -0
- package/dist/tools/coordinator/__tests__/approve-plan.test.d.ts +2 -0
- package/dist/tools/coordinator/__tests__/approve-plan.test.d.ts.map +1 -0
- package/dist/tools/coordinator/__tests__/approve-plan.test.js +114 -0
- package/dist/tools/coordinator/__tests__/approve-plan.test.js.map +1 -0
- package/dist/tools/coordinator/__tests__/ask-user-question.test.d.ts +2 -0
- package/dist/tools/coordinator/__tests__/ask-user-question.test.d.ts.map +1 -0
- package/dist/tools/coordinator/__tests__/ask-user-question.test.js +309 -0
- package/dist/tools/coordinator/__tests__/ask-user-question.test.js.map +1 -0
- package/dist/tools/coordinator/__tests__/task-list.test.d.ts +13 -0
- package/dist/tools/coordinator/__tests__/task-list.test.d.ts.map +1 -0
- package/dist/tools/coordinator/__tests__/task-list.test.js +162 -0
- package/dist/tools/coordinator/__tests__/task-list.test.js.map +1 -0
- package/dist/tools/coordinator/agent.d.ts +34 -0
- package/dist/tools/coordinator/agent.d.ts.map +1 -0
- package/dist/tools/coordinator/agent.js +107 -0
- package/dist/tools/coordinator/agent.js.map +1 -0
- package/dist/tools/coordinator/index.d.ts +15 -0
- package/dist/tools/coordinator/index.d.ts.map +1 -1
- package/dist/tools/coordinator/index.js +305 -35
- package/dist/tools/coordinator/index.js.map +1 -1
- package/dist/types/agent/base.d.ts +8 -0
- 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/reactive.d.ts +38 -0
- package/dist/types/agent/reactive.d.ts.map +1 -1
- package/dist/types/agent/supervisor.d.ts +32 -0
- package/dist/types/agent/supervisor.d.ts.map +1 -1
- package/dist/types/agent/working-memory.d.ts +29 -0
- package/dist/types/agent/working-memory.d.ts.map +1 -0
- package/dist/types/agent/working-memory.js +2 -0
- package/dist/types/agent/working-memory.js.map +1 -0
- package/dist/types/common/index.d.ts +10 -0
- package/dist/types/common/index.d.ts.map +1 -1
- package/dist/types/common/index.js +18 -0
- package/dist/types/common/index.js.map +1 -1
- package/dist/types/common/usage-merge.test.d.ts +2 -0
- package/dist/types/common/usage-merge.test.d.ts.map +1 -0
- package/dist/types/common/usage-merge.test.js +48 -0
- package/dist/types/common/usage-merge.test.js.map +1 -0
- package/dist/types/connector/mcp.d.ts +9 -2
- package/dist/types/connector/mcp.d.ts.map +1 -1
- package/dist/types/hitl/index.d.ts +42 -0
- package/dist/types/hitl/index.d.ts.map +1 -1
- package/dist/types/hitl/index.js +11 -0
- package/dist/types/hitl/index.js.map +1 -1
- package/dist/types/message/index.d.ts +22 -1
- package/dist/types/message/index.d.ts.map +1 -1
- package/dist/types/message/index.js +7 -2
- package/dist/types/message/index.js.map +1 -1
- package/dist/types/provider/chat.d.ts +11 -9
- package/dist/types/provider/chat.d.ts.map +1 -1
- package/dist/types/run/events.d.ts +6 -0
- package/dist/types/run/events.d.ts.map +1 -1
- package/dist/types/run/events.js.map +1 -1
- package/dist/types/sandbox/index.d.ts +193 -0
- package/dist/types/sandbox/index.d.ts.map +1 -1
- package/dist/types/sandbox/index.js.map +1 -1
- package/dist/types/skills/index.d.ts +2 -0
- package/dist/types/skills/index.d.ts.map +1 -1
- package/dist/types/tool/index.d.ts +22 -0
- package/dist/types/tool/index.d.ts.map +1 -1
- package/dist/types/toolset/index.d.ts +71 -0
- package/dist/types/toolset/index.d.ts.map +1 -0
- package/dist/types/toolset/index.js +2 -0
- package/dist/types/toolset/index.js.map +1 -0
- package/dist/types/workspace/index.d.ts +1 -0
- package/dist/types/workspace/index.d.ts.map +1 -1
- package/dist/types/workspace/shared-run.d.ts +61 -0
- package/dist/types/workspace/shared-run.d.ts.map +1 -0
- package/dist/types/workspace/shared-run.js +2 -0
- package/dist/types/workspace/shared-run.js.map +1 -0
- package/dist/verification/index.d.ts +1 -0
- package/dist/verification/index.d.ts.map +1 -1
- package/dist/verification/index.js +1 -0
- package/dist/verification/index.js.map +1 -1
- package/dist/verification/presets.d.ts +53 -0
- package/dist/verification/presets.d.ts.map +1 -0
- package/dist/verification/presets.js +70 -0
- package/dist/verification/presets.js.map +1 -0
- package/dist/verification/presets.test.d.ts +16 -0
- package/dist/verification/presets.test.d.ts.map +1 -0
- package/dist/verification/presets.test.js +79 -0
- package/dist/verification/presets.test.js.map +1 -0
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +25 -4
- package/dist/version.js.map +1 -1
- package/package.json +3 -2
- package/src/advisory/executor.test.ts +7 -4
- package/src/advisory/executor.ts +11 -2
- package/src/agents/ReactiveAgent.ts +7 -0
- package/src/agents/SupervisorAgent.ts +63 -16
- package/src/agents/__tests__/supervisor-ledger.test.ts +185 -0
- package/src/bridge/sse/mapper.test.ts +2 -2
- package/src/config/runtime.ts +9 -0
- package/src/connector/builtins/webhook.test.ts +21 -0
- package/src/connector/index.ts +1 -0
- package/src/connector/mcp/client.ts +4 -0
- package/src/connector/mcp/index.ts +1 -0
- package/src/connector/mcp/streamable-http.test.ts +169 -0
- package/src/connector/mcp/streamable-http.ts +152 -0
- package/src/constants/compaction/index.ts +8 -3
- package/src/constants/sandbox/index.ts +37 -0
- package/src/constants/tools/index.ts +33 -2
- package/src/manager/run/persistence.ts +34 -6
- package/src/persona/assembler.ts +43 -8
- package/src/provider/collect.test.ts +2 -2
- package/src/provider/collect.ts +4 -1
- package/src/public-runtime.ts +15 -1
- package/src/public-tools.ts +2 -0
- package/src/public-types.ts +7 -0
- package/src/registry/index.ts +7 -0
- package/src/registry/tool/execute.test.ts +211 -7
- package/src/registry/tool/execute.ts +199 -11
- package/src/registry/toolset/catalog.test.ts +165 -0
- package/src/registry/toolset/catalog.ts +283 -0
- package/src/runtime/query/__tests__/deferred-tools.test.ts +230 -0
- package/src/runtime/query/__tests__/executor-concurrency.test.ts +122 -0
- package/src/runtime/query/__tests__/executor-plugin-hooks.test.ts +48 -3
- package/src/runtime/query/__tests__/long-document-flow.test.ts +180 -0
- package/src/runtime/query/__tests__/prompt.test.ts +55 -2
- package/src/runtime/query/__tests__/stream-recovery.test.ts +156 -0
- package/src/runtime/query/continuation.ts +16 -0
- package/src/runtime/query/executor.ts +82 -13
- package/src/runtime/query/index.ts +58 -5
- package/src/runtime/query/iteration/index.ts +361 -74
- package/src/runtime/query/iteration/phases/checkpoint.ts +7 -2
- package/src/runtime/query/iteration/phases/compaction.ts +89 -3
- package/src/runtime/query/iteration/phases/context.ts +68 -0
- package/src/runtime/query/iteration/phases/hitl-abort-race.test.ts +86 -0
- package/src/runtime/query/iteration/phases/hitl-answer-question.test.ts +139 -0
- package/src/runtime/query/iteration/phases/tool-review.ts +7 -3
- package/src/runtime/query/iteration/phases/working-memory-compaction.test.ts +215 -0
- package/src/runtime/query/iteration/phases/working-memory.ts +86 -0
- package/src/runtime/query/prompt.ts +17 -1
- package/src/runtime/query/tooling.ts +2 -0
- package/src/sandbox/provider/local.ts +33 -0
- package/src/session/workspace/__tests__/shared-run.test.ts +181 -0
- package/src/session/workspace/index.ts +6 -0
- package/src/session/workspace/shared-run.ts +317 -0
- package/src/skills/loader.test.ts +89 -0
- package/src/skills/loader.ts +37 -6
- package/src/streaming/coalesce.test.ts +4 -4
- package/src/tools/builtins/__tests__/edit.test.ts +57 -0
- package/src/tools/builtins/__tests__/payload-budget.test.ts +92 -0
- package/src/tools/builtins/__tests__/read-file.test.ts +43 -0
- package/src/tools/builtins/__tests__/verify-outputs.test.ts +71 -0
- package/src/tools/builtins/__tests__/write-file.test.ts +97 -0
- package/src/tools/builtins/bash.ts +48 -7
- package/src/tools/builtins/edit.ts +162 -27
- package/src/tools/builtins/index.ts +13 -13
- package/src/tools/builtins/read-file.ts +81 -10
- package/src/tools/builtins/search-tools.ts +42 -7
- package/src/tools/builtins/verify-outputs.ts +126 -0
- package/src/tools/builtins/write-file.ts +83 -14
- package/src/tools/coordinator/__tests__/agent.test.ts +172 -0
- package/src/tools/coordinator/__tests__/approve-plan.test.ts +139 -0
- package/src/tools/coordinator/__tests__/ask-user-question.test.ts +370 -0
- package/src/tools/coordinator/__tests__/task-list.test.ts +182 -0
- package/src/tools/coordinator/agent.ts +157 -0
- package/src/tools/coordinator/index.ts +355 -39
- package/src/types/agent/base.ts +8 -0
- package/src/types/agent/index.ts +1 -0
- package/src/types/agent/reactive.ts +42 -0
- package/src/types/agent/supervisor.ts +36 -0
- package/src/types/agent/working-memory.ts +29 -0
- package/src/types/common/index.ts +19 -0
- package/src/types/common/usage-merge.test.ts +53 -0
- package/src/types/connector/mcp.ts +14 -2
- package/src/types/hitl/index.ts +52 -1
- package/src/types/message/index.ts +32 -2
- package/src/types/provider/chat.ts +12 -9
- package/src/types/run/events.ts +6 -0
- package/src/types/sandbox/index.ts +219 -0
- package/src/types/skills/index.ts +4 -0
- package/src/types/tool/index.ts +24 -0
- package/src/types/toolset/index.ts +86 -0
- package/src/types/workspace/index.ts +9 -0
- package/src/types/workspace/shared-run.ts +65 -0
- package/src/verification/index.ts +1 -0
- package/src/verification/presets.test.ts +112 -0
- package/src/verification/presets.ts +72 -0
- package/src/version.ts +26 -4
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
|
|
4
|
+
import type { ToolDefinition } from '../../types/tool/index.js'
|
|
5
|
+
import { ToolRegistry } from '../tool/execute.js'
|
|
6
|
+
import { ToolCatalog, createToolCatalogFromRegistry } from './catalog.js'
|
|
7
|
+
|
|
8
|
+
function makeTool(name: string, description = `${name} tool`): ToolDefinition {
|
|
9
|
+
return {
|
|
10
|
+
name,
|
|
11
|
+
description,
|
|
12
|
+
inputSchema: z.object({ query: z.string().optional() }),
|
|
13
|
+
async execute() {
|
|
14
|
+
return { success: true, output: `${name}-ran` }
|
|
15
|
+
},
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe('ToolCatalog', () => {
|
|
20
|
+
it('keeps sources, toolsets, and tools as separate records', () => {
|
|
21
|
+
const catalog = new ToolCatalog()
|
|
22
|
+
catalog.registerSource({
|
|
23
|
+
id: 'mcp:microsoft-learn',
|
|
24
|
+
kind: 'mcp_server',
|
|
25
|
+
name: 'Microsoft Learn',
|
|
26
|
+
mcpServer: {
|
|
27
|
+
name: 'microsoft-learn',
|
|
28
|
+
url: 'https://learn.microsoft.com/api/mcp',
|
|
29
|
+
transport: 'streamable_http',
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
catalog.registerToolset({
|
|
33
|
+
id: 'mcp-toolset:microsoft-learn',
|
|
34
|
+
sourceId: 'mcp:microsoft-learn',
|
|
35
|
+
name: 'Microsoft Learn toolset',
|
|
36
|
+
defaultPolicy: {
|
|
37
|
+
enabled: true,
|
|
38
|
+
loading: 'deferred',
|
|
39
|
+
preferred: true,
|
|
40
|
+
permissionPolicy: 'always_allow',
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
catalog.registerTool({
|
|
44
|
+
name: 'microsoft_docs_search',
|
|
45
|
+
description: 'Search Microsoft documentation',
|
|
46
|
+
sourceId: 'mcp:microsoft-learn',
|
|
47
|
+
toolsetId: 'mcp-toolset:microsoft-learn',
|
|
48
|
+
policy: { enabled: true, loading: 'deferred', preferred: true },
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
expect(catalog.listSources()).toHaveLength(1)
|
|
52
|
+
expect(catalog.listToolsets()).toHaveLength(1)
|
|
53
|
+
expect(catalog.getToolsByLoading(['deferred']).map((t) => t.name)).toEqual([
|
|
54
|
+
'microsoft_docs_search',
|
|
55
|
+
])
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('searches deferred tools by name, description, source, and toolset', () => {
|
|
59
|
+
const registry = new ToolRegistry()
|
|
60
|
+
registry.register(makeTool('github_search_issues', 'Search repository issues'), 'deferred')
|
|
61
|
+
registry.register(makeTool('slack_search_messages', 'Search team messages'), 'deferred')
|
|
62
|
+
registry.register(makeTool('bash', 'Run a shell command'))
|
|
63
|
+
|
|
64
|
+
const catalog = createToolCatalogFromRegistry(registry, {
|
|
65
|
+
source: {
|
|
66
|
+
id: 'host',
|
|
67
|
+
kind: 'host_tool',
|
|
68
|
+
name: 'Host runtime',
|
|
69
|
+
description: 'Local shell and collaboration tools',
|
|
70
|
+
},
|
|
71
|
+
toolset: {
|
|
72
|
+
id: 'default-host',
|
|
73
|
+
name: 'Default host tools',
|
|
74
|
+
defaultPolicy: { enabled: true, loading: 'eager' },
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
expect(
|
|
79
|
+
catalog.searchTools('repository', { loading: ['deferred'] }).map((r) => r.tool.name),
|
|
80
|
+
).toEqual(['github_search_issues'])
|
|
81
|
+
expect(catalog.toLLMTools().map((t) => t.function.name)).toEqual(['bash'])
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('scores and reports the matched facets: partial name, source text, toolset text', () => {
|
|
85
|
+
const catalog = new ToolCatalog()
|
|
86
|
+
catalog.registerSource({
|
|
87
|
+
id: 'host',
|
|
88
|
+
kind: 'host_tool',
|
|
89
|
+
name: 'GitHub',
|
|
90
|
+
description: 'repository automation',
|
|
91
|
+
})
|
|
92
|
+
catalog.registerToolset({
|
|
93
|
+
id: 'issues',
|
|
94
|
+
sourceId: 'host',
|
|
95
|
+
name: 'Issue toolset',
|
|
96
|
+
defaultPolicy: { enabled: true, loading: 'eager' },
|
|
97
|
+
})
|
|
98
|
+
catalog.registerTool({
|
|
99
|
+
name: 'create_issue',
|
|
100
|
+
description: 'open a ticket',
|
|
101
|
+
sourceId: 'host',
|
|
102
|
+
toolsetId: 'issues',
|
|
103
|
+
policy: { enabled: true, loading: 'eager' },
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
// 'issue' hits the tool NAME (create_issue, partial) AND the TOOLSET name.
|
|
107
|
+
const byIssue = catalog.searchTools('issue')
|
|
108
|
+
expect(byIssue).toHaveLength(1)
|
|
109
|
+
expect([...(byIssue[0]?.matched ?? [])].sort()).toEqual(['name', 'toolset'])
|
|
110
|
+
|
|
111
|
+
// 'github' hits only the SOURCE text.
|
|
112
|
+
const bySource = catalog.searchTools('github')
|
|
113
|
+
expect(bySource[0]?.matched).toEqual(['source'])
|
|
114
|
+
|
|
115
|
+
// An exact name match outscores a partial one.
|
|
116
|
+
const exact = catalog.searchTools('create_issue')
|
|
117
|
+
expect(exact[0]?.matched).toContain('name')
|
|
118
|
+
expect(exact[0]?.score ?? 0).toBeGreaterThan(byIssue[0]?.score ?? 0)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('adds the preferred boost so a preferred tool outranks an equal match', () => {
|
|
122
|
+
const catalog = new ToolCatalog()
|
|
123
|
+
catalog.registerSource({ id: 'host', kind: 'host_tool', name: 'Host' })
|
|
124
|
+
catalog.registerToolset({
|
|
125
|
+
id: 'ts',
|
|
126
|
+
sourceId: 'host',
|
|
127
|
+
name: 'Tools',
|
|
128
|
+
defaultPolicy: { enabled: true, loading: 'eager' },
|
|
129
|
+
})
|
|
130
|
+
catalog.registerTool({
|
|
131
|
+
name: 'search_plain',
|
|
132
|
+
description: 'search things',
|
|
133
|
+
sourceId: 'host',
|
|
134
|
+
toolsetId: 'ts',
|
|
135
|
+
policy: { enabled: true, loading: 'eager' },
|
|
136
|
+
})
|
|
137
|
+
catalog.registerTool({
|
|
138
|
+
name: 'search_pref',
|
|
139
|
+
description: 'search things',
|
|
140
|
+
sourceId: 'host',
|
|
141
|
+
toolsetId: 'ts',
|
|
142
|
+
policy: { enabled: true, loading: 'eager', preferred: true },
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
const results = catalog.searchTools('search')
|
|
146
|
+
expect(results.map((r) => r.tool.name)).toEqual(['search_pref', 'search_plain'])
|
|
147
|
+
const pref = results.find((r) => r.tool.name === 'search_pref')?.score ?? 0
|
|
148
|
+
const plain = results.find((r) => r.tool.name === 'search_plain')?.score ?? 0
|
|
149
|
+
expect(pref - plain).toBe(1)
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
it('preserves registry availability as catalog loading policy', () => {
|
|
153
|
+
const registry = new ToolRegistry()
|
|
154
|
+
registry.register(makeTool('read_file'))
|
|
155
|
+
registry.register(makeTool('web_search'), 'deferred')
|
|
156
|
+
registry.register(makeTool('write_file'), 'suspended')
|
|
157
|
+
|
|
158
|
+
const catalog = createToolCatalogFromRegistry(registry)
|
|
159
|
+
|
|
160
|
+
expect(catalog.getTool('read_file')?.policy.loading).toBe('eager')
|
|
161
|
+
expect(catalog.getTool('web_search')?.policy.loading).toBe('deferred')
|
|
162
|
+
expect(catalog.getTool('write_file')?.policy.loading).toBe('suspended')
|
|
163
|
+
expect(catalog.toLLMTools({ loading: ['suspended'] })).toEqual([])
|
|
164
|
+
})
|
|
165
|
+
})
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { zodToJsonSchema } from 'zod-to-json-schema'
|
|
2
|
+
import type { ToolRegistryContract } from '../../types/tool/index.js'
|
|
3
|
+
import type { LLMToolSchema, ToolAvailability, ToolDefinition } from '../../types/tool/index.js'
|
|
4
|
+
import type {
|
|
5
|
+
ToolCatalogEntry,
|
|
6
|
+
ToolCatalogSearchResult,
|
|
7
|
+
ToolCatalogSnapshot,
|
|
8
|
+
ToolLoadingMode,
|
|
9
|
+
ToolSource,
|
|
10
|
+
ToolsetDefinition,
|
|
11
|
+
ToolsetPolicy,
|
|
12
|
+
} from '../../types/toolset/index.js'
|
|
13
|
+
|
|
14
|
+
export interface ToolCatalogSearchOptions {
|
|
15
|
+
readonly loading?: readonly ToolLoadingMode[]
|
|
16
|
+
readonly limit?: number
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ToolCatalogFromRegistryOptions {
|
|
20
|
+
readonly source?: ToolSource
|
|
21
|
+
readonly toolset?: Omit<ToolsetDefinition, 'sourceId'> & {
|
|
22
|
+
readonly sourceId?: string
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const DEFAULT_HOST_SOURCE: ToolSource = {
|
|
27
|
+
id: 'host-tools',
|
|
28
|
+
kind: 'host_tool',
|
|
29
|
+
name: 'Host tools',
|
|
30
|
+
description: 'Tools executed by the host runtime.',
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const DEFAULT_HOST_TOOLSET: ToolsetDefinition = {
|
|
34
|
+
id: 'host-tools',
|
|
35
|
+
sourceId: DEFAULT_HOST_SOURCE.id,
|
|
36
|
+
name: 'Host tools',
|
|
37
|
+
defaultPolicy: {
|
|
38
|
+
enabled: true,
|
|
39
|
+
loading: 'eager',
|
|
40
|
+
permissionPolicy: 'default',
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class ToolCatalog {
|
|
45
|
+
private sources = new Map<string, ToolSource>()
|
|
46
|
+
private toolsets = new Map<string, ToolsetDefinition>()
|
|
47
|
+
private tools = new Map<string, ToolCatalogEntry>()
|
|
48
|
+
|
|
49
|
+
registerSource(source: ToolSource): void {
|
|
50
|
+
this.sources.set(source.id, source)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
registerToolset(toolset: ToolsetDefinition): void {
|
|
54
|
+
if (!this.sources.has(toolset.sourceId)) {
|
|
55
|
+
throw new Error(`Toolset "${toolset.id}" references unknown source "${toolset.sourceId}"`)
|
|
56
|
+
}
|
|
57
|
+
this.toolsets.set(toolset.id, toolset)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
registerTool(tool: ToolCatalogEntry): void {
|
|
61
|
+
if (!this.sources.has(tool.sourceId)) {
|
|
62
|
+
throw new Error(`Tool "${tool.name}" references unknown source "${tool.sourceId}"`)
|
|
63
|
+
}
|
|
64
|
+
if (!this.toolsets.has(tool.toolsetId)) {
|
|
65
|
+
throw new Error(`Tool "${tool.name}" references unknown toolset "${tool.toolsetId}"`)
|
|
66
|
+
}
|
|
67
|
+
this.tools.set(tool.name, tool)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
getSource(id: string): ToolSource | undefined {
|
|
71
|
+
return this.sources.get(id)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
getToolset(id: string): ToolsetDefinition | undefined {
|
|
75
|
+
return this.toolsets.get(id)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
getTool(name: string): ToolCatalogEntry | undefined {
|
|
79
|
+
return this.tools.get(name)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
listSources(): ToolSource[] {
|
|
83
|
+
return [...this.sources.values()]
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
listToolsets(): ToolsetDefinition[] {
|
|
87
|
+
return [...this.toolsets.values()]
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
listTools(): ToolCatalogEntry[] {
|
|
91
|
+
return [...this.tools.values()]
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
snapshot(): ToolCatalogSnapshot {
|
|
95
|
+
return {
|
|
96
|
+
sources: this.listSources(),
|
|
97
|
+
toolsets: this.listToolsets(),
|
|
98
|
+
tools: this.listTools(),
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
getToolsByLoading(loading: readonly ToolLoadingMode[]): ToolCatalogEntry[] {
|
|
103
|
+
const wanted = new Set(loading)
|
|
104
|
+
return this.listTools().filter((tool) => wanted.has(resolveToolLoading(tool.policy)))
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
searchTools(query: string, options: ToolCatalogSearchOptions = {}): ToolCatalogSearchResult[] {
|
|
108
|
+
const normalized = query.trim().toLowerCase()
|
|
109
|
+
const terms = normalized.split(/\s+/).filter(Boolean)
|
|
110
|
+
const loading = options.loading ? new Set(options.loading) : null
|
|
111
|
+
const results: ToolCatalogSearchResult[] = []
|
|
112
|
+
|
|
113
|
+
for (const tool of this.listTools()) {
|
|
114
|
+
if (loading && !loading.has(resolveToolLoading(tool.policy))) continue
|
|
115
|
+
if (tool.policy.enabled === false) continue
|
|
116
|
+
|
|
117
|
+
const source = this.sources.get(tool.sourceId)
|
|
118
|
+
const toolset = this.toolsets.get(tool.toolsetId)
|
|
119
|
+
if (!source || !toolset) continue
|
|
120
|
+
|
|
121
|
+
const scored = scoreToolSearch({
|
|
122
|
+
terms,
|
|
123
|
+
tool,
|
|
124
|
+
source,
|
|
125
|
+
toolset,
|
|
126
|
+
})
|
|
127
|
+
if (scored.score <= 0) continue
|
|
128
|
+
|
|
129
|
+
results.push({
|
|
130
|
+
tool,
|
|
131
|
+
source,
|
|
132
|
+
toolset,
|
|
133
|
+
score: scored.score,
|
|
134
|
+
matched: scored.matched,
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
results.sort((a, b) => b.score - a.score || a.tool.name.localeCompare(b.tool.name))
|
|
139
|
+
return results.slice(0, options.limit ?? 5)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
toLLMTools(options: { readonly loading?: readonly ToolLoadingMode[] } = {}): LLMToolSchema[] {
|
|
143
|
+
const loading = options.loading ?? ['eager']
|
|
144
|
+
return this.getToolsByLoading(loading)
|
|
145
|
+
.filter((tool) => tool.policy.enabled !== false)
|
|
146
|
+
.map((tool) => tool.llmSchema ?? toolDefinitionToLLMTool(tool.definition))
|
|
147
|
+
.filter((tool): tool is LLMToolSchema => Boolean(tool))
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function createToolCatalogFromRegistry(
|
|
152
|
+
registry: ToolRegistryContract,
|
|
153
|
+
options: ToolCatalogFromRegistryOptions = {},
|
|
154
|
+
): ToolCatalog {
|
|
155
|
+
const source = options.source ?? DEFAULT_HOST_SOURCE
|
|
156
|
+
const toolset: ToolsetDefinition = {
|
|
157
|
+
...DEFAULT_HOST_TOOLSET,
|
|
158
|
+
...options.toolset,
|
|
159
|
+
sourceId: options.toolset?.sourceId ?? source.id,
|
|
160
|
+
}
|
|
161
|
+
const catalog = new ToolCatalog()
|
|
162
|
+
catalog.registerSource(source)
|
|
163
|
+
catalog.registerToolset(toolset)
|
|
164
|
+
|
|
165
|
+
for (const definition of registry.getAll()) {
|
|
166
|
+
const availability = registry.getAvailability(definition.name)
|
|
167
|
+
catalog.registerTool(
|
|
168
|
+
toolDefinitionToCatalogEntry(definition, {
|
|
169
|
+
availability,
|
|
170
|
+
sourceId: source.id,
|
|
171
|
+
toolsetId: toolset.id,
|
|
172
|
+
toolsetPolicy: toolset.defaultPolicy,
|
|
173
|
+
}),
|
|
174
|
+
)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return catalog
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function toolDefinitionToCatalogEntry(
|
|
181
|
+
definition: ToolDefinition,
|
|
182
|
+
input: {
|
|
183
|
+
readonly availability?: ToolAvailability
|
|
184
|
+
readonly sourceId: string
|
|
185
|
+
readonly toolsetId: string
|
|
186
|
+
readonly toolsetPolicy?: ToolsetPolicy
|
|
187
|
+
},
|
|
188
|
+
): ToolCatalogEntry {
|
|
189
|
+
const loading = loadingFromAvailability(input.availability ?? 'active')
|
|
190
|
+
return {
|
|
191
|
+
name: definition.name,
|
|
192
|
+
description: definition.description,
|
|
193
|
+
sourceId: input.sourceId,
|
|
194
|
+
toolsetId: input.toolsetId,
|
|
195
|
+
definition,
|
|
196
|
+
permissions: definition.permissions,
|
|
197
|
+
category: definition.category,
|
|
198
|
+
policy: {
|
|
199
|
+
...input.toolsetPolicy,
|
|
200
|
+
enabled: input.toolsetPolicy?.enabled === false ? false : loading !== 'suspended',
|
|
201
|
+
loading,
|
|
202
|
+
},
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export function loadingFromAvailability(availability: ToolAvailability): ToolLoadingMode {
|
|
207
|
+
switch (availability) {
|
|
208
|
+
case 'deferred':
|
|
209
|
+
return 'deferred'
|
|
210
|
+
case 'suspended':
|
|
211
|
+
return 'suspended'
|
|
212
|
+
default:
|
|
213
|
+
return 'eager'
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function resolveToolLoading(policy: ToolsetPolicy): ToolLoadingMode {
|
|
218
|
+
if (policy.enabled === false) return 'disabled'
|
|
219
|
+
return policy.loading ?? 'eager'
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function toolDefinitionToLLMTool(definition: ToolDefinition | undefined): LLMToolSchema | null {
|
|
223
|
+
if (!definition) return null
|
|
224
|
+
return {
|
|
225
|
+
type: 'function',
|
|
226
|
+
function: {
|
|
227
|
+
name: definition.name,
|
|
228
|
+
description: definition.description,
|
|
229
|
+
parameters: zodToJsonSchema(definition.inputSchema, {
|
|
230
|
+
target: 'jsonSchema7',
|
|
231
|
+
$refStrategy: 'none',
|
|
232
|
+
}) as Record<string, unknown>,
|
|
233
|
+
},
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function scoreToolSearch(input: {
|
|
238
|
+
readonly terms: readonly string[]
|
|
239
|
+
readonly tool: ToolCatalogEntry
|
|
240
|
+
readonly source: ToolSource
|
|
241
|
+
readonly toolset: ToolsetDefinition
|
|
242
|
+
}): { score: number; matched: string[] } {
|
|
243
|
+
const terms = input.terms.length > 0 ? input.terms : ['']
|
|
244
|
+
const matched = new Set<string>()
|
|
245
|
+
let score = 0
|
|
246
|
+
|
|
247
|
+
for (const term of terms) {
|
|
248
|
+
if (!term) continue
|
|
249
|
+
|
|
250
|
+
const toolName = input.tool.name.toLowerCase()
|
|
251
|
+
const description = input.tool.description.toLowerCase()
|
|
252
|
+
const sourceText =
|
|
253
|
+
`${input.source.name} ${input.source.description ?? ''} ${input.source.kind}`.toLowerCase()
|
|
254
|
+
const toolsetText = `${input.toolset.name} ${input.toolset.description ?? ''}`.toLowerCase()
|
|
255
|
+
|
|
256
|
+
if (toolName === term) {
|
|
257
|
+
score += 12
|
|
258
|
+
matched.add('name')
|
|
259
|
+
} else if (toolName.includes(term)) {
|
|
260
|
+
score += 8
|
|
261
|
+
matched.add('name')
|
|
262
|
+
}
|
|
263
|
+
if (description.includes(term)) {
|
|
264
|
+
score += 5
|
|
265
|
+
matched.add('description')
|
|
266
|
+
}
|
|
267
|
+
if (sourceText.includes(term)) {
|
|
268
|
+
score += 3
|
|
269
|
+
matched.add('source')
|
|
270
|
+
}
|
|
271
|
+
if (toolsetText.includes(term)) {
|
|
272
|
+
score += 2
|
|
273
|
+
matched.add('toolset')
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (input.tool.policy.preferred && score > 0) score += 1
|
|
278
|
+
|
|
279
|
+
return {
|
|
280
|
+
score,
|
|
281
|
+
matched: [...matched],
|
|
282
|
+
}
|
|
283
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { mkdtemp, rm } from 'node:fs/promises'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { afterEach, describe, expect, it } from 'vitest'
|
|
5
|
+
import { z } from 'zod'
|
|
6
|
+
|
|
7
|
+
import { ToolRegistry } from '../../../registry/tool/execute.js'
|
|
8
|
+
import { SearchToolsTool } from '../../../tools/builtins/search-tools.js'
|
|
9
|
+
import type { RunId, SessionId, TenantId } from '../../../types/ids/index.js'
|
|
10
|
+
import { createUserMessage } from '../../../types/message/index.js'
|
|
11
|
+
import type {
|
|
12
|
+
ChatCompletionParams,
|
|
13
|
+
LLMProvider,
|
|
14
|
+
StreamChunk,
|
|
15
|
+
} from '../../../types/provider/index.js'
|
|
16
|
+
import type { ProjectId, ThreadId } from '../../../types/session/ids.js'
|
|
17
|
+
import { drainQuery } from '../index.js'
|
|
18
|
+
|
|
19
|
+
const ZERO_USAGE = {
|
|
20
|
+
promptTokens: 0,
|
|
21
|
+
completionTokens: 0,
|
|
22
|
+
totalTokens: 0,
|
|
23
|
+
cachedTokens: 0,
|
|
24
|
+
cacheWriteTokens: 0,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
class CapturingProvider implements LLMProvider {
|
|
28
|
+
readonly id = 'capturing'
|
|
29
|
+
readonly name = 'Capturing Provider'
|
|
30
|
+
lastParams?: ChatCompletionParams
|
|
31
|
+
|
|
32
|
+
async *chatStream(params: ChatCompletionParams): AsyncIterable<StreamChunk> {
|
|
33
|
+
this.lastParams = params
|
|
34
|
+
yield {
|
|
35
|
+
id: 'msg_1',
|
|
36
|
+
delta: { content: 'done' },
|
|
37
|
+
}
|
|
38
|
+
yield {
|
|
39
|
+
id: 'msg_1',
|
|
40
|
+
delta: {},
|
|
41
|
+
finishReason: 'stop',
|
|
42
|
+
usage: ZERO_USAGE,
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function registerDeferredDocumentTool(tools: ToolRegistry, name = 'generate_document'): void {
|
|
48
|
+
tools.register(
|
|
49
|
+
{
|
|
50
|
+
name,
|
|
51
|
+
description: 'Generate a project document by document id.',
|
|
52
|
+
inputSchema: z.object({
|
|
53
|
+
documentId: z.string(),
|
|
54
|
+
}),
|
|
55
|
+
execute: async () => ({ success: true, output: 'generated' }),
|
|
56
|
+
},
|
|
57
|
+
'deferred',
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
describe('query deferred tool discovery', () => {
|
|
62
|
+
let workdirs: string[] = []
|
|
63
|
+
|
|
64
|
+
afterEach(async () => {
|
|
65
|
+
await Promise.all(workdirs.map((dir) => rm(dir, { recursive: true, force: true })))
|
|
66
|
+
workdirs = []
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('auto-exposes search_tools when deferred tools are registered', async () => {
|
|
70
|
+
const provider = new CapturingProvider()
|
|
71
|
+
const tools = new ToolRegistry()
|
|
72
|
+
registerDeferredDocumentTool(tools)
|
|
73
|
+
|
|
74
|
+
const workingDirectory = await mkdtemp(join(tmpdir(), 'namzu-deferred-tools-'))
|
|
75
|
+
workdirs.push(workingDirectory)
|
|
76
|
+
|
|
77
|
+
const run = await drainQuery({
|
|
78
|
+
provider,
|
|
79
|
+
tools,
|
|
80
|
+
runConfig: {
|
|
81
|
+
model: 'mock-model',
|
|
82
|
+
timeoutMs: 5_000,
|
|
83
|
+
tokenBudget: 100_000,
|
|
84
|
+
maxIterations: 1,
|
|
85
|
+
maxResponseTokens: 256,
|
|
86
|
+
},
|
|
87
|
+
agentId: 'agent_test',
|
|
88
|
+
agentName: 'Test Agent',
|
|
89
|
+
messages: [createUserMessage('what tools can you use?')],
|
|
90
|
+
workingDirectory,
|
|
91
|
+
sessionId: 'ses_deferred_tools' as SessionId,
|
|
92
|
+
threadId: 'thd_deferred_tools' as ThreadId,
|
|
93
|
+
projectId: 'prj_deferred_tools' as ProjectId,
|
|
94
|
+
tenantId: 'tnt_deferred_tools' as TenantId,
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
expect(run.status).toBe('completed')
|
|
98
|
+
expect(tools.has(SearchToolsTool.name)).toBe(true)
|
|
99
|
+
expect(tools.getAvailability(SearchToolsTool.name)).toBe('active')
|
|
100
|
+
expect(tools.getAvailability('generate_document')).toBe('deferred')
|
|
101
|
+
|
|
102
|
+
const toolNames = provider.lastParams?.tools?.map((tool) => tool.function.name).sort() ?? []
|
|
103
|
+
expect(toolNames).toEqual([SearchToolsTool.name])
|
|
104
|
+
|
|
105
|
+
const systemPrompt = (provider.lastParams?.messages ?? [])
|
|
106
|
+
.filter((message) => message.role === 'system')
|
|
107
|
+
.map((message) => message.content)
|
|
108
|
+
.join('\n')
|
|
109
|
+
expect(systemPrompt).toContain('Use search_tools to load these before use:')
|
|
110
|
+
expect(systemPrompt).toContain('- generate_document')
|
|
111
|
+
expect(systemPrompt).not.toContain(
|
|
112
|
+
'Deferred tools are discoverable but not executable until the runtime activates them',
|
|
113
|
+
)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('keeps search_tools executable when allowedTools names a deferred tool', async () => {
|
|
117
|
+
const provider = new CapturingProvider()
|
|
118
|
+
const tools = new ToolRegistry()
|
|
119
|
+
registerDeferredDocumentTool(tools)
|
|
120
|
+
|
|
121
|
+
const workingDirectory = await mkdtemp(join(tmpdir(), 'namzu-deferred-tools-'))
|
|
122
|
+
workdirs.push(workingDirectory)
|
|
123
|
+
|
|
124
|
+
const run = await drainQuery({
|
|
125
|
+
provider,
|
|
126
|
+
tools,
|
|
127
|
+
allowedTools: ['generate_document'],
|
|
128
|
+
runConfig: {
|
|
129
|
+
model: 'mock-model',
|
|
130
|
+
timeoutMs: 5_000,
|
|
131
|
+
tokenBudget: 100_000,
|
|
132
|
+
maxIterations: 1,
|
|
133
|
+
maxResponseTokens: 256,
|
|
134
|
+
},
|
|
135
|
+
agentId: 'agent_test',
|
|
136
|
+
agentName: 'Test Agent',
|
|
137
|
+
messages: [createUserMessage('generate D-01')],
|
|
138
|
+
workingDirectory,
|
|
139
|
+
sessionId: 'ses_deferred_allowed_tools' as SessionId,
|
|
140
|
+
threadId: 'thd_deferred_allowed_tools' as ThreadId,
|
|
141
|
+
projectId: 'prj_deferred_allowed_tools' as ProjectId,
|
|
142
|
+
tenantId: 'tnt_deferred_allowed_tools' as TenantId,
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
expect(run.status).toBe('completed')
|
|
146
|
+
expect(tools.getAvailability('generate_document')).toBe('deferred')
|
|
147
|
+
|
|
148
|
+
const toolNames = provider.lastParams?.tools?.map((tool) => tool.function.name).sort() ?? []
|
|
149
|
+
expect(toolNames).toEqual([SearchToolsTool.name])
|
|
150
|
+
|
|
151
|
+
const systemPrompt = (provider.lastParams?.messages ?? [])
|
|
152
|
+
.filter((message) => message.role === 'system')
|
|
153
|
+
.map((message) => message.content)
|
|
154
|
+
.join('\n')
|
|
155
|
+
expect(systemPrompt).toContain('Use search_tools to load these before use:')
|
|
156
|
+
expect(systemPrompt).toContain('- generate_document')
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('does not let search_tools reveal or activate deferred tools outside allowedTools', async () => {
|
|
160
|
+
const tools = new ToolRegistry()
|
|
161
|
+
registerDeferredDocumentTool(tools)
|
|
162
|
+
registerDeferredDocumentTool(tools, 'dangerous_purge_document')
|
|
163
|
+
|
|
164
|
+
// 'dangerous' matches only the out-of-allowlist tool ('delete'-style
|
|
165
|
+
// CRUD verbs are stop tokens and never match anything by themselves).
|
|
166
|
+
const result = await SearchToolsTool.execute(
|
|
167
|
+
{ query: 'dangerous' },
|
|
168
|
+
{
|
|
169
|
+
runId: 'run_deferred_allowed_tools' as RunId,
|
|
170
|
+
workingDirectory: '/tmp',
|
|
171
|
+
abortSignal: new AbortController().signal,
|
|
172
|
+
env: {},
|
|
173
|
+
log: () => undefined,
|
|
174
|
+
toolRegistry: tools,
|
|
175
|
+
allowedTools: ['generate_document', SearchToolsTool.name],
|
|
176
|
+
},
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
expect(result.success).toBe(true)
|
|
180
|
+
expect(result.output).toContain('No deferred tools matching "dangerous"')
|
|
181
|
+
expect(result.output).not.toContain('dangerous_purge_document')
|
|
182
|
+
expect(tools.getAvailability('generate_document')).toBe('deferred')
|
|
183
|
+
expect(tools.getAvailability('dangerous_purge_document')).toBe('deferred')
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it('activates only the top-5 ranked matches and reports near-misses without activating', async () => {
|
|
187
|
+
const tools = new ToolRegistry()
|
|
188
|
+
// Eight deferred tools that all match "invoice" equally by name; the
|
|
189
|
+
// alphabetical tie-break makes the top-5 cut deterministic.
|
|
190
|
+
const names = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'].map((s) => `invoice_${s}`)
|
|
191
|
+
for (const name of names) {
|
|
192
|
+
tools.register(
|
|
193
|
+
{
|
|
194
|
+
name,
|
|
195
|
+
description: `Billing helper ${name.slice(-1)}.`,
|
|
196
|
+
inputSchema: z.object({ id: z.string() }),
|
|
197
|
+
execute: async () => ({ success: true, output: 'ok' }),
|
|
198
|
+
},
|
|
199
|
+
'deferred',
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const result = await SearchToolsTool.execute(
|
|
204
|
+
{ query: 'invoice' },
|
|
205
|
+
{
|
|
206
|
+
runId: 'run_deferred_top_k' as RunId,
|
|
207
|
+
workingDirectory: '/tmp',
|
|
208
|
+
abortSignal: new AbortController().signal,
|
|
209
|
+
env: {},
|
|
210
|
+
log: () => undefined,
|
|
211
|
+
toolRegistry: tools,
|
|
212
|
+
},
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
expect(result.success).toBe(true)
|
|
216
|
+
expect(result.output).toContain('Activated 5 tool(s)')
|
|
217
|
+
expect(result.output).toContain('NOT loaded')
|
|
218
|
+
expect(result.data).toMatchObject({
|
|
219
|
+
activated: ['invoice_a', 'invoice_b', 'invoice_c', 'invoice_d', 'invoice_e'],
|
|
220
|
+
count: 5,
|
|
221
|
+
nearMisses: ['invoice_f', 'invoice_g', 'invoice_h'],
|
|
222
|
+
})
|
|
223
|
+
for (const name of ['invoice_a', 'invoice_b', 'invoice_c', 'invoice_d', 'invoice_e']) {
|
|
224
|
+
expect(tools.getAvailability(name)).toBe('active')
|
|
225
|
+
}
|
|
226
|
+
for (const name of ['invoice_f', 'invoice_g', 'invoice_h']) {
|
|
227
|
+
expect(tools.getAvailability(name)).toBe('deferred')
|
|
228
|
+
}
|
|
229
|
+
})
|
|
230
|
+
})
|