@sema-agent/server 7.131.0 → 7.133.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/MIGRATION.md +575 -0
- package/README.md +12 -9
- package/README.zh-CN.md +9 -6
- package/USAGE.md +326 -98
- package/deploy/sema-up/README.md +19 -1
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -2
- package/deploy/sema-up/chart/templates/server.yaml +5 -2
- package/deploy/sema-up/stack/compose.yaml +3 -0
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -2
- package/dist/adoption/plan.d.ts +3 -2
- package/dist/adoption/plan.js +7 -5
- package/dist/adoption/runner.js +3 -10
- package/dist/adoption/sql.d.ts +3 -2
- package/dist/adoption/sql.js +3 -5
- package/dist/adoption/wire.d.ts +4 -1
- package/dist/adoption/wire.js +1 -0
- package/dist/approval-ask-audit-store.d.ts +31 -13
- package/dist/approval-ask-audit-store.js +272 -74
- package/dist/approval-ask-machine.d.ts +15 -0
- package/dist/approval-ask-machine.js +6 -0
- package/dist/approval-ask-retention.d.ts +136 -0
- package/dist/approval-ask-retention.js +102 -0
- package/dist/approval-card.d.ts +82 -20
- package/dist/approval-card.js +46 -16
- package/dist/approval-deny-reasons.d.ts +1 -1
- package/dist/approval.d.ts +9 -0
- package/dist/approval.js +24 -3
- package/dist/audit.d.ts +33 -19
- package/dist/audit.js +12 -16
- package/dist/auth-bridge.d.ts +4 -0
- package/dist/auth-bridge.js +10 -11
- package/dist/bake-runner/main.js +3 -2
- package/dist/boot/deferred-sandbox-path-env.js +1 -1
- package/dist/boot/deployment-mods.d.ts +31 -0
- package/dist/boot/deployment-mods.js +26 -0
- package/dist/boot/execution-env.d.ts +1 -1
- package/dist/boot/execution-env.js +27 -12
- package/dist/boot/execution-lane.js +11 -0
- package/dist/boot/leader.js +2 -0
- package/dist/boot/memory-boundary.d.ts +2 -2
- package/dist/boot/memory-boundary.js +2 -2
- package/dist/boot/memory-consolidation.d.ts +5 -4
- package/dist/boot/memory-consolidation.js +7 -6
- package/dist/boot/org-delivery.d.ts +28 -0
- package/dist/boot/org-delivery.js +20 -0
- package/dist/boot/read-deny-anchor-audit.d.ts +17 -0
- package/dist/boot/read-deny-anchor-audit.js +36 -0
- package/dist/boot/reapers.d.ts +3 -0
- package/dist/boot/reapers.js +21 -1
- package/dist/boot/resolve-spec.d.ts +4 -5
- package/dist/boot/resolve-spec.js +74 -123
- package/dist/boot/runner-deps.d.ts +19 -8
- package/dist/boot/runner-deps.js +15 -2
- package/dist/boot/session-faces.d.ts +2 -7
- package/dist/boot/session-faces.js +4 -2
- package/dist/boot/stage-02-web-admin-pull.js +4 -1
- package/dist/boot/stage-03-store-backend.d.ts +1 -1
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.d.ts +4 -4
- package/dist/boot/stage-05-execution-env.js +7 -10
- package/dist/boot/stage-06-runners.d.ts +4 -2
- package/dist/boot/stage-06-runners.js +11 -7
- package/dist/boot/stage-07-capability-layer.d.ts +4 -2
- package/dist/boot/stage-07-capability-layer.js +27 -6
- package/dist/boot/stage-08-reapers.d.ts +4 -2
- package/dist/boot/stage-08-reapers.js +2 -2
- package/dist/boot/stage-09-leader.d.ts +6 -9
- package/dist/boot/stage-10-http-server.d.ts +6 -9
- package/dist/boot/stage-10-http-server.js +7 -9
- package/dist/boot/stores.d.ts +1 -1
- package/dist/boot/stores.js +7 -8
- package/dist/boot/web-admin.d.ts +4 -3
- package/dist/boot/web-admin.js +186 -98
- package/dist/boot/workflow-orchestration.d.ts +2 -0
- package/dist/boot/workflow-orchestration.js +2 -1
- package/dist/brain.js +25 -25
- package/dist/breaker-key.d.ts +6 -0
- package/dist/breaker-key.js +29 -0
- package/dist/budget.js +5 -4
- package/dist/caller-text-echo.d.ts +23 -0
- package/dist/caller-text-echo.js +21 -0
- package/dist/capabilities/brand-identity.d.ts +26 -0
- package/dist/capabilities/brand-identity.js +27 -0
- package/dist/capabilities/center-plugins.d.ts +7 -0
- package/dist/capabilities/center-plugins.js +1 -1
- package/dist/capabilities/center-prompts.d.ts +32 -59
- package/dist/capabilities/center-prompts.js +18 -32
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/capabilities/engine-capabilities.js +2 -1
- package/dist/capabilities/execution-lane.js +2 -2
- package/dist/capabilities/hands-lane.d.ts +30 -6
- package/dist/capabilities/hands-lane.js +11 -1
- package/dist/capabilities/mcp-probe.d.ts +48 -3
- package/dist/capabilities/mcp-probe.js +47 -135
- package/dist/capabilities/scenarios.d.ts +95 -45
- package/dist/capabilities/scenarios.js +53 -38
- package/dist/capabilities/skills.d.ts +19 -4
- package/dist/capabilities/skills.js +30 -10
- package/dist/capability-facts.d.ts +34 -4
- package/dist/capability-facts.js +28 -2
- package/dist/center-config-tier.d.ts +69 -0
- package/dist/center-config-tier.js +42 -0
- package/dist/checkpoint-identity.d.ts +16 -0
- package/dist/checkpoint-identity.js +19 -0
- package/dist/config-catalog.d.ts +17 -10
- package/dist/config-catalog.js +47 -32
- package/dist/config-d-migration.d.ts +3 -1
- package/dist/config-d-migration.js +2 -2
- package/dist/config-dir-trust.d.ts +114 -0
- package/dist/config-dir-trust.js +388 -0
- package/dist/config-invariants.d.ts +18 -5
- package/dist/config-invariants.js +35 -3
- package/dist/config-lkg.d.ts +9 -9
- package/dist/config-lkg.js +20 -4
- package/dist/config-provider.d.ts +9 -2
- package/dist/config-provider.js +18 -6
- package/dist/config-types.d.ts +75 -20
- package/dist/config-types.js +8 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.js +137 -62
- package/dist/delegated-session-owner.d.ts +185 -0
- package/dist/delegated-session-owner.js +119 -0
- package/dist/device-protocol.d.ts +5 -3
- package/dist/device-protocol.js +1 -1
- package/dist/device-ws-hub.js +21 -2
- package/dist/device-ws-protocol.d.ts +70 -6
- package/dist/device-ws-protocol.js +50 -22
- package/dist/elicitation.js +3 -2
- package/dist/entry-problems.d.ts +34 -0
- package/dist/entry-problems.js +14 -0
- package/dist/env-name-allowlist-knobs.d.ts +12 -2
- package/dist/env-name-allowlist-knobs.js +5 -4
- package/dist/exec-bounds.d.ts +15 -3
- package/dist/exec-bounds.js +4 -0
- package/dist/execution-lane-caps.d.ts +56 -10
- package/dist/execution-lane-caps.js +50 -0
- package/dist/field-conflict.d.ts +43 -0
- package/dist/field-conflict.js +20 -0
- package/dist/fleet/fleet-bus.d.ts +80 -6
- package/dist/fleet/fleet-bus.js +41 -9
- package/dist/hooks/classic-stations.d.ts +91 -0
- package/dist/hooks/classic-stations.js +27 -0
- package/dist/hooks/command-spawn.d.ts +57 -0
- package/dist/hooks/command-spawn.js +139 -0
- package/dist/hooks/hook-llm.d.ts +8 -5
- package/dist/hooks/hook-llm.js +79 -36
- package/dist/hooks/hook-runner.d.ts +349 -95
- package/dist/hooks/hook-runner.js +855 -568
- package/dist/hooks/hook-source.d.ts +44 -0
- package/dist/hooks/hook-source.js +40 -0
- package/dist/http/active-run-conflict.d.ts +5 -13
- package/dist/http/active-run-conflict.js +17 -27
- package/dist/http/admission.d.ts +8 -2
- package/dist/http/admission.js +188 -101
- package/dist/http/approval-sweeps.js +99 -21
- package/dist/http/caller-trust.d.ts +77 -0
- package/dist/http/caller-trust.js +143 -0
- package/dist/http/checkpoint-ctx.d.ts +41 -24
- package/dist/http/checkpoint-ctx.js +23 -16
- package/dist/http/claimed-run.d.ts +14 -0
- package/dist/http/claimed-run.js +15 -0
- package/dist/http/device-placement.d.ts +2 -4
- package/dist/http/device-placement.js +7 -11
- package/dist/http/dispatch.d.ts +0 -4
- package/dist/http/dispatch.js +15 -13
- package/dist/http/durable-run-leg.d.ts +6 -33
- package/dist/http/durable-run-leg.js +36 -10
- package/dist/http/health-self-report.d.ts +7 -5
- package/dist/http/health-self-report.js +4 -18
- package/dist/http/owner-access.d.ts +56 -0
- package/dist/http/owner-access.js +42 -0
- package/dist/http/principal-gate.d.ts +70 -28
- package/dist/http/principal-gate.js +61 -15
- package/dist/http/readiness.d.ts +11 -5
- package/dist/http/readiness.js +10 -3
- package/dist/http/refusal-body.d.ts +21 -0
- package/dist/http/refusal-body.js +4 -0
- package/dist/http/request-guards.d.ts +43 -23
- package/dist/http/request-guards.js +53 -17
- package/dist/http/resume-ctx-read.d.ts +2 -5
- package/dist/http/resume-ctx-read.js +7 -4
- package/dist/http/resume-legs.d.ts +28 -4
- package/dist/http/resume-legs.js +169 -91
- package/dist/http/retired-service-deps.d.ts +43 -0
- package/dist/http/retired-service-deps.js +18 -0
- package/dist/http/route-ctx.d.ts +44 -28
- package/dist/http/route-ctx.js +4 -0
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/a2a-serve.js +3 -4
- package/dist/http/routes/admin-config-refresh.js +1 -1
- package/dist/http/routes/admin-drain.js +1 -1
- package/dist/http/routes/admin-memory-optout.js +5 -1
- package/dist/http/routes/adoption.js +2 -9
- package/dist/http/routes/approvals-assistant.js +49 -48
- package/dist/http/routes/background.js +3 -2
- package/dist/http/routes/capabilities.js +21 -5
- package/dist/http/routes/config-catalog.d.ts +3 -3
- package/dist/http/routes/config-catalog.js +1 -1
- package/dist/http/routes/devices.js +3 -17
- package/dist/http/routes/diagnostics.js +6 -2
- package/dist/http/routes/images.js +6 -7
- package/dist/http/routes/leader.js +1 -8
- package/dist/http/routes/mcp-reconnect.d.ts +1 -1
- package/dist/http/routes/mcp-reconnect.js +3 -2
- package/dist/http/routes/memory-bundle.js +1 -1
- package/dist/http/routes/memory-compliance.js +1 -1
- package/dist/http/routes/memory-consolidation.js +1 -1
- package/dist/http/routes/memory-origin.js +1 -1
- package/dist/http/routes/memory-policy.d.ts +1 -1
- package/dist/http/routes/memory-policy.js +3 -2
- package/dist/http/routes/notify-wake.js +8 -21
- package/dist/http/routes/observability.js +2 -2
- package/dist/http/routes/principal-inbox.d.ts +39 -0
- package/dist/http/routes/principal-inbox.js +76 -0
- package/dist/http/routes/retention-ops.js +2 -9
- package/dist/http/routes/rules.js +5 -18
- package/dist/http/routes/runs.d.ts +5 -0
- package/dist/http/routes/runs.js +34 -107
- package/dist/http/routes/session-sync.js +15 -26
- package/dist/http/routes/sessions.js +30 -40
- package/dist/http/routes/shared-memory.js +2 -13
- package/dist/http/routes/side-query.js +8 -7
- package/dist/http/routes/tasks.js +67 -21
- package/dist/http/routes/workflows.d.ts +351 -0
- package/dist/http/routes/workflows.js +153 -119
- package/dist/http/send.d.ts +33 -10
- package/dist/http/send.js +21 -4
- package/dist/http/server.d.ts +27 -18
- package/dist/http/server.js +34 -6
- package/dist/http/stored-body-replay.js +17 -4
- package/dist/http/submit-ctx.d.ts +25 -0
- package/dist/http/submit-ctx.js +40 -0
- package/dist/http/submit-replay.d.ts +4 -3
- package/dist/http/submit-replay.js +5 -4
- package/dist/http/wire-types.d.ts +11 -8
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -2
- package/dist/lane-home-probe.d.ts +112 -0
- package/dist/lane-home-probe.js +101 -0
- package/dist/leader/endpoint.d.ts +4 -1
- package/dist/leader/endpoint.js +11 -10
- package/dist/limit-refusal.d.ts +59 -0
- package/dist/limit-refusal.js +15 -0
- package/dist/main.js +1 -1
- package/dist/mcp-assertion-header.d.ts +32 -19
- package/dist/mcp-assertion-header.js +10 -9
- package/dist/mcp-tool-faces.d.ts +5 -0
- package/dist/mcp-tool-faces.js +6 -4
- package/dist/memory-project-layer.d.ts +37 -0
- package/dist/memory-project-layer.js +46 -0
- package/dist/memory-scope.d.ts +24 -17
- package/dist/memory-scope.js +24 -8
- package/dist/memory-sync-client.d.ts +27 -13
- package/dist/memory-sync-client.js +107 -18
- package/dist/model-entry-refusal.d.ts +9 -1
- package/dist/model-entry-refusal.js +6 -1
- package/dist/model-plane-face.d.ts +51 -0
- package/dist/model-plane-face.js +24 -0
- package/dist/model-provider.d.ts +44 -12
- package/dist/model-provider.js +21 -2
- package/dist/model-route-endpoint.d.ts +9 -12
- package/dist/model-route-endpoint.js +8 -11
- package/dist/model-route-env.d.ts +22 -0
- package/dist/model-route-env.js +2 -0
- package/dist/model-route-gap.d.ts +60 -30
- package/dist/model-route-gap.js +21 -15
- package/dist/observability/corrupt-read-seat.d.ts +7 -0
- package/dist/observability/corrupt-read-seat.js +9 -0
- package/dist/observability/cost-taxonomy.d.ts +7 -7
- package/dist/observability/err-text.d.ts +6 -0
- package/dist/observability/err-text.js +18 -4
- package/dist/observability/fail-open.d.ts +76 -14
- package/dist/observability/fail-open.js +76 -14
- package/dist/observability/metrics.js +4 -1
- package/dist/observability/prompt-manifest.d.ts +33 -82
- package/dist/observability/prompt-manifest.js +122 -17
- package/dist/observability/run-terminal.js +14 -6
- package/dist/observability/secret-env-scrub.d.ts +13 -1
- package/dist/observability/secret-env-scrub.js +13 -1
- package/dist/observability/tool-trace.d.ts +16 -21
- package/dist/observability/tool-trace.js +58 -49
- package/dist/operator-ask.d.ts +10 -0
- package/dist/operator-ask.js +3 -0
- package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
- package/dist/orchestration/workflow-agent-session-index.js +9 -13
- package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
- package/dist/orchestration/workflow-completion-inbox.js +13 -0
- package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
- package/dist/orchestration/workflow-notify-journal.js +27 -34
- package/dist/orchestration/workflow-park-decision.d.ts +89 -0
- package/dist/orchestration/workflow-park-decision.js +118 -0
- package/dist/org-delivery-gate.d.ts +81 -0
- package/dist/org-delivery-gate.js +59 -0
- package/dist/panel-tool-names.d.ts +23 -0
- package/dist/panel-tool-names.js +8 -0
- package/dist/parked-decide.d.ts +39 -6
- package/dist/parked-decide.js +98 -51
- package/dist/parked-revive-surface.d.ts +9 -2
- package/dist/parked-revive-surface.js +11 -8
- package/dist/per-task-image.d.ts +7 -1
- package/dist/per-task-image.js +3 -3
- package/dist/permission-rule-list.d.ts +1 -1
- package/dist/permission-rule-list.js +2 -2
- package/dist/plain-string-record.d.ts +25 -0
- package/dist/plain-string-record.js +32 -0
- package/dist/plugins/approval-ask-store-file.d.ts +16 -1
- package/dist/plugins/approval-ask-store-file.js +21 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
- package/dist/plugins/approval-ask-store-memory.js +34 -2
- package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
- package/dist/plugins/approval-ask-store-sql.js +37 -1
- package/dist/plugins/blob-backend.d.ts +83 -15
- package/dist/plugins/blob-backend.js +68 -15
- package/dist/plugins/breaker-state-sql.d.ts +2 -2
- package/dist/plugins/breaker-state-sql.js +4 -4
- package/dist/plugins/caching-session-store.d.ts +3 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +28 -4
- package/dist/plugins/checkpoint-store-sql.js +59 -28
- package/dist/plugins/file-history-store-sql.d.ts +5 -2
- package/dist/plugins/file-history-store-sql.js +3 -1
- package/dist/plugins/file-run-store.d.ts +5 -13
- package/dist/plugins/file-run-store.js +9 -0
- package/dist/plugins/fork-routing-session-store.d.ts +9 -1
- package/dist/plugins/fork-routing-session-store.js +12 -1
- package/dist/plugins/host-platform.d.ts +2 -0
- package/dist/plugins/host-platform.js +2 -1
- package/dist/plugins/k8s-bg-scripts.d.ts +11 -0
- package/dist/plugins/k8s-bg-scripts.js +22 -0
- package/dist/plugins/local-checkpoint-store.d.ts +2 -0
- package/dist/plugins/local-checkpoint-store.js +11 -3
- package/dist/plugins/local-session-store.d.ts +1 -1
- package/dist/plugins/local-session-store.js +1 -1
- package/dist/plugins/local-session-window.d.ts +39 -0
- package/dist/plugins/local-session-window.js +54 -0
- package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
- package/dist/plugins/mailbox-store-sql.d.ts +30 -48
- package/dist/plugins/mailbox-store-sql.js +77 -52
- package/dist/plugins/memory-embedder-fingerprint.js +2 -1
- package/dist/plugins/memory-run-store.d.ts +5 -13
- package/dist/plugins/memory-run-store.js +8 -0
- package/dist/plugins/one-time-migrations.d.ts +245 -93
- package/dist/plugins/one-time-migrations.js +668 -207
- package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
- package/dist/plugins/org-delivery-quota-store.js +228 -0
- package/dist/plugins/permission-rule-store-sql.d.ts +13 -7
- package/dist/plugins/permission-rule-store-sql.js +4 -18
- package/dist/plugins/pg-pool.js +39 -7
- package/dist/plugins/pg-session-storage.d.ts +20 -8
- package/dist/plugins/pg-session-storage.js +34 -21
- package/dist/plugins/remote-env-adb.d.ts +12 -12
- package/dist/plugins/remote-env-adb.js +21 -6
- package/dist/plugins/remote-env-device.js +3 -0
- package/dist/plugins/remote-env-e2b.d.ts +1 -1
- package/dist/plugins/remote-env-e2b.js +21 -9
- package/dist/plugins/remote-env-host.d.ts +9 -9
- package/dist/plugins/remote-env-host.js +10 -32
- package/dist/plugins/remote-env-k8s.d.ts +103 -38
- package/dist/plugins/remote-env-k8s.js +288 -95
- package/dist/plugins/remote-env-local-docker.d.ts +27 -13
- package/dist/plugins/remote-env-local-docker.js +82 -11
- package/dist/plugins/remote-env-ssh.d.ts +21 -12
- package/dist/plugins/remote-env-ssh.js +117 -5
- package/dist/plugins/remote-shell.d.ts +0 -1
- package/dist/plugins/remote-shell.js +1 -2
- package/dist/plugins/retention-store-sql.js +6 -2
- package/dist/plugins/run-store-sql.d.ts +16 -14
- package/dist/plugins/run-store-sql.js +22 -2
- package/dist/plugins/schema-consistency.d.ts +54 -0
- package/dist/plugins/schema-consistency.js +52 -0
- package/dist/plugins/schema-indexes.js +2 -0
- package/dist/plugins/send-user-file.js +2 -2
- package/dist/plugins/session-epoch-anchor.d.ts +39 -0
- package/dist/plugins/session-epoch-anchor.js +22 -0
- package/dist/plugins/session-store.d.ts +18 -8
- package/dist/plugins/session-store.js +15 -4
- package/dist/plugins/shared-memory-store-sql.d.ts +9 -3
- package/dist/plugins/shared-memory-store-sql.js +5 -16
- package/dist/plugins/sql-driver.d.ts +205 -1
- package/dist/plugins/sql-driver.js +325 -13
- package/dist/plugins/sql-errors.d.ts +64 -0
- package/dist/plugins/sql-errors.js +57 -0
- package/dist/plugins/store-backend.d.ts +36 -1
- package/dist/plugins/store-backend.js +42 -15
- package/dist/plugins/store-contracts.d.ts +42 -0
- package/dist/plugins/store-contracts.js +1 -0
- package/dist/plugins/tidb-pool.d.ts +6 -1
- package/dist/plugins/tidb-pool.js +44 -10
- package/dist/plugins/tidb-session-storage.d.ts +8 -11
- package/dist/plugins/tidb-session-storage.js +6 -16
- package/dist/plugins/tidb-session-store.d.ts +24 -4
- package/dist/plugins/tidb-session-store.js +29 -5
- package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
- package/dist/plugins/workflow-journal-store-sql.js +19 -6
- package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
- package/dist/plugins/workflow-run-store-sql.js +50 -9
- package/dist/posture-source.d.ts +18 -10
- package/dist/posture-source.js +4 -1
- package/dist/project-identity.d.ts +45 -6
- package/dist/project-identity.js +162 -8
- package/dist/project-layer-key.d.ts +28 -0
- package/dist/project-layer-key.js +29 -0
- package/dist/prompts-domain-validate.d.ts +17 -61
- package/dist/prompts-domain-validate.js +9 -119
- package/dist/question.js +3 -2
- package/dist/read-deny-entry.d.ts +25 -0
- package/dist/read-deny-entry.js +12 -0
- package/dist/read-face-posture.d.ts +37 -11
- package/dist/read-face-posture.js +32 -3
- package/dist/request-key-closure.d.ts +9 -2
- package/dist/request-key-closure.js +11 -5
- package/dist/request-value-closure.d.ts +5 -0
- package/dist/request-value-closure.js +11 -3
- package/dist/rule-entry-list.d.ts +38 -11
- package/dist/rule-entry-list.js +106 -30
- package/dist/rules-consent.js +3 -4
- package/dist/run-acceptance.d.ts +19 -3
- package/dist/run-acceptance.js +13 -1
- package/dist/run-local.js +54 -24
- package/dist/runs.d.ts +15 -8
- package/dist/runs.js +35 -1
- package/dist/runtime-caps-resolver.d.ts +16 -6
- package/dist/runtime-caps-resolver.js +18 -5
- package/dist/sandbox-pkg-source.d.ts +19 -1
- package/dist/sandbox-pkg-source.js +29 -7
- package/dist/security.d.ts +87 -9
- package/dist/security.js +52 -9
- package/dist/server-secret-env.d.ts +44 -18
- package/dist/server-secret-env.js +49 -8
- package/dist/session-error-wire.d.ts +19 -2
- package/dist/session-error-wire.js +5 -1
- package/dist/session-incarnation.d.ts +15 -5
- package/dist/session-incarnation.js +16 -9
- package/dist/session-titled-frame.d.ts +33 -0
- package/dist/session-titled-frame.js +4 -0
- package/dist/session-titler.d.ts +9 -1
- package/dist/session-titler.js +27 -6
- package/dist/spec-fields.d.ts +28 -16
- package/dist/spec-fields.js +66 -54
- package/dist/sql-engine-posture.d.ts +31 -4
- package/dist/sql-engine-posture.js +36 -1
- package/dist/stored-request-tool-axes-m19.d.ts +19 -4
- package/dist/stored-request-tool-axes-m19.js +30 -2
- package/dist/task-a2a.d.ts +9 -1
- package/dist/task-a2a.js +73 -47
- package/dist/task-cwd.d.ts +1 -1
- package/dist/task-mcp.d.ts +46 -58
- package/dist/task-mcp.js +82 -107
- package/dist/task-settings.d.ts +95 -108
- package/dist/task-settings.js +77 -98
- package/dist/text-bidi.d.ts +1 -48
- package/dist/text-bidi.js +3 -5
- package/dist/tighten-only-seats.d.ts +150 -0
- package/dist/tighten-only-seats.js +196 -0
- package/dist/tool-approval.d.ts +304 -88
- package/dist/tool-approval.js +623 -239
- package/dist/trace/core-keyset-guard.d.ts +122 -20
- package/dist/trace/engine-notice-wire.d.ts +11 -3
- package/dist/trace/engine-notice-wire.js +8 -1
- package/dist/trace/exit-seat.d.ts +28 -0
- package/dist/trace/exit-seat.js +76 -0
- package/dist/trace/ledger-events.d.ts +6 -3
- package/dist/trace/ledger-sink.js +4 -1
- package/dist/trace/model-segment.js +1 -1
- package/dist/trace/project.d.ts +98 -17
- package/dist/trace/project.js +98 -50
- package/dist/trace/projection-table.d.ts +100 -0
- package/dist/trace/projection-table.js +130 -0
- package/dist/trace/redact.d.ts +54 -0
- package/dist/trace/redact.js +778 -152
- package/dist/trace/self-minted-wire.d.ts +345 -1
- package/dist/trace/self-minted-wire.js +117 -1
- package/dist/trace/wire-projection-faces.d.ts +377 -3
- package/dist/trace/wire-projection-faces.js +164 -1
- package/dist/url-refusal.js +2 -0
- package/dist/web-admin-client/apply-effective.d.ts +12 -0
- package/dist/web-admin-client/apply-effective.js +56 -5
- package/dist/web-admin-client/candidate-gate.d.ts +6 -6
- package/dist/web-admin-client/candidate-gate.js +3 -3
- package/dist/web-admin-client/facade.d.ts +1 -1
- package/dist/web-admin-client/facade.js +1 -1
- package/dist/web-admin-client/http-client.js +0 -6
- package/dist/web-admin-client/read-face.js +5 -9
- package/dist/web-admin-client/read-warnings.d.ts +13 -0
- package/dist/web-admin-client/read-warnings.js +10 -0
- package/dist/web-admin-client/skills-mcp.d.ts +3 -0
- package/dist/web-admin-client/skills-mcp.js +11 -9
- package/dist/web-admin-client/types.d.ts +2 -3
- package/dist/workspace-cache.d.ts +35 -0
- package/dist/workspace-cache.js +36 -0
- package/dist/workspace-space.d.ts +3 -2
- package/dist/workspace-space.js +2 -0
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +65 -10
- package/package.json +8 -4
- package/scripts/drain-check-local.mjs +34 -1
- package/scripts/drain-check.mysql.sql +30 -2
- package/scripts/drain-check.pg.sql +29 -2
- package/dist/capabilities/memory-notice.d.ts +0 -138
- package/dist/capabilities/memory-notice.js +0 -64
- package/dist/capabilities/prompt.d.ts +0 -17
- package/dist/capabilities/prompt.js +0 -6
- package/dist/mcp-content-origin.d.ts +0 -34
- package/dist/mcp-content-origin.js +0 -10
- package/dist/tool-axis-words.d.ts +0 -27
- package/dist/tool-axis-words.js +0 -9
- package/dist/wire-name-bound.d.ts +0 -14
- package/dist/wire-name-bound.js +0 -13
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The local (File) leg's **bounded window** of one session — the reader that loads `[floor .. leaf]` instead of the whole tree
|
|
3
|
+
* (today: the session view, `audit.ts#buildSessionAuditLocal`). The twin of `TiDBSessionStorage.wake` / `PgSessionStorage.wake`.
|
|
4
|
+
*
|
|
5
|
+
* ## One rule: the view reads what the run reads
|
|
6
|
+
* A run on this backend wakes the **whole tree** (`LocalSessionStore.acquire` → core `FileSessionRepo.open`): core resolves the
|
|
7
|
+
* log's leaf and the engine walks the branch from that leaf to the root. A window shows the same thing only when it is cut **from
|
|
8
|
+
* that branch**, keeps **that leaf**, and carries the reading below its floor — the halves of core's bounded-storage contract:
|
|
9
|
+
* · the window = core's `boundedTail` over the **branch path** (root → the run's leaf), not over the log in file order. The log
|
|
10
|
+
* also holds abandoned branches (a resumeAt moves the leaf in place): cut in file order, the floor can come from a compaction
|
|
11
|
+
* the branch no longer contains — the view then reads a context the run does not (a rewind inside the kept tail), or cannot be
|
|
12
|
+
* built at all (a rewind past the last compaction: the branch's parent lies below the cut);
|
|
13
|
+
* · the leaf = the one core resolved over the whole log, handed to the window as is (a window that re-resolved its leaf from its
|
|
14
|
+
* own entries would read a leaf entry on the branch a second time and land on an entry it does not hold);
|
|
15
|
+
* · below the floor = `getEpochAnchor`, the one reading every windowed storage shares ({@link scanEpochAnchor}), paged over the
|
|
16
|
+
* branch below the floor — so the record the engine reads is the one the run's walk reaches.
|
|
17
|
+
* Read-only: the log is read once (`exportEntries`, pure), no append log is opened, and the window refuses writes.
|
|
18
|
+
*
|
|
19
|
+
* ## Cost: one linear walk
|
|
20
|
+
* The branch is the `parentId` chain from the leaf — the chain core's `getPathToRoot` follows, with the same stop rule (an entry
|
|
21
|
+
* without a parent ends it; a parent the log does not hold is `invalid_session`). It is walked here once, in linear time: core
|
|
22
|
+
* 7.52.0 builds its path with `unshift` (quadratic in the branch length — seconds on a long session, on the event loop), and the
|
|
23
|
+
* view must cost a window read, not a whole-branch walk. Every later read of the window goes through core's own walk, bounded by
|
|
24
|
+
* the floor.
|
|
25
|
+
*/
|
|
26
|
+
import { BaseSessionStorage } from "@sema-agent/core";
|
|
27
|
+
export declare class LocalSessionWindow extends BaseSessionStorage {
|
|
28
|
+
/** The branch below the floor, root first (empty when the window is the whole branch). */
|
|
29
|
+
private readonly below;
|
|
30
|
+
private constructor();
|
|
31
|
+
appendEntry(): Promise<void>;
|
|
32
|
+
setLeafId(): Promise<void>;
|
|
33
|
+
/** `SessionStorage.getEpochAnchor?()` — the nearest carrier on the branch below the floor, as stored ({@link scanEpochAnchor}).
|
|
34
|
+
* A row's `seq` is its position on the branch; the whole branch is in memory, so one page holds every row. */
|
|
35
|
+
getEpochAnchor(): Promise<unknown>;
|
|
36
|
+
/** Wake the window of `sessionId` under the local data root `root`; `null` if there is no such session. */
|
|
37
|
+
static wake(root: string, sessionId: string): Promise<LocalSessionWindow | null>;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=local-session-window.d.ts.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { BaseSessionStorage, InMemorySessionStorage, SessionError, boundedTail } from "@sema-agent/core";
|
|
2
|
+
import { createLocalSessionRepo } from "./local-session-store.js";
|
|
3
|
+
import { scanEpochAnchor } from "./session-epoch-anchor.js";
|
|
4
|
+
export class LocalSessionWindow extends BaseSessionStorage {
|
|
5
|
+
below;
|
|
6
|
+
constructor(metadata, window, leafId, floorEntryId, below) {
|
|
7
|
+
super(metadata, window, leafId, { floorEntryId });
|
|
8
|
+
this.below = below;
|
|
9
|
+
}
|
|
10
|
+
async appendEntry() {
|
|
11
|
+
throw new SessionError("storage", "LocalSessionWindow is a read-only view of a session — write through the session store");
|
|
12
|
+
}
|
|
13
|
+
async setLeafId() {
|
|
14
|
+
throw new SessionError("storage", "LocalSessionWindow is a read-only view of a session — write through the session store");
|
|
15
|
+
}
|
|
16
|
+
async getEpochAnchor() {
|
|
17
|
+
return scanEpochAnchor(this.below.length, async (beforeSeq) => this.below.slice(0, beforeSeq).map((entry, seq) => ({ seq, entry })).reverse(), (row) => row.entry);
|
|
18
|
+
}
|
|
19
|
+
static async wake(root, sessionId) {
|
|
20
|
+
const repo = createLocalSessionRepo(root);
|
|
21
|
+
let log;
|
|
22
|
+
try {
|
|
23
|
+
log = await repo.exportEntries(sessionId);
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
if (e.code === "not_found")
|
|
27
|
+
return null;
|
|
28
|
+
throw e;
|
|
29
|
+
}
|
|
30
|
+
const metadata = (await repo.list()).find((m) => m.id === sessionId) ?? { id: sessionId, createdAt: new Date().toISOString() };
|
|
31
|
+
const whole = new InMemorySessionStorage({ entries: log });
|
|
32
|
+
const leafId = await whole.getLeafId();
|
|
33
|
+
const branch = await branchOf(whole, leafId, log.length);
|
|
34
|
+
const { tail, floorEntryId } = boundedTail(branch);
|
|
35
|
+
return new LocalSessionWindow(metadata, tail, leafId, floorEntryId, branch.slice(0, branch.length - tail.length));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function branchOf(whole, leafId, logLength) {
|
|
39
|
+
const fromLeaf = [];
|
|
40
|
+
let current = leafId === null ? undefined : await whole.getEntry(leafId);
|
|
41
|
+
while (current) {
|
|
42
|
+
fromLeaf.push(current);
|
|
43
|
+
if (!current.parentId)
|
|
44
|
+
break;
|
|
45
|
+
if (fromLeaf.length > logLength)
|
|
46
|
+
throw new SessionError("invalid_session", `Entry ${current.id} is on a parent cycle`);
|
|
47
|
+
const parent = await whole.getEntry(current.parentId);
|
|
48
|
+
if (!parent)
|
|
49
|
+
throw new SessionError("invalid_session", `Entry ${current.parentId} not found`);
|
|
50
|
+
current = parent;
|
|
51
|
+
}
|
|
52
|
+
return fromLeaf.reverse();
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=local-session-window.js.map
|
|
@@ -66,8 +66,9 @@ export interface MailboxRecipientLifecycle {
|
|
|
66
66
|
* **只打标**——不删消息、不动租约、不碰盒行的高水位(理由 = core T2 试剂盒的两格副作用判据,见模块头)。
|
|
67
67
|
* 幂等(重复 retire 只更新时刻/名字)。
|
|
68
68
|
*
|
|
69
|
-
* @returns 是否真的落了一张耐久墓碑。`false`
|
|
70
|
-
* (拒的方向不变,退化的只有拒绝措辞与「正在删除中」那一行的可见性)
|
|
69
|
+
* @returns 是否真的落了一张耐久墓碑。`false` 有两种,都是「没落」:① 本后端没有预删除态,箱已被直接 `drop`
|
|
70
|
+
* (拒的方向不变,退化的只有拒绝措辞与「正在删除中」那一行的可见性);② 这只键收件箱的键判官不收(SQL 两孪生:没有箱可打标,
|
|
71
|
+
* 这只键的 `append` 本来就以判官那一句拒,不带墓碑码)。
|
|
71
72
|
*/
|
|
72
73
|
retireRecipient(scope: string, handle: string, at: number, label?: string): Promise<boolean>;
|
|
73
74
|
/** 本 scope 下句柄以 `handlePrefix` 开头的墓碑。无预删除态的后端恒返回空。 */
|
|
@@ -1,49 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MailboxStore SQL twins([ref] S3c server pg 半场,[ref] 提货单①)——core teammate 信箱
|
|
3
|
-
* (SendMessage 链)的 TiDB/PG 双方言实现。挂载缝 = S3c 行为车的 `RunnerDeps.mailboxStore`(core
|
|
4
|
-
* 命名预告,[ref]§三);本文件先就绪 store 半场,行为车到货接线。
|
|
5
|
-
*
|
|
6
|
-
* 语义真源 = core `InMemoryMailboxStore`(dist/core/mailbox-store.js)+ [ref] 定谳(core 1.372
|
|
7
|
-
* 终版文本,conformance 无两可):
|
|
8
|
-
* 1. **同主重 claim = 续期 + 纳新**(crash-retry 正形):活 lease 只挡**别的** owner;同 owner 任意
|
|
9
|
-
* 时刻重 claim 重设 TTL 并拿到当前全部未 ack 消息(maxSeq 随最新行走)。
|
|
10
|
-
* 2. **seq = 盒生命周期内不复用**:box 行携 `next_seq`,分配与 append 同事务;`drop` 删整盒(含 box 行)
|
|
11
|
-
* = 生命周期终结,重建从 1(core 定谳:行随盒亡,dedup 键携 handle)。⚠️ **`reap` 自 [ref](core
|
|
12
|
-
* 2026-07-25)起不再与 drop 同句**:reap 是收件人活着时的龄扫,**清箱保高水位**(删消息、清租约、盒行与
|
|
13
|
-
* next_seq 留着)——本文件 2026-09-03(车BF,codex r1 [high])才跟上;此前 reap 删盒行 ⇒ 下一条 append 从 1
|
|
14
|
-
* 重铸,陈旧 ack 可删掉一条没人见过的新消息。跨进程试剂盒明钉此条。
|
|
15
|
-
* 3. **ack 带 owner 围栏**(MB1,core 1.452 起;原「无守卫、信任 claim 赢者链」已被推翻):当前持租者才删
|
|
16
|
-
* `seq <= upToSeq` 的行;lease 的 `maxSeq <= upToSeq` 时顺带清 lease(全量 ack = 释放)。**围栏的判决报出来**
|
|
17
|
-
* (core 7.30.0 #1036,S-616):放行 ⇒ `{ acked: true }`(删 0 行也是 true —— 契约是「围栏放行」不是「删了几行」),
|
|
18
|
-
* 盒不在 / 无人持租 / 非持租者 ⇒ `{ acked: false }`;逐格与 core `InMemoryMailboxStore.ack` 同答。
|
|
19
|
-
* 4. **lease 过期判 = 严格 `expiresAt > now` 才挡**;`releaseLease` 只在 owner 匹配时清。
|
|
20
|
-
* 5. `peekCount` 含已 lease 消息(可见性 ≠ lease 态);空盒 claim = null(box 行在而消息 0 也 null)。
|
|
21
|
-
* 6. **reap = SQL 全量真扫**(core File 实现只扫已加载盒 = 进程内 backstop,[ref] 确认 SQL 是全量
|
|
22
|
-
* 真扫的正确层):`maxAgeMs` 缺省 → 0;按盒 newest `sentAt < now - maxAgeMs` **清箱**(删消息 + 清租约,
|
|
23
|
-
* 盒行/高水位保留,见定谳 2 的 [ref] 半句);空盒(有 box 行无消息)不清(InMemory 同形——`newest ===
|
|
24
|
-
* undefined` 不动)。
|
|
25
|
-
*
|
|
26
|
-
* 键列 = 字节等价(TiDB VARBINARY / PG COLLATE "C",roster F2 案):scope/handle/lease_owner 的
|
|
27
|
-
* `=` 必须纯字节——PAD SPACE 近撞不得穿隔离/抢别人 lease。PG unstorable bytes([ref] 三层定谳):
|
|
28
|
-
* `content` 是消息**内容面**(收件人将读到、注入对话)→ 与 PG 转录 payload 同族 lossy(pgSanitizeText,
|
|
29
|
-
* U+FFFD 标记,内容不失行);**身份键 scope/handle/owner/from 拒绝式**(pgHasUnstorable →
|
|
30
|
-
* PgUnstorableError fail-loud——attribution/路由键清洗形变 = 行与查询键错位,协议数据同向)。TiDB
|
|
31
|
-
* 侧 LONGTEXT/VARBINARY verbatim(replay 面定谳)。
|
|
32
|
-
*
|
|
33
|
-
* 并发正确性(InMemory 单进程无此象限、SQL 多副本有;发车复审 F2/F3/F4 批):
|
|
34
|
-
* - **锁序统一「盒行 → 消息行」**(append/claim/ack/drop/reap 五面同序)——ack/drop/reap 原为
|
|
35
|
-
* 消息先行,与 claim 的盒先行构成 ABBA 死锁形;统一后同盒并发只在盒行锁上排队。
|
|
36
|
-
* - drop/reap 先删/锁**盒行**再动消息:反序留「消息已删、盒行未删」窗,并发 append 完整穿过后
|
|
37
|
-
* 盒重建会撞存活的孤儿消息行(PK 冲突→此后 append 永久失败)。
|
|
38
|
-
* - reap 候删 = 事务外粗筛 + 事务内**逐盒锁定重验**(当前读 newest):窗内新到的消息救活盒,
|
|
39
|
-
* 绝不连带删信;盒行已被并发 drop = 跳过不计。
|
|
40
|
-
* - append 的 ensure 与 FOR UPDATE 之间被并发 drop 提交 = 同事务内重建一次(语义 = drop 后重建,
|
|
41
|
-
* seq 从 1)。建盒动词 = 形 A(S-127)`ON DUPLICATE KEY UPDATE <pk> = <pk>`:重复键取 X 锁,与随后的
|
|
42
|
-
* `FOR UPDATE` **同锁模式**(`INSERT IGNORE` 取 S 再升 X = InnoDB 上的并发死锁形,B-013)。
|
|
43
|
-
* - 键长 > 190 字节写入即拒(fail-loud):截断键与全长查询参数字节比对恒 miss(分配读空行崩/隔离键
|
|
44
|
-
* 错位)。守卫在**语句之前**,与建行动词无关 —— 换成 ON DUPLICATE 之后超长键由引擎直接报错(严格
|
|
45
|
-
* 模式下 IGNORE 会把它降级成静默截断),方向=更响亮,守卫依旧是第一道。
|
|
46
|
-
*/
|
|
47
1
|
import type { Pool as MySqlPool } from "mysql2/promise";
|
|
48
2
|
import type { Pool as PgPool } from "pg";
|
|
49
3
|
import type { MailboxAckResult, MailboxAppendMessage, MailboxLease, MailboxStore } from "@sema-agent/core";
|
|
@@ -57,6 +11,36 @@ export declare const MAILBOX_MSG_TABLE = "mailbox_message";
|
|
|
57
11
|
* —— `mailbox` 行是**盒**事实(next_seq / lease),墓碑是**收件人**事实,两者的生命周期本来就不同
|
|
58
12
|
* (`drop` 同时终结两者 —— 墓碑随箱亡,理由全文见 `mailbox-recipient-lifecycle.ts` 模块头)。 */
|
|
59
13
|
export declare const MAILBOX_TOMBSTONE_TABLE = "mailbox_tombstone";
|
|
14
|
+
/**
|
|
15
|
+
* 身份键(`scope` / `handle` / lease `owner`)的 UTF-8 字节上界 = 键列宽(TiDB `VARBINARY(190)`;PG 列按字符,本判官在两方言上都按字节拒)。
|
|
16
|
+
*/
|
|
17
|
+
export declare const MAILBOX_KEY_MAX_UTF8_BYTES = 190;
|
|
18
|
+
/**
|
|
19
|
+
* 🔴 **「这只串能当收件箱的身份键吗」的唯一判官**(三只键列:`scope` / `handle` / lease `owner`;两方言同一只、同一句拒因)。一只串当得了键 ⇔
|
|
20
|
+
* ⓪ `scope` 非空(引擎 InMemory 同一句「without a scope」:没有箱址;handle / owner 空照引擎参照形放行);
|
|
21
|
+
* ① **良构 Unicode**(没有孤立代理):两只驱动按 UTF-8 送库时都把孤立代理换成 U+FFFD 的三字节 ⇒ 库里它与另一只键同键(TiDB 写进别人的箱、续不了自己的租约;
|
|
22
|
+
* PG 另把它当不可存字节);
|
|
23
|
+
* ② **不含控制字符**(C0 含 NUL、DEL):键要能逐字节寻址([ref] 试剂盒:NUL 键两后端一致拒、不得串箱);
|
|
24
|
+
* ③ **UTF-8 字节不超过键列宽**:截断的键与全长查询参数逐字节比对恒 miss(seq 分配读空行崩 / 隔离键错位)。
|
|
25
|
+
* 答第一道不过的拒因,都过 ⇒ `undefined`。**判官拒的键没有箱**,两方言每一只入口在语句之前问它,一条律两种答法:建状态的两面(`append` 的 scope 与 handle、
|
|
26
|
+
* `claimLease` 写进租约的 owner)拒就抛这一句({@link assertMailboxKey});其余每一面(读 / 清 / 打标 / 放租 / 确认)照「箱不在」答、不把键送进驱动({@link keyless}):
|
|
27
|
+
* `peekCount` 0、`claimLease` null、`ack` `{ acked: false }`、`releaseLease` / `drop` 无事、`reap` 0(候选扫描交回的句柄同判:判官拒的跳过、零语句)、
|
|
28
|
+
* `retireRecipient` false(没落墓碑 —— 没有箱可打标;这只键的 append 本来就以判官那一句拒)、`listRetiredRecipients` 空。跨主体投递门在扣投递额度之前问它
|
|
29
|
+
* (收件人 scope 就是这只键,`org-delivery-gate.ts`)。库里已有的这种键(升级前写下的)由一次性迁移 M27 删掉,判据是同一只判官({@link storedMailboxKeyless})。没有第二道键判。
|
|
30
|
+
*/
|
|
31
|
+
export declare function mailboxKeyProblem(what: MailboxKeyColumn, v: string): string | undefined;
|
|
32
|
+
/** 收件箱的三只键列(判官的 `what`;闭集)。 */
|
|
33
|
+
export type MailboxKeyColumn = "scope" | "handle" | "owner";
|
|
34
|
+
/** 库里读回的一对键列判官拒不拒(与入口同一只判官;字节先无损读成串,读不成 = 不良构)。`reap` 的候选句柄与一次性迁移 M27 都按它判。 */
|
|
35
|
+
export declare function storedMailboxKeyless(scopeKey: unknown, handle: unknown): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* 收件箱表族:三张表的键都是 `(scope_key, handle)`。次序 = 锁序(盒行 → 消息行 → 墓碑行;盒行先删的理由见 `drop`)。
|
|
38
|
+
* 「丢掉一只箱」= 按这个次序逐表按键删 —— `drop` 与一次性迁移 M27 是同一组语句({@link mailboxKeyDeleteSql})。
|
|
39
|
+
*/
|
|
40
|
+
export declare const MAILBOX_KEYED_TABLES: readonly ["mailbox", "mailbox_message", "mailbox_tombstone"];
|
|
41
|
+
export type MailboxKeyedTable = (typeof MAILBOX_KEYED_TABLES)[number];
|
|
42
|
+
/** 按键删收件箱表族的一张表(两方言;参数 = [scope_key, handle])。 */
|
|
43
|
+
export declare function mailboxKeyDeleteSql(dialect: "tidb" | "pg", table: MailboxKeyedTable): string;
|
|
60
44
|
/** 店侧日志座(可选;boot 注入 `Logger`)。7.58.0 合并重扫 [medium]:坏行的 fail-closed 抛必须**响亮**——core 唯一的
|
|
61
45
|
* claimLease 调用方(peer-session-drain)吞掉该错,店不记这一笔就成了「静默永久卡箱」。抛之前记
|
|
62
46
|
* `mailbox_message_column_corrupt`(scope/handle/seq/column/code),运维按 seq 修行。
|
|
@@ -106,8 +90,6 @@ export declare class PgMailboxStore implements MailboxStore, MailboxRecipientLif
|
|
|
106
90
|
readonly crossProcessSafe = true;
|
|
107
91
|
constructor(pool: PgPool, logger?: MailboxStoreLogger | undefined);
|
|
108
92
|
private tx;
|
|
109
|
-
/** 身份键拒绝式([ref] 协议纪律):scope/handle/owner/from 清洗形变 = 路由/attribution 错位。 */
|
|
110
|
-
private assertIdentity;
|
|
111
93
|
append(scope: string, handle: string, msg: MailboxAppendMessage): Promise<number>;
|
|
112
94
|
claimLease(scope: string, handle: string, owner: string, ttlMs: number, now?: number): Promise<MailboxLease | null>;
|
|
113
95
|
ack(scope: string, handle: string, owner: string, upToSeq: number): Promise<MailboxAckResult>;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { isUtf8 } from "node:buffer";
|
|
1
2
|
import { MAILBOX_INVALID_PEER_META_CODE, MAILBOX_TOMBSTONED_RECIPIENT_CODE, MailboxStoreError, readMailboxPeerMeta } from "@sema-agent/core";
|
|
2
3
|
import { pgHasUnstorable, pgSanitizeText, PgUnstorableError } from "./pg-safe-json.js";
|
|
4
|
+
import { isWellFormedUnicode } from "../principal-jwt.js";
|
|
3
5
|
import { ensureIndexes } from "./ensure-index.js";
|
|
4
6
|
import { escapeLike } from "./sql-escape.js";
|
|
5
7
|
import { decodeNullableJsonColumn, foldJsonColumn, isJsonColumnBodyProblem, jsonColumnText, readStringArrayColumn } from "./sql-json-column.js";
|
|
@@ -19,20 +21,38 @@ function rowToTombstone(r) {
|
|
|
19
21
|
const label = r.label === null || r.label === undefined ? undefined : bufToStr(r.label);
|
|
20
22
|
return { handle: bufToStr(r.handle), retiredAt: Number(r.retired_at_ms), ...(label !== undefined ? { label } : {}) };
|
|
21
23
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
export const MAILBOX_KEY_MAX_UTF8_BYTES = 190;
|
|
25
|
+
export function mailboxKeyProblem(what, v) {
|
|
26
|
+
if (what === "scope" && (v === undefined || v === ""))
|
|
27
|
+
return "MailboxStore: refusing a message without a scope (an empty scope addresses no box)";
|
|
28
|
+
if (!isWellFormedUnicode(v))
|
|
29
|
+
return `MailboxStore: ${what} is not well-formed Unicode (lone surrogate) (refusing — the driver would store it as U+FFFD and alias a different key)`;
|
|
30
|
+
if ([...v].some((ch) => ch.charCodeAt(0) < 0x20 || ch.charCodeAt(0) === 0x7f))
|
|
31
|
+
return `MailboxStore: ${what} contains control characters (refusing — identity keys must be byte-exact addressable)`;
|
|
32
|
+
if (Buffer.byteLength(v, "utf8") > MAILBOX_KEY_MAX_UTF8_BYTES) {
|
|
33
|
+
return `MailboxStore: ${what} exceeds the ${MAILBOX_KEY_MAX_UTF8_BYTES}-byte key column (refusing — a truncated key would desync from its byte-exact lookups)`;
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
26
36
|
}
|
|
27
|
-
function
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
37
|
+
function assertMailboxKey(what, v) {
|
|
38
|
+
const problem = mailboxKeyProblem(what, v);
|
|
39
|
+
if (problem !== undefined)
|
|
40
|
+
throw new Error(problem);
|
|
31
41
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
42
|
+
const keyless = (scope, handle, owner) => mailboxKeyProblem("scope", scope) !== undefined || mailboxKeyProblem("handle", handle) !== undefined || (owner !== undefined && mailboxKeyProblem("owner", owner) !== undefined);
|
|
43
|
+
function storedKeyText(v) {
|
|
44
|
+
if (!Buffer.isBuffer(v))
|
|
45
|
+
return String(v);
|
|
46
|
+
return isUtf8(v) ? v.toString("utf8") : undefined;
|
|
47
|
+
}
|
|
48
|
+
export function storedMailboxKeyless(scopeKey, handle) {
|
|
49
|
+
const scope = storedKeyText(scopeKey);
|
|
50
|
+
const h = storedKeyText(handle);
|
|
51
|
+
return scope === undefined || h === undefined || keyless(scope, h);
|
|
52
|
+
}
|
|
53
|
+
export const MAILBOX_KEYED_TABLES = [MAILBOX_TABLE, MAILBOX_MSG_TABLE, MAILBOX_TOMBSTONE_TABLE];
|
|
54
|
+
export function mailboxKeyDeleteSql(dialect, table) {
|
|
55
|
+
return dialect === "tidb" ? `DELETE FROM ${table} WHERE scope_key = ? AND handle = ?` : `DELETE FROM ${table} WHERE scope_key = $1 AND handle = $2`;
|
|
36
56
|
}
|
|
37
57
|
function bufToStr(v) {
|
|
38
58
|
return Buffer.isBuffer(v) ? v.toString("utf8") : String(v);
|
|
@@ -220,11 +240,8 @@ export class TiDBMailboxStore {
|
|
|
220
240
|
}
|
|
221
241
|
}
|
|
222
242
|
async append(scope, handle, msg) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
assertIdentityChars("handle", handle);
|
|
226
|
-
assertKeyBytes("scope", scope);
|
|
227
|
-
assertKeyBytes("handle", handle);
|
|
243
|
+
assertMailboxKey("scope", scope);
|
|
244
|
+
assertMailboxKey("handle", handle);
|
|
228
245
|
const hopChain = encodeHopChain(msg.hopChain);
|
|
229
246
|
const peerMeta = encodePeerMeta(msg.peerMeta);
|
|
230
247
|
return this.tx(async (c) => {
|
|
@@ -244,6 +261,9 @@ export class TiDBMailboxStore {
|
|
|
244
261
|
});
|
|
245
262
|
}
|
|
246
263
|
async claimLease(scope, handle, owner, ttlMs, now = Date.now()) {
|
|
264
|
+
assertMailboxKey("owner", owner);
|
|
265
|
+
if (keyless(scope, handle))
|
|
266
|
+
return null;
|
|
247
267
|
return this.tx(async (c) => {
|
|
248
268
|
const [boxes] = (await c.query(`SELECT lease_owner, lease_expires_at_ms FROM ${MAILBOX_TABLE} WHERE scope_key = ? AND handle = ? FOR UPDATE`, [scope, handle]));
|
|
249
269
|
if (boxes.length === 0)
|
|
@@ -263,6 +283,8 @@ export class TiDBMailboxStore {
|
|
|
263
283
|
});
|
|
264
284
|
}
|
|
265
285
|
async ack(scope, handle, owner, upToSeq) {
|
|
286
|
+
if (keyless(scope, handle, owner))
|
|
287
|
+
return { acked: false };
|
|
266
288
|
return this.tx(async (c) => {
|
|
267
289
|
const [rows] = (await c.query(`SELECT lease_owner FROM ${MAILBOX_TABLE} WHERE scope_key = ? AND handle = ? FOR UPDATE`, [scope, handle]));
|
|
268
290
|
if (rows.length === 0 || rows[0].lease_owner == null || bufToStr(rows[0].lease_owner) !== owner)
|
|
@@ -274,28 +296,33 @@ export class TiDBMailboxStore {
|
|
|
274
296
|
});
|
|
275
297
|
}
|
|
276
298
|
async releaseLease(scope, handle, owner) {
|
|
299
|
+
if (keyless(scope, handle, owner))
|
|
300
|
+
return;
|
|
277
301
|
await this.pool.query(`UPDATE ${MAILBOX_TABLE} SET lease_owner = NULL, lease_expires_at_ms = NULL, lease_max_seq = NULL
|
|
278
302
|
WHERE scope_key = ? AND handle = ? AND lease_owner = ?`, [scope, handle, owner]);
|
|
279
303
|
}
|
|
280
304
|
async peekCount(scope, handle) {
|
|
305
|
+
if (keyless(scope, handle))
|
|
306
|
+
return 0;
|
|
281
307
|
const [rows] = (await this.pool.query(`SELECT COUNT(*) AS n FROM ${MAILBOX_MSG_TABLE} WHERE scope_key = ? AND handle = ?`, [scope, handle]));
|
|
282
308
|
return Number(rows[0].n);
|
|
283
309
|
}
|
|
284
310
|
async drop(scope, handle) {
|
|
311
|
+
if (keyless(scope, handle))
|
|
312
|
+
return;
|
|
285
313
|
await this.tx(async (c) => {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
await c.query(`DELETE FROM ${MAILBOX_TOMBSTONE_TABLE} WHERE scope_key = ? AND handle = ?`, [scope, handle]);
|
|
314
|
+
for (const table of MAILBOX_KEYED_TABLES)
|
|
315
|
+
await c.query(mailboxKeyDeleteSql("tidb", table), [scope, handle]);
|
|
289
316
|
});
|
|
290
317
|
}
|
|
291
318
|
async reap(scope, now, opts) {
|
|
292
|
-
if (opts?.maxAgeMs === undefined)
|
|
319
|
+
if (opts?.maxAgeMs === undefined || mailboxKeyProblem("scope", scope) !== undefined)
|
|
293
320
|
return 0;
|
|
294
321
|
const cutoff = now - opts.maxAgeMs;
|
|
295
322
|
const [cands] = (await this.pool.query(`SELECT handle FROM ${MAILBOX_MSG_TABLE} WHERE scope_key = ? GROUP BY handle HAVING MAX(sent_at_ms) < ?`, [scope, cutoff]));
|
|
296
|
-
|
|
323
|
+
const handles = cands.filter((r) => !storedMailboxKeyless(scope, r.handle)).map((r) => bufToStr(r.handle));
|
|
324
|
+
if (handles.length === 0)
|
|
297
325
|
return 0;
|
|
298
|
-
const handles = cands.map((r) => bufToStr(r.handle));
|
|
299
326
|
return this.tx(async (c) => {
|
|
300
327
|
let dropped = 0;
|
|
301
328
|
for (const h of handles) {
|
|
@@ -313,11 +340,8 @@ export class TiDBMailboxStore {
|
|
|
313
340
|
});
|
|
314
341
|
}
|
|
315
342
|
async retireRecipient(scope, handle, at, label) {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
assertIdentityChars("handle", handle);
|
|
319
|
-
assertKeyBytes("scope", scope);
|
|
320
|
-
assertKeyBytes("handle", handle);
|
|
343
|
+
if (keyless(scope, handle))
|
|
344
|
+
return false;
|
|
321
345
|
await this.tx(async (c) => {
|
|
322
346
|
await c.query(`INSERT INTO ${MAILBOX_TABLE} (scope_key, handle, scope, next_seq) VALUES (?, ?, ?, 1) ON DUPLICATE KEY UPDATE scope_key = scope_key`, [scope, handle, scope]);
|
|
323
347
|
await c.query(`SELECT next_seq FROM ${MAILBOX_TABLE} WHERE scope_key = ? AND handle = ? FOR UPDATE`, [scope, handle]);
|
|
@@ -327,6 +351,8 @@ export class TiDBMailboxStore {
|
|
|
327
351
|
return true;
|
|
328
352
|
}
|
|
329
353
|
async listRetiredRecipients(scope, handlePrefix) {
|
|
354
|
+
if (mailboxKeyProblem("scope", scope) !== undefined)
|
|
355
|
+
return [];
|
|
330
356
|
const [rows] = await this.pool.query(`SELECT handle, retired_at_ms, label FROM ${MAILBOX_TOMBSTONE_TABLE} WHERE scope_key = ? AND handle LIKE ? ESCAPE '\\\\'`, [scope, `${escapeLike(handlePrefix)}%`]);
|
|
331
357
|
return rows.map(rowToTombstone);
|
|
332
358
|
}
|
|
@@ -355,18 +381,12 @@ export class PgMailboxStore {
|
|
|
355
381
|
c.release();
|
|
356
382
|
}
|
|
357
383
|
}
|
|
358
|
-
assertIdentity(what, v) {
|
|
359
|
-
if (v !== undefined && pgHasUnstorable(v))
|
|
360
|
-
throw new PgUnstorableError(`mailbox ${what}`);
|
|
361
|
-
}
|
|
362
384
|
async append(scope, handle, msg) {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
385
|
+
assertMailboxKey("scope", scope);
|
|
386
|
+
assertMailboxKey("handle", handle);
|
|
387
|
+
if (msg.from !== undefined && pgHasUnstorable(msg.from))
|
|
388
|
+
throw new PgUnstorableError("mailbox from");
|
|
367
389
|
const content = pgSanitizeText(msg.content);
|
|
368
|
-
assertKeyBytes("scope", scope);
|
|
369
|
-
assertKeyBytes("handle", handle);
|
|
370
390
|
const hopChain = encodeHopChain(msg.hopChain);
|
|
371
391
|
const peerMeta = encodePeerMeta(msg.peerMeta);
|
|
372
392
|
return this.tx(async (c) => {
|
|
@@ -394,7 +414,9 @@ export class PgMailboxStore {
|
|
|
394
414
|
});
|
|
395
415
|
}
|
|
396
416
|
async claimLease(scope, handle, owner, ttlMs, now = Date.now()) {
|
|
397
|
-
|
|
417
|
+
assertMailboxKey("owner", owner);
|
|
418
|
+
if (keyless(scope, handle))
|
|
419
|
+
return null;
|
|
398
420
|
return this.tx(async (c) => {
|
|
399
421
|
const { rows: boxes } = await c.query(`SELECT lease_owner, lease_expires_at_ms FROM ${MAILBOX_TABLE} WHERE scope_key = $1 AND handle = $2 FOR UPDATE`, [scope, handle]);
|
|
400
422
|
if (boxes.length === 0)
|
|
@@ -411,6 +433,8 @@ export class PgMailboxStore {
|
|
|
411
433
|
});
|
|
412
434
|
}
|
|
413
435
|
async ack(scope, handle, owner, upToSeq) {
|
|
436
|
+
if (keyless(scope, handle, owner))
|
|
437
|
+
return { acked: false };
|
|
414
438
|
return this.tx(async (c) => {
|
|
415
439
|
const r = (await c.query(`SELECT lease_owner FROM ${MAILBOX_TABLE} WHERE scope_key = $1 AND handle = $2 FOR UPDATE`, [scope, handle]));
|
|
416
440
|
if (r.rows.length === 0 || r.rows[0].lease_owner == null || bufToStr(r.rows[0].lease_owner) !== owner)
|
|
@@ -422,31 +446,33 @@ export class PgMailboxStore {
|
|
|
422
446
|
});
|
|
423
447
|
}
|
|
424
448
|
async releaseLease(scope, handle, owner) {
|
|
425
|
-
|
|
449
|
+
if (keyless(scope, handle, owner))
|
|
450
|
+
return;
|
|
426
451
|
await this.pool.query(`UPDATE ${MAILBOX_TABLE} SET lease_owner = NULL, lease_expires_at_ms = NULL, lease_max_seq = NULL
|
|
427
452
|
WHERE scope_key = $1 AND handle = $2 AND lease_owner = $3`, [scope, handle, owner]);
|
|
428
453
|
}
|
|
429
454
|
async peekCount(scope, handle) {
|
|
430
|
-
if (
|
|
455
|
+
if (keyless(scope, handle))
|
|
431
456
|
return 0;
|
|
432
457
|
const { rows } = await this.pool.query(`SELECT COUNT(*) AS n FROM ${MAILBOX_MSG_TABLE} WHERE scope_key = $1 AND handle = $2`, [scope, handle]);
|
|
433
458
|
return Number(rows[0].n);
|
|
434
459
|
}
|
|
435
460
|
async drop(scope, handle) {
|
|
461
|
+
if (keyless(scope, handle))
|
|
462
|
+
return;
|
|
436
463
|
await this.tx(async (c) => {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
await c.query(`DELETE FROM ${MAILBOX_TOMBSTONE_TABLE} WHERE scope_key = $1 AND handle = $2`, [scope, handle]);
|
|
464
|
+
for (const table of MAILBOX_KEYED_TABLES)
|
|
465
|
+
await c.query(mailboxKeyDeleteSql("pg", table), [scope, handle]);
|
|
440
466
|
});
|
|
441
467
|
}
|
|
442
468
|
async reap(scope, now, opts) {
|
|
443
|
-
if (opts?.maxAgeMs === undefined)
|
|
469
|
+
if (opts?.maxAgeMs === undefined || mailboxKeyProblem("scope", scope) !== undefined)
|
|
444
470
|
return 0;
|
|
445
471
|
const cutoff = now - opts.maxAgeMs;
|
|
446
472
|
const { rows: cands } = await this.pool.query(`SELECT handle FROM ${MAILBOX_MSG_TABLE} WHERE scope_key = $1 GROUP BY handle HAVING MAX(sent_at_ms) < $2`, [scope, cutoff]);
|
|
447
|
-
|
|
473
|
+
const handles = cands.filter((r) => !storedMailboxKeyless(scope, r.handle)).map((r) => String(r.handle));
|
|
474
|
+
if (handles.length === 0)
|
|
448
475
|
return 0;
|
|
449
|
-
const handles = cands.map((r) => String(r.handle));
|
|
450
476
|
return this.tx(async (c) => {
|
|
451
477
|
let dropped = 0;
|
|
452
478
|
for (const h of handles) {
|
|
@@ -464,11 +490,8 @@ export class PgMailboxStore {
|
|
|
464
490
|
});
|
|
465
491
|
}
|
|
466
492
|
async retireRecipient(scope, handle, at, label) {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
this.assertIdentity("handle", handle);
|
|
470
|
-
assertKeyBytes("scope", scope);
|
|
471
|
-
assertKeyBytes("handle", handle);
|
|
493
|
+
if (keyless(scope, handle))
|
|
494
|
+
return false;
|
|
472
495
|
const bounded = boundedLabel(label);
|
|
473
496
|
const stored = bounded === null ? null : pgSanitizeText(bounded);
|
|
474
497
|
await this.tx(async (c) => {
|
|
@@ -480,6 +503,8 @@ export class PgMailboxStore {
|
|
|
480
503
|
return true;
|
|
481
504
|
}
|
|
482
505
|
async listRetiredRecipients(scope, handlePrefix) {
|
|
506
|
+
if (mailboxKeyProblem("scope", scope) !== undefined)
|
|
507
|
+
return [];
|
|
483
508
|
const { rows } = await this.pool.query(`SELECT handle, retired_at_ms, label FROM ${MAILBOX_TOMBSTONE_TABLE} WHERE scope_key = $1 AND handle LIKE $2 ESCAPE '\\'`, [scope, `${escapeLike(handlePrefix)}%`]);
|
|
484
509
|
return rows.map(rowToTombstone);
|
|
485
510
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { PG_MEMORY_ENGINE_TABLES } from "./memory-engine-pg.js";
|
|
3
3
|
import { createZodColumnReader, decodeJsonColumn, jsonColumnText, SqlJsonColumnError } from "./sql-json-column.js";
|
|
4
|
+
import { echoCallerText } from "../caller-text-echo.js";
|
|
4
5
|
export const PG_MEMORY_ENGINE_META_TABLE = "agent_memory_engine_meta";
|
|
5
6
|
export const EMBEDDER_IDENTITY_META_KEY = "embedder_identity";
|
|
6
7
|
export const CAS_MAX_ROUNDS = 3;
|
|
@@ -22,7 +23,7 @@ function parseStoredText(text) {
|
|
|
22
23
|
catch (err) {
|
|
23
24
|
if (!(err instanceof SqlJsonColumnError))
|
|
24
25
|
throw err;
|
|
25
|
-
return { kind: "unreadable", raw: `${text
|
|
26
|
+
return { kind: "unreadable", raw: `${echoCallerText(text, { maxChars: 160 })} [${err.problem}: ${echoCallerText(err.message, { maxChars: 120 })}]` };
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
29
|
async function readStored(query) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type UsageRow } from "../usage-analytics.js";
|
|
2
2
|
import type { TaskStatus } from "@sema-agent/core";
|
|
3
|
-
import { type CreateRunOutcome, type NewRunMeta, type RunIdemBinding, type RunRecord, type SessionSummary, type RunEvent, type PersistedTaskResult, type LatestRunRef } from "./store-contracts.js";
|
|
3
|
+
import { type FenceLanded, type InProcessClaimFence, type CreateRunOutcome, type NewRunMeta, type RunIdemBinding, type RunListQuery, type RunRecord, type SessionSummary, type RunEvent, type PersistedTaskResult, type LatestRunRef } from "./store-contracts.js";
|
|
4
4
|
import type { LedgerEventType } from "../trace/ledger-events.js";
|
|
5
5
|
import { type SpaceCommitClaim, type SpaceCommitReading, type SpaceCommitState } from "../workspace-space-commit.js";
|
|
6
6
|
/**
|
|
@@ -22,7 +22,7 @@ export interface RunStoreCheckpointProbe {
|
|
|
22
22
|
hasPending(sessionId: string): Promise<boolean>;
|
|
23
23
|
hasExpired(sessionId: string): Promise<boolean>;
|
|
24
24
|
}
|
|
25
|
-
export declare class MemoryRunStore {
|
|
25
|
+
export declare class MemoryRunStore implements InProcessClaimFence {
|
|
26
26
|
private readonly runs;
|
|
27
27
|
/** sessionId → taskId — the single-active-run claim (the `task_active` table). */
|
|
28
28
|
private readonly active;
|
|
@@ -82,19 +82,11 @@ export declare class MemoryRunStore {
|
|
|
82
82
|
* [ref](codex R1 [medium]):认领 = 接管 `instanceId`(= 当前持有副本;SQL 孪生同注)。CAS 输不改。 */
|
|
83
83
|
markResuming(taskId: string, instanceId: string): Promise<boolean>;
|
|
84
84
|
getActiveTaskId(sessionId: string): Promise<string | undefined>;
|
|
85
|
+
/** 认领当写栅栏用(契约 = `store-contracts.ts` 的 `InProcessClaimFence`):判、刷新活性与 `write` 是同一个同步段。 */
|
|
86
|
+
whileHoldingClaim(sessionId: string, taskId: string, write: () => FenceLanded): boolean;
|
|
85
87
|
getRun(taskId: string): Promise<RunRecord | undefined>;
|
|
86
88
|
/** Runs newest-first, keyset on (createdAt, taskId) DESC; optional exact-match filters (owner is exact, like the SQL). */
|
|
87
|
-
listRuns(opts:
|
|
88
|
-
status?: string;
|
|
89
|
-
jobId?: string;
|
|
90
|
-
source?: string;
|
|
91
|
-
owner?: string;
|
|
92
|
-
cursor?: {
|
|
93
|
-
createdAt: string;
|
|
94
|
-
taskId: string;
|
|
95
|
-
};
|
|
96
|
-
limit: number;
|
|
97
|
-
}): Promise<RunRecord[]>;
|
|
89
|
+
listRuns(opts: RunListQuery): Promise<RunRecord[]>;
|
|
98
90
|
/**
|
|
99
91
|
* S-297 —— 这个会话**最近一条腿**的窄指针({@link SqlRunStore.latestRunForSession} 的孪生:同一个排序口径
|
|
100
92
|
* `createdAt DESC, taskId DESC`,与本店 {@link MemoryRunStore.listSessions} 挑 `rn=1` 那一行的比较器逐字同一份)。
|
|
@@ -231,6 +231,14 @@ export class MemoryRunStore {
|
|
|
231
231
|
async getActiveTaskId(sessionId) {
|
|
232
232
|
return this.active.get(sessionId);
|
|
233
233
|
}
|
|
234
|
+
whileHoldingClaim(sessionId, taskId, write) {
|
|
235
|
+
const r = this.runs.get(taskId);
|
|
236
|
+
if (this.active.get(sessionId) !== taskId || r === undefined || r.status !== "running")
|
|
237
|
+
return false;
|
|
238
|
+
r.updatedAt = new Date();
|
|
239
|
+
write();
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
234
242
|
async getRun(taskId) {
|
|
235
243
|
const r = this.runs.get(taskId);
|
|
236
244
|
return r ? this.toRecord(r) : undefined;
|