@namzu/sdk 38.2.1 → 39.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 +700 -0
- package/dist/advisory/executor.d.ts +10 -1
- package/dist/advisory/executor.d.ts.map +1 -1
- package/dist/advisory/executor.js +5 -26
- package/dist/advisory/executor.js.map +1 -1
- package/dist/advisory/history.d.ts +9 -0
- package/dist/advisory/history.d.ts.map +1 -0
- package/dist/advisory/history.js +120 -0
- package/dist/advisory/history.js.map +1 -0
- package/dist/advisory/index.d.ts +1 -1
- package/dist/advisory/index.d.ts.map +1 -1
- package/dist/advisory/index.js.map +1 -1
- package/dist/agents/ReactiveAgent.d.ts.map +1 -1
- package/dist/agents/ReactiveAgent.js +3 -0
- package/dist/agents/ReactiveAgent.js.map +1 -1
- package/dist/agents/runAgent.d.ts +10 -0
- package/dist/agents/runAgent.d.ts.map +1 -1
- package/dist/agents/runAgent.js +3 -0
- package/dist/agents/runAgent.js.map +1 -1
- package/dist/compaction/manual.d.ts +6 -0
- package/dist/compaction/manual.d.ts.map +1 -1
- package/dist/compaction/manual.js +21 -2
- package/dist/compaction/manual.js.map +1 -1
- package/dist/compaction/summary.d.ts.map +1 -1
- package/dist/compaction/summary.js +4 -1
- package/dist/compaction/summary.js.map +1 -1
- package/dist/config/runtime.js +2 -2
- package/dist/config/runtime.js.map +1 -1
- package/dist/contracts/schemas.js +1 -1
- package/dist/contracts/schemas.js.map +1 -1
- package/dist/eval/harness-protection.d.ts +18 -0
- package/dist/eval/harness-protection.d.ts.map +1 -0
- package/dist/eval/harness-protection.js +58 -0
- package/dist/eval/harness-protection.js.map +1 -0
- package/dist/eval/harness-verification.d.ts +6 -1
- package/dist/eval/harness-verification.d.ts.map +1 -1
- package/dist/eval/harness-verification.js +19 -2
- package/dist/eval/harness-verification.js.map +1 -1
- package/dist/eval/index.d.ts +1 -0
- package/dist/eval/index.d.ts.map +1 -1
- package/dist/eval/index.js.map +1 -1
- package/dist/manager/resident/activity.d.ts +50 -0
- package/dist/manager/resident/activity.d.ts.map +1 -0
- package/dist/manager/resident/activity.js +125 -0
- package/dist/manager/resident/activity.js.map +1 -0
- package/dist/manager/resident/agenda.d.ts +13 -1
- package/dist/manager/resident/agenda.d.ts.map +1 -1
- package/dist/manager/resident/agenda.js +40 -5
- package/dist/manager/resident/agenda.js.map +1 -1
- package/dist/manager/resident/consumption.d.ts +104 -0
- package/dist/manager/resident/consumption.d.ts.map +1 -0
- package/dist/manager/resident/consumption.js +233 -0
- package/dist/manager/resident/consumption.js.map +1 -0
- package/dist/manager/resident/evidence-recall.d.ts +24 -0
- package/dist/manager/resident/evidence-recall.d.ts.map +1 -0
- package/dist/manager/resident/evidence-recall.js +295 -0
- package/dist/manager/resident/evidence-recall.js.map +1 -0
- package/dist/manager/resident/history-disk.d.ts +10 -0
- package/dist/manager/resident/history-disk.d.ts.map +1 -0
- package/dist/manager/resident/history-disk.js +50 -0
- package/dist/manager/resident/history-disk.js.map +1 -0
- package/dist/manager/resident/history.d.ts +79 -0
- package/dist/manager/resident/history.d.ts.map +1 -0
- package/dist/manager/resident/history.js +203 -0
- package/dist/manager/resident/history.js.map +1 -0
- package/dist/manager/resident/initiative.d.ts.map +1 -1
- package/dist/manager/resident/initiative.js +11 -3
- package/dist/manager/resident/initiative.js.map +1 -1
- package/dist/manager/resident/learning-cycle.d.ts +131 -0
- package/dist/manager/resident/learning-cycle.d.ts.map +1 -0
- package/dist/manager/resident/learning-cycle.js +306 -0
- package/dist/manager/resident/learning-cycle.js.map +1 -0
- package/dist/manager/resident/learning-observation.d.ts +80 -0
- package/dist/manager/resident/learning-observation.d.ts.map +1 -0
- package/dist/manager/resident/learning-observation.js +22 -0
- package/dist/manager/resident/learning-observation.js.map +1 -0
- package/dist/manager/resident/learning-store.d.ts +106 -0
- package/dist/manager/resident/learning-store.d.ts.map +1 -0
- package/dist/manager/resident/learning-store.js +598 -0
- package/dist/manager/resident/learning-store.js.map +1 -0
- package/dist/manager/resident/learning.d.ts +246 -3
- package/dist/manager/resident/learning.d.ts.map +1 -1
- package/dist/manager/resident/learning.js +96 -6
- package/dist/manager/resident/learning.js.map +1 -1
- package/dist/manager/resident/outbox.d.ts +4 -4
- package/dist/manager/resident/store.d.ts +37 -4
- package/dist/manager/resident/store.d.ts.map +1 -1
- package/dist/manager/resident/store.js +27 -3
- package/dist/manager/resident/store.js.map +1 -1
- package/dist/manager/resident/tool-evidence.d.ts +71 -0
- package/dist/manager/resident/tool-evidence.d.ts.map +1 -0
- package/dist/manager/resident/tool-evidence.js +285 -0
- package/dist/manager/resident/tool-evidence.js.map +1 -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/plugin/loader.d.ts.map +1 -1
- package/dist/plugin/loader.js +5 -3
- package/dist/plugin/loader.js.map +1 -1
- package/dist/prompt/coding-agent-doctrine.d.ts +1 -1
- package/dist/prompt/coding-agent-doctrine.d.ts.map +1 -1
- package/dist/prompt/coding-agent-doctrine.js +2 -0
- package/dist/prompt/coding-agent-doctrine.js.map +1 -1
- package/dist/prompt/index.d.ts +2 -0
- package/dist/prompt/index.d.ts.map +1 -1
- package/dist/prompt/index.js +1 -0
- package/dist/prompt/index.js.map +1 -1
- package/dist/prompt/resident-learning.d.ts +19 -0
- package/dist/prompt/resident-learning.d.ts.map +1 -0
- package/dist/prompt/resident-learning.js +125 -0
- package/dist/prompt/resident-learning.js.map +1 -0
- package/dist/prompt/resident-step.d.ts +8 -1
- package/dist/prompt/resident-step.d.ts.map +1 -1
- package/dist/prompt/resident-step.js +65 -4
- package/dist/prompt/resident-step.js.map +1 -1
- package/dist/provider/collect-chat-completion.d.ts +2 -1
- package/dist/provider/collect-chat-completion.d.ts.map +1 -1
- package/dist/provider/collect-chat-completion.js +7 -6
- package/dist/provider/collect-chat-completion.js.map +1 -1
- package/dist/provider/fallback.d.ts.map +1 -1
- package/dist/provider/fallback.js +2 -1
- package/dist/provider/fallback.js.map +1 -1
- package/dist/provider/stream-text.d.ts +16 -0
- package/dist/provider/stream-text.d.ts.map +1 -0
- package/dist/provider/stream-text.js +51 -0
- package/dist/provider/stream-text.js.map +1 -0
- package/dist/public-runtime.d.ts +13 -3
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +12 -3
- 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 +15 -3
- package/dist/public-types.d.ts.map +1 -1
- package/dist/run/LimitChecker.js +3 -3
- package/dist/run/LimitChecker.js.map +1 -1
- package/dist/run/evidence-query.d.ts +41 -0
- package/dist/run/evidence-query.d.ts.map +1 -0
- package/dist/run/evidence-query.js +270 -0
- package/dist/run/evidence-query.js.map +1 -0
- package/dist/run/evidence-recall.d.ts +99 -0
- package/dist/run/evidence-recall.d.ts.map +1 -0
- package/dist/run/evidence-recall.js +633 -0
- package/dist/run/evidence-recall.js.map +1 -0
- 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/json-claim-verifier.d.ts +83 -0
- package/dist/run/json-claim-verifier.d.ts.map +1 -0
- package/dist/run/json-claim-verifier.js +200 -0
- package/dist/run/json-claim-verifier.js.map +1 -0
- package/dist/run/preparation-context-error.d.ts +10 -0
- package/dist/run/preparation-context-error.d.ts.map +1 -0
- package/dist/run/preparation-context-error.js +15 -0
- package/dist/run/preparation-context-error.js.map +1 -0
- package/dist/run-query/index.d.ts +3 -1
- package/dist/run-query/index.d.ts.map +1 -1
- package/dist/runtime/query/callback-inference.d.ts +8 -0
- package/dist/runtime/query/callback-inference.d.ts.map +1 -0
- package/dist/runtime/query/callback-inference.js +89 -0
- package/dist/runtime/query/callback-inference.js.map +1 -0
- package/dist/runtime/query/checkpoint.d.ts +4 -0
- package/dist/runtime/query/checkpoint.d.ts.map +1 -1
- package/dist/runtime/query/checkpoint.js +13 -0
- package/dist/runtime/query/checkpoint.js.map +1 -1
- package/dist/runtime/query/events.d.ts +1 -0
- package/dist/runtime/query/events.d.ts.map +1 -1
- package/dist/runtime/query/events.js +18 -0
- package/dist/runtime/query/events.js.map +1 -1
- package/dist/runtime/query/executor.d.ts +7 -1
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +38 -7
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/file-evidence-context.d.ts +5 -0
- package/dist/runtime/query/file-evidence-context.d.ts.map +1 -0
- package/dist/runtime/query/file-evidence-context.js +64 -0
- package/dist/runtime/query/file-evidence-context.js.map +1 -0
- package/dist/runtime/query/guard.d.ts.map +1 -1
- package/dist/runtime/query/guard.js +4 -0
- package/dist/runtime/query/guard.js.map +1 -1
- package/dist/runtime/query/index.d.ts +10 -1
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +39 -24
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +9 -31
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +231 -93
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/phases/advisory.d.ts +2 -1
- package/dist/runtime/query/iteration/phases/advisory.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/advisory.js +2 -1
- package/dist/runtime/query/iteration/phases/advisory.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context.d.ts +2 -1
- 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 +3 -0
- package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
- package/dist/runtime/query/iteration/provider-rejected-image.d.ts +2 -1
- package/dist/runtime/query/iteration/provider-rejected-image.d.ts.map +1 -1
- package/dist/runtime/query/iteration/provider-rejected-image.js +5 -2
- package/dist/runtime/query/iteration/provider-rejected-image.js.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.d.ts +4 -1
- package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.js +22 -8
- package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
- package/dist/runtime/query/resume-pending.d.ts +18 -33
- package/dist/runtime/query/resume-pending.d.ts.map +1 -1
- package/dist/runtime/query/resume-pending.js +59 -42
- package/dist/runtime/query/resume-pending.js.map +1 -1
- package/dist/runtime/query/review-policy.d.ts +4 -4
- package/dist/runtime/query/review-policy.d.ts.map +1 -1
- package/dist/runtime/query/review-policy.js +10 -9
- package/dist/runtime/query/review-policy.js.map +1 -1
- package/dist/runtime/query/sandbox-lifecycle.d.ts.map +1 -1
- package/dist/runtime/query/sandbox-lifecycle.js +4 -0
- package/dist/runtime/query/sandbox-lifecycle.js.map +1 -1
- package/dist/runtime/query/tool-output-budget.d.ts +10 -6
- package/dist/runtime/query/tool-output-budget.d.ts.map +1 -1
- package/dist/runtime/query/tool-output-budget.js +54 -12
- package/dist/runtime/query/tool-output-budget.js.map +1 -1
- package/dist/runtime/query/tooling.d.ts +3 -1
- package/dist/runtime/query/tooling.d.ts.map +1 -1
- package/dist/runtime/query/tooling.js +4 -0
- package/dist/runtime/query/tooling.js.map +1 -1
- package/dist/scheduler/completion-inbox.d.ts +3 -0
- package/dist/scheduler/completion-inbox.d.ts.map +1 -1
- package/dist/scheduler/completion-inbox.js +28 -0
- package/dist/scheduler/completion-inbox.js.map +1 -1
- package/dist/store/evidence/compaction-archive.d.ts +109 -0
- package/dist/store/evidence/compaction-archive.d.ts.map +1 -0
- package/dist/store/evidence/compaction-archive.js +125 -0
- package/dist/store/evidence/compaction-archive.js.map +1 -0
- package/dist/store/evidence/compaction-provenance.d.ts +7 -0
- package/dist/store/evidence/compaction-provenance.d.ts.map +1 -0
- package/dist/store/evidence/compaction-provenance.js +49 -0
- package/dist/store/evidence/compaction-provenance.js.map +1 -0
- package/dist/store/evidence/compaction-text.d.ts +16 -0
- package/dist/store/evidence/compaction-text.d.ts.map +1 -0
- package/dist/store/evidence/compaction-text.js +51 -0
- package/dist/store/evidence/compaction-text.js.map +1 -0
- package/dist/store/evidence/disk.d.ts +11 -0
- package/dist/store/evidence/disk.d.ts.map +1 -0
- package/dist/store/evidence/disk.js +367 -0
- package/dist/store/evidence/disk.js.map +1 -0
- package/dist/store/evidence/format.d.ts +25 -0
- package/dist/store/evidence/format.d.ts.map +1 -0
- package/dist/store/evidence/format.js +115 -0
- package/dist/store/evidence/format.js.map +1 -0
- package/dist/store/evidence/index-page.d.ts +208 -0
- package/dist/store/evidence/index-page.d.ts.map +1 -0
- package/dist/store/evidence/index-page.js +262 -0
- package/dist/store/evidence/index-page.js.map +1 -0
- package/dist/store/evidence/io.d.ts +24 -0
- package/dist/store/evidence/io.d.ts.map +1 -0
- package/dist/store/evidence/io.js +69 -0
- package/dist/store/evidence/io.js.map +1 -0
- package/dist/store/evidence/linked.d.ts +9 -0
- package/dist/store/evidence/linked.d.ts.map +1 -0
- package/dist/store/evidence/linked.js +314 -0
- package/dist/store/evidence/linked.js.map +1 -0
- package/dist/store/evidence/passages.d.ts +15 -0
- package/dist/store/evidence/passages.d.ts.map +1 -0
- package/dist/store/evidence/passages.js +72 -0
- package/dist/store/evidence/passages.js.map +1 -0
- package/dist/store/evidence/record-chain.d.ts +42 -0
- package/dist/store/evidence/record-chain.d.ts.map +1 -0
- package/dist/store/evidence/record-chain.js +111 -0
- package/dist/store/evidence/record-chain.js.map +1 -0
- package/dist/store/evidence/search-input.d.ts +21 -0
- package/dist/store/evidence/search-input.d.ts.map +1 -0
- package/dist/store/evidence/search-input.js +44 -0
- package/dist/store/evidence/search-input.js.map +1 -0
- package/dist/store/evidence/selection.d.ts +9 -0
- package/dist/store/evidence/selection.d.ts.map +1 -0
- package/dist/store/evidence/selection.js +17 -0
- package/dist/store/evidence/selection.js.map +1 -0
- package/dist/store/evidence/source-kind.d.ts +11 -0
- package/dist/store/evidence/source-kind.d.ts.map +1 -0
- package/dist/store/evidence/source-kind.js +26 -0
- package/dist/store/evidence/source-kind.js.map +1 -0
- package/dist/store/evidence/source-text.d.ts +51 -0
- package/dist/store/evidence/source-text.d.ts.map +1 -0
- package/dist/store/evidence/source-text.js +213 -0
- package/dist/store/evidence/source-text.js.map +1 -0
- package/dist/store/evidence/types.d.ts +162 -0
- package/dist/store/evidence/types.d.ts.map +1 -0
- package/dist/store/evidence/types.js +2 -0
- package/dist/store/evidence/types.js.map +1 -0
- package/dist/store/memory/disk.d.ts +2 -0
- package/dist/store/memory/disk.d.ts.map +1 -1
- package/dist/store/memory/disk.js +2 -1
- package/dist/store/memory/disk.js.map +1 -1
- package/dist/store/run/disk.d.ts +10 -0
- package/dist/store/run/disk.d.ts.map +1 -1
- package/dist/store/run/disk.js +87 -7
- package/dist/store/run/disk.js.map +1 -1
- package/dist/store/run/memory.d.ts +1 -0
- package/dist/store/run/memory.d.ts.map +1 -1
- package/dist/store/run/memory.js +10 -0
- package/dist/store/run/memory.js.map +1 -1
- package/dist/store/run/tool-executions.d.ts +13 -0
- package/dist/store/run/tool-executions.d.ts.map +1 -0
- package/dist/store/run/tool-executions.js +99 -0
- package/dist/store/run/tool-executions.js.map +1 -0
- package/dist/store/session/index.d.ts +2 -0
- package/dist/store/session/index.d.ts.map +1 -1
- package/dist/store/session/index.js +1 -0
- package/dist/store/session/index.js.map +1 -1
- package/dist/store/session/sqlite.d.ts +57 -0
- package/dist/store/session/sqlite.d.ts.map +1 -0
- package/dist/store/session/sqlite.js +430 -0
- package/dist/store/session/sqlite.js.map +1 -0
- package/dist/tools/builtins/job.d.ts.map +1 -1
- package/dist/tools/builtins/job.js +4 -5
- package/dist/tools/builtins/job.js.map +1 -1
- package/dist/tools/builtins/write-file.js +2 -2
- package/dist/tools/builtins/write-file.js.map +1 -1
- package/dist/tools/defineTool.d.ts +2 -1
- package/dist/tools/defineTool.d.ts.map +1 -1
- package/dist/tools/defineTool.js +1 -1
- package/dist/tools/defineTool.js.map +1 -1
- package/dist/tools/file-read-tracker.d.ts.map +1 -1
- package/dist/tools/file-read-tracker.js +12 -3
- package/dist/tools/file-read-tracker.js.map +1 -1
- package/dist/tools/resident-history.d.ts +10 -0
- package/dist/tools/resident-history.d.ts.map +1 -0
- package/dist/tools/resident-history.js +80 -0
- package/dist/tools/resident-history.js.map +1 -0
- package/dist/tools/resident-tool-evidence.d.ts +5 -0
- package/dist/tools/resident-tool-evidence.d.ts.map +1 -0
- package/dist/tools/resident-tool-evidence.js +57 -0
- package/dist/tools/resident-tool-evidence.js.map +1 -0
- package/dist/types/advisory/config.d.ts +7 -0
- package/dist/types/advisory/config.d.ts.map +1 -1
- package/dist/types/agent/reactive.d.ts +1 -0
- package/dist/types/agent/reactive.d.ts.map +1 -1
- package/dist/types/authorization/index.d.ts +9 -9
- package/dist/types/authorization/index.d.ts.map +1 -1
- package/dist/types/authorization/index.js +1 -1
- package/dist/types/authorization/index.js.map +1 -1
- package/dist/types/hitl/index.d.ts +4 -0
- package/dist/types/hitl/index.d.ts.map +1 -1
- package/dist/types/hitl/index.js.map +1 -1
- package/dist/types/message/index.d.ts +16 -2
- package/dist/types/message/index.d.ts.map +1 -1
- package/dist/types/message/index.js +8 -1
- package/dist/types/message/index.js.map +1 -1
- package/dist/types/provider/chat.d.ts +2 -0
- package/dist/types/provider/chat.d.ts.map +1 -1
- package/dist/types/provider/stream.d.ts +4 -0
- package/dist/types/provider/stream.d.ts.map +1 -1
- package/dist/types/run/answer-review.d.ts +34 -3
- package/dist/types/run/answer-review.d.ts.map +1 -1
- package/dist/types/run/config.d.ts +3 -0
- package/dist/types/run/config.d.ts.map +1 -1
- package/dist/types/run/entity.d.ts +7 -0
- package/dist/types/run/entity.d.ts.map +1 -1
- package/dist/types/run/events.d.ts +31 -8
- 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 +53 -8
- package/dist/types/run/prepare-step.d.ts.map +1 -1
- package/dist/types/run/store.d.ts +29 -4
- package/dist/types/run/store.d.ts.map +1 -1
- package/dist/types/run/store.js +0 -28
- package/dist/types/run/store.js.map +1 -1
- package/dist/types/tool/index.d.ts +15 -1
- package/dist/types/tool/index.d.ts.map +1 -1
- package/dist/types/tool/index.js.map +1 -1
- package/dist/utils/await-with-abort.d.ts +8 -0
- package/dist/utils/await-with-abort.d.ts.map +1 -0
- package/dist/utils/await-with-abort.js +28 -0
- package/dist/utils/await-with-abort.js.map +1 -0
- package/dist/utils/evidence-time.d.ts +3 -0
- package/dist/utils/evidence-time.d.ts.map +1 -0
- package/dist/utils/evidence-time.js +10 -0
- package/dist/utils/evidence-time.js.map +1 -0
- package/dist/utils/evidence-tokens.d.ts +13 -0
- package/dist/utils/evidence-tokens.d.ts.map +1 -0
- package/dist/utils/evidence-tokens.js +29 -0
- package/dist/utils/evidence-tokens.js.map +1 -0
- package/package.json +1 -1
- package/src/advisory/executor.ts +15 -30
- package/src/advisory/history.ts +126 -0
- package/src/advisory/index.ts +5 -1
- package/src/agents/ReactiveAgent.ts +3 -0
- package/src/agents/runAgent.ts +14 -1
- package/src/compaction/manual.ts +30 -2
- package/src/compaction/summary.ts +4 -1
- package/src/config/runtime.ts +2 -2
- package/src/contracts/schemas.ts +1 -1
- package/src/eval/harness-protection.ts +79 -0
- package/src/eval/harness-verification.ts +31 -1
- package/src/eval/index.ts +1 -0
- package/src/manager/resident/activity.ts +187 -0
- package/src/manager/resident/agenda.ts +59 -5
- package/src/manager/resident/consumption.ts +311 -0
- package/src/manager/resident/evidence-recall.ts +363 -0
- package/src/manager/resident/history-disk.ts +63 -0
- package/src/manager/resident/history.ts +312 -0
- package/src/manager/resident/initiative.ts +13 -3
- package/src/manager/resident/learning-cycle.ts +499 -0
- package/src/manager/resident/learning-observation.ts +39 -0
- package/src/manager/resident/learning-store.ts +813 -0
- package/src/manager/resident/learning.ts +132 -8
- package/src/manager/resident/store.ts +31 -3
- package/src/manager/resident/tool-evidence.ts +412 -0
- package/src/manager/run/persistence.ts +6 -0
- package/src/plugin/loader.ts +8 -3
- package/src/prompt/coding-agent-doctrine.ts +2 -0
- package/src/prompt/index.ts +2 -0
- package/src/prompt/resident-learning.ts +143 -0
- package/src/prompt/resident-step.ts +83 -3
- package/src/provider/collect-chat-completion.ts +7 -6
- package/src/provider/fallback.ts +2 -1
- package/src/provider/stream-text.ts +56 -0
- package/src/public-runtime.ts +30 -0
- package/src/public-tools.ts +3 -0
- package/src/public-types.ts +98 -0
- package/src/run/LimitChecker.ts +3 -3
- package/src/run/evidence-query.ts +333 -0
- package/src/run/evidence-recall.ts +854 -0
- package/src/run/index.ts +11 -0
- package/src/run/json-claim-verifier.ts +298 -0
- package/src/run/preparation-context-error.ts +16 -0
- package/src/run-query/index.ts +1 -1
- package/src/runtime/query/callback-inference.ts +94 -0
- package/src/runtime/query/checkpoint.ts +14 -0
- package/src/runtime/query/events.ts +22 -0
- package/src/runtime/query/executor.ts +51 -9
- package/src/runtime/query/file-evidence-context.ts +65 -0
- package/src/runtime/query/guard.ts +2 -0
- package/src/runtime/query/index.ts +49 -25
- package/src/runtime/query/iteration/index.ts +269 -86
- package/src/runtime/query/iteration/phases/advisory.ts +3 -0
- package/src/runtime/query/iteration/phases/context.ts +2 -0
- package/src/runtime/query/iteration/phases/tool-review.ts +3 -0
- package/src/runtime/query/iteration/provider-rejected-image.ts +6 -1
- package/src/runtime/query/iteration/stream-turn.ts +35 -8
- package/src/runtime/query/resume-pending.ts +65 -40
- package/src/runtime/query/review-policy.ts +13 -9
- package/src/runtime/query/sandbox-lifecycle.ts +3 -0
- package/src/runtime/query/tool-output-budget.ts +65 -13
- package/src/runtime/query/tooling.ts +7 -1
- package/src/scheduler/completion-inbox.ts +26 -0
- package/src/store/evidence/compaction-archive.ts +139 -0
- package/src/store/evidence/compaction-provenance.ts +52 -0
- package/src/store/evidence/compaction-text.ts +61 -0
- package/src/store/evidence/disk.ts +461 -0
- package/src/store/evidence/format.ts +126 -0
- package/src/store/evidence/index-page.ts +292 -0
- package/src/store/evidence/io.ts +95 -0
- package/src/store/evidence/linked.ts +365 -0
- package/src/store/evidence/passages.ts +88 -0
- package/src/store/evidence/record-chain.ts +108 -0
- package/src/store/evidence/search-input.ts +62 -0
- package/src/store/evidence/selection.ts +25 -0
- package/src/store/evidence/source-kind.ts +36 -0
- package/src/store/evidence/source-text.ts +285 -0
- package/src/store/evidence/types.ts +177 -0
- package/src/store/memory/disk.ts +4 -1
- package/src/store/run/disk.ts +110 -8
- package/src/store/run/memory.ts +10 -0
- package/src/store/run/tool-executions.ts +112 -0
- package/src/store/session/index.ts +2 -0
- package/src/store/session/sqlite.ts +584 -0
- package/src/tools/builtins/job.ts +4 -5
- package/src/tools/builtins/write-file.ts +2 -2
- package/src/tools/defineTool.ts +4 -2
- package/src/tools/file-read-tracker.ts +8 -2
- package/src/tools/resident-history.ts +86 -0
- package/src/tools/resident-tool-evidence.ts +68 -0
- package/src/types/advisory/config.ts +7 -0
- package/src/types/agent/reactive.ts +1 -0
- package/src/types/authorization/index.ts +2 -2
- package/src/types/hitl/index.ts +4 -0
- package/src/types/message/index.ts +20 -0
- package/src/types/provider/chat.ts +2 -0
- package/src/types/provider/stream.ts +4 -0
- package/src/types/run/answer-review.ts +34 -3
- package/src/types/run/config.ts +3 -0
- package/src/types/run/entity.ts +7 -0
- package/src/types/run/events.ts +31 -8
- package/src/types/run/prepare-step.ts +59 -8
- package/src/types/run/store.ts +35 -4
- package/src/types/tool/index.ts +19 -1
- package/src/utils/await-with-abort.ts +26 -0
- package/src/utils/evidence-time.ts +9 -0
- package/src/utils/evidence-tokens.ts +32 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { constants } from 'node:fs'
|
|
2
|
+
import { open } from 'node:fs/promises'
|
|
3
|
+
import type { ToolExecutionRecord, ToolExecutionSnapshot } from '../../types/run/store.js'
|
|
4
|
+
|
|
5
|
+
const MAX_LOG_BYTES = 256 * 1024 * 1024
|
|
6
|
+
const MAX_RECORD_BYTES = 4 * 1024 * 1024
|
|
7
|
+
|
|
8
|
+
/** Scan metadata only; compaction attachments and retained output bodies are never loaded. */
|
|
9
|
+
export class ToolExecutionCollector {
|
|
10
|
+
private seq = 0
|
|
11
|
+
private readonly wanted: Set<string>
|
|
12
|
+
private readonly records = new Map<string, ToolExecutionRecord>()
|
|
13
|
+
constructor(
|
|
14
|
+
private readonly runId: string,
|
|
15
|
+
ids: readonly string[],
|
|
16
|
+
) {
|
|
17
|
+
if (ids.length > 4096) throw new Error('Tool recovery exceeds the 4096-call scan limit.')
|
|
18
|
+
this.wanted = new Set(ids)
|
|
19
|
+
}
|
|
20
|
+
accept(value: unknown): void {
|
|
21
|
+
const event = value as Record<string, unknown> | null
|
|
22
|
+
if (
|
|
23
|
+
!event ||
|
|
24
|
+
typeof event !== 'object' ||
|
|
25
|
+
typeof event.type !== 'string' ||
|
|
26
|
+
event.runId !== this.runId ||
|
|
27
|
+
event.seq !== this.seq + 1
|
|
28
|
+
) {
|
|
29
|
+
throw new Error('Tool recovery requires a complete, ordered log owned by this run.')
|
|
30
|
+
}
|
|
31
|
+
if (this.seq === 0 && event.type !== 'run_started')
|
|
32
|
+
throw new Error('Tool recovery cannot establish the beginning of this run.')
|
|
33
|
+
this.seq++
|
|
34
|
+
if (event.type !== 'tool_executing' && event.type !== 'tool_completed') return
|
|
35
|
+
if (typeof event.toolUseId !== 'string' || typeof event.toolName !== 'string')
|
|
36
|
+
throw new Error('Tool recovery found an invalid tool identity.')
|
|
37
|
+
if (!this.wanted.has(event.toolUseId)) return
|
|
38
|
+
const identity = { toolUseId: event.toolUseId, toolName: event.toolName }
|
|
39
|
+
if (event.type === 'tool_executing') {
|
|
40
|
+
// A later start invalidates an earlier completion, including retries.
|
|
41
|
+
this.records.set(event.toolUseId, { ...identity, status: 'started' })
|
|
42
|
+
} else {
|
|
43
|
+
if (typeof event.result !== 'string' || typeof event.isError !== 'boolean')
|
|
44
|
+
throw new Error('Tool recovery found an invalid completion.')
|
|
45
|
+
this.records.set(event.toolUseId, {
|
|
46
|
+
...identity,
|
|
47
|
+
status: 'completed',
|
|
48
|
+
result: event.result,
|
|
49
|
+
isError: event.isError,
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
finish(complete = true): ToolExecutionSnapshot {
|
|
54
|
+
return { complete: complete && this.seq > 0, records: this.records }
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function readToolExecutionsIn(
|
|
59
|
+
path: string,
|
|
60
|
+
runId: string,
|
|
61
|
+
ids: readonly string[],
|
|
62
|
+
signal?: AbortSignal,
|
|
63
|
+
): Promise<ToolExecutionSnapshot> {
|
|
64
|
+
signal?.throwIfAborted()
|
|
65
|
+
const collector = new ToolExecutionCollector(runId, ids)
|
|
66
|
+
const file = await open(path, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0))
|
|
67
|
+
try {
|
|
68
|
+
const before = await file.stat()
|
|
69
|
+
if (!before.isFile() || before.size > MAX_LOG_BYTES)
|
|
70
|
+
throw new Error('Tool recovery requires a regular transcript within the 256 MiB scan limit.')
|
|
71
|
+
let offset = 0
|
|
72
|
+
let pending = Buffer.alloc(0)
|
|
73
|
+
const buffer = Buffer.alloc(64 * 1024)
|
|
74
|
+
while (offset < before.size) {
|
|
75
|
+
signal?.throwIfAborted()
|
|
76
|
+
const { bytesRead } = await file.read(
|
|
77
|
+
buffer,
|
|
78
|
+
0,
|
|
79
|
+
Math.min(buffer.length, before.size - offset),
|
|
80
|
+
offset,
|
|
81
|
+
)
|
|
82
|
+
if (bytesRead === 0) throw new Error('Tool recovery transcript was shortened.')
|
|
83
|
+
offset += bytesRead
|
|
84
|
+
pending = Buffer.concat([pending, buffer.subarray(0, bytesRead)])
|
|
85
|
+
let start = 0
|
|
86
|
+
for (;;) {
|
|
87
|
+
const end = pending.indexOf(10, start)
|
|
88
|
+
if (end < 0) break
|
|
89
|
+
if (end - start > MAX_RECORD_BYTES) throw new Error('Tool recovery record exceeds 4 MiB.')
|
|
90
|
+
collector.accept(
|
|
91
|
+
JSON.parse(
|
|
92
|
+
new TextDecoder('utf-8', { fatal: true }).decode(pending.subarray(start, end)),
|
|
93
|
+
),
|
|
94
|
+
)
|
|
95
|
+
start = end + 1
|
|
96
|
+
}
|
|
97
|
+
pending = Buffer.from(pending.subarray(start))
|
|
98
|
+
if (pending.length > MAX_RECORD_BYTES) throw new Error('Tool recovery record exceeds 4 MiB.')
|
|
99
|
+
}
|
|
100
|
+
signal?.throwIfAborted()
|
|
101
|
+
const after = await file.stat()
|
|
102
|
+
if (
|
|
103
|
+
before.size !== after.size ||
|
|
104
|
+
before.mtimeMs !== after.mtimeMs ||
|
|
105
|
+
before.ctimeMs !== after.ctimeMs
|
|
106
|
+
)
|
|
107
|
+
throw new Error('Tool recovery transcript changed during the scan.')
|
|
108
|
+
return collector.finish(pending.length === 0)
|
|
109
|
+
} finally {
|
|
110
|
+
await file.close()
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
export { InMemorySessionStore } from './memory.js'
|
|
10
10
|
export { DiskSessionStore } from './disk.js'
|
|
11
|
+
export { SqliteSessionStore } from './sqlite.js'
|
|
12
|
+
export type { SqliteSessionStoreConfig } from './sqlite.js'
|
|
11
13
|
export type { DiskSessionStoreConfig } from './disk.js'
|
|
12
14
|
export type { SessionMessage } from '../../types/session/messages.js'
|
|
13
15
|
export { getAncestry, getChildren, orderChildren } from './linkage.js'
|
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
import { mkdirSync } from 'node:fs'
|
|
2
|
+
import { createRequire } from 'node:module'
|
|
3
|
+
import { dirname, resolve } from 'node:path'
|
|
4
|
+
import type { DatabaseSync } from 'node:sqlite'
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
ProjectRootPathTakenError,
|
|
8
|
+
StaleProjectError,
|
|
9
|
+
StaleSessionError,
|
|
10
|
+
TenantIsolationError,
|
|
11
|
+
} from '../../session/errors.js'
|
|
12
|
+
import { SessionAlreadySummarizedError } from '../../session/summary/errors.js'
|
|
13
|
+
import type {
|
|
14
|
+
MessageId,
|
|
15
|
+
ProjectId,
|
|
16
|
+
SessionId,
|
|
17
|
+
SubSessionId,
|
|
18
|
+
TenantId,
|
|
19
|
+
TopicId,
|
|
20
|
+
} from '../../types/ids/index.js'
|
|
21
|
+
import type { Message } from '../../types/message/index.js'
|
|
22
|
+
import type { Project, ProjectStatus } from '../../types/project/entity.js'
|
|
23
|
+
import type { Session } from '../../types/session/entity.js'
|
|
24
|
+
import type { SessionMessage } from '../../types/session/messages.js'
|
|
25
|
+
import type {
|
|
26
|
+
CreateProjectParams,
|
|
27
|
+
CreateSessionParams,
|
|
28
|
+
CreateSubSessionParams,
|
|
29
|
+
ProjectConfigInput,
|
|
30
|
+
SessionStore,
|
|
31
|
+
SessionView,
|
|
32
|
+
} from '../../types/session/store.js'
|
|
33
|
+
import type { SubSession } from '../../types/session/sub-session.js'
|
|
34
|
+
import type { SessionSummaryRef } from '../../types/summary/ref.js'
|
|
35
|
+
import {
|
|
36
|
+
asProjectId,
|
|
37
|
+
asSessionId,
|
|
38
|
+
asSubSessionId,
|
|
39
|
+
asTenantId,
|
|
40
|
+
asTopicId,
|
|
41
|
+
generateMessageId,
|
|
42
|
+
generateProjectId,
|
|
43
|
+
generateSessionId,
|
|
44
|
+
generateSubSessionId,
|
|
45
|
+
} from '../../utils/id.js'
|
|
46
|
+
import { canonicalizePath } from './canonical-path.js'
|
|
47
|
+
import { type LinkageView, getAncestry, getChildren, orderChildren } from './linkage.js'
|
|
48
|
+
|
|
49
|
+
export interface SqliteSessionStoreConfig {
|
|
50
|
+
/** Absolute SQLite filename. Parent privacy is owned by the host. Requires Node 22.13+. */
|
|
51
|
+
readonly databasePath: string
|
|
52
|
+
/** Inspection never creates a database, changes its schema, or creates journal sidecars. */
|
|
53
|
+
readonly readOnly?: boolean
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
type Table = 'projects' | 'sessions' | 'subsessions' | 'summaries'
|
|
57
|
+
type Row = { body: string; tenant_id: string }
|
|
58
|
+
const SCHEMA_VERSION = 1
|
|
59
|
+
const SCHEMA = `
|
|
60
|
+
CREATE TABLE projects (id TEXT PRIMARY KEY, tenant_id TEXT NOT NULL, root_path TEXT, created_at INTEGER NOT NULL, body TEXT NOT NULL, UNIQUE(tenant_id, root_path));
|
|
61
|
+
CREATE TABLE sessions (id TEXT PRIMARY KEY, tenant_id TEXT NOT NULL, project_id TEXT NOT NULL REFERENCES projects(id), topic_id TEXT NOT NULL, created_at INTEGER NOT NULL, body TEXT NOT NULL);
|
|
62
|
+
CREATE INDEX sessions_project ON sessions(tenant_id, project_id, created_at, id);
|
|
63
|
+
CREATE INDEX sessions_topic ON sessions(tenant_id, topic_id, created_at, id);
|
|
64
|
+
CREATE TABLE subsessions (id TEXT PRIMARY KEY, tenant_id TEXT NOT NULL, parent_id TEXT NOT NULL REFERENCES sessions(id), child_id TEXT NOT NULL REFERENCES sessions(id), body TEXT NOT NULL);
|
|
65
|
+
CREATE INDEX subsessions_parent ON subsessions(tenant_id, parent_id);
|
|
66
|
+
CREATE INDEX subsessions_child ON subsessions(tenant_id, child_id);
|
|
67
|
+
CREATE TABLE summaries (id TEXT PRIMARY KEY REFERENCES sessions(id), tenant_id TEXT NOT NULL, body TEXT NOT NULL);
|
|
68
|
+
CREATE TABLE messages (seq INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL REFERENCES sessions(id), kind TEXT NOT NULL CHECK(kind IN ('message','replacement')), body TEXT NOT NULL);
|
|
69
|
+
CREATE INDEX messages_session ON messages(session_id, seq);
|
|
70
|
+
CREATE INDEX messages_replacement ON messages(session_id, kind, seq);
|
|
71
|
+
`
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Indexed session metadata and append-only conversation records in one database.
|
|
75
|
+
* Operations own short-lived connections; no connection survives an await or
|
|
76
|
+
* needs a finalizer. Writes and CAS checks share one SQLite transaction, including
|
|
77
|
+
* across processes. Run transcripts and artifacts remain owned by RunStore.
|
|
78
|
+
*/
|
|
79
|
+
export class SqliteSessionStore implements SessionStore {
|
|
80
|
+
readonly databasePath: string
|
|
81
|
+
private readonly readOnly: boolean
|
|
82
|
+
|
|
83
|
+
constructor(config: SqliteSessionStoreConfig) {
|
|
84
|
+
this.databasePath = resolve(config.databasePath)
|
|
85
|
+
this.readOnly = config.readOnly === true
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private use<T>(write: boolean, operation: (db: DatabaseSync) => T): T {
|
|
89
|
+
if (write && this.readOnly) throw new Error('Session database is read-only')
|
|
90
|
+
// Loading the optional driver must not make importing the SDK require SQLite.
|
|
91
|
+
let Database: typeof DatabaseSync
|
|
92
|
+
try {
|
|
93
|
+
Database = (createRequire(import.meta.url)('node:sqlite') as typeof import('node:sqlite'))
|
|
94
|
+
.DatabaseSync
|
|
95
|
+
} catch (error) {
|
|
96
|
+
throw new Error('SqliteSessionStore requires Node.js 22.13 or newer.', { cause: error })
|
|
97
|
+
}
|
|
98
|
+
if (!this.readOnly) mkdirSync(dirname(this.databasePath), { recursive: true, mode: 0o700 })
|
|
99
|
+
const db = new Database(this.databasePath, { readOnly: this.readOnly })
|
|
100
|
+
try {
|
|
101
|
+
db.exec('PRAGMA busy_timeout = 5000; PRAGMA foreign_keys = ON;')
|
|
102
|
+
const version = Number(db.prepare('PRAGMA user_version').get()?.user_version)
|
|
103
|
+
if (version !== 0 && version !== SCHEMA_VERSION)
|
|
104
|
+
throw new Error(`Unsupported session database version ${version}`)
|
|
105
|
+
if (version === 0) {
|
|
106
|
+
if (this.readOnly) throw new Error('Session database has not been initialized')
|
|
107
|
+
db.exec('BEGIN IMMEDIATE')
|
|
108
|
+
try {
|
|
109
|
+
// Another first opener may have initialized it while we waited.
|
|
110
|
+
const current = Number(db.prepare('PRAGMA user_version').get()?.user_version)
|
|
111
|
+
if (current === 0) db.exec(`${SCHEMA} PRAGMA user_version = ${SCHEMA_VERSION};`)
|
|
112
|
+
else if (current !== SCHEMA_VERSION)
|
|
113
|
+
throw new Error(`Unsupported session database version ${current}`)
|
|
114
|
+
db.exec('COMMIT')
|
|
115
|
+
} catch (error) {
|
|
116
|
+
db.exec('ROLLBACK')
|
|
117
|
+
throw error
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (!this.readOnly) db.exec('PRAGMA journal_mode = DELETE; PRAGMA synchronous = FULL;')
|
|
121
|
+
db.exec(write ? 'BEGIN IMMEDIATE' : 'BEGIN')
|
|
122
|
+
try {
|
|
123
|
+
const result = operation(db)
|
|
124
|
+
db.exec('COMMIT')
|
|
125
|
+
return result
|
|
126
|
+
} catch (error) {
|
|
127
|
+
db.exec('ROLLBACK')
|
|
128
|
+
throw error
|
|
129
|
+
}
|
|
130
|
+
} finally {
|
|
131
|
+
db.close()
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private get<T>(db: DatabaseSync, table: Table, id: string, tenantId: TenantId): T | null {
|
|
136
|
+
asTenantId(tenantId)
|
|
137
|
+
const row = db.prepare(`SELECT body, tenant_id FROM ${table} WHERE id = ?`).get(id) as
|
|
138
|
+
| Row
|
|
139
|
+
| undefined
|
|
140
|
+
if (!row) return null
|
|
141
|
+
if (row.tenant_id !== tenantId)
|
|
142
|
+
throw new TenantIsolationError({ requested: tenantId, resource: `${table}(${id})` })
|
|
143
|
+
return decode<T>(row.body)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private requiredSession(db: DatabaseSync, id: SessionId, tenant: TenantId): Session {
|
|
147
|
+
const session = this.get<Session>(db, 'sessions', asSessionId(id), tenant)
|
|
148
|
+
if (!session) throw new Error(`Session ${id} not found`)
|
|
149
|
+
return session
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async createProject(params: CreateProjectParams, tenantId: TenantId): Promise<Project> {
|
|
153
|
+
if (params.tenantId !== tenantId)
|
|
154
|
+
throw new TenantIsolationError({ requested: tenantId, resource: 'project payload' })
|
|
155
|
+
asTenantId(tenantId)
|
|
156
|
+
const rootPath =
|
|
157
|
+
params.rootPath === undefined ? undefined : await canonicalizePath(params.rootPath)
|
|
158
|
+
return this.use(true, (db) => {
|
|
159
|
+
if (rootPath !== undefined) {
|
|
160
|
+
const existing = db
|
|
161
|
+
.prepare('SELECT id FROM projects WHERE tenant_id = ? AND root_path = ?')
|
|
162
|
+
.get(tenantId, rootPath)
|
|
163
|
+
if (existing)
|
|
164
|
+
throw new ProjectRootPathTakenError({
|
|
165
|
+
rootPath,
|
|
166
|
+
existingProjectId: asProjectId(String(existing.id)),
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
const now = new Date()
|
|
170
|
+
const project: Project = {
|
|
171
|
+
id: generateProjectId(),
|
|
172
|
+
tenantId,
|
|
173
|
+
name: params.name,
|
|
174
|
+
config: {
|
|
175
|
+
maxDelegationDepth: params.config?.maxDelegationDepth ?? 4,
|
|
176
|
+
maxDelegationWidth: params.config?.maxDelegationWidth ?? 8,
|
|
177
|
+
maxInterventionDepth: 10,
|
|
178
|
+
},
|
|
179
|
+
status: 'open',
|
|
180
|
+
ownerVersion: 0,
|
|
181
|
+
...(rootPath === undefined ? {} : { rootPath }),
|
|
182
|
+
createdAt: now,
|
|
183
|
+
updatedAt: now,
|
|
184
|
+
}
|
|
185
|
+
db.prepare('INSERT INTO projects VALUES (?, ?, ?, ?, ?)').run(
|
|
186
|
+
project.id,
|
|
187
|
+
tenantId,
|
|
188
|
+
rootPath ?? null,
|
|
189
|
+
now.getTime(),
|
|
190
|
+
encode(project),
|
|
191
|
+
)
|
|
192
|
+
return project
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async findProjectByRootPath(rootPath: string, tenantId: TenantId): Promise<Project | null> {
|
|
197
|
+
const canonical = await canonicalizePath(rootPath)
|
|
198
|
+
return this.use(false, (db) => {
|
|
199
|
+
const row = db
|
|
200
|
+
.prepare('SELECT body FROM projects WHERE tenant_id = ? AND root_path = ?')
|
|
201
|
+
.get(asTenantId(tenantId), canonical)
|
|
202
|
+
return row ? decode<Project>(String(row.body)) : null
|
|
203
|
+
})
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
async getProject(id: ProjectId, tenant: TenantId): Promise<Project | null> {
|
|
207
|
+
return this.use(false, (db) => this.get<Project>(db, 'projects', asProjectId(id), tenant))
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async updateProject(
|
|
211
|
+
id: ProjectId,
|
|
212
|
+
config: ProjectConfigInput,
|
|
213
|
+
tenant: TenantId,
|
|
214
|
+
): Promise<Project | null> {
|
|
215
|
+
return this.use(true, (db) => {
|
|
216
|
+
const old = this.get<Project>(db, 'projects', asProjectId(id), tenant)
|
|
217
|
+
if (!old) return null
|
|
218
|
+
const project = {
|
|
219
|
+
...old,
|
|
220
|
+
config: {
|
|
221
|
+
...old.config,
|
|
222
|
+
...(config.maxDelegationDepth === undefined
|
|
223
|
+
? {}
|
|
224
|
+
: { maxDelegationDepth: config.maxDelegationDepth }),
|
|
225
|
+
...(config.maxDelegationWidth === undefined
|
|
226
|
+
? {}
|
|
227
|
+
: { maxDelegationWidth: config.maxDelegationWidth }),
|
|
228
|
+
},
|
|
229
|
+
updatedAt: new Date(),
|
|
230
|
+
}
|
|
231
|
+
db.prepare('UPDATE projects SET body = ? WHERE id = ?').run(encode(project), id)
|
|
232
|
+
return project
|
|
233
|
+
})
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async setProjectStatus(
|
|
237
|
+
id: ProjectId,
|
|
238
|
+
status: ProjectStatus,
|
|
239
|
+
tenant: TenantId,
|
|
240
|
+
expectedOwnerVersion: number,
|
|
241
|
+
): Promise<Project | null> {
|
|
242
|
+
return this.use(true, (db) => {
|
|
243
|
+
const old = this.get<Project>(db, 'projects', asProjectId(id), tenant)
|
|
244
|
+
if (!old) return null
|
|
245
|
+
if (old.ownerVersion !== expectedOwnerVersion)
|
|
246
|
+
throw new StaleProjectError({
|
|
247
|
+
projectId: id,
|
|
248
|
+
expectedOwnerVersion,
|
|
249
|
+
actualOwnerVersion: old.ownerVersion,
|
|
250
|
+
})
|
|
251
|
+
const project = { ...old, status, ownerVersion: old.ownerVersion + 1, updatedAt: new Date() }
|
|
252
|
+
db.prepare('UPDATE projects SET body = ? WHERE id = ?').run(encode(project), id)
|
|
253
|
+
return project
|
|
254
|
+
})
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
async listProjects(tenant: TenantId): Promise<readonly Project[]> {
|
|
258
|
+
return this.use(false, (db) =>
|
|
259
|
+
db
|
|
260
|
+
.prepare('SELECT body FROM projects WHERE tenant_id = ? ORDER BY created_at, id')
|
|
261
|
+
.all(asTenantId(tenant))
|
|
262
|
+
.map((r) => decode<Project>(String(r.body))),
|
|
263
|
+
)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
async createSession(params: CreateSessionParams, tenant: TenantId): Promise<Session> {
|
|
267
|
+
return this.use(true, (db) => {
|
|
268
|
+
if (!this.get<Project>(db, 'projects', asProjectId(params.projectId), tenant))
|
|
269
|
+
throw new Error(`Project ${params.projectId} not found`)
|
|
270
|
+
const id = params.id === undefined ? generateSessionId() : asSessionId(params.id)
|
|
271
|
+
if (this.get<Session>(db, 'sessions', id, tenant))
|
|
272
|
+
throw new Error(`Session ${id} already exists`)
|
|
273
|
+
const now = new Date()
|
|
274
|
+
const session: Session = {
|
|
275
|
+
id,
|
|
276
|
+
topicId: asTopicId(params.topicId),
|
|
277
|
+
projectId: params.projectId,
|
|
278
|
+
tenantId: tenant,
|
|
279
|
+
status: 'idle',
|
|
280
|
+
currentActor: params.currentActor,
|
|
281
|
+
previousActors: [],
|
|
282
|
+
workspaceId: null,
|
|
283
|
+
ownerVersion: 0,
|
|
284
|
+
createdAt: now,
|
|
285
|
+
updatedAt: now,
|
|
286
|
+
}
|
|
287
|
+
db.prepare('INSERT INTO sessions VALUES (?, ?, ?, ?, ?, ?)').run(
|
|
288
|
+
id,
|
|
289
|
+
tenant,
|
|
290
|
+
session.projectId,
|
|
291
|
+
session.topicId,
|
|
292
|
+
now.getTime(),
|
|
293
|
+
encode(session),
|
|
294
|
+
)
|
|
295
|
+
return session
|
|
296
|
+
})
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
async getSession(id: SessionId, tenant: TenantId): Promise<Session | null> {
|
|
300
|
+
return this.use(false, (db) => this.get<Session>(db, 'sessions', asSessionId(id), tenant))
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
async listSessionsByProject(id: ProjectId, tenant: TenantId): Promise<readonly Session[]> {
|
|
304
|
+
return this.use(false, (db) =>
|
|
305
|
+
db
|
|
306
|
+
.prepare(
|
|
307
|
+
'SELECT body FROM sessions WHERE tenant_id = ? AND project_id = ? ORDER BY created_at, id',
|
|
308
|
+
)
|
|
309
|
+
.all(asTenantId(tenant), asProjectId(id))
|
|
310
|
+
.map((r) => decode<Session>(String(r.body))),
|
|
311
|
+
)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
async listSessionsByTopic(id: TopicId, tenant: TenantId): Promise<readonly Session[]> {
|
|
315
|
+
return this.use(false, (db) =>
|
|
316
|
+
db
|
|
317
|
+
.prepare(
|
|
318
|
+
'SELECT body FROM sessions WHERE tenant_id = ? AND topic_id = ? ORDER BY created_at, id',
|
|
319
|
+
)
|
|
320
|
+
.all(asTenantId(tenant), asTopicId(id))
|
|
321
|
+
.map((r) => decode<Session>(String(r.body))),
|
|
322
|
+
)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
async updateSession(
|
|
326
|
+
session: Session,
|
|
327
|
+
tenant: TenantId,
|
|
328
|
+
expectedOwnerVersion?: number,
|
|
329
|
+
): Promise<void> {
|
|
330
|
+
this.use(true, (db) => {
|
|
331
|
+
const old = this.requiredSession(db, session.id, tenant)
|
|
332
|
+
if (session.tenantId !== tenant)
|
|
333
|
+
throw new TenantIsolationError({ requested: tenant, resource: 'session payload' })
|
|
334
|
+
if (session.projectId !== old.projectId || session.topicId !== old.topicId)
|
|
335
|
+
throw new Error('Session project and topic bindings cannot change')
|
|
336
|
+
if (expectedOwnerVersion !== undefined && old.ownerVersion !== expectedOwnerVersion)
|
|
337
|
+
throw new StaleSessionError({
|
|
338
|
+
sessionId: session.id,
|
|
339
|
+
expectedVersion: expectedOwnerVersion,
|
|
340
|
+
actualVersion: old.ownerVersion,
|
|
341
|
+
})
|
|
342
|
+
db.prepare('UPDATE sessions SET body = ? WHERE id = ?').run(
|
|
343
|
+
encode({ ...session, updatedAt: new Date() }),
|
|
344
|
+
session.id,
|
|
345
|
+
)
|
|
346
|
+
})
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
async deleteSession(id: SessionId, tenant: TenantId): Promise<void> {
|
|
350
|
+
this.use(true, (db) => {
|
|
351
|
+
if (!this.get<Session>(db, 'sessions', asSessionId(id), tenant)) return
|
|
352
|
+
if (
|
|
353
|
+
db
|
|
354
|
+
.prepare('SELECT 1 FROM subsessions WHERE parent_id = ? OR child_id = ? LIMIT 1')
|
|
355
|
+
.get(id, id)
|
|
356
|
+
)
|
|
357
|
+
throw new Error(
|
|
358
|
+
`Session ${id} has attached sub-sessions; delete them before deleting the session`,
|
|
359
|
+
)
|
|
360
|
+
db.prepare('DELETE FROM messages WHERE session_id = ?').run(id)
|
|
361
|
+
db.prepare('DELETE FROM summaries WHERE id = ?').run(id)
|
|
362
|
+
db.prepare('DELETE FROM sessions WHERE id = ?').run(id)
|
|
363
|
+
})
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
async createSubSession(params: CreateSubSessionParams, tenant: TenantId): Promise<SubSession> {
|
|
367
|
+
return this.use(true, (db) => {
|
|
368
|
+
this.requiredSession(db, params.parentSessionId, tenant)
|
|
369
|
+
this.requiredSession(db, params.childSessionId, tenant)
|
|
370
|
+
const now = new Date()
|
|
371
|
+
const sub: SubSession = {
|
|
372
|
+
id: generateSubSessionId(),
|
|
373
|
+
parentSessionId: params.parentSessionId,
|
|
374
|
+
childSessionId: params.childSessionId,
|
|
375
|
+
kind: params.kind,
|
|
376
|
+
status: 'pending',
|
|
377
|
+
spawnedBy: params.spawnedBy,
|
|
378
|
+
spawnedAt: now,
|
|
379
|
+
failureMode: params.failureMode ?? 'delegate',
|
|
380
|
+
completionMode: params.completionMode ?? 'summary_ref',
|
|
381
|
+
workspaceId: null,
|
|
382
|
+
updatedAt: now,
|
|
383
|
+
}
|
|
384
|
+
db.prepare('INSERT INTO subsessions VALUES (?, ?, ?, ?, ?)').run(
|
|
385
|
+
sub.id,
|
|
386
|
+
tenant,
|
|
387
|
+
sub.parentSessionId,
|
|
388
|
+
sub.childSessionId,
|
|
389
|
+
encode(sub),
|
|
390
|
+
)
|
|
391
|
+
return sub
|
|
392
|
+
})
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
async getSubSession(id: SubSessionId, tenant: TenantId): Promise<SubSession | null> {
|
|
396
|
+
return this.use(false, (db) =>
|
|
397
|
+
this.get<SubSession>(db, 'subsessions', asSubSessionId(id), tenant),
|
|
398
|
+
)
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
async updateSubSession(sub: SubSession, tenant: TenantId): Promise<void> {
|
|
402
|
+
this.use(true, (db) => {
|
|
403
|
+
const old = this.get<SubSession>(db, 'subsessions', asSubSessionId(sub.id), tenant)
|
|
404
|
+
if (!old) throw new Error(`SubSession ${sub.id} not found`)
|
|
405
|
+
if (old.parentSessionId !== sub.parentSessionId || old.childSessionId !== sub.childSessionId)
|
|
406
|
+
throw new Error('Sub-session parent and child bindings cannot change')
|
|
407
|
+
db.prepare('UPDATE subsessions SET body = ? WHERE id = ?').run(
|
|
408
|
+
encode({ ...sub, updatedAt: new Date() }),
|
|
409
|
+
sub.id,
|
|
410
|
+
)
|
|
411
|
+
})
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
async deleteSubSession(id: SubSessionId, tenant: TenantId): Promise<void> {
|
|
415
|
+
this.use(true, (db) => {
|
|
416
|
+
if (this.get<SubSession>(db, 'subsessions', asSubSessionId(id), tenant))
|
|
417
|
+
db.prepare('DELETE FROM subsessions WHERE id = ?').run(id)
|
|
418
|
+
})
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
async appendMessage(id: SessionId, message: Message, tenant: TenantId): Promise<MessageId> {
|
|
422
|
+
return this.use(true, (db) => {
|
|
423
|
+
this.requiredSession(db, id, tenant)
|
|
424
|
+
const entry: SessionMessage = {
|
|
425
|
+
id: generateMessageId(),
|
|
426
|
+
sessionId: id,
|
|
427
|
+
tenantId: tenant,
|
|
428
|
+
message,
|
|
429
|
+
at: new Date(),
|
|
430
|
+
}
|
|
431
|
+
db.prepare("INSERT INTO messages (session_id, kind, body) VALUES (?, 'message', ?)").run(
|
|
432
|
+
id,
|
|
433
|
+
encode(entry),
|
|
434
|
+
)
|
|
435
|
+
return entry.id
|
|
436
|
+
})
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
async replaceMessages(
|
|
440
|
+
id: SessionId,
|
|
441
|
+
messages: readonly Message[],
|
|
442
|
+
tenant: TenantId,
|
|
443
|
+
): Promise<void> {
|
|
444
|
+
this.use(true, (db) => {
|
|
445
|
+
this.requiredSession(db, id, tenant)
|
|
446
|
+
const entries = messages.map(
|
|
447
|
+
(message): SessionMessage => ({
|
|
448
|
+
id: generateMessageId(),
|
|
449
|
+
sessionId: id,
|
|
450
|
+
tenantId: tenant,
|
|
451
|
+
message,
|
|
452
|
+
at: new Date(),
|
|
453
|
+
}),
|
|
454
|
+
)
|
|
455
|
+
db.prepare("INSERT INTO messages (session_id, kind, body) VALUES (?, 'replacement', ?)").run(
|
|
456
|
+
id,
|
|
457
|
+
encode(entries),
|
|
458
|
+
)
|
|
459
|
+
})
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
async loadMessages(id: SessionId, tenant: TenantId): Promise<readonly Message[]> {
|
|
463
|
+
return (await this.loadSessionMessages(id, tenant)).map((entry) => entry.message)
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
async loadSessionMessages(id: SessionId, tenant: TenantId): Promise<readonly SessionMessage[]> {
|
|
467
|
+
return this.use(false, (db) => {
|
|
468
|
+
if (!this.get<Session>(db, 'sessions', asSessionId(id), tenant)) return []
|
|
469
|
+
const replacement = db
|
|
470
|
+
.prepare(
|
|
471
|
+
"SELECT seq, body FROM messages WHERE session_id = ? AND kind = 'replacement' ORDER BY seq DESC LIMIT 1",
|
|
472
|
+
)
|
|
473
|
+
.get(id)
|
|
474
|
+
const entries = replacement
|
|
475
|
+
? (JSON.parse(String(replacement.body)) as unknown[]).map(decodeMessage)
|
|
476
|
+
: []
|
|
477
|
+
const later = db
|
|
478
|
+
.prepare(
|
|
479
|
+
"SELECT body FROM messages WHERE session_id = ? AND seq > ? AND kind = 'message' ORDER BY seq",
|
|
480
|
+
)
|
|
481
|
+
.all(id, Number(replacement?.seq ?? 0))
|
|
482
|
+
return entries.concat(later.map((row) => decodeMessage(JSON.parse(String(row.body)))))
|
|
483
|
+
})
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
private linkage(db: DatabaseSync, tenant: TenantId): LinkageView {
|
|
487
|
+
return {
|
|
488
|
+
findChildSubSessions: (id) =>
|
|
489
|
+
db
|
|
490
|
+
.prepare('SELECT body FROM subsessions WHERE tenant_id = ? AND parent_id = ?')
|
|
491
|
+
.all(tenant, id)
|
|
492
|
+
.map((r) => decode<SubSession>(String(r.body))),
|
|
493
|
+
findParentSubSession: (id) => {
|
|
494
|
+
const row = db
|
|
495
|
+
.prepare(
|
|
496
|
+
'SELECT body FROM subsessions WHERE tenant_id = ? AND child_id = ? ORDER BY id LIMIT 1',
|
|
497
|
+
)
|
|
498
|
+
.get(tenant, id)
|
|
499
|
+
return row ? decode<SubSession>(String(row.body)) : null
|
|
500
|
+
},
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
async getChildren(id: SessionId, tenant: TenantId): Promise<readonly SubSession[]> {
|
|
505
|
+
return this.use(false, (db) =>
|
|
506
|
+
this.get<Session>(db, 'sessions', asSessionId(id), tenant)
|
|
507
|
+
? orderChildren(getChildren(this.linkage(db, tenant), id))
|
|
508
|
+
: [],
|
|
509
|
+
)
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
async getAncestry(id: SessionId, tenant: TenantId): Promise<readonly SessionId[]> {
|
|
513
|
+
return this.use(false, (db) =>
|
|
514
|
+
this.get<Session>(db, 'sessions', asSessionId(id), tenant)
|
|
515
|
+
? getAncestry(this.linkage(db, tenant), id)
|
|
516
|
+
: [],
|
|
517
|
+
)
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
async drill(id: SessionId, tenant: TenantId): Promise<SessionView | null> {
|
|
521
|
+
return this.use(false, (db) => {
|
|
522
|
+
const session = this.get<Session>(db, 'sessions', asSessionId(id), tenant)
|
|
523
|
+
if (!session) return null
|
|
524
|
+
const view = this.linkage(db, tenant)
|
|
525
|
+
return {
|
|
526
|
+
session,
|
|
527
|
+
children: orderChildren(getChildren(view, id)),
|
|
528
|
+
ancestry: getAncestry(view, id),
|
|
529
|
+
}
|
|
530
|
+
})
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
async recordSummary(
|
|
534
|
+
summary: SessionSummaryRef & { materializedBy: 'kernel' },
|
|
535
|
+
tenant: TenantId,
|
|
536
|
+
): Promise<void> {
|
|
537
|
+
this.use(true, (db) => {
|
|
538
|
+
if (summary.tenantId !== tenant)
|
|
539
|
+
throw new TenantIsolationError({ requested: tenant, resource: 'summary payload' })
|
|
540
|
+
const session = this.requiredSession(db, summary.sessionRef, tenant)
|
|
541
|
+
const existing = this.get<SessionSummaryRef>(db, 'summaries', summary.sessionRef, tenant)
|
|
542
|
+
if (existing && existing.id !== summary.id)
|
|
543
|
+
throw new SessionAlreadySummarizedError({
|
|
544
|
+
sessionId: session.id,
|
|
545
|
+
existingSummaryId: existing.id,
|
|
546
|
+
})
|
|
547
|
+
if (!existing)
|
|
548
|
+
db.prepare('INSERT INTO summaries VALUES (?, ?, ?)').run(
|
|
549
|
+
session.id,
|
|
550
|
+
tenant,
|
|
551
|
+
encode(summary),
|
|
552
|
+
)
|
|
553
|
+
if (['active', 'locked', 'awaiting_merge'].includes(session.status))
|
|
554
|
+
db.prepare('UPDATE sessions SET body = ? WHERE id = ?').run(
|
|
555
|
+
encode({ ...session, status: 'idle', updatedAt: new Date() }),
|
|
556
|
+
session.id,
|
|
557
|
+
)
|
|
558
|
+
})
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
async getSummary(id: SessionId, tenant: TenantId): Promise<SessionSummaryRef | null> {
|
|
562
|
+
return this.use(false, (db) =>
|
|
563
|
+
this.get<SessionSummaryRef>(db, 'summaries', asSessionId(id), tenant),
|
|
564
|
+
)
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
function encode(value: unknown): string {
|
|
569
|
+
return JSON.stringify(value)
|
|
570
|
+
}
|
|
571
|
+
function decode<T>(body: string): T {
|
|
572
|
+
const value = JSON.parse(body) as Record<string, unknown>
|
|
573
|
+
for (const key of ['createdAt', 'updatedAt', 'spawnedAt', 'archivedAt', 'at']) {
|
|
574
|
+
if (typeof value[key] === 'string') value[key] = new Date(value[key] as string)
|
|
575
|
+
}
|
|
576
|
+
if (Array.isArray(value.keyDecisions)) {
|
|
577
|
+
value.keyDecisions = value.keyDecisions.map((entry) => ({ ...entry, at: new Date(entry.at) }))
|
|
578
|
+
}
|
|
579
|
+
return value as T
|
|
580
|
+
}
|
|
581
|
+
function decodeMessage(value: unknown): SessionMessage {
|
|
582
|
+
const entry = value as SessionMessage
|
|
583
|
+
return { ...entry, at: new Date(entry.at) }
|
|
584
|
+
}
|