@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
|
@@ -9,6 +9,8 @@ import { collect } from '../../../provider/collect.js'
|
|
|
9
9
|
import type { ActivityStore } from '../../../store/activity/memory.js'
|
|
10
10
|
import { GENAI, NAMZU, agentIterationSpanName } from '../../../telemetry/attributes.js'
|
|
11
11
|
import { getTracer } from '../../../telemetry/runtime-accessors.js'
|
|
12
|
+
import type { WorkingMemoryProvider } from '../../../types/agent/working-memory.js'
|
|
13
|
+
import { mergeTokenUsage } from '../../../types/common/index.js'
|
|
12
14
|
import type { ResumeHandler } from '../../../types/hitl/index.js'
|
|
13
15
|
import type { ToolUseId } from '../../../types/ids/index.js'
|
|
14
16
|
import { createAssistantMessage, createUserMessage } from '../../../types/message/index.js'
|
|
@@ -24,6 +26,7 @@ import { toErrorMessage } from '../../../utils/error.js'
|
|
|
24
26
|
import { generateMessageId } from '../../../utils/id.js'
|
|
25
27
|
import type { Logger } from '../../../utils/logger.js'
|
|
26
28
|
import type { CheckpointManager } from '../checkpoint.js'
|
|
29
|
+
import { AUTO_CONTINUATION_USER_MESSAGE } from '../continuation.js'
|
|
27
30
|
import type { EmitEvent } from '../events.js'
|
|
28
31
|
import type { ToolExecutor } from '../executor.js'
|
|
29
32
|
import type { GuardCoordinator } from '../guard.js'
|
|
@@ -34,6 +37,7 @@ import { runCompactionCheck } from './phases/compaction.js'
|
|
|
34
37
|
import type { IterationContext } from './phases/index.js'
|
|
35
38
|
import { runPlanGate } from './phases/plan.js'
|
|
36
39
|
import { runToolReview } from './phases/tool-review.js'
|
|
40
|
+
import { refreshWorkingMemory } from './phases/working-memory.js'
|
|
37
41
|
|
|
38
42
|
export type { IterationContext } from './phases/index.js'
|
|
39
43
|
export type { PhaseSignal } from './phases/index.js'
|
|
@@ -52,12 +56,42 @@ export interface IterationConfig {
|
|
|
52
56
|
>
|
|
53
57
|
compactionConfig?: CompactionConfig
|
|
54
58
|
workingStateManager?: WorkingStateManager
|
|
59
|
+
workingMemoryProvider?: WorkingMemoryProvider
|
|
55
60
|
advisoryCtx?: AdvisoryContext
|
|
56
61
|
agentBus?: import('../../../bus/index.js').AgentBus
|
|
57
62
|
verificationGate?: import('../../../verification/gate.js').VerificationGate
|
|
58
63
|
pluginManager?: import('../../../plugin/lifecycle.js').PluginLifecycleManager
|
|
59
64
|
}
|
|
60
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Escape the five XML metacharacters so an interpolated value cannot
|
|
68
|
+
* break out of a tag. Used for the simple identifier fields in the
|
|
69
|
+
* `<task-notification>` envelope (taskId, agentId, status) — values
|
|
70
|
+
* here are controlled enums / opaque ids in practice, but escaping
|
|
71
|
+
* keeps the envelope robust against any future producer that lets a
|
|
72
|
+
* `<` or `&` leak in.
|
|
73
|
+
*/
|
|
74
|
+
function xmlEscape(value: string): string {
|
|
75
|
+
return value
|
|
76
|
+
.replace(/&/g, '&')
|
|
77
|
+
.replace(/</g, '<')
|
|
78
|
+
.replace(/>/g, '>')
|
|
79
|
+
.replace(/"/g, '"')
|
|
80
|
+
.replace(/'/g, ''')
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Wrap free-form worker output in a CDATA section. CDATA preserves
|
|
85
|
+
* the raw text — code, markdown angle brackets, ampersands — so the
|
|
86
|
+
* supervisor sees what the worker actually produced instead of an
|
|
87
|
+
* escape-encoded approximation. The only termination CDATA forbids
|
|
88
|
+
* is the literal `]]>` sequence; we split-and-rejoin around it to
|
|
89
|
+
* keep the section well-formed regardless of payload.
|
|
90
|
+
*/
|
|
91
|
+
function cdataWrap(value: string): string {
|
|
92
|
+
return `<![CDATA[${value.replace(/]]>/g, ']]]]><![CDATA[>')}]]>`
|
|
93
|
+
}
|
|
94
|
+
|
|
61
95
|
/**
|
|
62
96
|
* Map a provider's coarse `finishReason` plus the orchestrator's
|
|
63
97
|
* `forceFinalize` flag onto the per-message {@link MessageStopReason}
|
|
@@ -104,8 +138,11 @@ interface StreamingTurnResult {
|
|
|
104
138
|
* finally-style fall-through path with `stopReason: 'refusal'`.
|
|
105
139
|
* - `tool_input_delta` with no `toolUseId` registered yet: we drop
|
|
106
140
|
* the fragment and log a warning (proxies seen to misorder events).
|
|
107
|
-
* - `chunk.error`:
|
|
108
|
-
*
|
|
141
|
+
* - `chunk.error`: when no tool input is recoverable, we surface as
|
|
142
|
+
* a thrown error after emitting the message_completed terminator so
|
|
143
|
+
* consumer cards still close. If a tool-use block was already open,
|
|
144
|
+
* we instead synthesize a tool call with runtime truncation metadata
|
|
145
|
+
* so the executor can return a model-readable retry hint.
|
|
109
146
|
*/
|
|
110
147
|
async function* streamProviderTurn(
|
|
111
148
|
provider: LLMProvider,
|
|
@@ -134,14 +171,60 @@ async function* streamProviderTurn(
|
|
|
134
171
|
}
|
|
135
172
|
const toolBuckets = new Map<
|
|
136
173
|
number,
|
|
137
|
-
{
|
|
174
|
+
{
|
|
175
|
+
id: string
|
|
176
|
+
name: string
|
|
177
|
+
argsBuf: string
|
|
178
|
+
started: boolean
|
|
179
|
+
completed: boolean
|
|
180
|
+
/**
|
|
181
|
+
* Parsed input. `null` while the bucket is still streaming.
|
|
182
|
+
* The synthesized
|
|
183
|
+
* `ChatCompletionResponse.toolCalls[].function.arguments` is
|
|
184
|
+
* derived from this — never from the raw buffer — so the
|
|
185
|
+
* downstream executor (`runtime/query/executor.ts`) never has
|
|
186
|
+
* to re-parse a truncated string. A truncated tool call is
|
|
187
|
+
* surfaced as `arguments: "{}"` plus `metadata.inputTruncated`
|
|
188
|
+
* so tool args remain clean while the executor can still
|
|
189
|
+
* return a specific retry hint.
|
|
190
|
+
*/
|
|
191
|
+
parsed: unknown | null
|
|
192
|
+
inputTruncated: boolean
|
|
193
|
+
}
|
|
138
194
|
>()
|
|
139
195
|
let streamError: string | undefined
|
|
140
196
|
|
|
141
197
|
const stream = provider.chatStream({ ...params, stream: true }) as AsyncIterable<StreamChunk>
|
|
142
198
|
|
|
199
|
+
// Drive the stream manually so each `.next()` can be RACED against the run
|
|
200
|
+
// abort: a Stop tears the in-flight model request down (the provider got
|
|
201
|
+
// `params.signal`), and we ALSO stop pulling within a tick even if a
|
|
202
|
+
// transport buffers or ignores the signal. The abort rejection propagates
|
|
203
|
+
// out of this generator so the run loop settles the turn as cancelled.
|
|
204
|
+
// `{ once: true }` keeps a multi-iteration run from leaking a listener/turn.
|
|
205
|
+
const it = stream[Symbol.asyncIterator]()
|
|
206
|
+
const signal = params.signal
|
|
207
|
+
let onAbort: (() => void) | undefined
|
|
208
|
+
const aborted: Promise<never> | undefined = signal
|
|
209
|
+
? new Promise<never>((_resolve, reject) => {
|
|
210
|
+
if (signal.aborted) {
|
|
211
|
+
reject(signal.reason)
|
|
212
|
+
return
|
|
213
|
+
}
|
|
214
|
+
onAbort = () => reject(signal.reason)
|
|
215
|
+
signal.addEventListener('abort', onAbort, { once: true })
|
|
216
|
+
})
|
|
217
|
+
: undefined
|
|
218
|
+
|
|
143
219
|
try {
|
|
144
|
-
for
|
|
220
|
+
for (;;) {
|
|
221
|
+
const next = it.next()
|
|
222
|
+
// Neutralize the dangling loser so an eventual rejection of the
|
|
223
|
+
// un-awaited `next` is never an unhandled rejection.
|
|
224
|
+
if (aborted) next.catch(() => {})
|
|
225
|
+
const res = await (aborted ? Promise.race([next, aborted]) : next)
|
|
226
|
+
if (res.done) break
|
|
227
|
+
const chunk = res.value
|
|
145
228
|
if (chunk.error) {
|
|
146
229
|
streamError = chunk.error
|
|
147
230
|
break
|
|
@@ -169,6 +252,8 @@ async function* streamProviderTurn(
|
|
|
169
252
|
argsBuf: '',
|
|
170
253
|
started: false,
|
|
171
254
|
completed: false,
|
|
255
|
+
parsed: null,
|
|
256
|
+
inputTruncated: false,
|
|
172
257
|
}
|
|
173
258
|
toolBuckets.set(tc.index, bucket)
|
|
174
259
|
}
|
|
@@ -218,53 +303,149 @@ async function* streamProviderTurn(
|
|
|
218
303
|
try {
|
|
219
304
|
parsed = bucket.argsBuf ? JSON.parse(bucket.argsBuf) : {}
|
|
220
305
|
} catch (err) {
|
|
306
|
+
bucket.inputTruncated = true
|
|
221
307
|
log.warn('tool input JSON parse failed at content_block_stop', {
|
|
222
308
|
runId,
|
|
223
309
|
toolUseId: endId,
|
|
224
310
|
error: err instanceof Error ? err.message : String(err),
|
|
225
311
|
})
|
|
226
312
|
}
|
|
313
|
+
bucket.parsed = parsed
|
|
227
314
|
await emitEvent({
|
|
228
315
|
type: 'tool_input_completed',
|
|
229
316
|
runId,
|
|
230
317
|
toolUseId: endId as ToolUseId,
|
|
231
318
|
input: parsed,
|
|
319
|
+
...(bucket.inputTruncated ? { inputTruncated: true } : {}),
|
|
232
320
|
})
|
|
233
321
|
yield* drainPending()
|
|
234
322
|
}
|
|
235
323
|
}
|
|
236
324
|
|
|
237
325
|
if (chunk.finishReason) finishReason = chunk.finishReason
|
|
238
|
-
|
|
326
|
+
// Merge (per-field max), not last-write-wins: a late usage frame that
|
|
327
|
+
// omits input/cache tokens must not zero the counts seen earlier in the
|
|
328
|
+
// stream, which would under-report this turn's accumulated usage.
|
|
329
|
+
if (chunk.usage) usage = mergeTokenUsage(usage, chunk.usage)
|
|
239
330
|
}
|
|
240
331
|
} catch (err) {
|
|
332
|
+
// An abort tears the turn down: propagate it so the run loop settles the
|
|
333
|
+
// run as cancelled rather than recording a normal (errored) turn. Any
|
|
334
|
+
// other stream error is captured into the synthesized response as before.
|
|
335
|
+
if (signal?.aborted) throw err
|
|
241
336
|
streamError = err instanceof Error ? err.message : String(err)
|
|
337
|
+
} finally {
|
|
338
|
+
if (onAbort) signal?.removeEventListener('abort', onAbort)
|
|
339
|
+
// Release the underlying connection on every exit (natural end, error,
|
|
340
|
+
// or abort). `for await` did this implicitly on natural completion; the
|
|
341
|
+
// manual drive must do it explicitly. `.return()` on an already-finished
|
|
342
|
+
// provider generator is a no-op.
|
|
343
|
+
await it.return?.().catch(() => {})
|
|
242
344
|
}
|
|
243
345
|
|
|
244
346
|
// Flush any tool buckets the provider failed to close (no toolCallEnd
|
|
245
|
-
// arrived — defensive against providers that don't yet emit it
|
|
347
|
+
// arrived — defensive against providers that don't yet emit it, and
|
|
348
|
+
// the load-bearing path when the provider stream ends with
|
|
349
|
+
// `stop_reason: "max_tokens"` mid-`input_json_delta`. In that case
|
|
350
|
+
// Anthropic's SSE never sends `content_block_stop` for the open
|
|
351
|
+
// tool_use block: the upstream model ran out of completion tokens
|
|
352
|
+
// before it could close the JSON literal, so the buffered
|
|
353
|
+
// `argsBuf` ends with something like `"content":"…some prefix` —
|
|
354
|
+
// not parseable.
|
|
355
|
+
//
|
|
356
|
+
// Two cases coalesce here:
|
|
357
|
+
// 1. The buffer parses cleanly (the provider just forgot to emit
|
|
358
|
+
// `content_block_stop` but the args are intact) — keep parsed.
|
|
359
|
+
// 2. The buffer is truncated mid-literal — `parsed = {}` is the
|
|
360
|
+
// safe fallback so the executor's `JSON.parse(arguments)`
|
|
361
|
+
// succeeds and downstream consumers don't crash. The PRICE
|
|
362
|
+
// we used to pay was the model getting back a generic
|
|
363
|
+
// "<field> is required" Zod error and not realising its
|
|
364
|
+
// previous tool call was truncated server-side, so it would
|
|
365
|
+
// retry with the SAME long input and hit the same cutoff in
|
|
366
|
+
// a loop. Detect the truncation case and mark the tool call
|
|
367
|
+
// with runtime metadata; the executor surfaces a specific
|
|
368
|
+
// "your tool call was cut off by max_tokens — retry with
|
|
369
|
+
// shorter input or split into smaller calls" message that the
|
|
370
|
+
// model can act on.
|
|
246
371
|
for (const bucket of toolBuckets.values()) {
|
|
247
372
|
if (bucket.started && !bucket.completed) {
|
|
248
373
|
bucket.completed = true
|
|
249
374
|
let parsed: unknown = {}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
375
|
+
let truncated = false
|
|
376
|
+
if (bucket.argsBuf) {
|
|
377
|
+
try {
|
|
378
|
+
parsed = JSON.parse(bucket.argsBuf)
|
|
379
|
+
} catch {
|
|
380
|
+
// argsBuf had content but didn't parse — almost
|
|
381
|
+
// certainly the max_tokens-mid-literal cutoff. Mark
|
|
382
|
+
// the bucket so the executor can return a model-
|
|
383
|
+
// readable hint instead of a generic Zod error.
|
|
384
|
+
truncated = true
|
|
385
|
+
parsed = {}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
bucket.parsed = parsed
|
|
389
|
+
bucket.inputTruncated = truncated
|
|
390
|
+
if (truncated) {
|
|
391
|
+
log.warn('tool input truncated by upstream cutoff (no toolCallEnd, argsBuf unparsable)', {
|
|
392
|
+
runId,
|
|
393
|
+
toolUseId: bucket.id,
|
|
394
|
+
toolName: bucket.name,
|
|
395
|
+
bufferLength: bucket.argsBuf.length,
|
|
396
|
+
})
|
|
254
397
|
}
|
|
255
398
|
await emitEvent({
|
|
256
399
|
type: 'tool_input_completed',
|
|
257
400
|
runId,
|
|
258
401
|
toolUseId: bucket.id as ToolUseId,
|
|
259
402
|
input: parsed,
|
|
403
|
+
...(truncated ? { inputTruncated: true } : {}),
|
|
260
404
|
})
|
|
261
405
|
yield* drainPending()
|
|
262
406
|
}
|
|
263
407
|
}
|
|
264
408
|
|
|
409
|
+
// `arguments` MUST be valid JSON for the executor's `JSON.parse`
|
|
410
|
+
// (`runtime/query/executor.ts:executeSingle`) to succeed. We
|
|
411
|
+
// always serialise from the bucket's `parsed` object (filled by
|
|
412
|
+
// either the `toolCallEnd` branch above or the post-stream flush
|
|
413
|
+
// loop) instead of re-emitting `argsBuf`. When the provider
|
|
414
|
+
// stream truncated mid-input, `metadata.inputTruncated` carries that
|
|
415
|
+
// state; the executor parses cleanly and returns a specific
|
|
416
|
+
// model-readable retry hint instead of the generic "Invalid JSON in
|
|
417
|
+
// tool arguments" intercept.
|
|
418
|
+
const toolCalls = [...toolBuckets.entries()]
|
|
419
|
+
.sort(([a], [b]) => a - b)
|
|
420
|
+
.map(([, b]) => ({
|
|
421
|
+
id: b.id,
|
|
422
|
+
type: 'function' as const,
|
|
423
|
+
function: {
|
|
424
|
+
name: b.name,
|
|
425
|
+
arguments: JSON.stringify(b.parsed ?? {}),
|
|
426
|
+
},
|
|
427
|
+
...(b.inputTruncated ? { metadata: { inputTruncated: true } } : {}),
|
|
428
|
+
}))
|
|
429
|
+
|
|
430
|
+
const recoveredToolInputFromStreamError =
|
|
431
|
+
streamError !== undefined && toolCalls.some((tc) => tc.id && tc.function.name)
|
|
432
|
+
const effectiveFinishReason: ChatCompletionResponse['finishReason'] =
|
|
433
|
+
recoveredToolInputFromStreamError ? 'tool_calls' : finishReason
|
|
434
|
+
|
|
435
|
+
if (recoveredToolInputFromStreamError) {
|
|
436
|
+
log.warn('provider stream failed after tool input; surfacing tool call to executor', {
|
|
437
|
+
runId,
|
|
438
|
+
iteration,
|
|
439
|
+
error: streamError,
|
|
440
|
+
toolCallCount: toolCalls.length,
|
|
441
|
+
})
|
|
442
|
+
}
|
|
443
|
+
|
|
265
444
|
const stopReason: MessageStopReason = streamError
|
|
266
|
-
?
|
|
267
|
-
|
|
445
|
+
? recoveredToolInputFromStreamError
|
|
446
|
+
? 'tool_use'
|
|
447
|
+
: 'refusal'
|
|
448
|
+
: synthesizeMessageStopReason(effectiveFinishReason, forceFinalize)
|
|
268
449
|
|
|
269
450
|
await emitEvent({
|
|
270
451
|
type: 'message_completed',
|
|
@@ -277,18 +458,10 @@ async function* streamProviderTurn(
|
|
|
277
458
|
})
|
|
278
459
|
yield* drainPending()
|
|
279
460
|
|
|
280
|
-
if (streamError) {
|
|
461
|
+
if (streamError && !recoveredToolInputFromStreamError) {
|
|
281
462
|
throw new Error(`Provider stream error: ${streamError}`)
|
|
282
463
|
}
|
|
283
464
|
|
|
284
|
-
const toolCalls = [...toolBuckets.entries()]
|
|
285
|
-
.sort(([a], [b]) => a - b)
|
|
286
|
-
.map(([, b]) => ({
|
|
287
|
-
id: b.id,
|
|
288
|
-
type: 'function' as const,
|
|
289
|
-
function: { name: b.name, arguments: b.argsBuf },
|
|
290
|
-
}))
|
|
291
|
-
|
|
292
465
|
const response: ChatCompletionResponse = {
|
|
293
466
|
id: id || messageId,
|
|
294
467
|
model: model || params.model,
|
|
@@ -297,7 +470,7 @@ async function* streamProviderTurn(
|
|
|
297
470
|
content: textBuf.length > 0 ? textBuf : null,
|
|
298
471
|
toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
299
472
|
},
|
|
300
|
-
finishReason,
|
|
473
|
+
finishReason: effectiveFinishReason,
|
|
301
474
|
usage,
|
|
302
475
|
}
|
|
303
476
|
return { response, messageId }
|
|
@@ -342,6 +515,7 @@ export class IterationOrchestrator {
|
|
|
342
515
|
launchedTasks: config.launchedTasks ?? new Map(),
|
|
343
516
|
compactionConfig: config.compactionConfig,
|
|
344
517
|
workingStateManager: config.workingStateManager,
|
|
518
|
+
workingMemoryProvider: config.workingMemoryProvider,
|
|
345
519
|
advisoryCtx: config.advisoryCtx,
|
|
346
520
|
agentBus: config.agentBus,
|
|
347
521
|
verificationGate: config.verificationGate,
|
|
@@ -354,17 +528,19 @@ export class IterationOrchestrator {
|
|
|
354
528
|
const { model } = runConfig
|
|
355
529
|
const tracer = getTracer()
|
|
356
530
|
|
|
531
|
+
// Worker-completion delivery used to fan out through a global
|
|
532
|
+
// onTaskCompleted listener that pushed handles onto
|
|
533
|
+
// `pendingNotifications`; the iteration loop then drained
|
|
534
|
+
// them as <task-notification> envelopes. Both `create_task`
|
|
535
|
+
// and the `Agent` tool are now blocking and return their
|
|
536
|
+
// worker output as the dispatching tool_use's canonical
|
|
537
|
+
// tool_result, so the listener path would only DUPLICATE
|
|
538
|
+
// every completion (once as tool_result, once as injected
|
|
539
|
+
// envelope user-message). Leaving the binding out closes
|
|
540
|
+
// the duplicate notification surface entirely; the dormant
|
|
541
|
+
// drain stays as a no-op until a follow-up tears it out.
|
|
357
542
|
let unsubscribeTaskListener: (() => void) | undefined
|
|
358
|
-
|
|
359
|
-
unsubscribeTaskListener = this.ctx.taskGateway.onTaskCompleted((handle) => {
|
|
360
|
-
this.ctx.pendingNotifications.push(handle)
|
|
361
|
-
this.ctx.log.debug('Task completion queued for notification', {
|
|
362
|
-
taskId: handle.taskId,
|
|
363
|
-
agentId: handle.agentId,
|
|
364
|
-
state: handle.state,
|
|
365
|
-
})
|
|
366
|
-
})
|
|
367
|
-
}
|
|
543
|
+
void unsubscribeTaskListener
|
|
368
544
|
|
|
369
545
|
try {
|
|
370
546
|
const planSignal = yield* runPlanGate(this.ctx)
|
|
@@ -442,11 +618,19 @@ export class IterationOrchestrator {
|
|
|
442
618
|
await this.injectOneTaskNotification()
|
|
443
619
|
}
|
|
444
620
|
|
|
621
|
+
// Re-pin the working-memory block from ground truth at the primacy
|
|
622
|
+
// edge BEFORE compaction runs (so the refreshed slot is what
|
|
623
|
+
// compaction preserves). No-op when no provider is configured.
|
|
624
|
+
await refreshWorkingMemory(this.ctx)
|
|
445
625
|
await runCompactionCheck(this.ctx)
|
|
446
626
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
627
|
+
// Cache discipline: keep the tools param byte-stable even on the
|
|
628
|
+
// forced-final iteration and forbid tool use via tool_choice
|
|
629
|
+
// 'none' instead. Dropping the tools array would invalidate the
|
|
630
|
+
// entire prompt-cache prefix (tools render at position 0) and
|
|
631
|
+
// risks a 400 because the history still carries
|
|
632
|
+
// tool_use/tool_result blocks.
|
|
633
|
+
const openAITools = this.ctx.tools.toLLMTools(this.ctx.allowedTools)
|
|
450
634
|
|
|
451
635
|
const messages = forceFinalize
|
|
452
636
|
? [
|
|
@@ -480,10 +664,15 @@ export class IterationOrchestrator {
|
|
|
480
664
|
{
|
|
481
665
|
model,
|
|
482
666
|
messages,
|
|
483
|
-
tools: openAITools
|
|
667
|
+
tools: openAITools.length > 0 ? openAITools : undefined,
|
|
668
|
+
toolChoice: forceFinalize && openAITools.length > 0 ? 'none' : undefined,
|
|
484
669
|
temperature: runConfig.temperature,
|
|
485
670
|
maxTokens: runConfig.maxResponseTokens,
|
|
486
671
|
cacheControl: { type: 'auto' },
|
|
672
|
+
// Thread the run abort into the model call so a Stop tears the
|
|
673
|
+
// in-flight turn down (provider passes it to fetch; the consumer
|
|
674
|
+
// also races it). Inert when never aborted.
|
|
675
|
+
signal: this.ctx.abortController.signal,
|
|
487
676
|
},
|
|
488
677
|
this.ctx.emitEvent,
|
|
489
678
|
this.ctx.drainPending,
|
|
@@ -588,6 +777,43 @@ export class IterationOrchestrator {
|
|
|
588
777
|
const hasContent =
|
|
589
778
|
response.message.content !== null && response.message.content.length > 0
|
|
590
779
|
|
|
780
|
+
// Auto-continuation on `stop_reason: max_tokens`. The
|
|
781
|
+
// model hit its per-call output cap mid-text (NOT
|
|
782
|
+
// mid-tool-use — that path is handled separately
|
|
783
|
+
// below via `inputTruncated`). Push a synthetic
|
|
784
|
+
// "continue" user message and let the loop fire
|
|
785
|
+
// another turn. The provider receives the partial
|
|
786
|
+
// assistant content + the continue prompt and
|
|
787
|
+
// resumes from where it left off, mirroring the
|
|
788
|
+
// Claude.ai "Continue" affordance.
|
|
789
|
+
//
|
|
790
|
+
// Guards:
|
|
791
|
+
// - `hasContent` so we don't loop forever on an
|
|
792
|
+
// empty cutoff (Anthropic occasionally emits
|
|
793
|
+
// `stop_reason: max_tokens` with no content
|
|
794
|
+
// when an injected pre-fill blocks the model).
|
|
795
|
+
// - `!forceFinalize` so the forced-finalize path
|
|
796
|
+
// never auto-continues — that path is invoked
|
|
797
|
+
// specifically to extract a closing summary.
|
|
798
|
+
// - max_iterations bounds the loop in any case.
|
|
799
|
+
if (!forceFinalize && response.finishReason === 'length' && hasContent) {
|
|
800
|
+
this.ctx.log.info('LLM hit max_tokens mid-text — auto-continuing', {
|
|
801
|
+
runId: runMgr.id,
|
|
802
|
+
iteration: iterationNum,
|
|
803
|
+
completionTokens: response.usage.completionTokens,
|
|
804
|
+
})
|
|
805
|
+
runMgr.pushMessage(createUserMessage(AUTO_CONTINUATION_USER_MESSAGE))
|
|
806
|
+
await this.ctx.emitEvent({
|
|
807
|
+
type: 'iteration_completed',
|
|
808
|
+
runId: runMgr.id,
|
|
809
|
+
iteration: iterationNum,
|
|
810
|
+
hasToolCalls: false,
|
|
811
|
+
})
|
|
812
|
+
yield* this.ctx.drainPending()
|
|
813
|
+
iterSpan.end()
|
|
814
|
+
continue
|
|
815
|
+
}
|
|
816
|
+
|
|
591
817
|
if (!hasContent && !forceFinalize) {
|
|
592
818
|
this.ctx.log.warn('Empty completion detected — requesting final summary', {
|
|
593
819
|
iteration: iterationNum,
|
|
@@ -604,6 +830,16 @@ export class IterationOrchestrator {
|
|
|
604
830
|
hasToolCalls: false,
|
|
605
831
|
})
|
|
606
832
|
yield* this.ctx.drainPending()
|
|
833
|
+
// A Stop that lands AFTER the final turn streamed but before
|
|
834
|
+
// this break must settle the run as cancelled, not end_turn —
|
|
835
|
+
// otherwise the just-produced answer is recorded as a clean
|
|
836
|
+
// completion. Mirrors the between-iteration cancel at :511.
|
|
837
|
+
if (this.ctx.abortController.signal.aborted) {
|
|
838
|
+
runMgr.setStopReason('cancelled')
|
|
839
|
+
runMgr.markCancelled()
|
|
840
|
+
iterSpan.end()
|
|
841
|
+
break
|
|
842
|
+
}
|
|
607
843
|
runMgr.setStopReason('end_turn')
|
|
608
844
|
iterSpan.end()
|
|
609
845
|
break
|
|
@@ -648,6 +884,20 @@ export class IterationOrchestrator {
|
|
|
648
884
|
yield* this.ctx.drainPending()
|
|
649
885
|
iterSpan.end()
|
|
650
886
|
} catch (err) {
|
|
887
|
+
// A Stop that aborted the in-flight turn surfaces here as a
|
|
888
|
+
// thrown abort (the provider stream was raced against the run
|
|
889
|
+
// signal). Settle it as a CANCELLATION — mirroring the
|
|
890
|
+
// between-iteration cancel at the top of the loop — rather than
|
|
891
|
+
// recording it as an SDK failure (error span + failed activity)
|
|
892
|
+
// and re-throwing. The run then returns cleanly with a
|
|
893
|
+
// 'cancelled' stop reason instead of propagating an error.
|
|
894
|
+
if (this.ctx.abortController.signal.aborted) {
|
|
895
|
+
runMgr.setStopReason('cancelled')
|
|
896
|
+
runMgr.markCancelled()
|
|
897
|
+
iterSpan.end()
|
|
898
|
+
break
|
|
899
|
+
}
|
|
900
|
+
|
|
651
901
|
if (iterationActivity) {
|
|
652
902
|
this.ctx.activityStore.fail(iterationActivity.id, toErrorMessage(err))
|
|
653
903
|
}
|
|
@@ -686,47 +936,75 @@ export class IterationOrchestrator {
|
|
|
686
936
|
await this.injectOneTaskNotification()
|
|
687
937
|
}
|
|
688
938
|
|
|
939
|
+
/**
|
|
940
|
+
* Canonical async completion delivery (ses_009-task-notification-envelope).
|
|
941
|
+
*
|
|
942
|
+
* Drains every pending task completion in one pass and emits each as
|
|
943
|
+
* a plain USER text message wrapped in the `<task-notification>`
|
|
944
|
+
* envelope the supervisor prompt expects.
|
|
945
|
+
*
|
|
946
|
+
* Why not a `tool_result` block bound to the dispatching tool_use_id:
|
|
947
|
+
* `create_task` is documented as NON-BLOCKING and returns
|
|
948
|
+
* "Task launched: …" immediately. That immediate return is already
|
|
949
|
+
* recorded as the canonical tool_result for that tool_use, so a
|
|
950
|
+
* second tool_result for the SAME tool_use_id — emitted later, after
|
|
951
|
+
* intervening assistant turns — is rejected by Anthropic with
|
|
952
|
+
* `messages.<n>.content.0: unexpected tool_use_id found in
|
|
953
|
+
* tool_result blocks` because the immediately-prior assistant
|
|
954
|
+
* message no longer carries the matching tool_use. Wrapping as a
|
|
955
|
+
* user text envelope sidesteps the pairing rule entirely.
|
|
956
|
+
*
|
|
957
|
+
* Coalescing N drops into one drain replaces the previous
|
|
958
|
+
* one-at-a-time pattern which forced a separate orchestrator
|
|
959
|
+
* iteration per completed task on wide fan-outs.
|
|
960
|
+
*/
|
|
689
961
|
private async injectOneTaskNotification(): Promise<void> {
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
const
|
|
694
|
-
handle.
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
962
|
+
if (this.ctx.pendingNotifications.length === 0) return
|
|
963
|
+
const handles = this.ctx.pendingNotifications.splice(0)
|
|
964
|
+
|
|
965
|
+
for (const handle of handles) {
|
|
966
|
+
const meta = this.ctx.launchedTasks.get(handle.taskId)
|
|
967
|
+
const resultText =
|
|
968
|
+
handle.result?.result ??
|
|
969
|
+
handle.result?.lastError ??
|
|
970
|
+
`Task finished with state: ${handle.state}`
|
|
971
|
+
|
|
972
|
+
if (meta?.planTaskId && this.ctx.taskStore) {
|
|
973
|
+
const success = handle.state === 'completed'
|
|
974
|
+
await this.ctx.taskStore.update(meta.planTaskId as `task_${string}`, {
|
|
975
|
+
status: 'completed',
|
|
976
|
+
description: success ? undefined : `Failed: ${resultText.substring(0, 200)}`,
|
|
977
|
+
})
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
this.ctx.launchedTasks.delete(handle.taskId)
|
|
981
|
+
|
|
982
|
+
// `remaining-tasks` = inflight workers still pending after this
|
|
983
|
+
// one drains. `launchedTasks` is the single source of truth:
|
|
984
|
+
// it holds every dispatched worker that has NOT yet been
|
|
985
|
+
// drained + delete()'d. The drain batch entries are still
|
|
986
|
+
// inside launchedTasks until each iteration's delete() above
|
|
987
|
+
// removes them, so reading the size right after that delete
|
|
988
|
+
// gives the honest count. Adding `handles.length - 1 - i`
|
|
989
|
+
// here used to double-count this same queue.
|
|
990
|
+
const remainingTasks = this.ctx.launchedTasks.size
|
|
991
|
+
const envelope =
|
|
992
|
+
`<task-notification>\n<task-id>${xmlEscape(handle.taskId)}</task-id>\n` +
|
|
993
|
+
`<agent-id>${xmlEscape(handle.agentId)}</agent-id>\n` +
|
|
994
|
+
`<status>${xmlEscape(handle.state)}</status>\n` +
|
|
995
|
+
`<result>${cdataWrap(resultText)}</result>\n` +
|
|
996
|
+
`<remaining-tasks>${remainingTasks}</remaining-tasks>\n</task-notification>`
|
|
997
|
+
|
|
998
|
+
this.ctx.runMgr.pushMessage(createUserMessage(envelope))
|
|
999
|
+
|
|
1000
|
+
this.ctx.log.info('Task notification injected', {
|
|
1001
|
+
taskId: handle.taskId,
|
|
1002
|
+
agentId: handle.agentId,
|
|
1003
|
+
state: handle.state,
|
|
1004
|
+
planTaskId: meta?.planTaskId,
|
|
1005
|
+
remainingNotifications: remainingTasks,
|
|
703
1006
|
})
|
|
704
1007
|
}
|
|
705
|
-
|
|
706
|
-
this.ctx.launchedTasks.delete(handle.taskId)
|
|
707
|
-
const remainingTasks = this.ctx.launchedTasks.size
|
|
708
|
-
|
|
709
|
-
const notification = [
|
|
710
|
-
'<task-notification>',
|
|
711
|
-
` <task-id>${handle.taskId}</task-id>`,
|
|
712
|
-
` <agent-id>${handle.agentId}</agent-id>`,
|
|
713
|
-
` <status>${handle.state}</status>`,
|
|
714
|
-
` <description>${meta?.description ?? 'agent task'}</description>`,
|
|
715
|
-
` <result>${resultText}</result>`,
|
|
716
|
-
` <remaining-tasks>${remainingTasks}</remaining-tasks>`,
|
|
717
|
-
'</task-notification>',
|
|
718
|
-
].join('\n')
|
|
719
|
-
|
|
720
|
-
this.ctx.runMgr.pushMessage(createUserMessage(notification))
|
|
721
|
-
|
|
722
|
-
this.ctx.log.info('Task notification injected', {
|
|
723
|
-
taskId: handle.taskId,
|
|
724
|
-
agentId: handle.agentId,
|
|
725
|
-
state: handle.state,
|
|
726
|
-
planTaskId: meta?.planTaskId,
|
|
727
|
-
remainingTasks,
|
|
728
|
-
remainingNotifications: this.ctx.pendingNotifications.length,
|
|
729
|
-
})
|
|
730
1008
|
}
|
|
731
1009
|
|
|
732
1010
|
private async requestFinalResponse(model: string, reason: StopReason): Promise<void> {
|
|
@@ -753,13 +1031,22 @@ export class IterationOrchestrator {
|
|
|
753
1031
|
),
|
|
754
1032
|
]
|
|
755
1033
|
|
|
1034
|
+
// Same cache discipline as the forced-final iteration: keep the
|
|
1035
|
+
// tools param identical to prior iterations (cache prefix intact,
|
|
1036
|
+
// no 400 on tool blocks in history) and forbid use via tool_choice.
|
|
1037
|
+
const finalTools = this.ctx.tools.toLLMTools(this.ctx.allowedTools)
|
|
756
1038
|
const response = await collect(
|
|
757
1039
|
this.ctx.provider.chatStream({
|
|
758
1040
|
model,
|
|
759
1041
|
messages: finalMessages,
|
|
1042
|
+
tools: finalTools.length > 0 ? finalTools : undefined,
|
|
1043
|
+
toolChoice: finalTools.length > 0 ? 'none' : undefined,
|
|
760
1044
|
temperature: this.ctx.runConfig.temperature,
|
|
761
1045
|
maxTokens: this.ctx.runConfig.maxResponseTokens,
|
|
762
1046
|
cacheControl: { type: 'auto' },
|
|
1047
|
+
// Cancellable too: a Stop during the closing summary must not
|
|
1048
|
+
// stream to completion.
|
|
1049
|
+
signal: this.ctx.abortController.signal,
|
|
763
1050
|
}),
|
|
764
1051
|
)
|
|
765
1052
|
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { RunEvent } from '../../../../types/run/index.js'
|
|
2
2
|
import { CheckpointManager } from '../../checkpoint.js'
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
type IterationContext,
|
|
5
|
+
type PhaseSignal,
|
|
6
|
+
awaitDecisionOrAbort,
|
|
7
|
+
handleHITLDecision,
|
|
8
|
+
} from './context.js'
|
|
4
9
|
|
|
5
10
|
export async function* runIterationCheckpoint(
|
|
6
11
|
ctx: IterationContext,
|
|
@@ -17,7 +22,7 @@ export async function* runIterationCheckpoint(
|
|
|
17
22
|
yield* ctx.drainPending()
|
|
18
23
|
|
|
19
24
|
const summary = CheckpointManager.buildSummary(ctx.runMgr, iterationNum)
|
|
20
|
-
const iterDecision = await ctx
|
|
25
|
+
const iterDecision = await awaitDecisionOrAbort(ctx, {
|
|
21
26
|
type: 'iteration_checkpoint',
|
|
22
27
|
runId: ctx.runMgr.id,
|
|
23
28
|
checkpointId: iterCheckpoint.id,
|