@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
|
@@ -3,15 +3,45 @@ import { extractFromAssistantMessage } from '../../../compaction/extractor.js';
|
|
|
3
3
|
import { collect } from '../../../provider/collect.js';
|
|
4
4
|
import { GENAI, NAMZU, agentIterationSpanName } from '../../../telemetry/attributes.js';
|
|
5
5
|
import { getTracer } from '../../../telemetry/runtime-accessors.js';
|
|
6
|
+
import { mergeTokenUsage } from '../../../types/common/index.js';
|
|
6
7
|
import { createAssistantMessage, createUserMessage } from '../../../types/message/index.js';
|
|
7
8
|
import { toErrorMessage } from '../../../utils/error.js';
|
|
8
9
|
import { generateMessageId } from '../../../utils/id.js';
|
|
10
|
+
import { AUTO_CONTINUATION_USER_MESSAGE } from '../continuation.js';
|
|
9
11
|
import { applyLifecycleHookResults } from '../plugin-hooks.js';
|
|
10
12
|
import { runAdvisoryPhase } from './phases/advisory.js';
|
|
11
13
|
import { runIterationCheckpoint } from './phases/checkpoint.js';
|
|
12
14
|
import { runCompactionCheck } from './phases/compaction.js';
|
|
13
15
|
import { runPlanGate } from './phases/plan.js';
|
|
14
16
|
import { runToolReview } from './phases/tool-review.js';
|
|
17
|
+
import { refreshWorkingMemory } from './phases/working-memory.js';
|
|
18
|
+
/**
|
|
19
|
+
* Escape the five XML metacharacters so an interpolated value cannot
|
|
20
|
+
* break out of a tag. Used for the simple identifier fields in the
|
|
21
|
+
* `<task-notification>` envelope (taskId, agentId, status) — values
|
|
22
|
+
* here are controlled enums / opaque ids in practice, but escaping
|
|
23
|
+
* keeps the envelope robust against any future producer that lets a
|
|
24
|
+
* `<` or `&` leak in.
|
|
25
|
+
*/
|
|
26
|
+
function xmlEscape(value) {
|
|
27
|
+
return value
|
|
28
|
+
.replace(/&/g, '&')
|
|
29
|
+
.replace(/</g, '<')
|
|
30
|
+
.replace(/>/g, '>')
|
|
31
|
+
.replace(/"/g, '"')
|
|
32
|
+
.replace(/'/g, ''');
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Wrap free-form worker output in a CDATA section. CDATA preserves
|
|
36
|
+
* the raw text — code, markdown angle brackets, ampersands — so the
|
|
37
|
+
* supervisor sees what the worker actually produced instead of an
|
|
38
|
+
* escape-encoded approximation. The only termination CDATA forbids
|
|
39
|
+
* is the literal `]]>` sequence; we split-and-rejoin around it to
|
|
40
|
+
* keep the section well-formed regardless of payload.
|
|
41
|
+
*/
|
|
42
|
+
function cdataWrap(value) {
|
|
43
|
+
return `<![CDATA[${value.replace(/]]>/g, ']]]]><![CDATA[>')}]]>`;
|
|
44
|
+
}
|
|
15
45
|
/**
|
|
16
46
|
* Map a provider's coarse `finishReason` plus the orchestrator's
|
|
17
47
|
* `forceFinalize` flag onto the per-message {@link MessageStopReason}
|
|
@@ -50,8 +80,11 @@ function synthesizeMessageStopReason(finishReason, forceFinalize) {
|
|
|
50
80
|
* finally-style fall-through path with `stopReason: 'refusal'`.
|
|
51
81
|
* - `tool_input_delta` with no `toolUseId` registered yet: we drop
|
|
52
82
|
* the fragment and log a warning (proxies seen to misorder events).
|
|
53
|
-
* - `chunk.error`:
|
|
54
|
-
*
|
|
83
|
+
* - `chunk.error`: when no tool input is recoverable, we surface as
|
|
84
|
+
* a thrown error after emitting the message_completed terminator so
|
|
85
|
+
* consumer cards still close. If a tool-use block was already open,
|
|
86
|
+
* we instead synthesize a tool call with runtime truncation metadata
|
|
87
|
+
* so the executor can return a model-readable retry hint.
|
|
55
88
|
*/
|
|
56
89
|
async function* streamProviderTurn(provider, params, emitEvent, drainPending, runId, iteration, forceFinalize, log) {
|
|
57
90
|
const messageId = generateMessageId();
|
|
@@ -71,8 +104,36 @@ async function* streamProviderTurn(provider, params, emitEvent, drainPending, ru
|
|
|
71
104
|
const toolBuckets = new Map();
|
|
72
105
|
let streamError;
|
|
73
106
|
const stream = provider.chatStream({ ...params, stream: true });
|
|
107
|
+
// Drive the stream manually so each `.next()` can be RACED against the run
|
|
108
|
+
// abort: a Stop tears the in-flight model request down (the provider got
|
|
109
|
+
// `params.signal`), and we ALSO stop pulling within a tick even if a
|
|
110
|
+
// transport buffers or ignores the signal. The abort rejection propagates
|
|
111
|
+
// out of this generator so the run loop settles the turn as cancelled.
|
|
112
|
+
// `{ once: true }` keeps a multi-iteration run from leaking a listener/turn.
|
|
113
|
+
const it = stream[Symbol.asyncIterator]();
|
|
114
|
+
const signal = params.signal;
|
|
115
|
+
let onAbort;
|
|
116
|
+
const aborted = signal
|
|
117
|
+
? new Promise((_resolve, reject) => {
|
|
118
|
+
if (signal.aborted) {
|
|
119
|
+
reject(signal.reason);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
onAbort = () => reject(signal.reason);
|
|
123
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
124
|
+
})
|
|
125
|
+
: undefined;
|
|
74
126
|
try {
|
|
75
|
-
for
|
|
127
|
+
for (;;) {
|
|
128
|
+
const next = it.next();
|
|
129
|
+
// Neutralize the dangling loser so an eventual rejection of the
|
|
130
|
+
// un-awaited `next` is never an unhandled rejection.
|
|
131
|
+
if (aborted)
|
|
132
|
+
next.catch(() => { });
|
|
133
|
+
const res = await (aborted ? Promise.race([next, aborted]) : next);
|
|
134
|
+
if (res.done)
|
|
135
|
+
break;
|
|
136
|
+
const chunk = res.value;
|
|
76
137
|
if (chunk.error) {
|
|
77
138
|
streamError = chunk.error;
|
|
78
139
|
break;
|
|
@@ -99,6 +160,8 @@ async function* streamProviderTurn(provider, params, emitEvent, drainPending, ru
|
|
|
99
160
|
argsBuf: '',
|
|
100
161
|
started: false,
|
|
101
162
|
completed: false,
|
|
163
|
+
parsed: null,
|
|
164
|
+
inputTruncated: false,
|
|
102
165
|
};
|
|
103
166
|
toolBuckets.set(tc.index, bucket);
|
|
104
167
|
}
|
|
@@ -149,54 +212,148 @@ async function* streamProviderTurn(provider, params, emitEvent, drainPending, ru
|
|
|
149
212
|
parsed = bucket.argsBuf ? JSON.parse(bucket.argsBuf) : {};
|
|
150
213
|
}
|
|
151
214
|
catch (err) {
|
|
215
|
+
bucket.inputTruncated = true;
|
|
152
216
|
log.warn('tool input JSON parse failed at content_block_stop', {
|
|
153
217
|
runId,
|
|
154
218
|
toolUseId: endId,
|
|
155
219
|
error: err instanceof Error ? err.message : String(err),
|
|
156
220
|
});
|
|
157
221
|
}
|
|
222
|
+
bucket.parsed = parsed;
|
|
158
223
|
await emitEvent({
|
|
159
224
|
type: 'tool_input_completed',
|
|
160
225
|
runId,
|
|
161
226
|
toolUseId: endId,
|
|
162
227
|
input: parsed,
|
|
228
|
+
...(bucket.inputTruncated ? { inputTruncated: true } : {}),
|
|
163
229
|
});
|
|
164
230
|
yield* drainPending();
|
|
165
231
|
}
|
|
166
232
|
}
|
|
167
233
|
if (chunk.finishReason)
|
|
168
234
|
finishReason = chunk.finishReason;
|
|
235
|
+
// Merge (per-field max), not last-write-wins: a late usage frame that
|
|
236
|
+
// omits input/cache tokens must not zero the counts seen earlier in the
|
|
237
|
+
// stream, which would under-report this turn's accumulated usage.
|
|
169
238
|
if (chunk.usage)
|
|
170
|
-
usage = chunk.usage;
|
|
239
|
+
usage = mergeTokenUsage(usage, chunk.usage);
|
|
171
240
|
}
|
|
172
241
|
}
|
|
173
242
|
catch (err) {
|
|
243
|
+
// An abort tears the turn down: propagate it so the run loop settles the
|
|
244
|
+
// run as cancelled rather than recording a normal (errored) turn. Any
|
|
245
|
+
// other stream error is captured into the synthesized response as before.
|
|
246
|
+
if (signal?.aborted)
|
|
247
|
+
throw err;
|
|
174
248
|
streamError = err instanceof Error ? err.message : String(err);
|
|
175
249
|
}
|
|
250
|
+
finally {
|
|
251
|
+
if (onAbort)
|
|
252
|
+
signal?.removeEventListener('abort', onAbort);
|
|
253
|
+
// Release the underlying connection on every exit (natural end, error,
|
|
254
|
+
// or abort). `for await` did this implicitly on natural completion; the
|
|
255
|
+
// manual drive must do it explicitly. `.return()` on an already-finished
|
|
256
|
+
// provider generator is a no-op.
|
|
257
|
+
await it.return?.().catch(() => { });
|
|
258
|
+
}
|
|
176
259
|
// Flush any tool buckets the provider failed to close (no toolCallEnd
|
|
177
|
-
// arrived — defensive against providers that don't yet emit it
|
|
260
|
+
// arrived — defensive against providers that don't yet emit it, and
|
|
261
|
+
// the load-bearing path when the provider stream ends with
|
|
262
|
+
// `stop_reason: "max_tokens"` mid-`input_json_delta`. In that case
|
|
263
|
+
// Anthropic's SSE never sends `content_block_stop` for the open
|
|
264
|
+
// tool_use block: the upstream model ran out of completion tokens
|
|
265
|
+
// before it could close the JSON literal, so the buffered
|
|
266
|
+
// `argsBuf` ends with something like `"content":"…some prefix` —
|
|
267
|
+
// not parseable.
|
|
268
|
+
//
|
|
269
|
+
// Two cases coalesce here:
|
|
270
|
+
// 1. The buffer parses cleanly (the provider just forgot to emit
|
|
271
|
+
// `content_block_stop` but the args are intact) — keep parsed.
|
|
272
|
+
// 2. The buffer is truncated mid-literal — `parsed = {}` is the
|
|
273
|
+
// safe fallback so the executor's `JSON.parse(arguments)`
|
|
274
|
+
// succeeds and downstream consumers don't crash. The PRICE
|
|
275
|
+
// we used to pay was the model getting back a generic
|
|
276
|
+
// "<field> is required" Zod error and not realising its
|
|
277
|
+
// previous tool call was truncated server-side, so it would
|
|
278
|
+
// retry with the SAME long input and hit the same cutoff in
|
|
279
|
+
// a loop. Detect the truncation case and mark the tool call
|
|
280
|
+
// with runtime metadata; the executor surfaces a specific
|
|
281
|
+
// "your tool call was cut off by max_tokens — retry with
|
|
282
|
+
// shorter input or split into smaller calls" message that the
|
|
283
|
+
// model can act on.
|
|
178
284
|
for (const bucket of toolBuckets.values()) {
|
|
179
285
|
if (bucket.started && !bucket.completed) {
|
|
180
286
|
bucket.completed = true;
|
|
181
287
|
let parsed = {};
|
|
182
|
-
|
|
183
|
-
|
|
288
|
+
let truncated = false;
|
|
289
|
+
if (bucket.argsBuf) {
|
|
290
|
+
try {
|
|
291
|
+
parsed = JSON.parse(bucket.argsBuf);
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
// argsBuf had content but didn't parse — almost
|
|
295
|
+
// certainly the max_tokens-mid-literal cutoff. Mark
|
|
296
|
+
// the bucket so the executor can return a model-
|
|
297
|
+
// readable hint instead of a generic Zod error.
|
|
298
|
+
truncated = true;
|
|
299
|
+
parsed = {};
|
|
300
|
+
}
|
|
184
301
|
}
|
|
185
|
-
|
|
186
|
-
|
|
302
|
+
bucket.parsed = parsed;
|
|
303
|
+
bucket.inputTruncated = truncated;
|
|
304
|
+
if (truncated) {
|
|
305
|
+
log.warn('tool input truncated by upstream cutoff (no toolCallEnd, argsBuf unparsable)', {
|
|
306
|
+
runId,
|
|
307
|
+
toolUseId: bucket.id,
|
|
308
|
+
toolName: bucket.name,
|
|
309
|
+
bufferLength: bucket.argsBuf.length,
|
|
310
|
+
});
|
|
187
311
|
}
|
|
188
312
|
await emitEvent({
|
|
189
313
|
type: 'tool_input_completed',
|
|
190
314
|
runId,
|
|
191
315
|
toolUseId: bucket.id,
|
|
192
316
|
input: parsed,
|
|
317
|
+
...(truncated ? { inputTruncated: true } : {}),
|
|
193
318
|
});
|
|
194
319
|
yield* drainPending();
|
|
195
320
|
}
|
|
196
321
|
}
|
|
322
|
+
// `arguments` MUST be valid JSON for the executor's `JSON.parse`
|
|
323
|
+
// (`runtime/query/executor.ts:executeSingle`) to succeed. We
|
|
324
|
+
// always serialise from the bucket's `parsed` object (filled by
|
|
325
|
+
// either the `toolCallEnd` branch above or the post-stream flush
|
|
326
|
+
// loop) instead of re-emitting `argsBuf`. When the provider
|
|
327
|
+
// stream truncated mid-input, `metadata.inputTruncated` carries that
|
|
328
|
+
// state; the executor parses cleanly and returns a specific
|
|
329
|
+
// model-readable retry hint instead of the generic "Invalid JSON in
|
|
330
|
+
// tool arguments" intercept.
|
|
331
|
+
const toolCalls = [...toolBuckets.entries()]
|
|
332
|
+
.sort(([a], [b]) => a - b)
|
|
333
|
+
.map(([, b]) => ({
|
|
334
|
+
id: b.id,
|
|
335
|
+
type: 'function',
|
|
336
|
+
function: {
|
|
337
|
+
name: b.name,
|
|
338
|
+
arguments: JSON.stringify(b.parsed ?? {}),
|
|
339
|
+
},
|
|
340
|
+
...(b.inputTruncated ? { metadata: { inputTruncated: true } } : {}),
|
|
341
|
+
}));
|
|
342
|
+
const recoveredToolInputFromStreamError = streamError !== undefined && toolCalls.some((tc) => tc.id && tc.function.name);
|
|
343
|
+
const effectiveFinishReason = recoveredToolInputFromStreamError ? 'tool_calls' : finishReason;
|
|
344
|
+
if (recoveredToolInputFromStreamError) {
|
|
345
|
+
log.warn('provider stream failed after tool input; surfacing tool call to executor', {
|
|
346
|
+
runId,
|
|
347
|
+
iteration,
|
|
348
|
+
error: streamError,
|
|
349
|
+
toolCallCount: toolCalls.length,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
197
352
|
const stopReason = streamError
|
|
198
|
-
?
|
|
199
|
-
|
|
353
|
+
? recoveredToolInputFromStreamError
|
|
354
|
+
? 'tool_use'
|
|
355
|
+
: 'refusal'
|
|
356
|
+
: synthesizeMessageStopReason(effectiveFinishReason, forceFinalize);
|
|
200
357
|
await emitEvent({
|
|
201
358
|
type: 'message_completed',
|
|
202
359
|
runId,
|
|
@@ -207,16 +364,9 @@ async function* streamProviderTurn(provider, params, emitEvent, drainPending, ru
|
|
|
207
364
|
content: textBuf || undefined,
|
|
208
365
|
});
|
|
209
366
|
yield* drainPending();
|
|
210
|
-
if (streamError) {
|
|
367
|
+
if (streamError && !recoveredToolInputFromStreamError) {
|
|
211
368
|
throw new Error(`Provider stream error: ${streamError}`);
|
|
212
369
|
}
|
|
213
|
-
const toolCalls = [...toolBuckets.entries()]
|
|
214
|
-
.sort(([a], [b]) => a - b)
|
|
215
|
-
.map(([, b]) => ({
|
|
216
|
-
id: b.id,
|
|
217
|
-
type: 'function',
|
|
218
|
-
function: { name: b.name, arguments: b.argsBuf },
|
|
219
|
-
}));
|
|
220
370
|
const response = {
|
|
221
371
|
id: id || messageId,
|
|
222
372
|
model: model || params.model,
|
|
@@ -225,7 +375,7 @@ async function* streamProviderTurn(provider, params, emitEvent, drainPending, ru
|
|
|
225
375
|
content: textBuf.length > 0 ? textBuf : null,
|
|
226
376
|
toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
227
377
|
},
|
|
228
|
-
finishReason,
|
|
378
|
+
finishReason: effectiveFinishReason,
|
|
229
379
|
usage,
|
|
230
380
|
};
|
|
231
381
|
return { response, messageId };
|
|
@@ -255,6 +405,7 @@ export class IterationOrchestrator {
|
|
|
255
405
|
launchedTasks: config.launchedTasks ?? new Map(),
|
|
256
406
|
compactionConfig: config.compactionConfig,
|
|
257
407
|
workingStateManager: config.workingStateManager,
|
|
408
|
+
workingMemoryProvider: config.workingMemoryProvider,
|
|
258
409
|
advisoryCtx: config.advisoryCtx,
|
|
259
410
|
agentBus: config.agentBus,
|
|
260
411
|
verificationGate: config.verificationGate,
|
|
@@ -265,17 +416,19 @@ export class IterationOrchestrator {
|
|
|
265
416
|
const { runConfig, runMgr } = this.ctx;
|
|
266
417
|
const { model } = runConfig;
|
|
267
418
|
const tracer = getTracer();
|
|
419
|
+
// Worker-completion delivery used to fan out through a global
|
|
420
|
+
// onTaskCompleted listener that pushed handles onto
|
|
421
|
+
// `pendingNotifications`; the iteration loop then drained
|
|
422
|
+
// them as <task-notification> envelopes. Both `create_task`
|
|
423
|
+
// and the `Agent` tool are now blocking and return their
|
|
424
|
+
// worker output as the dispatching tool_use's canonical
|
|
425
|
+
// tool_result, so the listener path would only DUPLICATE
|
|
426
|
+
// every completion (once as tool_result, once as injected
|
|
427
|
+
// envelope user-message). Leaving the binding out closes
|
|
428
|
+
// the duplicate notification surface entirely; the dormant
|
|
429
|
+
// drain stays as a no-op until a follow-up tears it out.
|
|
268
430
|
let unsubscribeTaskListener;
|
|
269
|
-
|
|
270
|
-
unsubscribeTaskListener = this.ctx.taskGateway.onTaskCompleted((handle) => {
|
|
271
|
-
this.ctx.pendingNotifications.push(handle);
|
|
272
|
-
this.ctx.log.debug('Task completion queued for notification', {
|
|
273
|
-
taskId: handle.taskId,
|
|
274
|
-
agentId: handle.agentId,
|
|
275
|
-
state: handle.state,
|
|
276
|
-
});
|
|
277
|
-
});
|
|
278
|
-
}
|
|
431
|
+
void unsubscribeTaskListener;
|
|
279
432
|
try {
|
|
280
433
|
const planSignal = yield* runPlanGate(this.ctx);
|
|
281
434
|
if (planSignal === 'stop')
|
|
@@ -339,10 +492,18 @@ export class IterationOrchestrator {
|
|
|
339
492
|
if (this.ctx.pendingNotifications.length > 0) {
|
|
340
493
|
await this.injectOneTaskNotification();
|
|
341
494
|
}
|
|
495
|
+
// Re-pin the working-memory block from ground truth at the primacy
|
|
496
|
+
// edge BEFORE compaction runs (so the refreshed slot is what
|
|
497
|
+
// compaction preserves). No-op when no provider is configured.
|
|
498
|
+
await refreshWorkingMemory(this.ctx);
|
|
342
499
|
await runCompactionCheck(this.ctx);
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
500
|
+
// Cache discipline: keep the tools param byte-stable even on the
|
|
501
|
+
// forced-final iteration and forbid tool use via tool_choice
|
|
502
|
+
// 'none' instead. Dropping the tools array would invalidate the
|
|
503
|
+
// entire prompt-cache prefix (tools render at position 0) and
|
|
504
|
+
// risks a 400 because the history still carries
|
|
505
|
+
// tool_use/tool_result blocks.
|
|
506
|
+
const openAITools = this.ctx.tools.toLLMTools(this.ctx.allowedTools);
|
|
346
507
|
const messages = forceFinalize
|
|
347
508
|
? [
|
|
348
509
|
...runMgr.messages,
|
|
@@ -365,10 +526,15 @@ export class IterationOrchestrator {
|
|
|
365
526
|
const { response } = yield* streamProviderTurn(this.ctx.provider, {
|
|
366
527
|
model,
|
|
367
528
|
messages,
|
|
368
|
-
tools: openAITools
|
|
529
|
+
tools: openAITools.length > 0 ? openAITools : undefined,
|
|
530
|
+
toolChoice: forceFinalize && openAITools.length > 0 ? 'none' : undefined,
|
|
369
531
|
temperature: runConfig.temperature,
|
|
370
532
|
maxTokens: runConfig.maxResponseTokens,
|
|
371
533
|
cacheControl: { type: 'auto' },
|
|
534
|
+
// Thread the run abort into the model call so a Stop tears the
|
|
535
|
+
// in-flight turn down (provider passes it to fetch; the consumer
|
|
536
|
+
// also races it). Inert when never aborted.
|
|
537
|
+
signal: this.ctx.abortController.signal,
|
|
372
538
|
}, this.ctx.emitEvent, this.ctx.drainPending, runMgr.id, iterationNum, forceFinalize, this.ctx.log);
|
|
373
539
|
runMgr.accumulateUsage(response.usage);
|
|
374
540
|
if (this.ctx.pluginManager) {
|
|
@@ -434,6 +600,42 @@ export class IterationOrchestrator {
|
|
|
434
600
|
continue;
|
|
435
601
|
}
|
|
436
602
|
const hasContent = response.message.content !== null && response.message.content.length > 0;
|
|
603
|
+
// Auto-continuation on `stop_reason: max_tokens`. The
|
|
604
|
+
// model hit its per-call output cap mid-text (NOT
|
|
605
|
+
// mid-tool-use — that path is handled separately
|
|
606
|
+
// below via `inputTruncated`). Push a synthetic
|
|
607
|
+
// "continue" user message and let the loop fire
|
|
608
|
+
// another turn. The provider receives the partial
|
|
609
|
+
// assistant content + the continue prompt and
|
|
610
|
+
// resumes from where it left off, mirroring the
|
|
611
|
+
// Claude.ai "Continue" affordance.
|
|
612
|
+
//
|
|
613
|
+
// Guards:
|
|
614
|
+
// - `hasContent` so we don't loop forever on an
|
|
615
|
+
// empty cutoff (Anthropic occasionally emits
|
|
616
|
+
// `stop_reason: max_tokens` with no content
|
|
617
|
+
// when an injected pre-fill blocks the model).
|
|
618
|
+
// - `!forceFinalize` so the forced-finalize path
|
|
619
|
+
// never auto-continues — that path is invoked
|
|
620
|
+
// specifically to extract a closing summary.
|
|
621
|
+
// - max_iterations bounds the loop in any case.
|
|
622
|
+
if (!forceFinalize && response.finishReason === 'length' && hasContent) {
|
|
623
|
+
this.ctx.log.info('LLM hit max_tokens mid-text — auto-continuing', {
|
|
624
|
+
runId: runMgr.id,
|
|
625
|
+
iteration: iterationNum,
|
|
626
|
+
completionTokens: response.usage.completionTokens,
|
|
627
|
+
});
|
|
628
|
+
runMgr.pushMessage(createUserMessage(AUTO_CONTINUATION_USER_MESSAGE));
|
|
629
|
+
await this.ctx.emitEvent({
|
|
630
|
+
type: 'iteration_completed',
|
|
631
|
+
runId: runMgr.id,
|
|
632
|
+
iteration: iterationNum,
|
|
633
|
+
hasToolCalls: false,
|
|
634
|
+
});
|
|
635
|
+
yield* this.ctx.drainPending();
|
|
636
|
+
iterSpan.end();
|
|
637
|
+
continue;
|
|
638
|
+
}
|
|
437
639
|
if (!hasContent && !forceFinalize) {
|
|
438
640
|
this.ctx.log.warn('Empty completion detected — requesting final summary', {
|
|
439
641
|
iteration: iterationNum,
|
|
@@ -449,6 +651,16 @@ export class IterationOrchestrator {
|
|
|
449
651
|
hasToolCalls: false,
|
|
450
652
|
});
|
|
451
653
|
yield* this.ctx.drainPending();
|
|
654
|
+
// A Stop that lands AFTER the final turn streamed but before
|
|
655
|
+
// this break must settle the run as cancelled, not end_turn —
|
|
656
|
+
// otherwise the just-produced answer is recorded as a clean
|
|
657
|
+
// completion. Mirrors the between-iteration cancel at :511.
|
|
658
|
+
if (this.ctx.abortController.signal.aborted) {
|
|
659
|
+
runMgr.setStopReason('cancelled');
|
|
660
|
+
runMgr.markCancelled();
|
|
661
|
+
iterSpan.end();
|
|
662
|
+
break;
|
|
663
|
+
}
|
|
452
664
|
runMgr.setStopReason('end_turn');
|
|
453
665
|
iterSpan.end();
|
|
454
666
|
break;
|
|
@@ -483,6 +695,19 @@ export class IterationOrchestrator {
|
|
|
483
695
|
iterSpan.end();
|
|
484
696
|
}
|
|
485
697
|
catch (err) {
|
|
698
|
+
// A Stop that aborted the in-flight turn surfaces here as a
|
|
699
|
+
// thrown abort (the provider stream was raced against the run
|
|
700
|
+
// signal). Settle it as a CANCELLATION — mirroring the
|
|
701
|
+
// between-iteration cancel at the top of the loop — rather than
|
|
702
|
+
// recording it as an SDK failure (error span + failed activity)
|
|
703
|
+
// and re-throwing. The run then returns cleanly with a
|
|
704
|
+
// 'cancelled' stop reason instead of propagating an error.
|
|
705
|
+
if (this.ctx.abortController.signal.aborted) {
|
|
706
|
+
runMgr.setStopReason('cancelled');
|
|
707
|
+
runMgr.markCancelled();
|
|
708
|
+
iterSpan.end();
|
|
709
|
+
break;
|
|
710
|
+
}
|
|
486
711
|
if (iterationActivity) {
|
|
487
712
|
this.ctx.activityStore.fail(iterationActivity.id, toErrorMessage(err));
|
|
488
713
|
}
|
|
@@ -516,42 +741,68 @@ export class IterationOrchestrator {
|
|
|
516
741
|
}
|
|
517
742
|
await this.injectOneTaskNotification();
|
|
518
743
|
}
|
|
744
|
+
/**
|
|
745
|
+
* Canonical async completion delivery (ses_009-task-notification-envelope).
|
|
746
|
+
*
|
|
747
|
+
* Drains every pending task completion in one pass and emits each as
|
|
748
|
+
* a plain USER text message wrapped in the `<task-notification>`
|
|
749
|
+
* envelope the supervisor prompt expects.
|
|
750
|
+
*
|
|
751
|
+
* Why not a `tool_result` block bound to the dispatching tool_use_id:
|
|
752
|
+
* `create_task` is documented as NON-BLOCKING and returns
|
|
753
|
+
* "Task launched: …" immediately. That immediate return is already
|
|
754
|
+
* recorded as the canonical tool_result for that tool_use, so a
|
|
755
|
+
* second tool_result for the SAME tool_use_id — emitted later, after
|
|
756
|
+
* intervening assistant turns — is rejected by Anthropic with
|
|
757
|
+
* `messages.<n>.content.0: unexpected tool_use_id found in
|
|
758
|
+
* tool_result blocks` because the immediately-prior assistant
|
|
759
|
+
* message no longer carries the matching tool_use. Wrapping as a
|
|
760
|
+
* user text envelope sidesteps the pairing rule entirely.
|
|
761
|
+
*
|
|
762
|
+
* Coalescing N drops into one drain replaces the previous
|
|
763
|
+
* one-at-a-time pattern which forced a separate orchestrator
|
|
764
|
+
* iteration per completed task on wide fan-outs.
|
|
765
|
+
*/
|
|
519
766
|
async injectOneTaskNotification() {
|
|
520
|
-
|
|
521
|
-
if (!handle)
|
|
767
|
+
if (this.ctx.pendingNotifications.length === 0)
|
|
522
768
|
return;
|
|
523
|
-
const
|
|
524
|
-
const
|
|
525
|
-
handle.
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
769
|
+
const handles = this.ctx.pendingNotifications.splice(0);
|
|
770
|
+
for (const handle of handles) {
|
|
771
|
+
const meta = this.ctx.launchedTasks.get(handle.taskId);
|
|
772
|
+
const resultText = handle.result?.result ??
|
|
773
|
+
handle.result?.lastError ??
|
|
774
|
+
`Task finished with state: ${handle.state}`;
|
|
775
|
+
if (meta?.planTaskId && this.ctx.taskStore) {
|
|
776
|
+
const success = handle.state === 'completed';
|
|
777
|
+
await this.ctx.taskStore.update(meta.planTaskId, {
|
|
778
|
+
status: 'completed',
|
|
779
|
+
description: success ? undefined : `Failed: ${resultText.substring(0, 200)}`,
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
this.ctx.launchedTasks.delete(handle.taskId);
|
|
783
|
+
// `remaining-tasks` = inflight workers still pending after this
|
|
784
|
+
// one drains. `launchedTasks` is the single source of truth:
|
|
785
|
+
// it holds every dispatched worker that has NOT yet been
|
|
786
|
+
// drained + delete()'d. The drain batch entries are still
|
|
787
|
+
// inside launchedTasks until each iteration's delete() above
|
|
788
|
+
// removes them, so reading the size right after that delete
|
|
789
|
+
// gives the honest count. Adding `handles.length - 1 - i`
|
|
790
|
+
// here used to double-count this same queue.
|
|
791
|
+
const remainingTasks = this.ctx.launchedTasks.size;
|
|
792
|
+
const envelope = `<task-notification>\n<task-id>${xmlEscape(handle.taskId)}</task-id>\n` +
|
|
793
|
+
`<agent-id>${xmlEscape(handle.agentId)}</agent-id>\n` +
|
|
794
|
+
`<status>${xmlEscape(handle.state)}</status>\n` +
|
|
795
|
+
`<result>${cdataWrap(resultText)}</result>\n` +
|
|
796
|
+
`<remaining-tasks>${remainingTasks}</remaining-tasks>\n</task-notification>`;
|
|
797
|
+
this.ctx.runMgr.pushMessage(createUserMessage(envelope));
|
|
798
|
+
this.ctx.log.info('Task notification injected', {
|
|
799
|
+
taskId: handle.taskId,
|
|
800
|
+
agentId: handle.agentId,
|
|
801
|
+
state: handle.state,
|
|
802
|
+
planTaskId: meta?.planTaskId,
|
|
803
|
+
remainingNotifications: remainingTasks,
|
|
532
804
|
});
|
|
533
805
|
}
|
|
534
|
-
this.ctx.launchedTasks.delete(handle.taskId);
|
|
535
|
-
const remainingTasks = this.ctx.launchedTasks.size;
|
|
536
|
-
const notification = [
|
|
537
|
-
'<task-notification>',
|
|
538
|
-
` <task-id>${handle.taskId}</task-id>`,
|
|
539
|
-
` <agent-id>${handle.agentId}</agent-id>`,
|
|
540
|
-
` <status>${handle.state}</status>`,
|
|
541
|
-
` <description>${meta?.description ?? 'agent task'}</description>`,
|
|
542
|
-
` <result>${resultText}</result>`,
|
|
543
|
-
` <remaining-tasks>${remainingTasks}</remaining-tasks>`,
|
|
544
|
-
'</task-notification>',
|
|
545
|
-
].join('\n');
|
|
546
|
-
this.ctx.runMgr.pushMessage(createUserMessage(notification));
|
|
547
|
-
this.ctx.log.info('Task notification injected', {
|
|
548
|
-
taskId: handle.taskId,
|
|
549
|
-
agentId: handle.agentId,
|
|
550
|
-
state: handle.state,
|
|
551
|
-
planTaskId: meta?.planTaskId,
|
|
552
|
-
remainingTasks,
|
|
553
|
-
remainingNotifications: this.ctx.pendingNotifications.length,
|
|
554
|
-
});
|
|
555
806
|
}
|
|
556
807
|
async requestFinalResponse(model, reason) {
|
|
557
808
|
const lastAssistant = [...this.ctx.runMgr.messages]
|
|
@@ -570,12 +821,21 @@ export class IterationOrchestrator {
|
|
|
570
821
|
...this.ctx.runMgr.messages,
|
|
571
822
|
createUserMessage(`[SYSTEM] Run is ending due to ${reason}. You MUST provide a final response now summarizing all your findings and work so far. Do not use any tools.`),
|
|
572
823
|
];
|
|
824
|
+
// Same cache discipline as the forced-final iteration: keep the
|
|
825
|
+
// tools param identical to prior iterations (cache prefix intact,
|
|
826
|
+
// no 400 on tool blocks in history) and forbid use via tool_choice.
|
|
827
|
+
const finalTools = this.ctx.tools.toLLMTools(this.ctx.allowedTools);
|
|
573
828
|
const response = await collect(this.ctx.provider.chatStream({
|
|
574
829
|
model,
|
|
575
830
|
messages: finalMessages,
|
|
831
|
+
tools: finalTools.length > 0 ? finalTools : undefined,
|
|
832
|
+
toolChoice: finalTools.length > 0 ? 'none' : undefined,
|
|
576
833
|
temperature: this.ctx.runConfig.temperature,
|
|
577
834
|
maxTokens: this.ctx.runConfig.maxResponseTokens,
|
|
578
835
|
cacheControl: { type: 'auto' },
|
|
836
|
+
// Cancellable too: a Stop during the closing summary must not
|
|
837
|
+
// stream to completion.
|
|
838
|
+
signal: this.ctx.abortController.signal,
|
|
579
839
|
}));
|
|
580
840
|
this.ctx.runMgr.accumulateUsage(response.usage);
|
|
581
841
|
const assistantMsg = createAssistantMessage(response.message.content);
|