@sema-agent/server 1.323.0 → 2.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/dist/approval-hmac.d.ts +40 -0
- package/dist/approval-hmac.js +67 -0
- package/dist/approval.d.ts +31 -0
- package/dist/approval.js +72 -4
- package/dist/audit.d.ts +26 -0
- package/dist/audit.js +40 -1
- package/dist/auth-bridge.d.ts +10 -0
- package/dist/auth-bridge.js +47 -4
- package/dist/auth-keys.d.ts +19 -0
- package/dist/auth-keys.js +13 -0
- package/dist/bake-runner/main.d.ts +5 -0
- package/dist/bake-runner/main.js +43 -4
- package/dist/bake-runner/protocol.d.ts +57 -0
- package/dist/bake-runner/protocol.js +58 -3
- package/dist/bake-runner/runner.d.ts +54 -0
- package/dist/bake-runner/runner.js +87 -5
- package/dist/bench/l8/artifact.d.ts +63 -0
- package/dist/bench/l8/artifact.js +61 -2
- package/dist/bench/l8/escape.d.ts +36 -0
- package/dist/bench/l8/escape.js +25 -0
- package/dist/bench/l8/index.d.ts +14 -0
- package/dist/bench/l8/index.js +14 -0
- package/dist/bench/l8/probes.d.ts +74 -0
- package/dist/bench/l8/probes.js +60 -0
- package/dist/bench/l8/run-probes.d.ts +43 -0
- package/dist/bench/l8/run-probes.js +45 -2
- package/dist/bench/s1/arms.d.ts +126 -0
- package/dist/bench/s1/arms.js +188 -13
- package/dist/bench/s1/live-deps.d.ts +66 -0
- package/dist/bench/s1/live-deps.js +249 -11
- package/dist/bench/s1/oracle.d.ts +49 -0
- package/dist/bench/s1/oracle.js +36 -1
- package/dist/bench/s1/repair-oracle-adapter.d.ts +33 -0
- package/dist/bench/s1/repair-oracle-adapter.js +30 -0
- package/dist/bench/s1/reviewer.d.ts +38 -0
- package/dist/bench/s1/reviewer.js +34 -0
- package/dist/bench/s1/row.d.ts +77 -0
- package/dist/bench/s1/row.js +62 -0
- package/dist/bench/s1/run-firm.d.ts +47 -0
- package/dist/bench/s1/run-firm.js +70 -4
- package/dist/bench/s1/runner-ctx.d.ts +71 -0
- package/dist/bench/s1/runner-ctx.js +36 -0
- package/dist/bench/s1/tasks.d.ts +108 -0
- package/dist/bench/s1/tasks.js +115 -0
- package/dist/boot-reclaim.d.ts +19 -0
- package/dist/boot-reclaim.js +20 -0
- package/dist/brain.d.ts +25 -0
- package/dist/brain.js +61 -1
- package/dist/budget.d.ts +66 -0
- package/dist/budget.js +128 -4
- package/dist/capabilities/builtin-tools.d.ts +3 -0
- package/dist/capabilities/builtin-tools.js +3 -0
- package/dist/capabilities/center-plugins.d.ts +17 -1
- package/dist/capabilities/center-plugins.js +45 -4
- package/dist/capabilities/center-prompts.d.ts +46 -0
- package/dist/capabilities/center-prompts.js +57 -3
- package/dist/capabilities/code-review-council.d.ts +28 -0
- package/dist/capabilities/code-review-council.js +40 -7
- package/dist/capabilities/collab-wire.d.ts +2 -0
- package/dist/capabilities/collab-workflows.d.ts +7 -0
- package/dist/capabilities/collab-workflows.js +44 -1
- package/dist/capabilities/oa-tools.d.ts +6 -0
- package/dist/capabilities/oa-tools.js +10 -0
- package/dist/capabilities/prompt.d.ts +14 -0
- package/dist/capabilities/prompt.js +14 -0
- package/dist/capabilities/prompts/code-review.d.ts +14 -0
- package/dist/capabilities/prompts/code-review.js +14 -0
- package/dist/capabilities/prompts/identity.d.ts +6 -0
- package/dist/capabilities/prompts/identity.js +6 -0
- package/dist/capabilities/prompts/team.d.ts +4 -0
- package/dist/capabilities/prompts/team.js +4 -0
- package/dist/capabilities/repo-tools.d.ts +11 -0
- package/dist/capabilities/repo-tools.js +8 -0
- package/dist/capabilities/sandbox-file-send.d.ts +95 -0
- package/dist/capabilities/sandbox-file-send.js +91 -3
- package/dist/capabilities/scenarios.d.ts +130 -0
- package/dist/capabilities/scenarios.js +180 -7
- package/dist/capabilities/select-environment-tool.d.ts +7 -0
- package/dist/capabilities/select-environment-tool.js +30 -0
- package/dist/capabilities/send-user-file-tool.d.ts +33 -0
- package/dist/capabilities/send-user-file-tool.js +65 -1
- package/dist/capabilities/skills.d.ts +29 -0
- package/dist/capabilities/skills.js +13 -2
- package/dist/capabilities/team.d.ts +22 -0
- package/dist/capabilities/team.js +22 -2
- package/dist/capabilities/tool-defer.d.ts +26 -0
- package/dist/capabilities/tool-defer.js +3 -0
- package/dist/config-center/apply-effective.d.ts +65 -0
- package/dist/config-center/apply-effective.js +204 -12
- package/dist/config-center/http-client.d.ts +34 -0
- package/dist/config-center/http-client.js +68 -0
- package/dist/config-center/restart-signal.d.ts +22 -0
- package/dist/config-center/restart-signal.js +39 -0
- package/dist/config-center/skills-mcp.d.ts +20 -1
- package/dist/config-center/skills-mcp.js +42 -7
- package/dist/config-center/types.d.ts +92 -1
- package/dist/config-lkg.d.ts +12 -0
- package/dist/config-lkg.js +41 -0
- package/dist/config-provider.d.ts +78 -0
- package/dist/config-provider.js +165 -2
- package/dist/config-types.d.ts +546 -0
- package/dist/config.d.ts +64 -0
- package/dist/config.js +455 -60
- package/dist/degenerate-instrument.d.ts +38 -0
- package/dist/degenerate-instrument.js +55 -3
- package/dist/elicitation.d.ts +39 -0
- package/dist/elicitation.js +87 -3
- package/dist/env-facts.d.ts +61 -0
- package/dist/env-facts.js +73 -7
- package/dist/fleet/fleet-bus.d.ts +185 -0
- package/dist/fleet/fleet-bus.js +333 -27
- package/dist/fleet/subagent-tail-bus.d.ts +11 -0
- package/dist/fleet/subagent-tail-bus.js +33 -2
- package/dist/fleet-client.d.ts +38 -0
- package/dist/fleet-client.js +44 -9
- package/dist/fleet-lease.d.ts +46 -0
- package/dist/fleet-lease.js +73 -5
- package/dist/hooks/branch-transcript.d.ts +8 -0
- package/dist/hooks/branch-transcript.js +33 -0
- package/dist/hooks/cc-stop-prompt.d.ts +42 -0
- package/dist/hooks/cc-stop-prompt.js +43 -1
- package/dist/hooks/hook-llm.d.ts +15 -0
- package/dist/hooks/hook-llm.js +47 -0
- package/dist/hooks/hook-runner.d.ts +89 -0
- package/dist/hooks/hook-runner.js +327 -18
- package/dist/http/idempotency.d.ts +31 -0
- package/dist/http/idempotency.js +34 -0
- package/dist/http/principal-gate.d.ts +17 -0
- package/dist/http/principal-gate.js +35 -3
- package/dist/http/route-ctx.d.ts +36 -0
- package/dist/http/routes/approvals-assistant.d.ts +25 -0
- package/dist/http/routes/approvals-assistant.js +253 -23
- package/dist/http/routes/attachments.js +22 -4
- package/dist/http/routes/capabilities.d.ts +7 -0
- package/dist/http/routes/capabilities.js +202 -1
- package/dist/http/routes/fleet.d.ts +6 -0
- package/dist/http/routes/fleet.js +94 -5
- package/dist/http/routes/images.d.ts +17 -0
- package/dist/http/routes/images.js +222 -14
- package/dist/http/routes/leader.d.ts +7 -0
- package/dist/http/routes/leader.js +10 -0
- package/dist/http/routes/memory-policy.d.ts +6 -0
- package/dist/http/routes/memory-policy.js +38 -6
- package/dist/http/routes/notify-wake.d.ts +10 -0
- package/dist/http/routes/notify-wake.js +19 -3
- package/dist/http/routes/observability.d.ts +6 -0
- package/dist/http/routes/observability.js +19 -2
- package/dist/http/routes/runs.d.ts +15 -0
- package/dist/http/routes/runs.js +464 -41
- package/dist/http/routes/session-sync.d.ts +15 -0
- package/dist/http/routes/session-sync.js +229 -19
- package/dist/http/routes/sessions-list.d.ts +6 -0
- package/dist/http/routes/sessions-list.js +35 -4
- package/dist/http/routes/sessions.d.ts +14 -0
- package/dist/http/routes/sessions.js +176 -31
- package/dist/http/routes/side-query.d.ts +8 -0
- package/dist/http/routes/side-query.js +26 -1
- package/dist/http/routes/tasks.d.ts +18 -0
- package/dist/http/routes/tasks.js +501 -38
- package/dist/http/routes/trace-usage.d.ts +10 -0
- package/dist/http/routes/trace-usage.js +66 -14
- package/dist/http/routes/workflows.d.ts +12 -0
- package/dist/http/routes/workflows.js +180 -19
- package/dist/http/run-meta.d.ts +11 -0
- package/dist/http/run-meta.js +6 -0
- package/dist/http/send.d.ts +19 -0
- package/dist/http/send.js +11 -0
- package/dist/http/server.d.ts +255 -0
- package/dist/http/server.js +921 -75
- package/dist/http/sse-log.d.ts +15 -0
- package/dist/http/sse-log.js +16 -0
- package/dist/http/tar.d.ts +9 -0
- package/dist/http/tar.js +21 -5
- package/dist/http/wire-gate.d.ts +9 -0
- package/dist/http/wire-gate.js +9 -0
- package/dist/http/wire-types.d.ts +187 -0
- package/dist/http/workspace-content.d.ts +8 -0
- package/dist/http/workspace-content.js +10 -0
- package/dist/images/bake-validate.d.ts +63 -0
- package/dist/images/bake-validate.js +71 -1
- package/dist/images/manifest.d.ts +19 -0
- package/dist/images/manifest.js +6 -1
- package/dist/index.d.ts +1 -5
- package/dist/index.js +10 -5
- package/dist/key-resolver.d.ts +23 -0
- package/dist/key-resolver.js +27 -2
- package/dist/leader/diffout.d.ts +23 -0
- package/dist/leader/diffout.js +8 -1
- package/dist/leader/diffup.d.ts +32 -0
- package/dist/leader/diffup.js +43 -0
- package/dist/leader/endpoint.d.ts +20 -0
- package/dist/leader/endpoint.js +25 -2
- package/dist/leader/fanout.d.ts +60 -0
- package/dist/leader/fanout.js +29 -3
- package/dist/leader/grader-env-factory.d.ts +74 -0
- package/dist/leader/grader-env-factory.js +62 -3
- package/dist/leader/leader.d.ts +97 -0
- package/dist/leader/leader.js +151 -4
- package/dist/leader/merge.d.ts +94 -0
- package/dist/leader/merge.js +112 -9
- package/dist/leader/planner.d.ts +52 -0
- package/dist/leader/planner.js +47 -3
- package/dist/leader/repair-oracle.d.ts +61 -0
- package/dist/leader/repair-oracle.js +59 -1
- package/dist/leader/repair-wire.d.ts +78 -0
- package/dist/leader/repair-wire.js +79 -2
- package/dist/leader/wire.d.ts +79 -0
- package/dist/leader/wire.js +255 -8
- package/dist/lsp/e2b-bridge.d.ts +16 -0
- package/dist/lsp/e2b-bridge.js +32 -4
- package/dist/lsp/e2b-manager.d.ts +10 -0
- package/dist/lsp/e2b-manager.js +18 -2
- package/dist/lsp/lsp-frames.d.ts +12 -0
- package/dist/lsp/lsp-frames.js +12 -0
- package/dist/lsp/manager.d.ts +12 -0
- package/dist/lsp/manager.js +35 -2
- package/dist/lsp/types.d.ts +10 -0
- package/dist/lsp/ws-transport.d.ts +12 -0
- package/dist/lsp/ws-transport.js +53 -5
- package/dist/lsp-evict.d.ts +14 -0
- package/dist/lsp-evict.js +15 -1
- package/dist/main.js +2132 -96
- package/dist/memory-export.d.ts +1 -0
- package/dist/memory-export.js +4 -0
- package/dist/memory-scope.d.ts +49 -0
- package/dist/memory-scope.js +87 -4
- package/dist/memory-sync-client.d.ts +24 -0
- package/dist/memory-sync-client.js +41 -2
- package/dist/memory-sync.d.ts +23 -0
- package/dist/memory-sync.js +70 -1
- package/dist/model-select.d.ts +39 -0
- package/dist/model-select.js +42 -1
- package/dist/observability/cost-quota.d.ts +20 -0
- package/dist/observability/cost-quota.js +4 -0
- package/dist/observability/cost-taxonomy.d.ts +45 -0
- package/dist/observability/cost-taxonomy.js +34 -0
- package/dist/observability/logger.d.ts +1 -0
- package/dist/observability/logger.js +6 -0
- package/dist/observability/metrics.d.ts +13 -0
- package/dist/observability/metrics.js +63 -0
- package/dist/observability/otel-exporter.d.ts +9 -0
- package/dist/observability/otel-exporter.js +11 -3
- package/dist/observability/principal-context.d.ts +9 -0
- package/dist/observability/principal-context.js +9 -0
- package/dist/observability/prompt-manifest.d.ts +37 -0
- package/dist/observability/prompt-manifest.js +35 -1
- package/dist/observability/rate-limit.d.ts +10 -0
- package/dist/observability/rate-limit.js +1 -0
- package/dist/observability/tool-trace.d.ts +24 -0
- package/dist/observability/tool-trace.js +41 -1
- package/dist/orchestration/hardened-vm-runner.d.ts +107 -0
- package/dist/orchestration/hardened-vm-runner.js +119 -4
- package/dist/orchestration/hardened-vm-worker-runner.d.ts +14 -0
- package/dist/orchestration/hardened-vm-worker-runner.js +26 -1
- package/dist/orchestration/hardened-vm-worker.js +27 -0
- package/dist/orchestration/subagent-steer.d.ts +44 -0
- package/dist/orchestration/subagent-steer.js +45 -1
- package/dist/orchestration/workflow-agent-steer.d.ts +54 -0
- package/dist/orchestration/workflow-agent-steer.js +80 -1
- package/dist/orchestration/workflow-completion-inbox.d.ts +189 -2
- package/dist/orchestration/workflow-completion-inbox.js +283 -32
- package/dist/orchestration/workflow-notify-journal.d.ts +132 -1
- package/dist/orchestration/workflow-notify-journal.js +187 -13
- package/dist/parked-decide.d.ts +61 -0
- package/dist/parked-decide.js +58 -1
- package/dist/per-task-image.d.ts +54 -0
- package/dist/per-task-image.js +41 -0
- package/dist/plan-cache-probe.d.ts +35 -0
- package/dist/plan-cache-probe.js +18 -3
- package/dist/plugins/approval-exemption-store.d.ts +7 -0
- package/dist/plugins/approval-exemption-store.js +28 -2
- package/dist/plugins/approval-store-sql.d.ts +64 -0
- package/dist/plugins/approval-store-sql.js +32 -0
- package/dist/plugins/background-agent-store-sql.d.ts +55 -0
- package/dist/plugins/background-agent-store-sql.js +91 -4
- package/dist/plugins/background-shell-support.d.ts +98 -0
- package/dist/plugins/background-shell-support.js +117 -13
- package/dist/plugins/blob-backend.d.ts +104 -0
- package/dist/plugins/blob-backend.js +163 -6
- package/dist/plugins/breaker-state-sql.d.ts +65 -1
- package/dist/plugins/breaker-state-sql.js +46 -8
- package/dist/plugins/caching-session-store.d.ts +42 -0
- package/dist/plugins/caching-session-store.js +63 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +179 -0
- package/dist/plugins/checkpoint-store-sql.js +239 -11
- package/dist/plugins/file-outcome-sink.d.ts +4 -0
- package/dist/plugins/file-outcome-sink.js +9 -0
- package/dist/plugins/file-resume-anchor-store.d.ts +20 -0
- package/dist/plugins/file-resume-anchor-store.js +43 -4
- package/dist/plugins/file-run-store.d.ts +90 -0
- package/dist/plugins/file-run-store.js +145 -13
- package/dist/plugins/file-snapshot-store-sql.d.ts +133 -1
- package/dist/plugins/file-snapshot-store-sql.js +178 -10
- package/dist/plugins/file-workflow-journal-store.d.ts +10 -0
- package/dist/plugins/file-workflow-journal-store.js +10 -0
- package/dist/plugins/fork-routing-session-store.d.ts +47 -0
- package/dist/plugins/fork-routing-session-store.js +51 -3
- package/dist/plugins/host-platform.d.ts +69 -0
- package/dist/plugins/host-platform.js +81 -2
- package/dist/plugins/image-bake-store-sql.d.ts +136 -1
- package/dist/plugins/image-bake-store-sql.js +241 -7
- package/dist/plugins/image-index-sql.d.ts +46 -0
- package/dist/plugins/image-index-sql.js +113 -4
- package/dist/plugins/k8s-bg-scripts.d.ts +34 -0
- package/dist/plugins/k8s-bg-scripts.js +88 -4
- package/dist/plugins/k8s-exec-protocol.d.ts +33 -0
- package/dist/plugins/k8s-exec-protocol.js +41 -0
- package/dist/plugins/local-checkpoint-store.d.ts +40 -0
- package/dist/plugins/local-checkpoint-store.js +86 -7
- package/dist/plugins/local-session-store.d.ts +157 -0
- package/dist/plugins/local-session-store.js +289 -34
- package/dist/plugins/local-task-attachment-store.js +14 -2
- package/dist/plugins/mailbox-store-sql.d.ts +38 -0
- package/dist/plugins/mailbox-store-sql.js +39 -6
- package/dist/plugins/memory-engine-pg.d.ts +30 -0
- package/dist/plugins/memory-engine-pg.js +122 -4
- package/dist/plugins/memory-engine-tidb.d.ts +26 -0
- package/dist/plugins/memory-engine-tidb.js +115 -5
- package/dist/plugins/memory-engine-vector-util.d.ts +5 -0
- package/dist/plugins/memory-engine-vector-util.js +5 -0
- package/dist/plugins/memory-resume-anchor-store.d.ts +8 -0
- package/dist/plugins/memory-resume-anchor-store.js +17 -0
- package/dist/plugins/memory-run-store.d.ts +63 -0
- package/dist/plugins/memory-run-store.js +73 -8
- package/dist/plugins/memory-session-policy-store.d.ts +17 -0
- package/dist/plugins/memory-session-policy-store.js +17 -0
- package/dist/plugins/memory-sync-store-pg.d.ts +42 -0
- package/dist/plugins/memory-sync-store-pg.js +45 -2
- package/dist/plugins/memory-sync-store-tidb.d.ts +9 -0
- package/dist/plugins/memory-sync-store-tidb.js +31 -1
- package/dist/plugins/outcome-ledger-sql.d.ts +63 -0
- package/dist/plugins/outcome-ledger-sql.js +97 -3
- package/dist/plugins/pg-approval-store.d.ts +7 -0
- package/dist/plugins/pg-approval-store.js +7 -0
- package/dist/plugins/pg-breaker-state.d.ts +6 -0
- package/dist/plugins/pg-breaker-state.js +6 -0
- package/dist/plugins/pg-checkpoint-store.d.ts +8 -0
- package/dist/plugins/pg-checkpoint-store.js +8 -0
- package/dist/plugins/pg-cost-quota.d.ts +17 -0
- package/dist/plugins/pg-cost-quota.js +6 -0
- package/dist/plugins/pg-file-snapshot-store.d.ts +6 -0
- package/dist/plugins/pg-file-snapshot-store.js +6 -0
- package/dist/plugins/pg-image-bake.d.ts +9 -0
- package/dist/plugins/pg-image-bake.js +9 -0
- package/dist/plugins/pg-image-index.d.ts +9 -0
- package/dist/plugins/pg-image-index.js +9 -0
- package/dist/plugins/pg-outcome-ledger.d.ts +9 -0
- package/dist/plugins/pg-outcome-ledger.js +9 -0
- package/dist/plugins/pg-pool.d.ts +50 -0
- package/dist/plugins/pg-pool.js +78 -0
- package/dist/plugins/pg-query.d.ts +11 -0
- package/dist/plugins/pg-rate-limiter.d.ts +23 -0
- package/dist/plugins/pg-rate-limiter.js +12 -2
- package/dist/plugins/pg-resume-anchor-store.d.ts +5 -0
- package/dist/plugins/pg-resume-anchor-store.js +5 -0
- package/dist/plugins/pg-run-store.d.ts +7 -0
- package/dist/plugins/pg-run-store.js +7 -0
- package/dist/plugins/pg-safe-json.d.ts +13 -0
- package/dist/plugins/pg-safe-json.js +40 -4
- package/dist/plugins/pg-session-policy-store.d.ts +5 -0
- package/dist/plugins/pg-session-policy-store.js +5 -0
- package/dist/plugins/pg-session-storage.d.ts +72 -0
- package/dist/plugins/pg-session-storage.js +152 -20
- package/dist/plugins/pg-session-store.d.ts +10 -0
- package/dist/plugins/pg-session-store.js +10 -0
- package/dist/plugins/pg-tool-result-store.d.ts +7 -0
- package/dist/plugins/pg-tool-result-store.js +7 -0
- package/dist/plugins/pg-workflow-journal-store.d.ts +7 -0
- package/dist/plugins/pg-workflow-journal-store.js +7 -0
- package/dist/plugins/pg-workflow-run-store.d.ts +7 -0
- package/dist/plugins/pg-workflow-run-store.js +7 -0
- package/dist/plugins/posix-shell-fs.d.ts +3 -0
- package/dist/plugins/posix-shell-fs.js +31 -1
- package/dist/plugins/remote-env-adb.d.ts +25 -0
- package/dist/plugins/remote-env-adb.js +95 -12
- package/dist/plugins/remote-env-e2b.d.ts +146 -0
- package/dist/plugins/remote-env-e2b.js +371 -40
- package/dist/plugins/remote-env-file-error.d.ts +34 -0
- package/dist/plugins/remote-env-file-error.js +37 -0
- package/dist/plugins/remote-env-host.d.ts +151 -0
- package/dist/plugins/remote-env-host.js +468 -70
- package/dist/plugins/remote-env-k8s.d.ts +135 -0
- package/dist/plugins/remote-env-k8s.js +318 -32
- package/dist/plugins/remote-env-local-docker.d.ts +65 -0
- package/dist/plugins/remote-env-local-docker.js +149 -24
- package/dist/plugins/remote-env-ssh.d.ts +35 -0
- package/dist/plugins/remote-env-ssh.js +117 -20
- package/dist/plugins/remote-scratchpad.d.ts +38 -0
- package/dist/plugins/remote-scratchpad.js +32 -2
- package/dist/plugins/remote-shell.d.ts +22 -0
- package/dist/plugins/remote-shell.js +27 -1
- package/dist/plugins/resume-anchor-store-sql.d.ts +28 -0
- package/dist/plugins/resume-anchor-store-sql.js +11 -0
- package/dist/plugins/roster-store-sql.d.ts +27 -0
- package/dist/plugins/roster-store-sql.js +54 -0
- package/dist/plugins/run-store-sql.d.ts +194 -0
- package/dist/plugins/run-store-sql.js +210 -9
- package/dist/plugins/s3-presign.d.ts +20 -0
- package/dist/plugins/s3-presign.js +49 -2
- package/dist/plugins/scheduler-support.d.ts +12 -0
- package/dist/plugins/scheduler-support.js +75 -3
- package/dist/plugins/send-file-ledger.d.ts +15 -0
- package/dist/plugins/send-file-ledger.js +53 -4
- package/dist/plugins/send-user-file.d.ts +77 -0
- package/dist/plugins/send-user-file.js +92 -4
- package/dist/plugins/session-policy-store-sql.d.ts +15 -0
- package/dist/plugins/session-policy-store-sql.js +75 -3
- package/dist/plugins/session-store.d.ts +45 -0
- package/dist/plugins/session-store.js +51 -0
- package/dist/plugins/sql-driver.d.ts +77 -0
- package/dist/plugins/sql-driver.js +4 -0
- package/dist/plugins/sql-escape.d.ts +8 -0
- package/dist/plugins/sql-escape.js +8 -0
- package/dist/plugins/sql-row-helpers.d.ts +25 -0
- package/dist/plugins/sql-row-helpers.js +25 -0
- package/dist/plugins/store-backend.d.ts +103 -0
- package/dist/plugins/store-backend.js +120 -27
- package/dist/plugins/store-contracts.d.ts +62 -0
- package/dist/plugins/store-contracts.js +3 -0
- package/dist/plugins/task-attachment-store.d.ts +60 -0
- package/dist/plugins/task-attachment-store.js +49 -3
- package/dist/plugins/task-list-store-sql.d.ts +25 -0
- package/dist/plugins/task-list-store-sql.js +21 -0
- package/dist/plugins/tidb-approval-store.d.ts +6 -0
- package/dist/plugins/tidb-approval-store.js +6 -0
- package/dist/plugins/tidb-breaker-state.d.ts +5 -0
- package/dist/plugins/tidb-breaker-state.js +5 -0
- package/dist/plugins/tidb-checkpoint-store.d.ts +7 -0
- package/dist/plugins/tidb-checkpoint-store.js +7 -0
- package/dist/plugins/tidb-cost-quota.d.ts +6 -0
- package/dist/plugins/tidb-cost-quota.js +1 -0
- package/dist/plugins/tidb-file-snapshot-store.d.ts +6 -0
- package/dist/plugins/tidb-file-snapshot-store.js +6 -0
- package/dist/plugins/tidb-image-bake.d.ts +8 -0
- package/dist/plugins/tidb-image-bake.js +8 -0
- package/dist/plugins/tidb-image-index.d.ts +8 -0
- package/dist/plugins/tidb-image-index.js +8 -0
- package/dist/plugins/tidb-outcome-ledger.d.ts +10 -0
- package/dist/plugins/tidb-outcome-ledger.js +10 -0
- package/dist/plugins/tidb-pool.d.ts +56 -0
- package/dist/plugins/tidb-pool.js +181 -1
- package/dist/plugins/tidb-rate-limiter.d.ts +11 -0
- package/dist/plugins/tidb-rate-limiter.js +5 -2
- package/dist/plugins/tidb-resume-anchor-store.d.ts +5 -0
- package/dist/plugins/tidb-resume-anchor-store.js +5 -0
- package/dist/plugins/tidb-run-store.d.ts +7 -0
- package/dist/plugins/tidb-run-store.js +7 -0
- package/dist/plugins/tidb-session-policy-store.d.ts +5 -0
- package/dist/plugins/tidb-session-policy-store.js +5 -0
- package/dist/plugins/tidb-session-storage.d.ts +43 -0
- package/dist/plugins/tidb-session-storage.js +62 -3
- package/dist/plugins/tidb-session-store.d.ts +142 -0
- package/dist/plugins/tidb-session-store.js +264 -16
- package/dist/plugins/tidb-tool-result-store.d.ts +5 -0
- package/dist/plugins/tidb-tool-result-store.js +7 -0
- package/dist/plugins/tidb-workflow-journal-store.d.ts +7 -0
- package/dist/plugins/tidb-workflow-journal-store.js +7 -0
- package/dist/plugins/tidb-workflow-run-store.d.ts +8 -0
- package/dist/plugins/tidb-workflow-run-store.js +8 -0
- package/dist/plugins/tool-result-store-sql.d.ts +58 -0
- package/dist/plugins/tool-result-store-sql.js +38 -2
- package/dist/plugins/web-search.d.ts +35 -0
- package/dist/plugins/web-search.js +45 -9
- package/dist/plugins/workflow-journal-limits.d.ts +10 -0
- package/dist/plugins/workflow-journal-limits.js +10 -0
- package/dist/plugins/workflow-journal-store-sql.d.ts +78 -0
- package/dist/plugins/workflow-journal-store-sql.js +58 -2
- package/dist/plugins/workflow-run-store-sql.d.ts +84 -0
- package/dist/plugins/workflow-run-store-sql.js +84 -6
- package/dist/plugins/worktree-isolation.d.ts +45 -0
- package/dist/plugins/worktree-isolation.js +105 -6
- package/dist/plugins/write-behind-counter.d.ts +56 -1
- package/dist/plugins/write-behind-counter.js +53 -14
- package/dist/principal-jwt.d.ts +24 -0
- package/dist/principal-jwt.js +60 -5
- package/dist/project-memory.d.ts +22 -0
- package/dist/project-memory.js +144 -15
- package/dist/prompts-domain-validate.d.ts +28 -0
- package/dist/prompts-domain-validate.js +42 -1
- package/dist/question.d.ts +33 -0
- package/dist/question.js +69 -2
- package/dist/resource-suspend.d.ts +21 -0
- package/dist/resource-suspend.js +16 -0
- package/dist/router/route-orchestration.d.ts +78 -0
- package/dist/router/route-orchestration.js +77 -0
- package/dist/run-local.d.ts +32 -0
- package/dist/run-local.js +172 -8
- package/dist/runs.d.ts +189 -4
- package/dist/runs.js +465 -24
- package/dist/runtime-caps-resolver.d.ts +106 -0
- package/dist/runtime-caps-resolver.js +89 -4
- package/dist/runtime-governance.d.ts +84 -0
- package/dist/runtime-governance.js +127 -1
- package/dist/sandbox-pkg-source.d.ts +23 -0
- package/dist/sandbox-pkg-source.js +37 -0
- package/dist/sealed-key.d.ts +54 -0
- package/dist/sealed-key.js +68 -3
- package/dist/security.d.ts +108 -0
- package/dist/security.js +145 -6
- package/dist/sema-registry.d.ts +21 -0
- package/dist/sema-registry.js +21 -0
- package/dist/session-leaf-bus.d.ts +31 -0
- package/dist/session-leaf-bus.js +32 -0
- package/dist/session-sync-content.d.ts +46 -0
- package/dist/session-sync-content.js +47 -1
- package/dist/session-sync-kernel.d.ts +89 -0
- package/dist/session-sync-kernel.js +48 -3
- package/dist/session-sync.d.ts +125 -0
- package/dist/session-sync.js +181 -8
- package/dist/session-titler.d.ts +26 -0
- package/dist/session-titler.js +41 -7
- package/dist/session-watch.d.ts +53 -1
- package/dist/session-watch.js +73 -9
- package/dist/sighup-idle.d.ts +30 -0
- package/dist/sighup-idle.js +12 -1
- package/dist/spec-fields.d.ts +91 -3
- package/dist/spec-fields.js +116 -4
- package/dist/task-cwd.d.ts +50 -0
- package/dist/task-cwd.js +68 -1
- package/dist/task-mcp.d.ts +47 -0
- package/dist/task-mcp.js +29 -0
- package/dist/task-settings.d.ts +175 -0
- package/dist/task-settings.js +226 -11
- package/dist/task-workflow.d.ts +67 -0
- package/dist/task-workflow.js +75 -8
- package/dist/tool-approval.d.ts +91 -0
- package/dist/tool-approval.js +215 -0
- package/dist/trace/artifacts.d.ts +9 -0
- package/dist/trace/artifacts.js +30 -5
- package/dist/trace/core-keyset-guard.d.ts +18 -0
- package/dist/trace/ledger-sink.d.ts +43 -0
- package/dist/trace/ledger-sink.js +64 -5
- package/dist/trace/project.d.ts +133 -0
- package/dist/trace/project.js +189 -2
- package/dist/trace/redact.d.ts +19 -0
- package/dist/trace/redact.js +66 -9
- package/dist/usage-analytics.d.ts +26 -0
- package/dist/usage-analytics.js +26 -3
- package/package.json +1 -1
|
@@ -1,10 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory async run registry + replayable event log — the LOCAL (DB-less) twin of {@link TiDBRunStore}/
|
|
3
|
+
* {@link PgRunStore} (clay 2026-06-25: the seamless local↔cloud switch — a locally-run HTTP service must serve the
|
|
4
|
+
* SAME contract a cloud worker does, incl. `/v1/runs` async runs + the trace event log). Behaviourally identical to
|
|
5
|
+
* the SQL twins (the shared `storeBehaviorSuite` keeps them in lock-step), but process-local + ephemeral: a restart
|
|
6
|
+
* loses run history (file-backed durability is the immediate follow-on; the conversation HISTORY + checkpoints DO
|
|
7
|
+
* persist via core's FileStorageBackend). Single-process, so the cross-replica/durable reapers degrade — see below.
|
|
8
|
+
*
|
|
9
|
+
* Mirrors the SQL semantics exactly: the `task_active` single-active-run claim (a Map keyed by sessionId), the
|
|
10
|
+
* NON-terminal suspend/needs_review parks that KEEP the claim, the markResuming CAS that resets cancel/preempt, the
|
|
11
|
+
* owner null-safe guard on the flag/heartbeat paths (`<=>` → JS `(a??null)===(b??null)`), and the keyset list order.
|
|
12
|
+
*/
|
|
1
13
|
import { projectUsageStats, USAGE_SCAN_LIMIT } from "../usage-analytics.js";
|
|
14
|
+
/** Null-safe owner equality — the JS twin of the SQL `owner <=> ?` guard (a legacy null-owner run matches owner=null). */
|
|
2
15
|
const ownerEq = (a, b) => (a ?? null) === (b ?? null);
|
|
3
16
|
export class MemoryRunStore {
|
|
4
17
|
runs = new Map();
|
|
18
|
+
/** sessionId → taskId — the single-active-run claim (the `task_active` table). */
|
|
5
19
|
active = new Map();
|
|
20
|
+
/** taskId → events (kept seq-sorted on read). */
|
|
6
21
|
events = new Map();
|
|
22
|
+
/** [868] the checkpoint-table stand-in (see {@link RunStoreCheckpointProbe}); absent ⇒ reapers NO-OP. */
|
|
7
23
|
checkpointProbe;
|
|
24
|
+
/** [868] wire the checkpoint probe (backend assembly, where checkpoint + run store are built together). */
|
|
8
25
|
setCheckpointProbe(probe) {
|
|
9
26
|
this.checkpointProbe = probe;
|
|
10
27
|
}
|
|
@@ -25,6 +42,7 @@ export class MemoryRunStore {
|
|
|
25
42
|
updatedAt: r.updatedAt.toISOString(),
|
|
26
43
|
};
|
|
27
44
|
}
|
|
45
|
+
/** Create a run iff the session has no active run (the task_active unique-key claim). */
|
|
28
46
|
async createRun(taskId, sessionId, owner, instanceId, meta = {}) {
|
|
29
47
|
const claimed = this.active.get(sessionId);
|
|
30
48
|
if (claimed !== undefined)
|
|
@@ -79,8 +97,12 @@ export class MemoryRunStore {
|
|
|
79
97
|
}
|
|
80
98
|
async appendEvent(taskId, seq, type, data) {
|
|
81
99
|
const list = this.events.get(taskId) ?? [];
|
|
100
|
+
// Mirror the (task_id, seq) PK: a duplicate seq is a caller bug (callers use ++seq); ignore a re-append of the
|
|
101
|
+
// same seq rather than corrupt the log (the SQL twin would throw ER_DUP_ENTRY — callers never hit it).
|
|
82
102
|
if (list.some((e) => e.seq === seq))
|
|
83
103
|
return;
|
|
104
|
+
// Deep-clone `data` on WRITE so the stored event is isolated from later caller mutation — the SQL twin
|
|
105
|
+
// JSON.stringify's it into the column, giving the same write-isolation (parity oracle).
|
|
84
106
|
list.push({ seq, type, data: data == null ? null : structuredClone(data), ts: new Date().toISOString() });
|
|
85
107
|
this.events.set(taskId, list);
|
|
86
108
|
}
|
|
@@ -94,11 +116,15 @@ export class MemoryRunStore {
|
|
|
94
116
|
}
|
|
95
117
|
async getEvents(taskId, afterSeq) {
|
|
96
118
|
const list = this.events.get(taskId) ?? [];
|
|
119
|
+
// Deep-clone `data` on READ so each call yields a fresh, mutation-isolated object — the SQL twin re-parses the
|
|
120
|
+
// JSON column per read (parity oracle); a shallow `{...e}` would alias `data` into the stored Map (review footgun).
|
|
97
121
|
return list
|
|
98
122
|
.filter((e) => e.seq > afterSeq)
|
|
99
123
|
.sort((a, b) => a.seq - b.seq)
|
|
100
124
|
.map((e) => ({ ...e, data: e.data == null ? null : structuredClone(e.data) }));
|
|
101
125
|
}
|
|
126
|
+
/** [888] FIRST terminal writer wins(SQL 孪生同款正向 CAS on running/suspended/needs_review,
|
|
127
|
+
* [1.207 codex M1] 负向形漏 blocked/timeout);claim 释放保持无条件(幂等)。 */
|
|
102
128
|
async setTerminal(taskId, status, result, error) {
|
|
103
129
|
const r = this.runs.get(taskId);
|
|
104
130
|
if (!r)
|
|
@@ -110,9 +136,11 @@ export class MemoryRunStore {
|
|
|
110
136
|
r.errorCode = result?.errorCode ?? null;
|
|
111
137
|
r.updatedAt = new Date();
|
|
112
138
|
}
|
|
139
|
+
// Release the single-active-run claim (DELETE FROM task_active WHERE task_id = ?).
|
|
113
140
|
if (this.active.get(r.sessionId) === taskId)
|
|
114
141
|
this.active.delete(r.sessionId);
|
|
115
142
|
}
|
|
143
|
+
/** Durable F4: park NON-terminal `suspended`, KEEP the task_active claim. CAS on running/suspended (reaper-revert guard). */
|
|
116
144
|
async setSuspended(taskId) {
|
|
117
145
|
const r = this.runs.get(taskId);
|
|
118
146
|
if (r && (r.status === "running" || r.status === "suspended")) {
|
|
@@ -120,6 +148,7 @@ export class MemoryRunStore {
|
|
|
120
148
|
r.updatedAt = new Date();
|
|
121
149
|
}
|
|
122
150
|
}
|
|
151
|
+
/** design/80 D-B: park NON-terminal `needs_review`, KEEP the claim. CAS on running/needs_review. */
|
|
123
152
|
async setNeedsReview(taskId) {
|
|
124
153
|
const r = this.runs.get(taskId);
|
|
125
154
|
if (r && (r.status === "running" || r.status === "needs_review")) {
|
|
@@ -127,6 +156,7 @@ export class MemoryRunStore {
|
|
|
127
156
|
r.updatedAt = new Date();
|
|
128
157
|
}
|
|
129
158
|
}
|
|
159
|
+
/** Durable F4 resume: flip suspended/needs_review → running (CAS) + reset cancel/preempt flags. */
|
|
130
160
|
async markResuming(taskId) {
|
|
131
161
|
const r = this.runs.get(taskId);
|
|
132
162
|
if (!r || (r.status !== "suspended" && r.status !== "needs_review"))
|
|
@@ -144,7 +174,11 @@ export class MemoryRunStore {
|
|
|
144
174
|
const r = this.runs.get(taskId);
|
|
145
175
|
return r ? this.toRecord(r) : undefined;
|
|
146
176
|
}
|
|
177
|
+
/** Runs newest-first, keyset on (createdAt, taskId) DESC; optional exact-match filters (owner is exact, like the SQL). */
|
|
147
178
|
async listRuns(opts) {
|
|
179
|
+
// 夜测 N1(2026-07-09,LOW):a non-date cursor.createdAt made the four backends diverge (PG threw a raw
|
|
180
|
+
// DB error; the other three returned an empty page). HTTP's decodeCursor pre-validates, so this is
|
|
181
|
+
// defence-in-depth for direct store callers — normalize ALL backends to the empty page.
|
|
148
182
|
if (opts.cursor && Number.isNaN(Date.parse(opts.cursor.createdAt)))
|
|
149
183
|
return [];
|
|
150
184
|
const cursorAt = opts.cursor ? Date.parse(opts.cursor.createdAt) : undefined;
|
|
@@ -152,31 +186,33 @@ export class MemoryRunStore {
|
|
|
152
186
|
.filter((r) => (opts.status ? r.status === opts.status : true))
|
|
153
187
|
.filter((r) => (opts.jobId ? r.jobId === opts.jobId : true))
|
|
154
188
|
.filter((r) => (opts.source ? r.source === opts.source : true))
|
|
155
|
-
.filter((r) => (opts.owner ? r.owner === opts.owner : true))
|
|
189
|
+
.filter((r) => (opts.owner ? r.owner === opts.owner : true)) // exact (SQL `owner = ?`): a set owner excludes null-owner rows
|
|
156
190
|
.filter((r) => {
|
|
157
191
|
if (cursorAt === undefined)
|
|
158
192
|
return true;
|
|
159
193
|
const t = r.createdAt.getTime();
|
|
160
|
-
return t < cursorAt || (t === cursorAt && r.taskId < opts.cursor.taskId);
|
|
194
|
+
return t < cursorAt || (t === cursorAt && r.taskId < opts.cursor.taskId); // keyset: strictly older, ties by taskId
|
|
161
195
|
})
|
|
162
196
|
.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime() || (a.taskId < b.taskId ? 1 : a.taskId > b.taskId ? -1 : 0));
|
|
163
197
|
return rows.slice(0, opts.limit).map((r) => this.toRecord(r));
|
|
164
198
|
}
|
|
199
|
+
/** DISTINCT sessions newest-first by last activity (the CC /resume picker): latest run's preview/status + first/last/count. */
|
|
165
200
|
async listSessions(opts) {
|
|
166
201
|
const bySession = new Map();
|
|
167
202
|
for (const r of this.runs.values()) {
|
|
168
203
|
if (opts.owner && r.owner !== opts.owner)
|
|
169
|
-
continue;
|
|
204
|
+
continue; // exact owner filter (SQL `owner = ?`)
|
|
170
205
|
const arr = bySession.get(r.sessionId) ?? [];
|
|
171
206
|
arr.push(r);
|
|
172
207
|
bySession.set(r.sessionId, arr);
|
|
173
208
|
}
|
|
174
209
|
const cursorAt = opts.cursor ? Date.parse(opts.cursor.lastActivityAt) : undefined;
|
|
175
|
-
const qlc = opts.q?.toLowerCase();
|
|
210
|
+
const qlc = opts.q?.toLowerCase(); // ?q= search: any-run preview match (the in-memory twin of the SQL EXISTS)
|
|
176
211
|
const summaries = [];
|
|
177
212
|
for (const [sessionId, arr] of bySession) {
|
|
178
213
|
if (qlc && !arr.some((r) => r.objectivePreview?.toLowerCase().includes(qlc)))
|
|
179
214
|
continue;
|
|
215
|
+
// rn=1 = latest run (createdAt DESC, taskId DESC) → preview/status/owner.
|
|
180
216
|
const sorted = [...arr].sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime() || (a.taskId < b.taskId ? 1 : a.taskId > b.taskId ? -1 : 0));
|
|
181
217
|
const latest = sorted[0];
|
|
182
218
|
const times = arr.map((r) => r.createdAt.getTime());
|
|
@@ -190,8 +226,8 @@ export class MemoryRunStore {
|
|
|
190
226
|
runCount: arr.length,
|
|
191
227
|
objectivePreview: latest.objectivePreview,
|
|
192
228
|
lastStatus: latest.status,
|
|
193
|
-
lastRunId: latest.taskId,
|
|
194
|
-
title: null,
|
|
229
|
+
lastRunId: latest.taskId, // K-5c: latest run id = the live-tail re-attach anchor
|
|
230
|
+
title: null, // honest degrade (no session_meta on the memory twin)
|
|
195
231
|
});
|
|
196
232
|
}
|
|
197
233
|
return summaries
|
|
@@ -204,6 +240,7 @@ export class MemoryRunStore {
|
|
|
204
240
|
.sort((a, b) => Date.parse(b.lastActivityAt) - Date.parse(a.lastActivityAt) || (a.sessionId < b.sessionId ? 1 : a.sessionId > b.sessionId ? -1 : 0))
|
|
205
241
|
.slice(0, opts.limit);
|
|
206
242
|
}
|
|
243
|
+
/** E21 (§0.5 delete) — purge the runs ledger for one session, owner-guarded; aborts (returns {active}) if a run is live. */
|
|
207
244
|
async deleteBySession(sessionId, owner) {
|
|
208
245
|
const claimed = this.active.get(sessionId);
|
|
209
246
|
if (claimed !== undefined)
|
|
@@ -218,6 +255,7 @@ export class MemoryRunStore {
|
|
|
218
255
|
}
|
|
219
256
|
return { removed };
|
|
220
257
|
}
|
|
258
|
+
/** 用量扫窗——in-memory 腿:遍历窗内行,投影同 usage-analytics 纯函数(SQL 孪生 parity)。 */
|
|
221
259
|
async usageScan(fromMs, toMs, opts) {
|
|
222
260
|
const limit = Math.min(opts?.limit ?? USAGE_SCAN_LIMIT, USAGE_SCAN_LIMIT);
|
|
223
261
|
const all = [];
|
|
@@ -238,13 +276,14 @@ export class MemoryRunStore {
|
|
|
238
276
|
for (const r of this.runs.values()) {
|
|
239
277
|
if (r.createdAt.getTime() < sinceMs)
|
|
240
278
|
continue;
|
|
241
|
-
const key = JSON.stringify([r.source, r.status]);
|
|
279
|
+
const key = JSON.stringify([r.source, r.status]); // collision-proof + keeps NULL distinct from "" (SQL GROUP BY parity)
|
|
242
280
|
const cur = counts.get(key) ?? { source: r.source, status: r.status, count: 0 };
|
|
243
281
|
cur.count += 1;
|
|
244
282
|
counts.set(key, cur);
|
|
245
283
|
}
|
|
246
284
|
return [...counts.values()];
|
|
247
285
|
}
|
|
286
|
+
/** Fail stale `running` rows (crashed-run backstop) + release task_active for any now-terminal row. */
|
|
248
287
|
async reapStale(olderThanMs) {
|
|
249
288
|
const cutoff = Date.now() - olderThanMs;
|
|
250
289
|
let reaped = 0;
|
|
@@ -256,15 +295,20 @@ export class MemoryRunStore {
|
|
|
256
295
|
reaped += 1;
|
|
257
296
|
}
|
|
258
297
|
}
|
|
298
|
+
// Release the claim for TERMINAL rows only (suspended/needs_review intentionally keep it).
|
|
259
299
|
this.releaseTerminalClaims();
|
|
260
300
|
return reaped;
|
|
261
301
|
}
|
|
302
|
+
/** [868] shared tail of both suspended-run reapers: flip one parked row → failed('approval.expired'), the
|
|
303
|
+
* in-memory twin of the SQL UPDATE (`error`/`error_code` set directly — no result blob to derive from). */
|
|
262
304
|
failExpiredPark(r) {
|
|
263
305
|
r.status = "failed";
|
|
264
306
|
r.error = "approval expired before decision";
|
|
265
307
|
r.errorCode = "approval.expired";
|
|
266
308
|
r.updatedAt = new Date();
|
|
267
309
|
}
|
|
310
|
+
/** Release the claim for TERMINAL rows only — suspended/needs_review keep it (the `DELETE ta … WHERE tr.status
|
|
311
|
+
* NOT IN ('running','suspended','needs_review')` twin, shared by reapStale + the [868] suspended reapers). */
|
|
268
312
|
releaseTerminalClaims() {
|
|
269
313
|
for (const [sessionId, taskId] of [...this.active]) {
|
|
270
314
|
const r = this.runs.get(taskId);
|
|
@@ -272,6 +316,16 @@ export class MemoryRunStore {
|
|
|
272
316
|
this.active.delete(sessionId);
|
|
273
317
|
}
|
|
274
318
|
}
|
|
319
|
+
/**
|
|
320
|
+
* [868] Durable F4 expiry — the local twin of TiDBRunStore.reapSuspended, driven by the injected checkpoint
|
|
321
|
+
* probe instead of a SQL JOIN (formerly a NO-OP, which was one of the five closed doors in the "suspended run
|
|
322
|
+
* locks the session forever" incident). Semantics verbatim from the SQL twin: suspended ∧ updatedAt < cutoff
|
|
323
|
+
* ∧ NOT probe.hasPending(session) → failed 'approval expired before decision' / error_code 'approval.expired'
|
|
324
|
+
* + release the task_active claim. The NOT-pending clause is the design/80 D-D adversarial-blocker guard
|
|
325
|
+
* (see tidb-run-store.ts:577-583): a row whose checkpoint is STILL pending belongs to the checkpoint-state
|
|
326
|
+
* sweeps (SLA deny-sweep / failSuspendedWithExpiredCheckpoint) — time-reaping it here would orphan a model
|
|
327
|
+
* leg on a now-unlocked session. Probe absent ⇒ honest NO-OP (never kill a park without the guard).
|
|
328
|
+
*/
|
|
275
329
|
async reapSuspended(olderThanMs) {
|
|
276
330
|
const probe = this.checkpointProbe;
|
|
277
331
|
if (!probe)
|
|
@@ -283,7 +337,10 @@ export class MemoryRunStore {
|
|
|
283
337
|
continue;
|
|
284
338
|
const snap = r.updatedAt.getTime();
|
|
285
339
|
if (await probe.hasPending(r.sessionId))
|
|
286
|
-
continue;
|
|
340
|
+
continue; // D-D guard: a still-pending checkpoint owns this row
|
|
341
|
+
// codex H2:probe 的 await 让出事件循环——markResuming(approve 恢复)/cancel/新一轮 park 可能已改行。
|
|
342
|
+
// 复核与改写之间无 await(Node 单线程 ⇒ 原子);状态或 updatedAt 变了就放手,绝不覆盖一条已被别腿
|
|
343
|
+
// 认领的行(SQL 孪生靠单条条件 UPDATE 天然原子,这里的 snap 复核就是它的本地等价)。
|
|
287
344
|
if (r.status !== "suspended" || r.updatedAt.getTime() !== snap)
|
|
288
345
|
continue;
|
|
289
346
|
this.failExpiredPark(r);
|
|
@@ -292,6 +349,13 @@ export class MemoryRunStore {
|
|
|
292
349
|
this.releaseTerminalClaims();
|
|
293
350
|
return reaped;
|
|
294
351
|
}
|
|
352
|
+
/**
|
|
353
|
+
* [868] design/80 §3 inv#3 crash-safe backstop — the local twin of TiDBRunStore.failSuspendedWithExpiredCheckpoint
|
|
354
|
+
* (checkpoint-STATE-driven, not time-driven; runs UNCONDITIONALLY every reaper tick, no APPROVAL_TIMEOUT_SEC gate).
|
|
355
|
+
* Semantics verbatim from the SQL twin: (suspended ∨ needs_review) ∧ probe.hasExpired(session) ∧ NOT
|
|
356
|
+
* probe.hasPending(session) → same fail + claim release. The NOT-pending clause covers a re-suspended session
|
|
357
|
+
* that minted a NEW pending gate (wq64gmm5e: an abandoned needs_review park leaks exactly like a suspended one).
|
|
358
|
+
*/
|
|
295
359
|
async failSuspendedWithExpiredCheckpoint() {
|
|
296
360
|
const probe = this.checkpointProbe;
|
|
297
361
|
if (!probe)
|
|
@@ -306,6 +370,7 @@ export class MemoryRunStore {
|
|
|
306
370
|
continue;
|
|
307
371
|
if (await probe.hasPending(r.sessionId))
|
|
308
372
|
continue;
|
|
373
|
+
// codex H2 同款 snap 复核(两个 await 窗都盖住):行被别腿改过就放手。
|
|
309
374
|
if (r.status !== parkedAs || r.updatedAt.getTime() !== snap)
|
|
310
375
|
continue;
|
|
311
376
|
this.failExpiredPark(r);
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory SessionPolicyStore + the service's `deleteBySession` extension (E21 purge / 2c overwrite-dst wipe).
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS (and not core's `InMemorySessionPolicyStore`): core's in-memory/file policy stores implement only
|
|
5
|
+
* the core interface (getRules/putRules/listBySession) — they have NO deletion seam, so neither the E21 session purge
|
|
6
|
+
* nor the 2c `overwrite-dst` subsystem wipe can remove policy rows on a backend that uses them (the SQL twins carry
|
|
7
|
+
* `deleteBySession` as a service extension; see tidb/pg-session-policy-store.ts). This store is the delete-capable
|
|
8
|
+
* in-memory twin. The seam itself is also requested upstream (core: optional `deleteBySession?` on the interface +
|
|
9
|
+
* the File/InMemory impls) — if core lands it, this class can retire in favor of core's.
|
|
10
|
+
*
|
|
11
|
+
* BYTE-MATCH DISCIPLINE: getRules/putRules/listBySession replicate core's `InMemorySessionPolicyStore` semantics
|
|
12
|
+
* exactly (same key shape, same CAS `conflict` on expectedRev mismatch, same tighten-only `loosen_forbidden` gate via
|
|
13
|
+
* core's exported `normalizeRules`/`loosenReasons`/`stripRev`, same rev start/bump). Any divergence is a bug here.
|
|
14
|
+
*/
|
|
1
15
|
import { type PutRulesOptions, type SessionPermissionRules, type SessionPolicyStore, type SessionRulesRecord, type StoredSessionRules } from "@sema-agent/core";
|
|
2
16
|
export declare class MemorySessionPolicyStore implements SessionPolicyStore {
|
|
3
17
|
private readonly map;
|
|
@@ -5,6 +19,9 @@ export declare class MemorySessionPolicyStore implements SessionPolicyStore {
|
|
|
5
19
|
getRules(sessionId: string, principal?: string): Promise<StoredSessionRules | null>;
|
|
6
20
|
putRules(sessionId: string, principal: string | undefined, rules: SessionPermissionRules, opts?: PutRulesOptions): Promise<StoredSessionRules>;
|
|
7
21
|
listBySession(sessionId: string): Promise<SessionRulesRecord[]>;
|
|
22
|
+
/** Purge ALL policy rows for a session, across every principal. Scoped by session_id alone — the caller
|
|
23
|
+
* (E21 route / importSession overwrite-dst) already proved ownership. Shape = core 1.423's optional
|
|
24
|
+
* `SessionPolicyStore.deleteBySession?` seam (`Promise<void>` — the count was incidental; nothing consumed it). */
|
|
8
25
|
deleteBySession(sessionId: string): Promise<void>;
|
|
9
26
|
}
|
|
10
27
|
//# sourceMappingURL=memory-session-policy-store.d.ts.map
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory SessionPolicyStore + the service's `deleteBySession` extension (E21 purge / 2c overwrite-dst wipe).
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS (and not core's `InMemorySessionPolicyStore`): core's in-memory/file policy stores implement only
|
|
5
|
+
* the core interface (getRules/putRules/listBySession) — they have NO deletion seam, so neither the E21 session purge
|
|
6
|
+
* nor the 2c `overwrite-dst` subsystem wipe can remove policy rows on a backend that uses them (the SQL twins carry
|
|
7
|
+
* `deleteBySession` as a service extension; see tidb/pg-session-policy-store.ts). This store is the delete-capable
|
|
8
|
+
* in-memory twin. The seam itself is also requested upstream (core: optional `deleteBySession?` on the interface +
|
|
9
|
+
* the File/InMemory impls) — if core lands it, this class can retire in favor of core's.
|
|
10
|
+
*
|
|
11
|
+
* BYTE-MATCH DISCIPLINE: getRules/putRules/listBySession replicate core's `InMemorySessionPolicyStore` semantics
|
|
12
|
+
* exactly (same key shape, same CAS `conflict` on expectedRev mismatch, same tighten-only `loosen_forbidden` gate via
|
|
13
|
+
* core's exported `normalizeRules`/`loosenReasons`/`stripRev`, same rev start/bump). Any divergence is a bug here.
|
|
14
|
+
*/
|
|
1
15
|
import { normalizeRules, loosenReasons, stripRev, SessionPolicyError, } from "@sema-agent/core";
|
|
2
16
|
export class MemorySessionPolicyStore {
|
|
3
17
|
map = new Map();
|
|
@@ -34,6 +48,9 @@ export class MemorySessionPolicyStore {
|
|
|
34
48
|
}
|
|
35
49
|
return out;
|
|
36
50
|
}
|
|
51
|
+
/** Purge ALL policy rows for a session, across every principal. Scoped by session_id alone — the caller
|
|
52
|
+
* (E21 route / importSession overwrite-dst) already proved ownership. Shape = core 1.423's optional
|
|
53
|
+
* `SessionPolicyStore.deleteBySession?` seam (`Promise<void>` — the count was incidental; nothing consumed it). */
|
|
37
54
|
async deleteBySession(sessionId) {
|
|
38
55
|
for (const k of [...this.map.keys()]) {
|
|
39
56
|
const [sid] = JSON.parse(k);
|
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
import type { MemorySyncCursor } from "@sema-agent/core";
|
|
2
2
|
import type { PgQueryFn } from "./pg-query.js";
|
|
3
|
+
/** Table names (single source). SAME names as the TiDB twin (the two dialects never share one DB). */
|
|
3
4
|
export declare const PG_MEMORY_SYNC_TABLES: {
|
|
4
5
|
readonly syncCursors: "agent_memory_engine_sync_cursors";
|
|
5
6
|
readonly pushQueue: "agent_memory_engine_push_queue";
|
|
6
7
|
readonly history: "agent_memory_engine_history";
|
|
7
8
|
};
|
|
9
|
+
/** What the caller hands `enqueue` — the transport-neutral unit (§3 传输中立包:payload = the full
|
|
10
|
+
* entry, opaque to this store; this queue never interprets it). */
|
|
8
11
|
export interface PushQueueItem {
|
|
12
|
+
/** uuidv7 minted by the caller (time-ordered id = queue order tiebreak). */
|
|
9
13
|
id: string;
|
|
10
14
|
scope: string;
|
|
11
15
|
entryId: string;
|
|
16
|
+
/** JSON-serializable entry payload — stored verbatim, returned parsed. */
|
|
12
17
|
payload: unknown;
|
|
18
|
+
/** Epoch ms at/after which the item is due (caller-injected clock, core precedent). */
|
|
13
19
|
nextAttemptAtMs: number;
|
|
14
20
|
}
|
|
21
|
+
/** A row handed back by `claimDue` — `attempts`/`lastError` reflect the state BEFORE this claim
|
|
22
|
+
* (`fail` is what increments), so the consumer can enforce its attempt cap fail-loud. */
|
|
15
23
|
export interface ClaimedPushQueueItem {
|
|
16
24
|
id: string;
|
|
17
25
|
scope: string;
|
|
@@ -19,18 +27,30 @@ export interface ClaimedPushQueueItem {
|
|
|
19
27
|
payload: unknown;
|
|
20
28
|
attempts: number;
|
|
21
29
|
lastError: string | null;
|
|
30
|
+
/** The lease deadline this claim holds the row until (nowMs + claimLeaseMs). */
|
|
22
31
|
leasedUntilMs: number;
|
|
23
32
|
}
|
|
33
|
+
/** The dialect-neutral contract both twins implement (anti-drift: one shared integration suite,
|
|
34
|
+
* test/memory-sync-store-db-integration.test.ts, runs the SAME scenarios against BOTH engines). */
|
|
24
35
|
export interface MemorySyncStore {
|
|
25
36
|
getCursor(scope: string, peer: string): Promise<MemorySyncCursor | undefined>;
|
|
37
|
+
/** Whole-row replace (round semantics — baseRevs is swapped as one map, never merged). */
|
|
26
38
|
putCursor(cursor: MemorySyncCursor): Promise<void>;
|
|
27
39
|
enqueue(item: PushQueueItem): Promise<void>;
|
|
40
|
+
/** Lease-claim up to `limit` due rows (next_attempt_at <= nowMs), oldest-due first. Claimed rows
|
|
41
|
+
* are invisible to other claimers until `complete`/`fail` or lease expiry (crash self-heal). */
|
|
28
42
|
claimDue(nowMs: number, limit: number): Promise<ClaimedPushQueueItem[]>;
|
|
43
|
+
/** Success = delete the row (outbox posture: the queue only holds outstanding work). */
|
|
29
44
|
complete(id: string): Promise<void>;
|
|
45
|
+
/** Transient failure: attempts+1 (SQL-atomic), record the error, schedule the next attempt. */
|
|
30
46
|
fail(id: string, error: string, nextAttemptAtMs: number): Promise<void>;
|
|
31
47
|
}
|
|
48
|
+
/** Idempotent DDL for the sync plane (PG dialect). Call once at startup. */
|
|
32
49
|
export declare function ensurePgMemorySyncSchema(query: PgQueryFn): Promise<void>;
|
|
50
|
+
/** Options for {@link PgMemorySyncStore}. */
|
|
33
51
|
export interface PgMemorySyncStoreOptions {
|
|
52
|
+
/** How long a `claimDue` lease holds a row invisible before a crashed worker's claim self-heals.
|
|
53
|
+
* Must exceed the consumer's worst-case push round-trip. Default 60s. */
|
|
34
54
|
claimLeaseMs?: number;
|
|
35
55
|
}
|
|
36
56
|
export declare class PgMemorySyncStore implements MemorySyncStore {
|
|
@@ -44,15 +64,26 @@ export declare class PgMemorySyncStore implements MemorySyncStore {
|
|
|
44
64
|
complete(id: string): Promise<void>;
|
|
45
65
|
fail(id: string, error: string, nextAttemptAtMs: number): Promise<void>;
|
|
46
66
|
}
|
|
67
|
+
/** One committed entry version, as the caller hands it to `appendHistory`. `prevRev` links the rev
|
|
68
|
+
* chain (chain head = absent); a `delete` row is the tombstone (no snapshot). */
|
|
47
69
|
export interface MemoryHistoryAppendRow {
|
|
70
|
+
/** Entry id (NOT unique alone — one id has many versions; PK is (id, rev)). */
|
|
48
71
|
id: string;
|
|
72
|
+
/** This version's committed rev (content hash — the same rev the entry plane CAS'd on). */
|
|
49
73
|
rev: string;
|
|
74
|
+
/** The rev this version replaced; absent on the chain head (first add). */
|
|
50
75
|
prevRev?: string;
|
|
51
76
|
op: "add" | "update" | "delete";
|
|
77
|
+
/** ⚠️ DESIGN-DOC AMENDMENT (142-S4 §1.3 has no scope column): the §1.4 export face and the
|
|
78
|
+
* countByScope ops read NEED per-scope addressing, so the column is added here — denormalized
|
|
79
|
+
* from the entry at write time (a deleted entry's row can't be joined back to the entries table). */
|
|
52
80
|
scope: string;
|
|
81
|
+
/** Full entry snapshot for add/update; absent (→ SQL NULL) on delete tombstones. */
|
|
53
82
|
snapshot?: unknown;
|
|
83
|
+
/** Caller-injected clock (core precedent) — the append point stamps the commit time. */
|
|
54
84
|
writtenAtMs: number;
|
|
55
85
|
}
|
|
86
|
+
/** A history row read back (`historyOf`) — same shape with SQL NULLs made explicit. */
|
|
56
87
|
export interface MemoryHistoryRow {
|
|
57
88
|
id: string;
|
|
58
89
|
rev: string;
|
|
@@ -62,11 +93,21 @@ export interface MemoryHistoryRow {
|
|
|
62
93
|
snapshot: unknown | null;
|
|
63
94
|
writtenAtMs: number;
|
|
64
95
|
}
|
|
96
|
+
/** The dialect-neutral history contract both twins implement (append-only: no update/delete face). */
|
|
65
97
|
export interface MemoryHistoryStore {
|
|
98
|
+
/** Batch append. A duplicate (id, rev) is IGNORED idempotently (PG ON CONFLICT DO NOTHING /
|
|
99
|
+
* TiDB no-op ON DUPLICATE KEY) — replaying a batch after a partial failure must not error and
|
|
100
|
+
* must not rewrite committed history rows. Empty input = no-op. */
|
|
66
101
|
appendHistory(rows: readonly MemoryHistoryAppendRow[]): Promise<void>;
|
|
102
|
+
/** All versions of one entry, oldest-first (written_at_ms; the authoritative ORDER within a same-ms
|
|
103
|
+
* burst is the prev_rev chain itself — the sort is the read convenience, rev tie-break keeps it
|
|
104
|
+
* deterministic). */
|
|
67
105
|
historyOf(id: string): Promise<MemoryHistoryRow[]>;
|
|
106
|
+
/** Ops read face (§1.3 保留策略: v1 无界 + 运维计数 — quota/pruning waits for a demand signal). */
|
|
68
107
|
countByScope(scope: string): Promise<number>;
|
|
69
108
|
}
|
|
109
|
+
/** Idempotent DDL for the history table (PG dialect). Separate from the sync-plane ensure so S5.1
|
|
110
|
+
* can wire the write point independently of the S4 sync wiring. */
|
|
70
111
|
export declare function ensurePgMemoryHistorySchema(query: PgQueryFn): Promise<void>;
|
|
71
112
|
export declare class PgMemoryHistoryStore implements MemoryHistoryStore {
|
|
72
113
|
private readonly query;
|
|
@@ -75,5 +116,6 @@ export declare class PgMemoryHistoryStore implements MemoryHistoryStore {
|
|
|
75
116
|
historyOf(id: string): Promise<MemoryHistoryRow[]>;
|
|
76
117
|
countByScope(scope: string): Promise<number>;
|
|
77
118
|
}
|
|
119
|
+
/** Shared row mapper (both dialects' SELECTs project the same column set). */
|
|
78
120
|
export declare function historyRowFrom(r: Record<string, unknown>): MemoryHistoryRow;
|
|
79
121
|
//# sourceMappingURL=memory-sync-store-pg.d.ts.map
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { pgSafeJsonStringify, pgProtocolJsonStringify } from "./pg-safe-json.js";
|
|
2
|
+
/** Table names (single source). SAME names as the TiDB twin (the two dialects never share one DB). */
|
|
2
3
|
export const PG_MEMORY_SYNC_TABLES = {
|
|
3
4
|
syncCursors: "agent_memory_engine_sync_cursors",
|
|
4
5
|
pushQueue: "agent_memory_engine_push_queue",
|
|
5
6
|
history: "agent_memory_engine_history",
|
|
6
7
|
};
|
|
8
|
+
/** Idempotent DDL for the sync plane (PG dialect). Call once at startup. */
|
|
7
9
|
export async function ensurePgMemorySyncSchema(query) {
|
|
8
10
|
await query(`CREATE TABLE IF NOT EXISTS ${PG_MEMORY_SYNC_TABLES.syncCursors} (
|
|
9
11
|
scope varchar(190) NOT NULL,
|
|
@@ -21,13 +23,18 @@ export async function ensurePgMemorySyncSchema(query) {
|
|
|
21
23
|
next_attempt_at bigint NOT NULL,
|
|
22
24
|
last_error text NULL
|
|
23
25
|
)`);
|
|
26
|
+
// Scan face (§1.2): the reaper/consumer sweeps by due time. Perf add-on, never correctness.
|
|
24
27
|
await query(`CREATE INDEX IF NOT EXISTS ${PG_MEMORY_SYNC_TABLES.pushQueue}_next_attempt_idx ON ${PG_MEMORY_SYNC_TABLES.pushQueue} (next_attempt_at)`);
|
|
25
28
|
}
|
|
29
|
+
/** jsonb defense: node-pg hands back parsed objects, but a text-typed round-trip (or a foreign
|
|
30
|
+
* writer) may yield a string — same posture as parseJson in pg-run-store.ts. */
|
|
26
31
|
function fromJsonb(v) {
|
|
27
32
|
if (typeof v === "string")
|
|
28
33
|
return JSON.parse(v);
|
|
29
34
|
return v;
|
|
30
35
|
}
|
|
36
|
+
/** node-pg returns bigint columns as strings (int8 overflows JS numbers in general; ours are epoch
|
|
37
|
+
* ms, safely within 2^53) — normalize defensively. */
|
|
31
38
|
function toMs(v) {
|
|
32
39
|
return typeof v === "number" ? v : Number(v);
|
|
33
40
|
}
|
|
@@ -42,6 +49,7 @@ export class PgMemorySyncStore {
|
|
|
42
49
|
}
|
|
43
50
|
this.claimLeaseMs = lease;
|
|
44
51
|
}
|
|
52
|
+
// ── cursors ────────────────────────────────────────────────────────────────
|
|
45
53
|
async getCursor(scope, peer) {
|
|
46
54
|
const res = await this.query(`SELECT base_revs, updated_at_ms FROM ${PG_MEMORY_SYNC_TABLES.syncCursors} WHERE scope = $1 AND peer = $2`, [scope, peer]);
|
|
47
55
|
const row = res.rows[0];
|
|
@@ -55,18 +63,40 @@ export class PgMemorySyncStore {
|
|
|
55
63
|
};
|
|
56
64
|
}
|
|
57
65
|
async putCursor(cursor) {
|
|
66
|
+
// PK (scope,peer) is the table's ONLY unique key ⇒ ON CONFLICT has exactly one target, no
|
|
67
|
+
// hijack face (纪律:the entries-table ban on blind upserts does NOT apply here).
|
|
58
68
|
await this.query(`INSERT INTO ${PG_MEMORY_SYNC_TABLES.syncCursors} (scope, peer, base_revs, updated_at_ms)
|
|
59
69
|
VALUES ($1, $2, $3::jsonb, $4)
|
|
60
|
-
ON CONFLICT (scope, peer) DO UPDATE SET base_revs = EXCLUDED.base_revs, updated_at_ms = EXCLUDED.updated_at_ms`,
|
|
70
|
+
ON CONFLICT (scope, peer) DO UPDATE SET base_revs = EXCLUDED.base_revs, updated_at_ms = EXCLUDED.updated_at_ms`,
|
|
71
|
+
// codex R11:baseRevs=对账基线(entry id→rev,协议数据)——有损改写=peer 收到的与库里存的
|
|
72
|
+
// 是两份 map,对账决策对着被改写的身份/rev 做。拒绝式(与 outbox/add/update 同族)。
|
|
73
|
+
[cursor.scope, cursor.peer, pgProtocolJsonStringify(cursor.baseRevs, "memory sync cursor baseRevs"), cursor.updatedAtMs]);
|
|
61
74
|
}
|
|
75
|
+
// ── push queue ─────────────────────────────────────────────────────────────
|
|
62
76
|
async enqueue(item) {
|
|
77
|
+
// Plain INSERT, fail-loud on a duplicate id: the caller mints uuidv7 per enqueue, so a dup is a
|
|
78
|
+
// caller bug (or a replay the caller must decide about) — never silently absorbed here.
|
|
63
79
|
await this.query(`INSERT INTO ${PG_MEMORY_SYNC_TABLES.pushQueue} (id, scope, entry_id, payload, attempts, next_attempt_at, last_error)
|
|
64
|
-
VALUES ($1, $2, $3, $4::jsonb, 0, $5, NULL)`,
|
|
80
|
+
VALUES ($1, $2, $3, $4::jsonb, 0, $5, NULL)`,
|
|
81
|
+
// codex R10:payload=协议数据(文档明言 verbatim;rev=内容哈希)——jsonb 列存不了脏值,但有损
|
|
82
|
+
// 改写=payload 与 rev 内部矛盾(消费端永拒/应用脏内容)。协议纪律:拒绝式(与 memory add/update
|
|
83
|
+
// 的 unstorable_bytes 同族;上游 add/update 已拒,此处=纵深防御)。
|
|
84
|
+
[item.id, item.scope, item.entryId, pgProtocolJsonStringify(item.payload, "memory outbox payload"), item.nextAttemptAtMs]);
|
|
65
85
|
}
|
|
66
86
|
async claimDue(nowMs, limit) {
|
|
67
87
|
if (limit <= 0)
|
|
68
88
|
return [];
|
|
69
89
|
const leasedUntilMs = nowMs + this.claimLeaseMs;
|
|
90
|
+
// ONE statement = one implicit transaction: SKIP LOCKED excludes claimers overlapping in time,
|
|
91
|
+
// the next_attempt_at bump (lease) excludes everyone arriving after we commit. RETURNING gives
|
|
92
|
+
// the post-update row, so attempts/last_error are the pre-claim values (fail() is the only
|
|
93
|
+
// incrementer) and next_attempt_at is the lease we just wrote.
|
|
94
|
+
// ⚠️ MATERIALIZED CTE, NOT `WHERE id IN (SELECT … LIMIT n FOR UPDATE SKIP LOCKED)`: the IN-subquery
|
|
95
|
+
// form lets the planner RESCAN the locking subquery (e.g. as a rescanned semi-join inner), and each
|
|
96
|
+
// rescan skips the rows the previous pass locked and picks the NEXT due ones — an over-claim beyond
|
|
97
|
+
// LIMIT. Plan-dependent ⇒ intermittent: caught live on the build-host test DB (claimDue(limit=2) returned
|
|
98
|
+
// 3 rows, serial single-claimer run — the "sync-store env flake" real root cause). AS MATERIALIZED
|
|
99
|
+
// (PG12+) pins one evaluation; UPDATE … FROM joins the pinned id set.
|
|
70
100
|
const res = await this.query(`WITH due AS MATERIALIZED (
|
|
71
101
|
SELECT id FROM ${PG_MEMORY_SYNC_TABLES.pushQueue}
|
|
72
102
|
WHERE next_attempt_at <= $1
|
|
@@ -91,12 +121,19 @@ export class PgMemorySyncStore {
|
|
|
91
121
|
await this.query(`DELETE FROM ${PG_MEMORY_SYNC_TABLES.pushQueue} WHERE id = $1`, [id]);
|
|
92
122
|
}
|
|
93
123
|
async fail(id, error, nextAttemptAtMs) {
|
|
124
|
+
// attempts = attempts + 1 is SQL-atomic — a read-modify-write in JS would race a concurrent
|
|
125
|
+
// failer and lose increments (the attempt cap is the fail-loud stop, it must count honestly).
|
|
94
126
|
await this.query(`UPDATE ${PG_MEMORY_SYNC_TABLES.pushQueue}
|
|
95
127
|
SET attempts = attempts + 1, last_error = $2, next_attempt_at = $3
|
|
96
128
|
WHERE id = $1`, [id, error, nextAttemptAtMs]);
|
|
97
129
|
}
|
|
98
130
|
}
|
|
131
|
+
/** Idempotent DDL for the history table (PG dialect). Separate from the sync-plane ensure so S5.1
|
|
132
|
+
* can wire the write point independently of the S4 sync wiring. */
|
|
99
133
|
export async function ensurePgMemoryHistorySchema(query) {
|
|
134
|
+
// scope column = design-doc amendment (see MemoryHistoryAppendRow.scope). written_at_ms BIGINT
|
|
135
|
+
// (caller-injected epoch ms) instead of the draft's TIMESTAMP — the family's clock discipline
|
|
136
|
+
// (sync_cursors.updated_at_ms precedent; DB clocks never judge anything).
|
|
100
137
|
await query(`CREATE TABLE IF NOT EXISTS ${PG_MEMORY_SYNC_TABLES.history} (
|
|
101
138
|
id char(36) NOT NULL,
|
|
102
139
|
rev varchar(128) NOT NULL,
|
|
@@ -107,6 +144,7 @@ export async function ensurePgMemoryHistorySchema(query) {
|
|
|
107
144
|
written_at_ms bigint NOT NULL,
|
|
108
145
|
PRIMARY KEY (id, rev)
|
|
109
146
|
)`);
|
|
147
|
+
// countByScope / future per-scope export-with-history scan face. Perf add-on, never correctness.
|
|
110
148
|
await query(`CREATE INDEX IF NOT EXISTS ${PG_MEMORY_SYNC_TABLES.history}_scope_idx ON ${PG_MEMORY_SYNC_TABLES.history} (scope)`);
|
|
111
149
|
}
|
|
112
150
|
export class PgMemoryHistoryStore {
|
|
@@ -117,6 +155,9 @@ export class PgMemoryHistoryStore {
|
|
|
117
155
|
async appendHistory(rows) {
|
|
118
156
|
if (rows.length === 0)
|
|
119
157
|
return;
|
|
158
|
+
// ONE multi-row INSERT (the batch is "one applyPatches commit's worth" — small). ON CONFLICT
|
|
159
|
+
// (id, rev) DO NOTHING = idempotent replay; PK is the table's ONLY unique key, so the conflict
|
|
160
|
+
// target is unambiguous (no hijack face — append-only, nothing is ever updated).
|
|
120
161
|
const params = [];
|
|
121
162
|
const tuples = rows.map((r, i) => {
|
|
122
163
|
params.push(r.id, r.rev, r.prevRev ?? null, r.op, r.scope, r.snapshot === undefined || r.snapshot === null ? null : pgSafeJsonStringify(r.snapshot), r.writtenAtMs);
|
|
@@ -135,10 +176,12 @@ export class PgMemoryHistoryStore {
|
|
|
135
176
|
return res.rows.map((r) => historyRowFrom(r));
|
|
136
177
|
}
|
|
137
178
|
async countByScope(scope) {
|
|
179
|
+
// COUNT(*) comes back as a bigint-string from node-pg — normalize (toMs posture).
|
|
138
180
|
const res = await this.query(`SELECT COUNT(*) AS n FROM ${PG_MEMORY_SYNC_TABLES.history} WHERE scope = $1`, [scope]);
|
|
139
181
|
return toMs(res.rows[0]?.n ?? 0);
|
|
140
182
|
}
|
|
141
183
|
}
|
|
184
|
+
/** Shared row mapper (both dialects' SELECTs project the same column set). */
|
|
142
185
|
export function historyRowFrom(r) {
|
|
143
186
|
return {
|
|
144
187
|
id: String(r.id),
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import type { ClaimedPushQueueItem, MemoryHistoryAppendRow, MemoryHistoryRow, MemoryHistoryStore, MemorySyncStore, PushQueueItem } from "./memory-sync-store-pg.js";
|
|
2
2
|
import type { MemorySyncCursor } from "@sema-agent/core";
|
|
3
3
|
import type { Pool } from "mysql2/promise";
|
|
4
|
+
/** Table names (single source) — SAME names as PG_MEMORY_SYNC_TABLES (the two dialects never share
|
|
5
|
+
* one database). */
|
|
4
6
|
export declare const TIDB_MEMORY_SYNC_TABLES: {
|
|
5
7
|
readonly syncCursors: "agent_memory_engine_sync_cursors";
|
|
6
8
|
readonly pushQueue: "agent_memory_engine_push_queue";
|
|
7
9
|
readonly history: "agent_memory_engine_history";
|
|
8
10
|
};
|
|
11
|
+
/** Idempotent DDL for the sync plane (TiDB dialect). Call once at startup.
|
|
12
|
+
* Key budget: utf8mb4 = 4 bytes/char, index cap 3072 bytes ⇒ PK(scope,peer) = 380 chars = 1520 B ✓. */
|
|
9
13
|
export declare function ensureTiDBMemorySyncSchema(pool: Pool): Promise<void>;
|
|
14
|
+
/** Options for {@link TiDBMemorySyncStore} — signature parity with the PG twin. */
|
|
10
15
|
export interface TiDBMemorySyncStoreOptions {
|
|
16
|
+
/** How long a `claimDue` claim holds a row invisible before a crashed worker's claim self-heals.
|
|
17
|
+
* Must exceed the consumer's worst-case push round-trip. Default 60s. */
|
|
11
18
|
claimLeaseMs?: number;
|
|
12
19
|
}
|
|
13
20
|
export declare class TiDBMemorySyncStore implements MemorySyncStore {
|
|
@@ -21,6 +28,8 @@ export declare class TiDBMemorySyncStore implements MemorySyncStore {
|
|
|
21
28
|
complete(id: string): Promise<void>;
|
|
22
29
|
fail(id: string, error: string, nextAttemptAtMs: number): Promise<void>;
|
|
23
30
|
}
|
|
31
|
+
/** Idempotent DDL for the history table (TiDB dialect). Key budget: PK(id,rev) = CHAR(36)+
|
|
32
|
+
* VARCHAR(128) = 164 chars ≤ 3072-byte utf8mb4 index cap ✓; KEY(scope) = 190 chars ✓. */
|
|
24
33
|
export declare function ensureTiDBMemoryHistorySchema(pool: Pool): Promise<void>;
|
|
25
34
|
export declare class TiDBMemoryHistoryStore implements MemoryHistoryStore {
|
|
26
35
|
private readonly pool;
|