@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,157 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import type { AgentRuntimeContext } from '../../types/agent/base.js'
|
|
4
|
+
import type { TaskGateway } from '../../types/agent/gateway.js'
|
|
5
|
+
import type { ToolDefinition } from '../../types/tool/index.js'
|
|
6
|
+
import { defineTool } from '../defineTool.js'
|
|
7
|
+
|
|
8
|
+
import type { TaskLaunchedCallback } from './index.js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Build the canonical Claude Code `Agent` tool — synchronous subagent
|
|
12
|
+
* delegation that mirrors what Claude is trained against in
|
|
13
|
+
* `code.claude.com/docs/en/sub-agents`.
|
|
14
|
+
*
|
|
15
|
+
* Semantics: parent calls `Agent({ description, prompt, subagent_type })`,
|
|
16
|
+
* the runtime spawns the chosen subagent with its own context window,
|
|
17
|
+
* the parent's tool call BLOCKS until the subagent finishes, and the
|
|
18
|
+
* subagent's final text comes back as the tool result. Intermediate
|
|
19
|
+
* subagent tool calls are isolated — only the summary surfaces to
|
|
20
|
+
* the parent.
|
|
21
|
+
*
|
|
22
|
+
* This is **NOT** the same shape as the legacy `create_task` /
|
|
23
|
+
* `continue_task` / `cancel_task` trio that this package ships
|
|
24
|
+
* alongside it: those are non-blocking and use a `<task-notification>`
|
|
25
|
+
* callback model. The async pattern is useful for hosts that want a
|
|
26
|
+
* work-queue surface, but it is not what Claude Code trained against.
|
|
27
|
+
* For free agentic alignment, prefer the canonical `Agent` tool; keep
|
|
28
|
+
* the legacy coordinator tools only when you genuinely need
|
|
29
|
+
* fire-and-forget multi-task fan-out.
|
|
30
|
+
*/
|
|
31
|
+
export interface AgentToolOptions {
|
|
32
|
+
gateway: TaskGateway
|
|
33
|
+
workingDirectory: string
|
|
34
|
+
runtimeContext?: AgentRuntimeContext
|
|
35
|
+
allowedAgentIds: string[]
|
|
36
|
+
|
|
37
|
+
onTaskLaunched?: TaskLaunchedCallback
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function buildAgentTool(opts: AgentToolOptions): ToolDefinition {
|
|
41
|
+
const { gateway, allowedAgentIds: agentIds, onTaskLaunched } = opts
|
|
42
|
+
const cwd = opts.workingDirectory
|
|
43
|
+
|
|
44
|
+
const subagentTypeEnum =
|
|
45
|
+
agentIds.length > 0 ? z.enum(agentIds as [string, ...string[]]) : z.string()
|
|
46
|
+
|
|
47
|
+
return defineTool({
|
|
48
|
+
name: 'Agent',
|
|
49
|
+
description: `Delegate a task to a specialized subagent. BLOCKING: returns when the subagent has finished, with the subagent's final text as the tool result. The subagent runs in its own context window and cannot see your conversation — include all necessary context in the prompt. Available subagents: ${agentIds.join(', ')}. To run multiple subagents in parallel, call this tool multiple times in a single response.`,
|
|
50
|
+
inputSchema: z.object({
|
|
51
|
+
description: z.string().describe('Short label for tracking (shown to the user)'),
|
|
52
|
+
prompt: z
|
|
53
|
+
.string()
|
|
54
|
+
.describe('Self-contained task description with all context the subagent needs'),
|
|
55
|
+
subagent_type:
|
|
56
|
+
agentIds.length === 1
|
|
57
|
+
? subagentTypeEnum
|
|
58
|
+
.optional()
|
|
59
|
+
.describe(`Which subagent to run (defaults to the only one: ${agentIds[0]})`)
|
|
60
|
+
: subagentTypeEnum.describe('Which subagent to run'),
|
|
61
|
+
}),
|
|
62
|
+
category: 'custom',
|
|
63
|
+
permissions: [],
|
|
64
|
+
readOnly: false,
|
|
65
|
+
destructive: false,
|
|
66
|
+
concurrencySafe: true,
|
|
67
|
+
async execute({ description, prompt, subagent_type }, context) {
|
|
68
|
+
// With a single registered subagent the type is optional — default to
|
|
69
|
+
// it so the model can't trip the "subagent_type required" validation.
|
|
70
|
+
const agentId = subagent_type ?? (agentIds.length === 1 ? agentIds[0] : undefined)
|
|
71
|
+
if (!agentId) {
|
|
72
|
+
return {
|
|
73
|
+
success: false,
|
|
74
|
+
output: '',
|
|
75
|
+
error: `subagent_type is required — choose one of: ${agentIds.join(', ')}`,
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const handle = await gateway.createTask({
|
|
79
|
+
agentId,
|
|
80
|
+
prompt,
|
|
81
|
+
workingDirectory: cwd,
|
|
82
|
+
runtimeContext: opts.runtimeContext,
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
onTaskLaunched?.(handle.taskId, {
|
|
86
|
+
agentId,
|
|
87
|
+
description,
|
|
88
|
+
// Same canonical-envelope plumbing as coordinator/index.ts
|
|
89
|
+
// (ses_009-task-notification-envelope). For Agent-tool path
|
|
90
|
+
// the subagent run is awaited synchronously below, so this
|
|
91
|
+
// id is only used if a probe / hook unexpectedly forks the
|
|
92
|
+
// completion to the background notification channel.
|
|
93
|
+
originalToolUseId: context.toolUseId,
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
const completed = await gateway.waitForTask(handle.taskId)
|
|
97
|
+
|
|
98
|
+
// Two layers can disagree on whether the subagent succeeded:
|
|
99
|
+
//
|
|
100
|
+
// 1. `TaskHandle.state` — the gateway's terminal task state.
|
|
101
|
+
// Some gateways (e.g. vandal's) explicitly map
|
|
102
|
+
// `result.status !== 'completed'` to `state = 'failed'`,
|
|
103
|
+
// others (e.g. SDK's `LocalTaskGateway`) just forward
|
|
104
|
+
// whatever the AgentManager set, which does not always
|
|
105
|
+
// reflect run-level failure.
|
|
106
|
+
// 2. `BaseAgentResult.status` — the run's own status. The
|
|
107
|
+
// canonical source of truth for whether the agent actually
|
|
108
|
+
// finished its work; `lastError` carries the failure
|
|
109
|
+
// message when set.
|
|
110
|
+
//
|
|
111
|
+
// Treat the subagent as successful only when BOTH agree.
|
|
112
|
+
// Reporting a failed subagent as successful would silently
|
|
113
|
+
// hand the parent garbage output and make debugging
|
|
114
|
+
// impossible, which is what Codex flagged on the first cut.
|
|
115
|
+
const runStatus = completed.result?.status
|
|
116
|
+
const succeeded =
|
|
117
|
+
completed.state === 'completed' && (runStatus === undefined || runStatus === 'completed')
|
|
118
|
+
|
|
119
|
+
const resultText =
|
|
120
|
+
typeof completed.result?.result === 'string'
|
|
121
|
+
? completed.result.result
|
|
122
|
+
: completed.result?.result !== undefined
|
|
123
|
+
? JSON.stringify(completed.result.result)
|
|
124
|
+
: ''
|
|
125
|
+
|
|
126
|
+
if (!succeeded) {
|
|
127
|
+
const failureLabel =
|
|
128
|
+
completed.state !== 'completed' ? completed.state : (runStatus ?? 'failed')
|
|
129
|
+
const detail =
|
|
130
|
+
completed.result?.lastError ?? resultText ?? '(subagent provided no failure detail)'
|
|
131
|
+
return {
|
|
132
|
+
success: false,
|
|
133
|
+
output: '',
|
|
134
|
+
error: `Subagent ${agentId} ${failureLabel}: ${detail}`,
|
|
135
|
+
data: {
|
|
136
|
+
task_id: handle.taskId,
|
|
137
|
+
subagent_type: agentId,
|
|
138
|
+
state: completed.state,
|
|
139
|
+
status: runStatus,
|
|
140
|
+
lastError: completed.result?.lastError,
|
|
141
|
+
},
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
success: true,
|
|
147
|
+
output: resultText || '(subagent returned no text)',
|
|
148
|
+
data: {
|
|
149
|
+
task_id: handle.taskId,
|
|
150
|
+
subagent_type: agentId,
|
|
151
|
+
state: completed.state,
|
|
152
|
+
status: runStatus,
|
|
153
|
+
},
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
})
|
|
157
|
+
}
|
|
@@ -2,6 +2,7 @@ import { z } from 'zod'
|
|
|
2
2
|
import type { PlanManager } from '../../manager/plan/lifecycle.js'
|
|
3
3
|
import type { AgentRuntimeContext } from '../../types/agent/base.js'
|
|
4
4
|
import type { TaskGateway } from '../../types/agent/gateway.js'
|
|
5
|
+
import type { ResumeHandler, UserQuestionOption } from '../../types/hitl/index.js'
|
|
5
6
|
import type { RunId, TaskId } from '../../types/ids/index.js'
|
|
6
7
|
import type { TaskStore } from '../../types/task/index.js'
|
|
7
8
|
import type { ToolDefinition } from '../../types/tool/index.js'
|
|
@@ -13,6 +14,13 @@ export type TaskLaunchedCallback = (
|
|
|
13
14
|
agentId: string
|
|
14
15
|
description: string
|
|
15
16
|
planTaskId?: string
|
|
17
|
+
/**
|
|
18
|
+
* The assistant `tool_use_id` that dispatched this task.
|
|
19
|
+
* Threaded from `ToolContext.toolUseId` so the runtime can
|
|
20
|
+
* later emit a canonical `tool_result` content block bound
|
|
21
|
+
* to the same id when the background task completes.
|
|
22
|
+
*/
|
|
23
|
+
originalToolUseId?: string
|
|
16
24
|
},
|
|
17
25
|
) => void
|
|
18
26
|
|
|
@@ -29,6 +37,52 @@ export interface CoordinatorToolsOptions {
|
|
|
29
37
|
getPlanManager?: () => PlanManager | undefined
|
|
30
38
|
|
|
31
39
|
onTaskLaunched?: TaskLaunchedCallback
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* HITL park channel for `ask_user_question`. The tool is registered
|
|
43
|
+
* only when BOTH `resumeHandler` and `runId` are present — without a
|
|
44
|
+
* handler there is no one to route the question to, and without a
|
|
45
|
+
* runId the park request cannot be addressed.
|
|
46
|
+
*/
|
|
47
|
+
resumeHandler?: ResumeHandler
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const approvePlanStepSchema = z.object({
|
|
51
|
+
description: z.string().describe('What this step does'),
|
|
52
|
+
agent_id: z
|
|
53
|
+
.string()
|
|
54
|
+
.optional()
|
|
55
|
+
.describe('Which agent handles this (omit for orchestrator-owned steps)'),
|
|
56
|
+
depends_on: z.array(z.string()).optional().describe('Step descriptions this depends on'),
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
function normalizeApprovePlanSteps(value: unknown): unknown {
|
|
60
|
+
if (typeof value !== 'string') return value
|
|
61
|
+
|
|
62
|
+
const trimmed = value.trim()
|
|
63
|
+
if (!trimmed) return []
|
|
64
|
+
|
|
65
|
+
if (trimmed.startsWith('[')) {
|
|
66
|
+
try {
|
|
67
|
+
return JSON.parse(trimmed)
|
|
68
|
+
} catch {
|
|
69
|
+
// Fall through to plain-text line parsing.
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const lines = trimmed
|
|
74
|
+
.split(/\r?\n+/)
|
|
75
|
+
.map((line) =>
|
|
76
|
+
line
|
|
77
|
+
.trim()
|
|
78
|
+
.replace(/^(?:[-*•]|\d+[.)])\s*/, '')
|
|
79
|
+
.trim(),
|
|
80
|
+
)
|
|
81
|
+
.filter(Boolean)
|
|
82
|
+
|
|
83
|
+
return (lines.length ? lines : [trimmed]).map((description) => ({
|
|
84
|
+
description,
|
|
85
|
+
}))
|
|
32
86
|
}
|
|
33
87
|
|
|
34
88
|
export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefinition[] {
|
|
@@ -38,21 +92,30 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
|
|
|
38
92
|
taskStore,
|
|
39
93
|
runId,
|
|
40
94
|
getPlanManager,
|
|
41
|
-
|
|
95
|
+
resumeHandler,
|
|
96
|
+
// `onTaskLaunched` was the entry point for the old
|
|
97
|
+
// non-blocking + envelope-injection flow. create_task is now
|
|
98
|
+
// blocking, so the callback is no longer wired here.
|
|
99
|
+
// Intentionally not destructured to keep the unused-binding
|
|
100
|
+
// lint clean; callers can still pass it for backwards
|
|
101
|
+
// compatibility (Agent tool consumes it from its own path).
|
|
42
102
|
} = opts
|
|
43
103
|
const cwd = opts.workingDirectory
|
|
104
|
+
void opts.onTaskLaunched
|
|
44
105
|
|
|
45
106
|
const agentIdEnum = agentIds.length > 0 ? z.enum(agentIds as [string, ...string[]]) : z.string()
|
|
46
107
|
|
|
47
108
|
const createTask = defineTool({
|
|
48
109
|
name: 'create_task',
|
|
49
|
-
description: `Launch a task on a specialized agent.
|
|
110
|
+
description: `Launch a task on a specialized agent and await its result. BLOCKING: returns the agent's final output as this call's tool_result. Available agents: ${agentIds.join(', ')}. Prefer compact assignments; for large context, write/read shared workspace files and pass filenames or references. To launch multiple tasks in parallel, call this tool multiple times in a single assistant turn — the runtime executes every tool_use block from one response concurrently and delivers all tool_results together, so 'fan out 8 specialists' is one assistant message with 8 create_task blocks.`,
|
|
50
111
|
inputSchema: z.object({
|
|
51
112
|
agent_id: agentIdEnum.describe('Which agent to run'),
|
|
52
113
|
prompt: z
|
|
53
114
|
.string()
|
|
54
|
-
.describe(
|
|
55
|
-
|
|
115
|
+
.describe(
|
|
116
|
+
'Self-contained assignment for the agent. For large generated content, prefer workspace file references so provider output-token limits do not cut off the tool call.',
|
|
117
|
+
),
|
|
118
|
+
description: z.string().describe('Short summary for tracking, shown to the user.'),
|
|
56
119
|
plan_task_id: z
|
|
57
120
|
.string()
|
|
58
121
|
.optional()
|
|
@@ -65,7 +128,7 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
|
|
|
65
128
|
readOnly: false,
|
|
66
129
|
destructive: false,
|
|
67
130
|
concurrencySafe: true,
|
|
68
|
-
async execute({ agent_id, prompt, description, plan_task_id }) {
|
|
131
|
+
async execute({ agent_id, prompt, description, plan_task_id }, _context) {
|
|
69
132
|
let resolvedPlanTaskId = plan_task_id
|
|
70
133
|
|
|
71
134
|
if (taskStore) {
|
|
@@ -93,22 +156,36 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
|
|
|
93
156
|
runtimeContext: opts.runtimeContext,
|
|
94
157
|
})
|
|
95
158
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
159
|
+
// Industrial-standard Anthropic tool pattern: tool returns
|
|
160
|
+
// its real result as the tool_result for the dispatching
|
|
161
|
+
// tool_use. Parallel fan-out happens at the executor layer
|
|
162
|
+
// — when the supervisor emits N create_task blocks in one
|
|
163
|
+
// assistant turn, the runtime runs them with Promise.all
|
|
164
|
+
// and delivers all N tool_results together. No async
|
|
165
|
+
// envelope injection, no second tool_result for the same
|
|
166
|
+
// tool_use_id (which Anthropic rejects with 400).
|
|
167
|
+
const completed = await gateway.waitForTask(handle.taskId)
|
|
168
|
+
const success = completed.state === 'completed'
|
|
169
|
+
const resultText =
|
|
170
|
+
completed.result?.result ??
|
|
171
|
+
completed.result?.lastError ??
|
|
172
|
+
`Task finished with state: ${completed.state}`
|
|
173
|
+
|
|
174
|
+
if (resolvedPlanTaskId && taskStore) {
|
|
175
|
+
await taskStore.update(resolvedPlanTaskId as `task_${string}`, {
|
|
176
|
+
status: 'completed',
|
|
177
|
+
description: success ? undefined : `Failed: ${resultText.substring(0, 200)}`,
|
|
101
178
|
})
|
|
102
179
|
}
|
|
103
180
|
|
|
104
181
|
return {
|
|
105
|
-
success
|
|
106
|
-
output:
|
|
182
|
+
success,
|
|
183
|
+
output: resultText,
|
|
107
184
|
data: {
|
|
108
185
|
task_id: handle.taskId,
|
|
109
186
|
agent_id,
|
|
110
187
|
description,
|
|
111
|
-
state:
|
|
188
|
+
state: completed.state,
|
|
112
189
|
plan_task_id: resolvedPlanTaskId,
|
|
113
190
|
},
|
|
114
191
|
}
|
|
@@ -118,11 +195,9 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
|
|
|
118
195
|
const continueTask = defineTool({
|
|
119
196
|
name: 'continue_task',
|
|
120
197
|
description:
|
|
121
|
-
|
|
198
|
+
"Send a follow-up message to a previously completed task and await the agent's next reply. BLOCKING: returns the agent's new output as this call's tool_result, the same shape as create_task. Only use this with a task_id from a previous create_task. To run multiple follow-ups in parallel, call this tool multiple times in a single assistant turn.",
|
|
122
199
|
inputSchema: z.object({
|
|
123
|
-
task_id: z
|
|
124
|
-
.string()
|
|
125
|
-
.describe('Agent task ID from a previous create_task or task-notification'),
|
|
200
|
+
task_id: z.string().describe('Agent task ID from a previous create_task'),
|
|
126
201
|
message: z.string().describe('Follow-up instruction for the agent'),
|
|
127
202
|
}),
|
|
128
203
|
category: 'custom',
|
|
@@ -132,11 +207,22 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
|
|
|
132
207
|
concurrencySafe: true,
|
|
133
208
|
async execute({ task_id, message }) {
|
|
134
209
|
await gateway.continueTask(task_id as TaskId, message)
|
|
135
|
-
|
|
210
|
+
// Mirror create_task's blocking pattern: await the new
|
|
211
|
+
// completion and return the agent's output inline. The
|
|
212
|
+
// previous non-blocking shape ('You will receive a
|
|
213
|
+
// task-notification…') relied on a global
|
|
214
|
+
// onTaskCompleted listener that the iteration loop
|
|
215
|
+
// no longer registers (envelope path is dead).
|
|
216
|
+
const completed = await gateway.waitForTask(task_id as TaskId)
|
|
217
|
+
const success = completed.state === 'completed'
|
|
218
|
+
const resultText =
|
|
219
|
+
completed.result?.result ??
|
|
220
|
+
completed.result?.lastError ??
|
|
221
|
+
`Task finished with state: ${completed.state}`
|
|
136
222
|
return {
|
|
137
|
-
success
|
|
138
|
-
output:
|
|
139
|
-
data: { task_id, state:
|
|
223
|
+
success,
|
|
224
|
+
output: resultText,
|
|
225
|
+
data: { task_id, state: completed.state },
|
|
140
226
|
}
|
|
141
227
|
},
|
|
142
228
|
})
|
|
@@ -163,7 +249,75 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
|
|
|
163
249
|
},
|
|
164
250
|
})
|
|
165
251
|
|
|
166
|
-
const
|
|
252
|
+
const agentTaskList = defineTool({
|
|
253
|
+
name: 'agent_task_list',
|
|
254
|
+
description:
|
|
255
|
+
"Inspect the live state of every agent task launched on this gateway via create_task: returns each task's id, agent, state (pending/running/completed/failed/canceled), and timing. Distinct from the plan-task store's `task_list` (which lists planning tasks): this tool lists running/completed worker invocations. Use it BEFORE declaring multi-worker work done — confirm every launched task reached `completed`, none still `running` or `failed`. Read-only and safe to call repeatedly.",
|
|
256
|
+
inputSchema: z.object({
|
|
257
|
+
state: z
|
|
258
|
+
.enum(['pending', 'running', 'completed', 'failed', 'canceled'])
|
|
259
|
+
.optional()
|
|
260
|
+
.describe('Filter by terminal/non-terminal state. Omit to list every task.'),
|
|
261
|
+
}),
|
|
262
|
+
category: 'custom',
|
|
263
|
+
permissions: [],
|
|
264
|
+
readOnly: true,
|
|
265
|
+
destructive: false,
|
|
266
|
+
concurrencySafe: true,
|
|
267
|
+
async execute({ state }) {
|
|
268
|
+
const handles = gateway.listTasks()
|
|
269
|
+
const filtered = state ? handles.filter((h) => h.state === state) : handles
|
|
270
|
+
const items = filtered.map((h) => {
|
|
271
|
+
const runStatus = h.result?.status
|
|
272
|
+
const lastError = h.result?.lastError ?? undefined
|
|
273
|
+
return {
|
|
274
|
+
task_id: h.taskId,
|
|
275
|
+
agent_id: h.agentId,
|
|
276
|
+
state: h.state,
|
|
277
|
+
run_status: runStatus,
|
|
278
|
+
created_at: new Date(h.createdAt).toISOString(),
|
|
279
|
+
completed_at: h.completedAt ? new Date(h.completedAt).toISOString() : null,
|
|
280
|
+
duration_ms: h.completedAt ? h.completedAt - h.createdAt : null,
|
|
281
|
+
last_error: lastError,
|
|
282
|
+
}
|
|
283
|
+
})
|
|
284
|
+
const summary = {
|
|
285
|
+
total: handles.length,
|
|
286
|
+
running: handles.filter((h) => h.state === 'running').length,
|
|
287
|
+
completed: handles.filter((h) => h.state === 'completed').length,
|
|
288
|
+
failed: handles.filter((h) => h.state === 'failed').length,
|
|
289
|
+
canceled: handles.filter((h) => h.state === 'canceled').length,
|
|
290
|
+
}
|
|
291
|
+
const lines = items.length
|
|
292
|
+
? items.map(
|
|
293
|
+
(i) =>
|
|
294
|
+
`- ${i.task_id} → ${i.agent_id} [${i.state}${i.run_status && i.run_status !== i.state ? ` / ${i.run_status}` : ''}]${
|
|
295
|
+
i.duration_ms !== null ? ` (${Math.round(i.duration_ms / 1000)}s)` : ''
|
|
296
|
+
}${i.last_error ? ` — error: ${i.last_error.slice(0, 200)}` : ''}`,
|
|
297
|
+
)
|
|
298
|
+
: ['(no tasks launched yet)']
|
|
299
|
+
const header = `Tasks: ${summary.total} total — ${summary.running} running, ${summary.completed} completed, ${summary.failed} failed, ${summary.canceled} canceled`
|
|
300
|
+
return {
|
|
301
|
+
success: true,
|
|
302
|
+
output: [header, '', ...lines].join('\n'),
|
|
303
|
+
data: { items, summary },
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
// `continue_task` was a follow-up channel for a still-alive worker
|
|
309
|
+
// task. With `create_task` now blocking + tool_result returning
|
|
310
|
+
// the worker's final output, every worker reaches a terminal
|
|
311
|
+
// state by the time the supervisor wants to follow up — and the
|
|
312
|
+
// agent manager rejects `continue` on terminal tasks. The
|
|
313
|
+
// industrial pattern is to issue a fresh `create_task` that
|
|
314
|
+
// references the prior worker's output path, so we drop
|
|
315
|
+
// `continue_task` from the registered surface entirely. The
|
|
316
|
+
// definition stays in this file for now in case a future
|
|
317
|
+
// non-default gateway (one that keeps the worker process alive
|
|
318
|
+
// for follow-ups) wants to re-register it.
|
|
319
|
+
void continueTask
|
|
320
|
+
const tools: ToolDefinition[] = [createTask, cancelTask, agentTaskList]
|
|
167
321
|
|
|
168
322
|
if (getPlanManager) {
|
|
169
323
|
const approvePlan = defineTool({
|
|
@@ -176,26 +330,18 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
|
|
|
176
330
|
.describe('Short title for the plan (e.g. "TypeScript Security & Performance Review")'),
|
|
177
331
|
summary: z.string().describe('1-3 sentence summary of what you plan to do'),
|
|
178
332
|
steps: z
|
|
179
|
-
.array(
|
|
180
|
-
z.object({
|
|
181
|
-
description: z.string().describe('What this step does'),
|
|
182
|
-
agent_id: z
|
|
183
|
-
.string()
|
|
184
|
-
.optional()
|
|
185
|
-
.describe('Which agent handles this (omit for orchestrator-owned steps)'),
|
|
186
|
-
depends_on: z
|
|
187
|
-
.array(z.string())
|
|
188
|
-
.optional()
|
|
189
|
-
.describe('Step descriptions this depends on'),
|
|
190
|
-
}),
|
|
191
|
-
)
|
|
333
|
+
.preprocess(normalizeApprovePlanSteps, z.array(approvePlanStepSchema))
|
|
192
334
|
.describe('Ordered list of planned steps'),
|
|
193
335
|
}),
|
|
194
336
|
category: 'custom',
|
|
195
337
|
permissions: [],
|
|
196
338
|
readOnly: true,
|
|
197
339
|
destructive: false,
|
|
198
|
-
|
|
340
|
+
// Parks through the SAME runId-keyed host resume registry as
|
|
341
|
+
// ask_user_question — concurrent parks in one batch clobber the
|
|
342
|
+
// registry entry and deadlock the loser, so the executor must
|
|
343
|
+
// serialize this tool exactly like the question tool.
|
|
344
|
+
concurrencySafe: false,
|
|
199
345
|
async execute({ title, summary, steps }) {
|
|
200
346
|
const pm = getPlanManager()
|
|
201
347
|
if (!pm) {
|
|
@@ -224,17 +370,27 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
|
|
|
224
370
|
|
|
225
371
|
if (response.approved) {
|
|
226
372
|
pm.startExecution()
|
|
373
|
+
// Approve-with-edits: when the user attached feedback to an
|
|
374
|
+
// approval, embed it in the model-visible output so the
|
|
375
|
+
// supervisor applies the edits during execution. A bare
|
|
376
|
+
// approve keeps the historical output byte-identical.
|
|
377
|
+
const output = response.feedback
|
|
378
|
+
? `Plan approved by user with required edits — apply them during execution:\n${response.feedback}\nProceed with execution — launch workers via create_task.`
|
|
379
|
+
: 'Plan approved by user. Proceed with execution — launch workers via create_task.'
|
|
227
380
|
return {
|
|
228
381
|
success: true,
|
|
229
|
-
output
|
|
230
|
-
'Plan approved by user. Proceed with execution — launch workers via create_task.',
|
|
382
|
+
output,
|
|
231
383
|
data: { approved: true, feedback: response.feedback },
|
|
232
384
|
}
|
|
233
385
|
}
|
|
234
386
|
|
|
387
|
+
// Rejection guidance follows the FEEDBACK, not a baked-in
|
|
388
|
+
// revise loop: the old unconditional "revise … and call
|
|
389
|
+
// approve_plan again" contradicted stop-style feedback, so a
|
|
390
|
+
// user rejecting a plan got another plan instead of a halt.
|
|
235
391
|
return {
|
|
236
392
|
success: false,
|
|
237
|
-
output: `Plan rejected. User feedback: ${response.feedback ?? 'No feedback provided'}.
|
|
393
|
+
output: `Plan rejected. User feedback: ${response.feedback ?? 'No feedback provided'}. Follow this feedback: if it requests changes, revise your plan and call approve_plan again; if it asks you to stop, acknowledge briefly and end your turn. If no feedback was provided, ask the user how to proceed before planning again.`,
|
|
238
394
|
data: { approved: false, feedback: response.feedback },
|
|
239
395
|
}
|
|
240
396
|
},
|
|
@@ -242,5 +398,165 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
|
|
|
242
398
|
tools.push(approvePlan)
|
|
243
399
|
}
|
|
244
400
|
|
|
401
|
+
if (resumeHandler && runId) {
|
|
402
|
+
const parkRunId = runId
|
|
403
|
+
const parkHandler = resumeHandler
|
|
404
|
+
const askUserQuestion = defineTool({
|
|
405
|
+
name: 'ask_user_question',
|
|
406
|
+
description:
|
|
407
|
+
'Ask the user ONE question ONLY when you are blocked on a decision that is genuinely theirs to make — one you cannot resolve from their request, your tools, the files you can read, or sensible defaults. The question must be the genuinely undecidable thing in THIS task. Never ask for information a tool can discover (do not ask what you can read, list, or search), never re-ask what the conversation already answers, and never ask meta-questions like "Shall I proceed?" — plan ratification goes through approve_plan. Provide 2-4 genuinely distinct options derived from the actual context — concrete paths, never generic placeholders (for example, asked to prepare a presentation, ask "Who is the audience?" with options like Board / Engineering team / Customer); keep labels short (1-5 words) and give each option a one-line description of what practically changes if it is chosen. Put your recommended option FIRST and append " (Recommended)" to its label. Set multiSelect: true only when several options can apply at once. A free-text "Something else" escape hatch is always shown automatically — do not add your own "Other" option. Ask ONE question per call and prefer at most one question per assistant turn; if several decisions block you, ask only the ones that materially change your next actions, in sequence — most work needs at most 2-3 questions, so prefer proceeding on stated defaults over interrogating the user. Never invent answers or synthetic content on the user\'s behalf unless they explicitly asked for a random/test scenario. The answer arrives as this tool\'s result; if the result says the user did not answer, do not ask this or any other question again — proceed on your best judgment without assuming consent.',
|
|
408
|
+
inputSchema: z.object({
|
|
409
|
+
question: z
|
|
410
|
+
.string()
|
|
411
|
+
.min(1)
|
|
412
|
+
.describe('Full question text — clear, specific, ends with a question mark.'),
|
|
413
|
+
header: z
|
|
414
|
+
.string()
|
|
415
|
+
.max(24)
|
|
416
|
+
.optional()
|
|
417
|
+
.describe('Very short topic label for the question (e.g. "Audience", "Auth method").'),
|
|
418
|
+
options: z
|
|
419
|
+
.array(
|
|
420
|
+
z.object({
|
|
421
|
+
label: z
|
|
422
|
+
.string()
|
|
423
|
+
.min(1)
|
|
424
|
+
.max(80)
|
|
425
|
+
.describe(
|
|
426
|
+
'Concise option label (1-5 words). Recommended option goes first with " (Recommended)" appended.',
|
|
427
|
+
),
|
|
428
|
+
description: z
|
|
429
|
+
.string()
|
|
430
|
+
.max(300)
|
|
431
|
+
.optional()
|
|
432
|
+
.describe('One line on what practically changes if this option is chosen.'),
|
|
433
|
+
}),
|
|
434
|
+
)
|
|
435
|
+
.min(2)
|
|
436
|
+
.max(4)
|
|
437
|
+
.describe('2-4 genuinely distinct, context-derived options.'),
|
|
438
|
+
multiSelect: z
|
|
439
|
+
.boolean()
|
|
440
|
+
.optional()
|
|
441
|
+
.default(false)
|
|
442
|
+
.describe('True only when several options can apply at once.'),
|
|
443
|
+
allowFreeText: z
|
|
444
|
+
.boolean()
|
|
445
|
+
.optional()
|
|
446
|
+
.default(true)
|
|
447
|
+
.describe('Whether the user may answer in their own words.'),
|
|
448
|
+
}),
|
|
449
|
+
category: 'custom',
|
|
450
|
+
permissions: [],
|
|
451
|
+
readOnly: true,
|
|
452
|
+
destructive: false,
|
|
453
|
+
// MUST stay false: the executor serializes non-concurrency-safe
|
|
454
|
+
// tools in a single chain, so N question blocks in one assistant
|
|
455
|
+
// turn park strictly one-at-a-time. Hosts key their park/resolve
|
|
456
|
+
// registries by runId — concurrent parks on one run clobber each
|
|
457
|
+
// other and the first promise never resolves (run hangs to TTL).
|
|
458
|
+
concurrencySafe: false,
|
|
459
|
+
async execute({ question, header, options, multiSelect, allowFreeText }, context) {
|
|
460
|
+
const toolUseId = context.toolUseId
|
|
461
|
+
if (!toolUseId) {
|
|
462
|
+
// Without the executing tool_use_id the question has no
|
|
463
|
+
// stable identity: the host could never merge the awaiting
|
|
464
|
+
// card with its resolution, and answers could not be matched
|
|
465
|
+
// back. Hard-fail instead of parking an unmergeable id.
|
|
466
|
+
return {
|
|
467
|
+
success: false,
|
|
468
|
+
output: '',
|
|
469
|
+
error:
|
|
470
|
+
'ask_user_question requires an executor that threads ToolContext.toolUseId; the question cannot be tracked without it.',
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
const questionOptions: UserQuestionOption[] = options.map((opt, i) => ({
|
|
475
|
+
id: `opt_${i + 1}`,
|
|
476
|
+
label: opt.label,
|
|
477
|
+
...(opt.description !== undefined ? { description: opt.description } : {}),
|
|
478
|
+
}))
|
|
479
|
+
|
|
480
|
+
const decision = await parkHandler({
|
|
481
|
+
type: 'user_question',
|
|
482
|
+
runId: parkRunId,
|
|
483
|
+
checkpointId: `cp_question_${toolUseId}`,
|
|
484
|
+
question: {
|
|
485
|
+
questionId: toolUseId,
|
|
486
|
+
question,
|
|
487
|
+
...(header !== undefined ? { header } : {}),
|
|
488
|
+
options: questionOptions,
|
|
489
|
+
multiSelect,
|
|
490
|
+
allowFreeText,
|
|
491
|
+
},
|
|
492
|
+
})
|
|
493
|
+
|
|
494
|
+
// The no-answer sentinel (explicitly NOT consent — fixes the
|
|
495
|
+
// "empty answer reads as approval" ambiguity): used for empty
|
|
496
|
+
// answers, misdirected legacy decisions (e.g. a stale replica
|
|
497
|
+
// resolving with approve/continue verbs), and answers that
|
|
498
|
+
// carry a different question's id.
|
|
499
|
+
const noAnswer = {
|
|
500
|
+
success: true,
|
|
501
|
+
output:
|
|
502
|
+
'The user did not answer this question. Do not assume a choice or consent; proceed on your best judgment or continue without this information.',
|
|
503
|
+
data: { question, answered: false },
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (decision.action === 'abort') {
|
|
507
|
+
return {
|
|
508
|
+
success: false,
|
|
509
|
+
output:
|
|
510
|
+
'The user declined to answer and asked to stop. Acknowledge briefly and end your turn.',
|
|
511
|
+
data: { question, answered: false, declined: true },
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (decision.action !== 'answer_question') return noAnswer
|
|
516
|
+
if (decision.questionId !== undefined && decision.questionId !== toolUseId) {
|
|
517
|
+
// Misdirection guard: this answer was meant for a different
|
|
518
|
+
// question parked under the same run (stale client). Never
|
|
519
|
+
// fabricate a selection against the wrong question.
|
|
520
|
+
return noAnswer
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const stripRecommended = (label: string) =>
|
|
524
|
+
label.replace(/\s*\(recommended\)\s*$/i, '').trim()
|
|
525
|
+
|
|
526
|
+
const selected = decision.selectedOptionIds
|
|
527
|
+
.map((id) => questionOptions.find((opt) => opt.id === id))
|
|
528
|
+
.filter((opt): opt is UserQuestionOption => opt !== undefined)
|
|
529
|
+
.map((opt) => ({ id: opt.id, label: stripRecommended(opt.label) }))
|
|
530
|
+
|
|
531
|
+
const freeText = decision.freeText?.trim() ?? ''
|
|
532
|
+
|
|
533
|
+
if (selected.length === 0 && !freeText) return noAnswer
|
|
534
|
+
|
|
535
|
+
let output: string
|
|
536
|
+
if (selected.length > 0) {
|
|
537
|
+
const joined = selected.map((s) => `"${s.label}"`).join(', ')
|
|
538
|
+
output = `User answered "${question}": ${joined}`
|
|
539
|
+
if (freeText) {
|
|
540
|
+
output += `\nAdditional note from the user: "${freeText}"`
|
|
541
|
+
}
|
|
542
|
+
} else {
|
|
543
|
+
output = `User answered "${question}" in their own words: "${freeText}"`
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return {
|
|
547
|
+
success: true,
|
|
548
|
+
output,
|
|
549
|
+
data: {
|
|
550
|
+
question,
|
|
551
|
+
selected,
|
|
552
|
+
...(freeText ? { freeText } : {}),
|
|
553
|
+
answered: true,
|
|
554
|
+
},
|
|
555
|
+
}
|
|
556
|
+
},
|
|
557
|
+
})
|
|
558
|
+
tools.push(askUserQuestion)
|
|
559
|
+
}
|
|
560
|
+
|
|
245
561
|
return tools
|
|
246
562
|
}
|
package/src/types/agent/base.ts
CHANGED
|
@@ -65,6 +65,14 @@ export type RuntimeToolOverrides = Record<string, ToolAvailability | 'disabled'>
|
|
|
65
65
|
export interface AgentRuntimeContext {
|
|
66
66
|
label?: string
|
|
67
67
|
outputDirectory?: string
|
|
68
|
+
/**
|
|
69
|
+
* Optional working/scratch directory the runtime exposes to the
|
|
70
|
+
* agent — sibling to `outputDirectory`, invisible to the
|
|
71
|
+
* output collector. Mirrors the Anthropic Cowork pattern
|
|
72
|
+
* where `/home/claude` is scratch and `/mnt/user-data/outputs` is
|
|
73
|
+
* user-visible.
|
|
74
|
+
*/
|
|
75
|
+
scratchDirectory?: string
|
|
68
76
|
outputFileMarker?: string
|
|
69
77
|
notes?: readonly string[]
|
|
70
78
|
}
|