@namzu/sdk 36.0.0 → 38.0.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 +244 -0
- package/README.md +68 -41
- package/dist/bridge/a2a/mapper.d.ts.map +1 -1
- package/dist/bridge/a2a/mapper.js +4 -0
- package/dist/bridge/a2a/mapper.js.map +1 -1
- package/dist/bridge/sse/mapper.d.ts.map +1 -1
- package/dist/bridge/sse/mapper.js +16 -1
- package/dist/bridge/sse/mapper.js.map +1 -1
- package/dist/compaction/extractor.d.ts +1 -1
- package/dist/compaction/extractor.d.ts.map +1 -1
- package/dist/compaction/extractor.js +15 -7
- package/dist/compaction/extractor.js.map +1 -1
- package/dist/compaction/manager.d.ts +2 -0
- package/dist/compaction/manager.d.ts.map +1 -1
- package/dist/compaction/manager.js +12 -1
- package/dist/compaction/manager.js.map +1 -1
- package/dist/compaction/verifier.d.ts.map +1 -1
- package/dist/compaction/verifier.js +82 -15
- package/dist/compaction/verifier.js.map +1 -1
- package/dist/config/runtime.d.ts +16 -6
- package/dist/config/runtime.d.ts.map +1 -1
- package/dist/config/runtime.js +2 -0
- package/dist/config/runtime.js.map +1 -1
- package/dist/contracts/api.d.ts +1 -1
- package/dist/contracts/api.d.ts.map +1 -1
- package/dist/contracts/schemas.d.ts +10 -10
- package/dist/eval/harness-verification.d.ts +63 -0
- package/dist/eval/harness-verification.d.ts.map +1 -0
- package/dist/eval/harness-verification.js +165 -0
- package/dist/eval/harness-verification.js.map +1 -0
- package/dist/eval/index.d.ts +2 -0
- package/dist/eval/index.d.ts.map +1 -1
- package/dist/eval/index.js +1 -0
- package/dist/eval/index.js.map +1 -1
- package/dist/execution/code-runtime/json-value.d.ts +10 -0
- package/dist/execution/code-runtime/json-value.d.ts.map +1 -0
- package/dist/execution/code-runtime/json-value.js +89 -0
- package/dist/execution/code-runtime/json-value.js.map +1 -0
- package/dist/execution/code-runtime/worker-program.d.ts +8 -0
- package/dist/execution/code-runtime/worker-program.d.ts.map +1 -0
- package/dist/execution/code-runtime/worker-program.js +240 -0
- package/dist/execution/code-runtime/worker-program.js.map +1 -0
- package/dist/execution/code-runtime/worker.d.ts +22 -0
- package/dist/execution/code-runtime/worker.d.ts.map +1 -1
- package/dist/execution/code-runtime/worker.js +148 -111
- package/dist/execution/code-runtime/worker.js.map +1 -1
- package/dist/manager/agent/lifecycle.d.ts +12 -0
- package/dist/manager/agent/lifecycle.d.ts.map +1 -1
- package/dist/manager/agent/lifecycle.js +316 -46
- package/dist/manager/agent/lifecycle.js.map +1 -1
- package/dist/manager/run/persistence.d.ts +2 -0
- package/dist/manager/run/persistence.d.ts.map +1 -1
- package/dist/manager/run/persistence.js +6 -0
- package/dist/manager/run/persistence.js.map +1 -1
- package/dist/prompt/coding-agent-doctrine.d.ts +2 -2
- package/dist/prompt/coding-agent-doctrine.d.ts.map +1 -1
- package/dist/prompt/coding-agent-doctrine.js +11 -5
- package/dist/prompt/coding-agent-doctrine.js.map +1 -1
- package/dist/provider/capabilities.d.ts +5 -1
- package/dist/provider/capabilities.d.ts.map +1 -1
- package/dist/provider/capabilities.js +24 -0
- package/dist/provider/capabilities.js.map +1 -1
- package/dist/provider/fallback.d.ts.map +1 -1
- package/dist/provider/fallback.js +6 -2
- package/dist/provider/fallback.js.map +1 -1
- package/dist/public-runtime.d.ts +4 -1
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +3 -1
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-tools.d.ts +2 -1
- package/dist/public-tools.d.ts.map +1 -1
- package/dist/public-tools.js +2 -1
- package/dist/public-tools.js.map +1 -1
- package/dist/public-types.d.ts +2 -0
- package/dist/public-types.d.ts.map +1 -1
- package/dist/registry/tool/execute.d.ts +3 -0
- package/dist/registry/tool/execute.d.ts.map +1 -1
- package/dist/registry/tool/execute.js +11 -80
- package/dist/registry/tool/execute.js.map +1 -1
- package/dist/run/command-gate.d.ts.map +1 -1
- package/dist/run/command-gate.js +65 -12
- package/dist/run/command-gate.js.map +1 -1
- package/dist/run/index.d.ts +2 -0
- package/dist/run/index.d.ts.map +1 -1
- package/dist/run/index.js +1 -0
- package/dist/run/index.js.map +1 -1
- package/dist/run/memory-promoter.d.ts +3 -35
- package/dist/run/memory-promoter.d.ts.map +1 -1
- package/dist/run/memory-promoter.js +32 -40
- package/dist/run/memory-promoter.js.map +1 -1
- package/dist/run/memory-recall.d.ts +25 -0
- package/dist/run/memory-recall.d.ts.map +1 -0
- package/dist/run/memory-recall.js +228 -0
- package/dist/run/memory-recall.js.map +1 -0
- package/dist/run/reporter.d.ts.map +1 -1
- package/dist/run/reporter.js +2 -0
- package/dist/run/reporter.js.map +1 -1
- package/dist/run/token-budget.d.ts +12 -4
- package/dist/run/token-budget.d.ts.map +1 -1
- package/dist/run/token-budget.js +49 -14
- package/dist/run/token-budget.js.map +1 -1
- package/dist/run/workspace-fingerprint.d.ts +10 -3
- package/dist/run/workspace-fingerprint.d.ts.map +1 -1
- package/dist/run/workspace-fingerprint.js +17 -8
- package/dist/run/workspace-fingerprint.js.map +1 -1
- package/dist/runtime/query/checkpoint.d.ts +14 -0
- package/dist/runtime/query/checkpoint.d.ts.map +1 -1
- package/dist/runtime/query/checkpoint.js +82 -1
- package/dist/runtime/query/checkpoint.js.map +1 -1
- package/dist/runtime/query/executor.d.ts +8 -3
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +94 -30
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/index.d.ts +7 -8
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +55 -7
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +12 -0
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +348 -38
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/native-output.d.ts +10 -0
- package/dist/runtime/query/iteration/native-output.d.ts.map +1 -0
- package/dist/runtime/query/iteration/native-output.js +32 -0
- package/dist/runtime/query/iteration/native-output.js.map +1 -0
- package/dist/runtime/query/iteration/phases/advisory.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/advisory.js +18 -13
- package/dist/runtime/query/iteration/phases/advisory.js.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.d.ts +2 -0
- package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.js +32 -11
- package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context.d.ts +9 -0
- package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/context.js.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.js +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
- package/dist/runtime/query/iteration/phases/working-memory.d.ts +1 -1
- package/dist/runtime/query/iteration/phases/working-memory.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/working-memory.js +23 -6
- package/dist/runtime/query/iteration/phases/working-memory.js.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.js +12 -0
- package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
- package/dist/runtime/query/observation-context.d.ts +10 -0
- package/dist/runtime/query/observation-context.d.ts.map +1 -0
- package/dist/runtime/query/observation-context.js +84 -0
- package/dist/runtime/query/observation-context.js.map +1 -0
- package/dist/runtime/query/request-context.d.ts +30 -0
- package/dist/runtime/query/request-context.d.ts.map +1 -0
- package/dist/runtime/query/request-context.js +76 -0
- package/dist/runtime/query/request-context.js.map +1 -0
- package/dist/runtime/query/request-rich-content.d.ts.map +1 -1
- package/dist/runtime/query/request-rich-content.js +6 -3
- package/dist/runtime/query/request-rich-content.js.map +1 -1
- package/dist/runtime/query/review-policy.d.ts +3 -0
- package/dist/runtime/query/review-policy.d.ts.map +1 -1
- package/dist/runtime/query/review-policy.js +4 -1
- package/dist/runtime/query/review-policy.js.map +1 -1
- package/dist/runtime/query/steering.d.ts +6 -2
- package/dist/runtime/query/steering.d.ts.map +1 -1
- package/dist/runtime/query/steering.js +17 -2
- package/dist/runtime/query/steering.js.map +1 -1
- package/dist/runtime/query/tool-call-budget.d.ts +19 -0
- package/dist/runtime/query/tool-call-budget.d.ts.map +1 -0
- package/dist/runtime/query/tool-call-budget.js +110 -0
- package/dist/runtime/query/tool-call-budget.js.map +1 -0
- package/dist/runtime/query/tooling.d.ts +3 -0
- package/dist/runtime/query/tooling.d.ts.map +1 -1
- package/dist/runtime/query/tooling.js +5 -0
- package/dist/runtime/query/tooling.js.map +1 -1
- package/dist/sandbox/file-walk-program.d.ts.map +1 -1
- package/dist/sandbox/file-walk-program.js +8 -0
- package/dist/sandbox/file-walk-program.js.map +1 -1
- package/dist/sandbox/file-walk.d.ts.map +1 -1
- package/dist/sandbox/file-walk.js +9 -0
- package/dist/sandbox/file-walk.js.map +1 -1
- package/dist/scheduler/completion-inbox.d.ts.map +1 -1
- package/dist/scheduler/completion-inbox.js +3 -0
- package/dist/scheduler/completion-inbox.js.map +1 -1
- package/dist/scheduler/local.d.ts.map +1 -1
- package/dist/scheduler/local.js +1 -0
- package/dist/scheduler/local.js.map +1 -1
- package/dist/session/handoff/capacity.d.ts +2 -2
- package/dist/session/handoff/capacity.d.ts.map +1 -1
- package/dist/session/handoff/capacity.js +3 -2
- package/dist/session/handoff/capacity.js.map +1 -1
- package/dist/store/memory/disk.d.ts +6 -2
- package/dist/store/memory/disk.d.ts.map +1 -1
- package/dist/store/memory/disk.js +42 -25
- package/dist/store/memory/disk.js.map +1 -1
- package/dist/store/memory/index.d.ts +4 -0
- package/dist/store/memory/index.d.ts.map +1 -1
- package/dist/store/memory/index.js +55 -19
- package/dist/store/memory/index.js.map +1 -1
- package/dist/store/memory/memory.d.ts +3 -2
- package/dist/store/memory/memory.d.ts.map +1 -1
- package/dist/store/memory/memory.js +11 -2
- package/dist/store/memory/memory.js.map +1 -1
- package/dist/store/memory/operation-lock.d.ts +11 -0
- package/dist/store/memory/operation-lock.d.ts.map +1 -0
- package/dist/store/memory/operation-lock.js +94 -0
- package/dist/store/memory/operation-lock.js.map +1 -0
- package/dist/store/run/token-budget-disk.js +3 -0
- package/dist/store/run/token-budget-disk.js.map +1 -1
- package/dist/tools/builtins/computer-use.d.ts.map +1 -1
- package/dist/tools/builtins/computer-use.js +60 -10
- package/dist/tools/builtins/computer-use.js.map +1 -1
- package/dist/tools/builtins/edit.d.ts.map +1 -1
- package/dist/tools/builtins/edit.js +12 -26
- package/dist/tools/builtins/edit.js.map +1 -1
- package/dist/tools/builtins/file-write-result.d.ts +4 -0
- package/dist/tools/builtins/file-write-result.d.ts.map +1 -0
- package/dist/tools/builtins/file-write-result.js +72 -0
- package/dist/tools/builtins/file-write-result.js.map +1 -0
- package/dist/tools/builtins/glob.d.ts.map +1 -1
- package/dist/tools/builtins/glob.js +8 -1
- package/dist/tools/builtins/glob.js.map +1 -1
- package/dist/tools/builtins/grep.d.ts.map +1 -1
- package/dist/tools/builtins/grep.js +10 -0
- package/dist/tools/builtins/grep.js.map +1 -1
- package/dist/tools/builtins/job.d.ts.map +1 -1
- package/dist/tools/builtins/job.js +6 -0
- package/dist/tools/builtins/job.js.map +1 -1
- package/dist/tools/builtins/read-file.d.ts.map +1 -1
- package/dist/tools/builtins/read-file.js +10 -0
- package/dist/tools/builtins/read-file.js.map +1 -1
- package/dist/tools/builtins/run-code.d.ts +6 -0
- package/dist/tools/builtins/run-code.d.ts.map +1 -1
- package/dist/tools/builtins/run-code.js +15 -4
- package/dist/tools/builtins/run-code.js.map +1 -1
- package/dist/tools/builtins/search-tools.d.ts.map +1 -1
- package/dist/tools/builtins/search-tools.js +14 -2
- package/dist/tools/builtins/search-tools.js.map +1 -1
- package/dist/tools/builtins/write-file.d.ts.map +1 -1
- package/dist/tools/builtins/write-file.js +30 -44
- package/dist/tools/builtins/write-file.js.map +1 -1
- package/dist/tools/defineTool.d.ts +2 -0
- package/dist/tools/defineTool.d.ts.map +1 -1
- package/dist/tools/defineTool.js +3 -0
- package/dist/tools/defineTool.js.map +1 -1
- package/dist/tools/file-read-tracker.d.ts +4 -0
- package/dist/tools/file-read-tracker.d.ts.map +1 -0
- package/dist/tools/file-read-tracker.js +16 -0
- package/dist/tools/file-read-tracker.js.map +1 -0
- package/dist/tools/memory/delete.d.ts +4 -0
- package/dist/tools/memory/delete.d.ts.map +1 -0
- package/dist/tools/memory/delete.js +26 -0
- package/dist/tools/memory/delete.js.map +1 -0
- package/dist/tools/memory/index.d.ts +2 -0
- package/dist/tools/memory/index.d.ts.map +1 -1
- package/dist/tools/memory/index.js +6 -0
- package/dist/tools/memory/index.js.map +1 -1
- package/dist/tools/memory/save.d.ts.map +1 -1
- package/dist/tools/memory/save.js +3 -2
- package/dist/tools/memory/save.js.map +1 -1
- package/dist/tools/memory/search.d.ts.map +1 -1
- package/dist/tools/memory/search.js +12 -5
- package/dist/tools/memory/search.js.map +1 -1
- package/dist/tools/memory/update.d.ts +4 -0
- package/dist/tools/memory/update.d.ts.map +1 -0
- package/dist/tools/memory/update.js +47 -0
- package/dist/tools/memory/update.js.map +1 -0
- package/dist/tools/task/list.js +2 -2
- package/dist/tools/task/list.js.map +1 -1
- package/dist/types/agent/scheduler.d.ts +5 -0
- package/dist/types/agent/scheduler.d.ts.map +1 -1
- package/dist/types/agent/task.d.ts +10 -0
- package/dist/types/agent/task.d.ts.map +1 -1
- package/dist/types/computer-use/index.d.ts +6 -0
- package/dist/types/computer-use/index.d.ts.map +1 -1
- package/dist/types/computer-use/index.js.map +1 -1
- package/dist/types/errors/catalog.js +1 -1
- package/dist/types/errors/catalog.js.map +1 -1
- package/dist/types/hitl/index.d.ts +11 -1
- package/dist/types/hitl/index.d.ts.map +1 -1
- package/dist/types/hitl/index.js.map +1 -1
- package/dist/types/memory/index.d.ts +14 -1
- package/dist/types/memory/index.d.ts.map +1 -1
- package/dist/types/plugin/index.d.ts +7 -0
- package/dist/types/plugin/index.d.ts.map +1 -1
- package/dist/types/plugin/index.js.map +1 -1
- package/dist/types/project/entity.d.ts +1 -0
- package/dist/types/project/entity.d.ts.map +1 -1
- package/dist/types/provider/chat.d.ts +4 -0
- package/dist/types/provider/chat.d.ts.map +1 -1
- package/dist/types/provider/config.d.ts +4 -0
- package/dist/types/provider/config.d.ts.map +1 -1
- package/dist/types/provider/model.d.ts +4 -0
- package/dist/types/provider/model.d.ts.map +1 -1
- package/dist/types/provider/stream.d.ts +6 -0
- package/dist/types/provider/stream.d.ts.map +1 -1
- package/dist/types/run/answer-review.d.ts +2 -0
- package/dist/types/run/answer-review.d.ts.map +1 -1
- package/dist/types/run/config.d.ts +2 -0
- package/dist/types/run/config.d.ts.map +1 -1
- package/dist/types/run/events.d.ts +19 -0
- package/dist/types/run/events.d.ts.map +1 -1
- package/dist/types/run/events.js.map +1 -1
- package/dist/types/run/prepare-step.d.ts +19 -1
- package/dist/types/run/prepare-step.d.ts.map +1 -1
- package/dist/types/sandbox/index.d.ts +1 -0
- package/dist/types/sandbox/index.d.ts.map +1 -1
- package/dist/types/sandbox/index.js.map +1 -1
- package/dist/types/structured-output/index.d.ts +8 -2
- package/dist/types/structured-output/index.d.ts.map +1 -1
- package/dist/types/tool/index.d.ts +15 -0
- package/dist/types/tool/index.d.ts.map +1 -1
- package/dist/types/tool/index.js.map +1 -1
- package/dist/types/tool/presentation.d.ts +4 -0
- package/dist/types/tool/presentation.d.ts.map +1 -1
- package/dist/utils/json-snapshot.d.ts +3 -0
- package/dist/utils/json-snapshot.d.ts.map +1 -0
- package/dist/utils/json-snapshot.js +79 -0
- package/dist/utils/json-snapshot.js.map +1 -0
- package/package.json +4 -2
- package/src/bridge/a2a/mapper.ts +4 -0
- package/src/bridge/sse/mapper.ts +16 -1
- package/src/compaction/extractor.ts +21 -8
- package/src/compaction/manager.ts +11 -1
- package/src/compaction/verifier.ts +80 -18
- package/src/config/runtime.ts +2 -0
- package/src/contracts/api.ts +1 -0
- package/src/eval/harness-verification.ts +270 -0
- package/src/eval/index.ts +10 -0
- package/src/execution/code-runtime/json-value.ts +82 -0
- package/src/execution/code-runtime/worker-program.ts +239 -0
- package/src/execution/code-runtime/worker.ts +164 -111
- package/src/manager/agent/lifecycle.ts +352 -54
- package/src/manager/run/persistence.ts +7 -0
- package/src/prompt/coding-agent-doctrine.ts +11 -5
- package/src/provider/capabilities.ts +41 -1
- package/src/provider/fallback.ts +9 -2
- package/src/public-runtime.ts +6 -0
- package/src/public-tools.ts +7 -1
- package/src/public-types.ts +7 -0
- package/src/registry/tool/execute.ts +17 -79
- package/src/run/command-gate.ts +61 -13
- package/src/run/index.ts +2 -0
- package/src/run/memory-promoter.ts +32 -40
- package/src/run/memory-recall.ts +254 -0
- package/src/run/reporter.ts +2 -0
- package/src/run/token-budget.ts +55 -14
- package/src/run/workspace-fingerprint.ts +17 -8
- package/src/runtime/query/checkpoint.ts +96 -2
- package/src/runtime/query/executor.ts +100 -29
- package/src/runtime/query/index.ts +76 -16
- package/src/runtime/query/iteration/index.ts +405 -46
- package/src/runtime/query/iteration/native-output.ts +35 -0
- package/src/runtime/query/iteration/phases/advisory.ts +21 -11
- package/src/runtime/query/iteration/phases/compaction.ts +36 -14
- package/src/runtime/query/iteration/phases/context.ts +9 -0
- package/src/runtime/query/iteration/phases/tool-review.ts +5 -1
- package/src/runtime/query/iteration/phases/working-memory.ts +23 -5
- package/src/runtime/query/iteration/stream-turn.ts +15 -0
- package/src/runtime/query/observation-context.ts +86 -0
- package/src/runtime/query/request-context.ts +103 -0
- package/src/runtime/query/request-rich-content.ts +8 -3
- package/src/runtime/query/review-policy.ts +7 -1
- package/src/runtime/query/steering.ts +19 -2
- package/src/runtime/query/tool-call-budget.ts +115 -0
- package/src/runtime/query/tooling.ts +8 -0
- package/src/sandbox/file-walk-program.ts +8 -0
- package/src/sandbox/file-walk.ts +9 -0
- package/src/scheduler/completion-inbox.ts +3 -0
- package/src/scheduler/local.ts +1 -0
- package/src/session/handoff/capacity.ts +7 -3
- package/src/store/memory/disk.ts +52 -30
- package/src/store/memory/index.ts +75 -27
- package/src/store/memory/memory.ts +18 -6
- package/src/store/memory/operation-lock.ts +99 -0
- package/src/store/run/token-budget-disk.ts +3 -0
- package/src/tools/builtins/computer-use.ts +61 -7
- package/src/tools/builtins/edit.ts +12 -27
- package/src/tools/builtins/file-write-result.ts +84 -0
- package/src/tools/builtins/glob.ts +7 -1
- package/src/tools/builtins/grep.ts +10 -0
- package/src/tools/builtins/job.ts +8 -0
- package/src/tools/builtins/read-file.ts +10 -0
- package/src/tools/builtins/run-code.ts +24 -5
- package/src/tools/builtins/search-tools.ts +18 -3
- package/src/tools/builtins/write-file.ts +39 -44
- package/src/tools/defineTool.ts +5 -0
- package/src/tools/file-read-tracker.ts +16 -0
- package/src/tools/memory/delete.ts +29 -0
- package/src/tools/memory/index.ts +6 -0
- package/src/tools/memory/save.ts +4 -2
- package/src/tools/memory/search.ts +12 -5
- package/src/tools/memory/update.ts +50 -0
- package/src/tools/task/list.ts +2 -2
- package/src/types/agent/scheduler.ts +6 -0
- package/src/types/agent/task.ts +13 -0
- package/src/types/computer-use/index.ts +6 -0
- package/src/types/errors/catalog.ts +1 -1
- package/src/types/hitl/index.ts +11 -1
- package/src/types/memory/index.ts +16 -1
- package/src/types/plugin/index.ts +10 -0
- package/src/types/project/entity.ts +1 -0
- package/src/types/provider/chat.ts +2 -0
- package/src/types/provider/config.ts +4 -0
- package/src/types/provider/model.ts +4 -0
- package/src/types/provider/stream.ts +7 -0
- package/src/types/run/answer-review.ts +2 -0
- package/src/types/run/config.ts +2 -0
- package/src/types/run/events.ts +20 -0
- package/src/types/run/prepare-step.ts +19 -1
- package/src/types/sandbox/index.ts +1 -0
- package/src/types/structured-output/index.ts +15 -2
- package/src/types/tool/index.ts +16 -0
- package/src/types/tool/presentation.ts +4 -0
- package/src/utils/json-snapshot.ts +76 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AGENT_MANAGER_DEFAULTS } from '../../constants/agent/index.js';
|
|
2
|
+
import { EMPTY_TOKEN_USAGE } from '../../constants/limits.js';
|
|
2
3
|
import { GENAI } from '../../constants/telemetry/index.js';
|
|
3
4
|
import { DelegationCapacityExceeded, } from '../../session/handoff/capacity.js';
|
|
4
5
|
import { isTerminalAgentTaskState } from '../../types/agent/task.js';
|
|
@@ -13,6 +14,9 @@ import { SCOPE_ATTRIBUTE } from '../../utils/log/types.js';
|
|
|
13
14
|
import { resolveLogger } from '../../utils/logger.js';
|
|
14
15
|
import { requireOpenProject } from '../project/lifecycle.js';
|
|
15
16
|
import { resolveTopicManager } from '../topic/dependency.js';
|
|
17
|
+
/** Internal backpressure: the parent's unmeasured request owns its budget until its receipt. */
|
|
18
|
+
class ParentBudgetRequestPending extends Error {
|
|
19
|
+
}
|
|
16
20
|
/**
|
|
17
21
|
* Combine a child's own environment with what its parent passed down.
|
|
18
22
|
*
|
|
@@ -42,9 +46,18 @@ export class AgentManager {
|
|
|
42
46
|
spawnLocks = new Map();
|
|
43
47
|
deps;
|
|
44
48
|
topicManager;
|
|
49
|
+
pendingSpawns = new Map();
|
|
50
|
+
drainingParents = new Set();
|
|
51
|
+
executingTasks = new Set();
|
|
52
|
+
cancelingTasks = new Set();
|
|
53
|
+
admissionTimer;
|
|
54
|
+
disposed = false;
|
|
45
55
|
constructor(registry, config, deps) {
|
|
46
56
|
this.registry = registry;
|
|
47
57
|
this.config = { ...AGENT_MANAGER_DEFAULTS, ...config };
|
|
58
|
+
const maxPending = this.config.maxPendingTasks ?? 128;
|
|
59
|
+
if (!Number.isSafeInteger(maxPending) || maxPending < 1)
|
|
60
|
+
throw new Error('maxPendingTasks must be a positive safe integer');
|
|
48
61
|
this.log = resolveLogger(deps.log).child({
|
|
49
62
|
[SCOPE_ATTRIBUTE]: 'manager/agent/lifecycle',
|
|
50
63
|
});
|
|
@@ -52,6 +65,170 @@ export class AgentManager {
|
|
|
52
65
|
this.topicManager = resolveTopicManager(deps);
|
|
53
66
|
}
|
|
54
67
|
async sendMessage(options, context, listener) {
|
|
68
|
+
if (this.disposed)
|
|
69
|
+
throw new Error('Agent manager is disposed');
|
|
70
|
+
if (this.config.capacityBehavior === 'queue')
|
|
71
|
+
return this.enqueueMessage(options, context, listener);
|
|
72
|
+
return this.startMessage(options, context, listener);
|
|
73
|
+
}
|
|
74
|
+
async enqueueMessage(options, context, listener) {
|
|
75
|
+
context.parentAbortController.signal.throwIfAborted();
|
|
76
|
+
if (context.depth >= this.config.maxDepth)
|
|
77
|
+
throw new Error(`Max task depth ${this.config.maxDepth} exceeded`);
|
|
78
|
+
if (options.tenantId !== context.tenantId)
|
|
79
|
+
throw new Error('Tenant mismatch: cross-tenant spawn rejected');
|
|
80
|
+
const definition = this.registry.getOrThrow(options.agentId);
|
|
81
|
+
const count = [...this.pendingSpawns.values()].reduce((sum, queue) => sum + queue.length, 0);
|
|
82
|
+
if (count >= (this.config.maxPendingTasks ?? 128))
|
|
83
|
+
throw new Error(`Delegation queue is full (${this.config.maxPendingTasks ?? 128} pending tasks). Wait for existing tasks before submitting more work.`);
|
|
84
|
+
const task = {
|
|
85
|
+
taskId: generateTaskId(),
|
|
86
|
+
agentId: options.agentId,
|
|
87
|
+
agent: definition.typedAgent,
|
|
88
|
+
childAbortController: createChildAbortController(context.parentAbortController),
|
|
89
|
+
context,
|
|
90
|
+
state: 'pending',
|
|
91
|
+
pendingMessages: [],
|
|
92
|
+
createdAt: Date.now(),
|
|
93
|
+
runEventListener: listener,
|
|
94
|
+
};
|
|
95
|
+
this.instances.set(task.taskId, task);
|
|
96
|
+
const onAbort = () => {
|
|
97
|
+
// Before admission this observer owns cancellation. Once child scope
|
|
98
|
+
// exists, startup rollback may abort its controller for a configuration
|
|
99
|
+
// error; that is a failure, not a user cancellation.
|
|
100
|
+
if (task.context === context || context.parentAbortController.signal.aborted)
|
|
101
|
+
this.cancel(task.taskId, 'parent');
|
|
102
|
+
};
|
|
103
|
+
task.childAbortController.signal.addEventListener('abort', onAbort, { once: true });
|
|
104
|
+
const entry = {
|
|
105
|
+
ready: false,
|
|
106
|
+
task,
|
|
107
|
+
options,
|
|
108
|
+
context,
|
|
109
|
+
listener,
|
|
110
|
+
removeAbortListener: () => task.childAbortController.signal.removeEventListener('abort', onAbort),
|
|
111
|
+
};
|
|
112
|
+
const queue = this.pendingSpawns.get(options.parentSessionId) ?? [];
|
|
113
|
+
queue.push(entry);
|
|
114
|
+
this.pendingSpawns.set(options.parentSessionId, queue);
|
|
115
|
+
this.emit({
|
|
116
|
+
type: 'pending',
|
|
117
|
+
taskId: task.taskId,
|
|
118
|
+
agentId: options.agentId,
|
|
119
|
+
parentAgentId: context.parentAgentId,
|
|
120
|
+
depth: context.depth,
|
|
121
|
+
});
|
|
122
|
+
try {
|
|
123
|
+
await listener?.({
|
|
124
|
+
type: 'agent_pending',
|
|
125
|
+
runId: context.parentRunId,
|
|
126
|
+
taskId: task.taskId,
|
|
127
|
+
parentAgentId: context.parentAgentId,
|
|
128
|
+
childAgentId: options.agentId,
|
|
129
|
+
depth: context.depth,
|
|
130
|
+
});
|
|
131
|
+
entry.ready = true;
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
this.failAdmission(entry, error);
|
|
135
|
+
}
|
|
136
|
+
this.pumpAdmissions(options.parentSessionId);
|
|
137
|
+
return task;
|
|
138
|
+
}
|
|
139
|
+
pumpAdmissions(parentSessionId) {
|
|
140
|
+
if (this.disposed || this.drainingParents.has(parentSessionId))
|
|
141
|
+
return;
|
|
142
|
+
this.drainingParents.add(parentSessionId);
|
|
143
|
+
void this.drainAdmissions(parentSessionId)
|
|
144
|
+
.finally(() => {
|
|
145
|
+
this.drainingParents.delete(parentSessionId);
|
|
146
|
+
// External handoffs and metadata changes have no manager event. A
|
|
147
|
+
// single slow, unref'ed timer observes those without spinning or
|
|
148
|
+
// keeping a host alive. Actual completions wake admission directly.
|
|
149
|
+
if (!this.disposed && this.pendingSpawns.size > 0 && !this.admissionTimer) {
|
|
150
|
+
this.admissionTimer = setTimeout(() => {
|
|
151
|
+
this.admissionTimer = undefined;
|
|
152
|
+
for (const parent of this.pendingSpawns.keys())
|
|
153
|
+
this.pumpAdmissions(parent);
|
|
154
|
+
}, 250);
|
|
155
|
+
this.admissionTimer.unref?.();
|
|
156
|
+
}
|
|
157
|
+
})
|
|
158
|
+
.catch((error) => this.log.error('Delegation admission failed', {
|
|
159
|
+
'exception.message': toErrorMessage(error),
|
|
160
|
+
}));
|
|
161
|
+
}
|
|
162
|
+
async drainAdmissions(parentSessionId) {
|
|
163
|
+
const queue = this.pendingSpawns.get(parentSessionId);
|
|
164
|
+
if (!queue)
|
|
165
|
+
return;
|
|
166
|
+
while (!this.disposed && queue.length > 0) {
|
|
167
|
+
const entry = queue[0];
|
|
168
|
+
if (!entry)
|
|
169
|
+
break;
|
|
170
|
+
if (isTerminalAgentTaskState(entry.task.state)) {
|
|
171
|
+
entry.removeAbortListener();
|
|
172
|
+
queue.shift();
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
// A concurrent enqueue can pump this same FIFO while the head's
|
|
176
|
+
// pending listener still owns its acknowledgement. Do not provision
|
|
177
|
+
// or spend until that acknowledgement succeeds.
|
|
178
|
+
if (!entry.ready)
|
|
179
|
+
return;
|
|
180
|
+
try {
|
|
181
|
+
await entry.options.beforeStart?.();
|
|
182
|
+
entry.task.childAbortController.signal.throwIfAborted();
|
|
183
|
+
await this.validateSpawn(entry.options, entry.context);
|
|
184
|
+
entry.task.childAbortController.signal.throwIfAborted();
|
|
185
|
+
await this.startMessage(entry.options, entry.context, entry.listener, entry.task);
|
|
186
|
+
entry.removeAbortListener();
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
if ((error instanceof ParentBudgetRequestPending ||
|
|
190
|
+
(error instanceof DelegationCapacityExceeded && error.details.dimension === 'width')) &&
|
|
191
|
+
!isTerminalAgentTaskState(entry.task.state))
|
|
192
|
+
return;
|
|
193
|
+
this.failAdmission(entry, error);
|
|
194
|
+
}
|
|
195
|
+
queue.shift();
|
|
196
|
+
}
|
|
197
|
+
if (queue.length === 0 && this.pendingSpawns.get(parentSessionId) === queue)
|
|
198
|
+
this.pendingSpawns.delete(parentSessionId);
|
|
199
|
+
}
|
|
200
|
+
failAdmission(entry, reason) {
|
|
201
|
+
entry.removeAbortListener();
|
|
202
|
+
const task = entry.task;
|
|
203
|
+
if (isTerminalAgentTaskState(task.state))
|
|
204
|
+
return;
|
|
205
|
+
task.childAbortController.abort(reason);
|
|
206
|
+
const error = toErrorMessage(reason);
|
|
207
|
+
task.result = {
|
|
208
|
+
runId: entry.context.parentRunId,
|
|
209
|
+
status: 'failed',
|
|
210
|
+
usage: { ...EMPTY_TOKEN_USAGE },
|
|
211
|
+
cost: { ...ZERO_COST },
|
|
212
|
+
iterations: 0,
|
|
213
|
+
durationMs: Date.now() - task.createdAt,
|
|
214
|
+
messages: [],
|
|
215
|
+
lastError: error,
|
|
216
|
+
};
|
|
217
|
+
task.state = 'failed';
|
|
218
|
+
task.completedAt = Date.now();
|
|
219
|
+
this.emit({ type: 'failed', taskId: task.taskId, error });
|
|
220
|
+
this.emitRunEvent(task, {
|
|
221
|
+
type: 'agent_failed',
|
|
222
|
+
runId: entry.context.parentRunId,
|
|
223
|
+
taskId: task.taskId,
|
|
224
|
+
error,
|
|
225
|
+
});
|
|
226
|
+
this.scheduleEviction(task.taskId);
|
|
227
|
+
this.resolveCompletionCallbacks(task.taskId);
|
|
228
|
+
}
|
|
229
|
+
async startMessage(options, context, listener, queuedTask) {
|
|
230
|
+
await options.beforeStart?.();
|
|
231
|
+
queuedTask?.childAbortController.signal.throwIfAborted();
|
|
55
232
|
if (context.depth >= this.config.maxDepth) {
|
|
56
233
|
throw new Error(`Max task depth ${this.config.maxDepth} exceeded (current: ${context.depth}). Recursive agent delegation is limited to prevent resource exhaustion.`);
|
|
57
234
|
}
|
|
@@ -83,20 +260,37 @@ export class AgentManager {
|
|
|
83
260
|
// Reserve synchronously before provisioning yields. The authority is shared
|
|
84
261
|
// across managers and nested sessions, while the session lock below only
|
|
85
262
|
// serializes filesystem capacity checks.
|
|
263
|
+
// Queued siblings share the available budget with the parent. The first
|
|
264
|
+
// of eight children receives at most one ninth; later siblings receive
|
|
265
|
+
// comparable grants instead of a geometric 1/2, 1/4, ... starvation tail.
|
|
266
|
+
let budgetShares = 1;
|
|
267
|
+
if (queuedTask) {
|
|
268
|
+
const project = await requireOpenProject(this.deps.sessionStore, context.projectId, context.tenantId, 'spawn');
|
|
269
|
+
const children = await this.deps.sessionStore.getChildren(options.parentSessionId, context.tenantId);
|
|
270
|
+
const active = children.filter((child) => child.status !== 'idle' && child.status !== 'failed' && child.status !== 'archived').length;
|
|
271
|
+
budgetShares = Math.max(2, project.config.maxDelegationWidth - active + 1);
|
|
272
|
+
}
|
|
273
|
+
context.parentAbortController.signal.throwIfAborted();
|
|
274
|
+
queuedTask?.childAbortController.signal.throwIfAborted();
|
|
86
275
|
const remaining = context.budget.remaining;
|
|
87
276
|
const maxAllocation = Number.isFinite(remaining)
|
|
88
|
-
? Math.floor(remaining * this.config.maxBudgetFraction)
|
|
89
|
-
: (options.budgetAllocation?.tokenBudget ??
|
|
90
|
-
(options.configOverrides?.tokenBudget === 0
|
|
91
|
-
? 200_000
|
|
92
|
-
: (options.configOverrides?.tokenBudget ?? 200_000)));
|
|
277
|
+
? Math.floor(Math.min(remaining * this.config.maxBudgetFraction, remaining / budgetShares))
|
|
278
|
+
: (options.budgetAllocation?.tokenBudget ?? options.configOverrides?.tokenBudget ?? 200_000);
|
|
93
279
|
const allocatedTokens = Math.min(options.budgetAllocation?.tokenBudget ?? maxAllocation, maxAllocation);
|
|
94
|
-
if (!Number.isSafeInteger(allocatedTokens) ||
|
|
280
|
+
if (!Number.isSafeInteger(allocatedTokens) ||
|
|
281
|
+
allocatedTokens < 0 ||
|
|
282
|
+
(allocatedTokens === 0 && Number.isFinite(remaining))) {
|
|
95
283
|
throw new NamzuError({
|
|
96
284
|
code: 'invalid_config',
|
|
97
|
-
message: `Cannot spawn "${options.agentId}": the parent has ${remaining} tokens remaining; a child allocation must be a finite positive integer.`,
|
|
285
|
+
message: `Cannot spawn "${options.agentId}": the parent has ${remaining} tokens remaining; a child allocation must be a finite positive integer, or zero under an unlimited parent budget.`,
|
|
98
286
|
});
|
|
99
287
|
}
|
|
288
|
+
// No await between this check and reserve: a parent's response may start
|
|
289
|
+
// during the scope reads above. Its own in-flight request is temporary
|
|
290
|
+
// backpressure; descendant requests are expected during a fan-out.
|
|
291
|
+
// Invalid/zero allocations above still fail rather than waiting forever.
|
|
292
|
+
if (queuedTask && context.budget.hasInFlightRequest)
|
|
293
|
+
throw new ParentBudgetRequestPending('The parent provider request is still in flight');
|
|
100
294
|
const childBudget = context.budget.reserve(allocatedTokens);
|
|
101
295
|
let spawnRecord;
|
|
102
296
|
try {
|
|
@@ -111,8 +305,11 @@ export class AgentManager {
|
|
|
111
305
|
let childAbortController;
|
|
112
306
|
let agentTask;
|
|
113
307
|
try {
|
|
114
|
-
childAbortController =
|
|
115
|
-
|
|
308
|
+
childAbortController =
|
|
309
|
+
queuedTask?.childAbortController ??
|
|
310
|
+
createChildAbortController(context.parentAbortController);
|
|
311
|
+
childAbortController.signal.throwIfAborted();
|
|
312
|
+
const taskId = queuedTask?.taskId ?? generateTaskId();
|
|
116
313
|
const childParentActor = {
|
|
117
314
|
kind: 'agent',
|
|
118
315
|
agentId: context.parentAgentId,
|
|
@@ -155,38 +352,40 @@ export class AgentManager {
|
|
|
155
352
|
parentActor: childParentActor,
|
|
156
353
|
...(resolvedDenies.length > 0 ? { toolDenies: resolvedDenies } : {}),
|
|
157
354
|
};
|
|
158
|
-
agentTask = {
|
|
355
|
+
agentTask = Object.assign(queuedTask ?? {}, {
|
|
159
356
|
taskId,
|
|
160
357
|
agentId: options.agentId,
|
|
161
358
|
agent,
|
|
162
359
|
childAbortController,
|
|
163
360
|
context: childContext,
|
|
164
361
|
state: 'pending',
|
|
165
|
-
pendingMessages: [],
|
|
166
|
-
createdAt: Date.now(),
|
|
362
|
+
pendingMessages: queuedTask?.pendingMessages ?? [],
|
|
363
|
+
createdAt: queuedTask?.createdAt ?? Date.now(),
|
|
167
364
|
runEventListener: listener,
|
|
168
|
-
};
|
|
365
|
+
});
|
|
169
366
|
childAbortController.signal.throwIfAborted();
|
|
170
367
|
this.instances.set(taskId, agentTask);
|
|
171
368
|
if (resolvedDenies.length > 0)
|
|
172
369
|
spawnRecord.resolvedToolDenies = resolvedDenies;
|
|
173
370
|
this.spawnRecords.set(taskId, spawnRecord);
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
agentId: options.agentId,
|
|
178
|
-
parentAgentId: context.parentAgentId,
|
|
179
|
-
depth: context.depth,
|
|
180
|
-
});
|
|
181
|
-
if (listener) {
|
|
182
|
-
await listener({
|
|
183
|
-
type: 'agent_pending',
|
|
184
|
-
runId: context.parentRunId,
|
|
371
|
+
if (!queuedTask)
|
|
372
|
+
this.emit({
|
|
373
|
+
type: 'pending',
|
|
185
374
|
taskId,
|
|
375
|
+
agentId: options.agentId,
|
|
186
376
|
parentAgentId: context.parentAgentId,
|
|
187
|
-
childAgentId: options.agentId,
|
|
188
377
|
depth: context.depth,
|
|
189
378
|
});
|
|
379
|
+
if (listener) {
|
|
380
|
+
if (!queuedTask)
|
|
381
|
+
await listener({
|
|
382
|
+
type: 'agent_pending',
|
|
383
|
+
runId: context.parentRunId,
|
|
384
|
+
taskId,
|
|
385
|
+
parentAgentId: context.parentAgentId,
|
|
386
|
+
childAgentId: options.agentId,
|
|
387
|
+
depth: context.depth,
|
|
388
|
+
});
|
|
190
389
|
const lineage = {
|
|
191
390
|
parentSessionId: spawnRecord.parentSessionId,
|
|
192
391
|
rootSessionId: spawnRecord.rootSessionId,
|
|
@@ -326,9 +525,11 @@ export class AgentManager {
|
|
|
326
525
|
});
|
|
327
526
|
}
|
|
328
527
|
childConfig.tokenBudget =
|
|
329
|
-
|
|
330
|
-
?
|
|
331
|
-
:
|
|
528
|
+
allocatedTokens === 0
|
|
529
|
+
? childConfig.tokenBudget
|
|
530
|
+
: childConfig.tokenBudget === 0
|
|
531
|
+
? allocatedTokens
|
|
532
|
+
: Math.min(childConfig.tokenBudget, allocatedTokens);
|
|
332
533
|
childBudget.narrow(childConfig.tokenBudget);
|
|
333
534
|
// Stamped AFTER the builder, for the fourth time and the same reason:
|
|
334
535
|
// a `configBuilder` is written by whoever registered the agent and
|
|
@@ -373,7 +574,10 @@ export class AgentManager {
|
|
|
373
574
|
childAbortController.signal.throwIfAborted();
|
|
374
575
|
await childBudget.flush();
|
|
375
576
|
childAbortController.signal.throwIfAborted();
|
|
376
|
-
this.
|
|
577
|
+
this.executingTasks.add(taskId);
|
|
578
|
+
const runningTask = agentTask;
|
|
579
|
+
this.runChild(runningTask, options, childConfig, listener)
|
|
580
|
+
.catch(async (err) => {
|
|
377
581
|
// A thrown invocation supplied no final usage receipt. Keep its
|
|
378
582
|
// reservation, including when its task handle was canceled or evicted.
|
|
379
583
|
let failure = err;
|
|
@@ -383,8 +587,24 @@ export class AgentManager {
|
|
|
383
587
|
catch (writeError) {
|
|
384
588
|
failure = writeError;
|
|
385
589
|
}
|
|
386
|
-
|
|
387
|
-
|
|
590
|
+
// Cancellation may already have published a terminal handle. Its
|
|
591
|
+
// invocation has only NOW stopped; release the persisted edge here.
|
|
592
|
+
if (!this.instances.has(taskId) || isTerminalAgentTaskState(runningTask.state)) {
|
|
593
|
+
await this.failSubSession(spawnRecord);
|
|
594
|
+
}
|
|
595
|
+
else
|
|
596
|
+
this.markFailed(taskId, toErrorMessage(failure));
|
|
597
|
+
})
|
|
598
|
+
.finally(() => {
|
|
599
|
+
this.executingTasks.delete(taskId);
|
|
600
|
+
if (!this.instances.has(taskId))
|
|
601
|
+
this.spawnRecords.delete(taskId);
|
|
602
|
+
this.pumpAdmissions(options.parentSessionId);
|
|
603
|
+
})
|
|
604
|
+
.catch((error) => this.log.warn('Child cleanup failed', {
|
|
605
|
+
'namzu.task.id': taskId,
|
|
606
|
+
'exception.message': toErrorMessage(error),
|
|
607
|
+
}));
|
|
388
608
|
return agentTask;
|
|
389
609
|
}
|
|
390
610
|
catch (err) {
|
|
@@ -392,7 +612,7 @@ export class AgentManager {
|
|
|
392
612
|
// provisioned resources are still ours to return. A builder/listener
|
|
393
613
|
// failure must not strand a pending task the caller never received.
|
|
394
614
|
if (agentTask) {
|
|
395
|
-
await this.rollbackUnstartedSpawn(agentTask, spawnRecord, err);
|
|
615
|
+
await this.rollbackUnstartedSpawn(agentTask, spawnRecord, err, queuedTask !== undefined);
|
|
396
616
|
}
|
|
397
617
|
else {
|
|
398
618
|
childAbortController?.abort();
|
|
@@ -403,7 +623,7 @@ export class AgentManager {
|
|
|
403
623
|
throw err;
|
|
404
624
|
}
|
|
405
625
|
}
|
|
406
|
-
async rollbackUnstartedSpawn(agentTask, spawnRecord, reason) {
|
|
626
|
+
async rollbackUnstartedSpawn(agentTask, spawnRecord, reason, retainHandle = false) {
|
|
407
627
|
agentTask.childAbortController.abort();
|
|
408
628
|
agentTask.context.budget.settle(0);
|
|
409
629
|
await agentTask.context.budget.flush();
|
|
@@ -427,7 +647,22 @@ export class AgentManager {
|
|
|
427
647
|
}
|
|
428
648
|
}
|
|
429
649
|
this.clearEvictionTimer(agentTask.taskId);
|
|
430
|
-
|
|
650
|
+
if (retainHandle) {
|
|
651
|
+
agentTask.result ??= {
|
|
652
|
+
runId: agentTask.context.parentRunId,
|
|
653
|
+
status: 'failed',
|
|
654
|
+
usage: { ...EMPTY_TOKEN_USAGE },
|
|
655
|
+
cost: { ...ZERO_COST },
|
|
656
|
+
iterations: 0,
|
|
657
|
+
durationMs: Date.now() - agentTask.createdAt,
|
|
658
|
+
messages: [],
|
|
659
|
+
lastError: toErrorMessage(reason),
|
|
660
|
+
};
|
|
661
|
+
agentTask.completedAt = Date.now();
|
|
662
|
+
this.scheduleEviction(agentTask.taskId);
|
|
663
|
+
}
|
|
664
|
+
else
|
|
665
|
+
this.instances.delete(agentTask.taskId);
|
|
431
666
|
this.spawnRecords.delete(agentTask.taskId);
|
|
432
667
|
this.resolveCompletionCallbacks(agentTask.taskId);
|
|
433
668
|
await this.rollbackSpawnResources(spawnRecord);
|
|
@@ -448,14 +683,24 @@ export class AgentManager {
|
|
|
448
683
|
}
|
|
449
684
|
}
|
|
450
685
|
cancel(taskId, cause) {
|
|
686
|
+
if (this.cancelingTasks.has(taskId))
|
|
687
|
+
return;
|
|
451
688
|
const agentTask = this.instances.get(taskId);
|
|
452
689
|
if (!agentTask || isTerminalAgentTaskState(agentTask.state))
|
|
453
690
|
return;
|
|
454
691
|
// Was the bare string `'canceled'`, which `abortReasonText` suppresses
|
|
455
692
|
// by name — its docblock cites this exact call site — so the child's
|
|
456
693
|
// run saw a cancellation with no attributable origin at all.
|
|
457
|
-
|
|
458
|
-
this
|
|
694
|
+
// Abort listeners run synchronously. A pending task's parent observer
|
|
695
|
+
// must not reenter this method and replace an explicit user's cause.
|
|
696
|
+
this.cancelingTasks.add(taskId);
|
|
697
|
+
try {
|
|
698
|
+
agentTask.childAbortController.abort(cause ? new RunCancelled(cause) : undefined);
|
|
699
|
+
this.markCanceled(taskId, cause);
|
|
700
|
+
}
|
|
701
|
+
finally {
|
|
702
|
+
this.cancelingTasks.delete(taskId);
|
|
703
|
+
}
|
|
459
704
|
}
|
|
460
705
|
cancelAll(parentRunId, cause = 'parent') {
|
|
461
706
|
// `'parent'` by default, because this call site IS a parent
|
|
@@ -539,11 +784,20 @@ export class AgentManager {
|
|
|
539
784
|
if (isTerminalAgentTaskState(agentTask.state)) {
|
|
540
785
|
this.clearEvictionTimer(taskId);
|
|
541
786
|
this.instances.delete(taskId);
|
|
542
|
-
this.
|
|
787
|
+
if (!this.executingTasks.has(taskId))
|
|
788
|
+
this.spawnRecords.delete(taskId);
|
|
543
789
|
}
|
|
544
790
|
}
|
|
545
791
|
}
|
|
546
792
|
dispose() {
|
|
793
|
+
this.disposed = true;
|
|
794
|
+
if (this.admissionTimer)
|
|
795
|
+
clearTimeout(this.admissionTimer);
|
|
796
|
+
this.admissionTimer = undefined;
|
|
797
|
+
for (const queue of this.pendingSpawns.values())
|
|
798
|
+
for (const entry of queue)
|
|
799
|
+
entry.removeAbortListener();
|
|
800
|
+
this.pendingSpawns.clear();
|
|
547
801
|
for (const taskId of this.instances.keys()) {
|
|
548
802
|
this.clearEvictionTimer(taskId);
|
|
549
803
|
}
|
|
@@ -555,7 +809,9 @@ export class AgentManager {
|
|
|
555
809
|
this.cancel(taskId);
|
|
556
810
|
}
|
|
557
811
|
this.instances.clear();
|
|
558
|
-
this.spawnRecords.
|
|
812
|
+
for (const taskId of this.spawnRecords.keys())
|
|
813
|
+
if (!this.executingTasks.has(taskId))
|
|
814
|
+
this.spawnRecords.delete(taskId);
|
|
559
815
|
this.listeners.length = 0;
|
|
560
816
|
}
|
|
561
817
|
/**
|
|
@@ -591,7 +847,7 @@ export class AgentManager {
|
|
|
591
847
|
this.spawnLocks.delete(key);
|
|
592
848
|
}
|
|
593
849
|
}
|
|
594
|
-
async
|
|
850
|
+
async validateSpawn(options, context) {
|
|
595
851
|
// Phase 9: deps are unconditional required. Every spawn produces a
|
|
596
852
|
// SubSession + Session + WorkspaceRef triple (Convention #0: no
|
|
597
853
|
// partial/legacy path).
|
|
@@ -618,6 +874,8 @@ export class AgentManager {
|
|
|
618
874
|
if (!parentSession) {
|
|
619
875
|
throw new Error(`Parent session ${options.parentSessionId} not found for tenant ${context.tenantId} — spawn rejected`);
|
|
620
876
|
}
|
|
877
|
+
if (parentSession.status === 'archived')
|
|
878
|
+
throw new Error('Delegation parent session is archived');
|
|
621
879
|
if (parentSession.topicId !== context.topicId) {
|
|
622
880
|
throw new Error(`Topic mismatch on spawn: parent session ${parentSession.id} is on topic ${parentSession.topicId}, but context.topicId=${context.topicId}. Cross-topic spawn is forbidden (session-hierarchy.md §6.3).`);
|
|
623
881
|
}
|
|
@@ -633,6 +891,11 @@ export class AgentManager {
|
|
|
633
891
|
// chain; width counts existing direct children of the parent.
|
|
634
892
|
await this.deps.capacity.validateDepth(options.parentSessionId, project.config.maxDelegationDepth, context.tenantId);
|
|
635
893
|
await this.deps.capacity.validateWidth(options.parentSessionId, 1, project.config.maxDelegationWidth, context.tenantId);
|
|
894
|
+
}
|
|
895
|
+
async provisionSpawnUnlocked(options, context) {
|
|
896
|
+
await this.validateSpawn(options, context);
|
|
897
|
+
context.parentAbortController.signal.throwIfAborted();
|
|
898
|
+
const store = this.deps.sessionStore;
|
|
636
899
|
// Ancestry walk gives both the child depth and the root session id
|
|
637
900
|
// attached to every sub-session event from here down.
|
|
638
901
|
const parentAncestry = await store.getAncestry(options.parentSessionId, context.tenantId);
|
|
@@ -995,13 +1258,16 @@ export class AgentManager {
|
|
|
995
1258
|
return agentTask;
|
|
996
1259
|
}
|
|
997
1260
|
scheduleEviction(taskId) {
|
|
1261
|
+
if (this.disposed)
|
|
1262
|
+
return;
|
|
998
1263
|
const agentTask = this.instances.get(taskId);
|
|
999
1264
|
if (!agentTask)
|
|
1000
1265
|
return;
|
|
1001
1266
|
agentTask.evictAfter = Date.now() + this.config.evictionMs;
|
|
1002
1267
|
const timer = setTimeout(() => {
|
|
1003
1268
|
this.instances.delete(taskId);
|
|
1004
|
-
this.
|
|
1269
|
+
if (!this.executingTasks.has(taskId))
|
|
1270
|
+
this.spawnRecords.delete(taskId);
|
|
1005
1271
|
this.evictionTimers.delete(taskId);
|
|
1006
1272
|
this.log.info('Agent task evicted', { 'namzu.agent.task_id': taskId });
|
|
1007
1273
|
}, this.config.evictionMs);
|
|
@@ -1038,15 +1304,19 @@ export class AgentManager {
|
|
|
1038
1304
|
emitRunEvent(agentTask, event) {
|
|
1039
1305
|
if (!agentTask.runEventListener)
|
|
1040
1306
|
return;
|
|
1041
|
-
|
|
1042
|
-
agentTask.runEventListener(event);
|
|
1043
|
-
}
|
|
1044
|
-
catch (err) {
|
|
1307
|
+
const reportFailure = (error) => {
|
|
1045
1308
|
this.log.error('RunEvent emission error', {
|
|
1046
1309
|
'namzu.event.type': event.type,
|
|
1047
|
-
'
|
|
1048
|
-
'exception.message': toErrorMessage(err),
|
|
1310
|
+
'exception.message': toErrorMessage(error),
|
|
1049
1311
|
});
|
|
1312
|
+
};
|
|
1313
|
+
try {
|
|
1314
|
+
// Terminal observation must not delay completion or leak a rejected
|
|
1315
|
+
// listener promise into the host as an unhandled rejection.
|
|
1316
|
+
void Promise.resolve(agentTask.runEventListener(event)).catch(reportFailure);
|
|
1317
|
+
}
|
|
1318
|
+
catch (error) {
|
|
1319
|
+
reportFailure(error);
|
|
1050
1320
|
}
|
|
1051
1321
|
}
|
|
1052
1322
|
}
|