@sema-agent/server 7.146.0 → 7.147.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 +384 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +170 -66
- package/deploy/facts/lanes.json +7 -0
- package/deploy/sema-up/README.md +2 -2
- package/deploy/sema-up/chart/templates/_helpers.tpl +22 -0
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -4
- package/deploy/sema-up/chart/templates/server.yaml +5 -4
- package/deploy/sema-up/chart/values.yaml +1 -1
- package/deploy/sema-up/cluster-up.sh +2 -1
- package/deploy/sema-up/lib/flagshape.sh +4 -0
- package/deploy/sema-up/lib/lanes.json +2 -5
- package/deploy/sema-up/sema-up.sh +12 -9
- package/deploy/sema-up/stack/compose.yaml +5 -4
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -3
- package/dist/approval-card.d.ts +4 -4
- package/dist/approval.d.ts +3 -3
- package/dist/audit.js +2 -2
- package/dist/bench/s1/live-deps.js +3 -1
- package/dist/boot/crash-last.js +2 -1
- package/dist/boot/device-lane.js +5 -5
- package/dist/boot/engine-lease.d.ts +12 -11
- package/dist/boot/execution-env.d.ts +2 -1
- package/dist/boot/execution-env.js +45 -33
- package/dist/boot/execution-lane.d.ts +37 -9
- package/dist/boot/execution-lane.js +74 -20
- package/dist/boot/exit-boundary.d.ts +1 -1
- package/dist/boot/exit-last.js +2 -1
- package/dist/boot/governance-seams.d.ts +2 -2
- package/dist/boot/leader.js +1 -1
- package/dist/boot/memory-boundary.d.ts +11 -11
- package/dist/boot/memory-boundary.js +3 -3
- package/dist/boot/memory-consolidation.d.ts +13 -24
- package/dist/boot/memory-consolidation.js +0 -13
- package/dist/boot/org-memory.js +3 -2
- package/dist/boot/parked-revive-gate.d.ts +1 -1
- package/dist/boot/parked-revive-gate.js +1 -1
- package/dist/boot/reapers.js +1 -1
- package/dist/boot/resolve-spec.js +91 -111
- package/dist/boot/retention-lane.d.ts +4 -42
- package/dist/boot/session-faces.d.ts +1 -0
- package/dist/boot/session-faces.js +8 -2
- package/dist/boot/stage-01-config.d.ts +1 -1
- package/dist/boot/stage-01-config.js +6 -2
- package/dist/boot/stage-02-web-admin-pull.d.ts +1 -1
- package/dist/boot/stage-02-web-admin-pull.js +10 -8
- package/dist/boot/stage-03-store-backend.d.ts +1 -1
- package/dist/boot/stage-04-stores.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.d.ts +2 -2
- package/dist/boot/stage-05-execution-env.js +3 -3
- package/dist/boot/stage-06-runners.d.ts +3 -3
- package/dist/boot/stage-06-runners.js +1 -3
- package/dist/boot/stage-07-capability-layer.d.ts +3 -3
- package/dist/boot/stage-07-capability-layer.js +4 -9
- package/dist/boot/stage-08-reapers.d.ts +3 -3
- package/dist/boot/stage-09-leader.d.ts +4 -3
- package/dist/boot/stage-10-http-server.d.ts +4 -3
- package/dist/boot/stage-10-http-server.js +2 -1
- package/dist/boot/stores.d.ts +9 -0
- package/dist/boot/stores.js +18 -7
- package/dist/boot/web-admin.js +3 -3
- package/dist/capabilities/center-plugins.d.ts +2 -0
- package/dist/capabilities/center-plugins.js +6 -2
- package/dist/capabilities/composite-members.d.ts +1 -0
- package/dist/capabilities/composite-members.js +1 -0
- package/dist/capabilities/execution-lane.d.ts +7 -7
- package/dist/capabilities/execution-lane.js +2 -2
- package/dist/capabilities/hands-lane.d.ts +1 -1
- package/dist/capabilities/scenarios.d.ts +32 -18
- package/dist/capabilities/scenarios.js +13 -9
- package/dist/capabilities/settings-contract.d.ts +29 -0
- package/dist/capabilities/settings-contract.js +14 -0
- package/dist/capabilities/skills.d.ts +5 -5
- package/dist/capability-facts.d.ts +38 -0
- package/dist/capability-facts.js +34 -1
- package/dist/center-credential-renewer.js +3 -2
- package/dist/config-catalog.js +6 -5
- package/dist/config-invariants.d.ts +18 -3
- package/dist/config-invariants.js +36 -19
- package/dist/config-lkg.d.ts +1 -1
- package/dist/config-lkg.js +5 -6
- package/dist/config-provider.js +2 -0
- package/dist/config-types.d.ts +190 -186
- package/dist/config.d.ts +68 -5
- package/dist/config.js +80 -54
- package/dist/degenerate-instrument.js +1 -1
- package/dist/deploy-facts.js +3 -2
- package/dist/deployment-shape.d.ts +21 -12
- package/dist/deployment-shape.js +24 -6
- package/dist/env-facts.d.ts +7 -5
- package/dist/env-facts.js +10 -6
- package/dist/execution-config-root.d.ts +5 -5
- package/dist/execution-config-root.js +5 -5
- package/dist/execution-env-purpose.d.ts +14 -0
- package/dist/execution-env-purpose.js +29 -0
- package/dist/execution-lane-caps.d.ts +49 -86
- package/dist/execution-lane-caps.js +52 -62
- package/dist/execution-placement.d.ts +18 -2
- package/dist/execution-placement.js +19 -0
- package/dist/file-history-disclosure.d.ts +2 -2
- package/dist/fleet/drain-entry.d.ts +17 -10
- package/dist/fleet/drain-entry.js +1 -1
- package/dist/fleet/serving-lease.js +3 -4
- package/dist/history-anchor.d.ts +22 -0
- package/dist/history-anchor.js +14 -0
- package/dist/hooks/command-spawn.d.ts +1 -4
- package/dist/hooks/command-spawn.js +0 -11
- package/dist/hooks/hook-runner.d.ts +52 -8
- package/dist/hooks/hook-runner.js +160 -36
- package/dist/http/approval-sweeps.d.ts +2 -5
- package/dist/http/approval-sweeps.js +3 -2
- package/dist/http/checkpoint-ctx.d.ts +17 -0
- package/dist/http/checkpoint-ctx.js +6 -0
- package/dist/http/claim-latency.d.ts +10 -0
- package/dist/http/claim-latency.js +12 -0
- package/dist/http/dispatch.js +1 -1
- package/dist/http/durable-run-leg.js +2 -1
- package/dist/http/execution-context.d.ts +3 -1
- package/dist/http/execution-context.js +4 -0
- package/dist/http/memory-compliance-failure-reply.d.ts +1 -1
- package/dist/http/memory-compliance-failure-reply.js +3 -0
- package/dist/http/memory-store-refusal-reply.d.ts +3 -3
- package/dist/http/memory-store-refusal-reply.js +3 -0
- package/dist/http/owner-access.d.ts +11 -0
- package/dist/http/owner-access.js +7 -4
- package/dist/http/principal-gate.d.ts +3 -14
- package/dist/http/principal-gate.js +0 -13
- package/dist/http/request-guards.d.ts +1 -1
- package/dist/http/resume-legs.d.ts +7 -10
- package/dist/http/resume-legs.js +79 -50
- package/dist/http/rewind-files-reply.d.ts +34 -0
- package/dist/http/rewind-files-reply.js +36 -0
- package/dist/http/route-ctx.d.ts +32 -16
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/approvals-assistant.js +5 -25
- package/dist/http/routes/capabilities.js +8 -2
- package/dist/http/routes/devices.js +1 -1
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/notify-wake.js +2 -1
- package/dist/http/routes/projects.d.ts +70 -0
- package/dist/http/routes/projects.js +86 -0
- package/dist/http/routes/rules.js +30 -2
- package/dist/http/routes/runs.js +8 -8
- package/dist/http/routes/session-sync.js +27 -10
- package/dist/http/routes/sessions.d.ts +7 -1
- package/dist/http/routes/sessions.js +104 -2
- package/dist/http/routes/tasks.js +9 -3
- package/dist/http/server.d.ts +24 -10
- package/dist/http/server.js +17 -6
- package/dist/http/stored-body-replay.d.ts +5 -3
- package/dist/http/stored-body-replay.js +10 -1
- package/dist/http/wire-types.d.ts +19 -10
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/instruction-source-notice.d.ts +1 -1
- package/dist/memory-embedder-reembed.d.ts +38 -0
- package/dist/memory-embedder-reembed.js +20 -0
- package/dist/memory-incident-sink.d.ts +0 -28
- package/dist/memory-incident-sink.js +5 -0
- package/dist/memory-scope.d.ts +2 -2
- package/dist/memory-scope.js +1 -1
- package/dist/memory-store-refusal.d.ts +17 -4
- package/dist/memory-store-refusal.js +1 -1
- package/dist/memory-sync-client.d.ts +2 -0
- package/dist/memory-sync-client.js +13 -11
- package/dist/memory-sync.js +1 -1
- package/dist/model-compat.d.ts +35 -21
- package/dist/model-compat.js +49 -21
- package/dist/model-entry-refusal.d.ts +11 -1
- package/dist/model-entry-refusal.js +7 -0
- package/dist/namespaced-rule-name.d.ts +18 -1
- package/dist/namespaced-rule-name.js +12 -0
- package/dist/observability/fail-open.d.ts +17 -9
- package/dist/observability/fail-open.js +17 -9
- package/dist/observability/metrics.d.ts +2 -0
- package/dist/observability/metrics.js +2 -0
- package/dist/observability/secret-env-scrub.d.ts +30 -4
- package/dist/observability/secret-env-scrub.js +15 -3
- package/dist/orchestration/workflow-agent-session-index.d.ts +7 -12
- package/dist/orchestration/workflow-agent-session-index.js +1 -6
- package/dist/orchestration/workflow-completion-inbox.d.ts +26 -6
- package/dist/orchestration/workflow-completion-inbox.js +63 -45
- package/dist/org-memory-admission.d.ts +5 -2
- package/dist/org-memory-admission.js +25 -10
- package/dist/parked-decide.d.ts +33 -26
- package/dist/parked-decide.js +36 -44
- package/dist/plugins/approval-ask-store-file.d.ts +10 -2
- package/dist/plugins/approval-ask-store-file.js +37 -4
- package/dist/plugins/approval-ask-store-memory.d.ts +5 -3
- package/dist/plugins/approval-ask-store-memory.js +11 -2
- package/dist/plugins/approval-ask-store-sql.d.ts +3 -0
- package/dist/plugins/approval-ask-store-sql.js +3 -1
- package/dist/plugins/blob-backend.d.ts +38 -195
- package/dist/plugins/blob-backend.js +33 -229
- package/dist/plugins/caching-session-store.d.ts +9 -4
- package/dist/plugins/checkpoint-index-columns.d.ts +1 -1
- package/dist/plugins/checkpoint-index-columns.js +3 -2
- package/dist/plugins/checkpoint-store-face.d.ts +1 -1
- package/dist/plugins/device-store-sql.d.ts +2 -2
- package/dist/plugins/device-store-sql.js +5 -10
- package/dist/plugins/execution-lane-rename-m40.d.ts +20 -0
- package/dist/plugins/execution-lane-rename-m40.js +10 -0
- package/dist/plugins/execution-placement-sql.d.ts +63 -88
- package/dist/plugins/execution-placement-sql.js +94 -54
- package/dist/plugins/file-run-store.d.ts +26 -12
- package/dist/plugins/file-run-store.js +63 -63
- package/dist/plugins/imported-layer-root-retirement.d.ts +17 -8
- package/dist/plugins/imported-layer-root-retirement.js +4 -8
- package/dist/plugins/inbox-payload-column.d.ts +14 -0
- package/dist/plugins/inbox-payload-column.js +13 -0
- package/dist/plugins/local-checkpoint-store.d.ts +5 -0
- package/dist/plugins/local-checkpoint-store.js +11 -7
- package/dist/plugins/local-data-dir-modes-m39.d.ts +48 -0
- package/dist/plugins/local-data-dir-modes-m39.js +182 -0
- package/dist/plugins/local-engine-high-water.d.ts +11 -0
- package/dist/plugins/local-engine-high-water.js +59 -0
- package/dist/plugins/local-session-store.d.ts +91 -25
- package/dist/plugins/local-session-store.js +124 -45
- package/dist/plugins/local-task-attachment-store.d.ts +2 -0
- package/dist/plugins/local-task-attachment-store.js +10 -11
- package/dist/plugins/memory-embedder-fingerprint.d.ts +33 -10
- package/dist/plugins/memory-embedder-fingerprint.js +52 -12
- package/dist/plugins/memory-embedder.d.ts +1 -1
- package/dist/plugins/memory-embedder.js +2 -2
- package/dist/plugins/memory-engine-pg.d.ts +4 -3
- package/dist/plugins/memory-engine-pg.js +4 -4
- package/dist/plugins/memory-engine-sql-apply.d.ts +13 -4
- package/dist/plugins/memory-engine-sql-apply.js +1 -1
- package/dist/plugins/memory-engine-tidb.d.ts +8 -5
- package/dist/plugins/memory-engine-tidb.js +7 -8
- package/dist/plugins/one-time-migrations.d.ts +145 -35
- package/dist/plugins/one-time-migrations.js +272 -120
- package/dist/plugins/owner-only-file-mode.d.ts +29 -0
- package/dist/plugins/owner-only-file-mode.js +141 -0
- package/dist/plugins/permission-rule-store-file.d.ts +8 -8
- package/dist/plugins/permission-rule-store-file.js +14 -2
- package/dist/plugins/pg-pool.d.ts +2 -1
- package/dist/plugins/pg-pool.js +11 -4
- package/dist/plugins/release-version.d.ts +20 -0
- package/dist/plugins/release-version.js +28 -0
- package/dist/plugins/remote-env-adb.d.ts +20 -4
- package/dist/plugins/remote-env-adb.js +39 -11
- package/dist/plugins/remote-env-e2b.d.ts +12 -3
- package/dist/plugins/remote-env-e2b.js +6 -4
- package/dist/plugins/remote-env-host.d.ts +9 -1
- package/dist/plugins/remote-env-host.js +6 -5
- package/dist/plugins/remote-env-k8s.d.ts +5 -2
- package/dist/plugins/remote-env-k8s.js +15 -4
- package/dist/plugins/remote-env-local-docker.d.ts +4 -1
- package/dist/plugins/remote-env-local-docker.js +3 -3
- package/dist/plugins/remote-env-ssh.d.ts +8 -2
- package/dist/plugins/remote-env-ssh.js +26 -24
- package/dist/plugins/remote-shell.d.ts +59 -30
- package/dist/plugins/remote-shell.js +175 -62
- package/dist/plugins/retention-declaration.d.ts +37 -0
- package/dist/plugins/retention-declaration.js +9 -0
- package/dist/plugins/retention-deployment.d.ts +126 -0
- package/dist/plugins/retention-deployment.js +88 -0
- package/dist/plugins/retention-lane-store-sql.d.ts +74 -4
- package/dist/plugins/retention-lane-store-sql.js +103 -1
- package/dist/plugins/retention-sql.d.ts +29 -0
- package/dist/plugins/retention-sql.js +8 -0
- package/dist/plugins/schema-consistency.d.ts +0 -6
- package/dist/plugins/schema-consistency.js +1 -2
- package/dist/plugins/schema-ensure-legs.d.ts +1 -1
- package/dist/plugins/schema-ensure-legs.js +11 -1
- package/dist/plugins/session-ext-table.d.ts +74 -0
- package/dist/plugins/session-ext-table.js +121 -0
- package/dist/plugins/session-fork.d.ts +1 -1
- package/dist/plugins/session-row-sql.d.ts +8 -7
- package/dist/plugins/session-row-sql.js +15 -7
- package/dist/plugins/session-store-sql.d.ts +131 -0
- package/dist/plugins/session-store-sql.js +298 -0
- package/dist/plugins/session-workspace-cell.d.ts +2 -2
- package/dist/plugins/session-workspace-cell.js +2 -2
- package/dist/plugins/shared-memory-store-sql.d.ts +10 -0
- package/dist/plugins/shared-memory-store-sql.js +13 -13
- package/dist/plugins/snapshot-bucket-presence.js +1 -1
- package/dist/plugins/sql-driver.d.ts +23 -7
- package/dist/plugins/sql-driver.js +41 -8
- package/dist/plugins/sql-errors.d.ts +5 -2
- package/dist/plugins/sql-errors.js +4 -0
- package/dist/plugins/store-backend.d.ts +35 -8
- package/dist/plugins/store-backend.js +184 -62
- package/dist/plugins/store-contracts.d.ts +9 -2
- package/dist/plugins/store-contracts.js +1 -0
- package/dist/plugins/task-attachment-store.d.ts +6 -8
- package/dist/plugins/task-attachment-store.js +15 -10
- package/dist/plugins/task-list-store-sql.d.ts +1 -1
- package/dist/plugins/text-column-capacity.d.ts +21 -0
- package/dist/plugins/text-column-capacity.js +5 -0
- package/dist/plugins/tidb-pool.d.ts +3 -2
- package/dist/plugins/tidb-pool.js +19 -31
- package/dist/plugins/user-input-ledger-sql.d.ts +1 -1
- package/dist/read-face-posture.d.ts +6 -6
- package/dist/read-face-posture.js +2 -2
- package/dist/request-value-closure.d.ts +5 -5
- package/dist/request-value-closure.js +1 -1
- package/dist/rules-consent.d.ts +41 -13
- package/dist/rules-consent.js +101 -53
- package/dist/run-local.js +17 -13
- package/dist/runs.d.ts +48 -30
- package/dist/runs.js +26 -16
- package/dist/runtime-caps-resolver.d.ts +15 -8
- package/dist/runtime-caps-resolver.js +14 -10
- package/dist/sealed-key-layout.d.ts +2 -3
- package/dist/sealed-key-layout.js +0 -1
- package/dist/sealed-key.js +7 -5
- package/dist/security.d.ts +5 -3
- package/dist/sema-config-dir.js +2 -2
- package/dist/server-secret-env.d.ts +2 -0
- package/dist/service-version.d.ts +2 -1
- package/dist/service-version.js +2 -2
- package/dist/session-error-wire.d.ts +1 -1
- package/dist/session-incarnation.d.ts +8 -5
- package/dist/session-resident-background.d.ts +85 -32
- package/dist/session-resident-background.js +75 -7
- package/dist/session-row.d.ts +1 -1
- package/dist/session-sync-kernel.d.ts +1 -1
- package/dist/session-workspace.d.ts +11 -2
- package/dist/session-workspace.js +5 -0
- package/dist/sighup-idle.d.ts +1 -1
- package/dist/store-posture.d.ts +2 -1
- package/dist/stored-request-hooks-m20.d.ts +3 -2
- package/dist/stored-request-hooks-m20.js +19 -14
- package/dist/stores-sql/blob-index-sql.d.ts +148 -0
- package/dist/stores-sql/blob-index-sql.js +154 -0
- package/dist/stores-sql/checkpoint-store-sql.d.ts +1 -1
- package/dist/stores-sql/checkpoint-store-sql.js +11 -27
- package/dist/{plugins → stores-sql}/file-history-store-sql.d.ts +23 -11
- package/dist/{plugins → stores-sql}/file-history-store-sql.js +23 -18
- package/dist/{plugins → stores-sql}/pg-session-storage.d.ts +23 -76
- package/dist/{plugins → stores-sql}/pg-session-storage.js +80 -209
- package/dist/{plugins → stores-sql}/retention-store-sql.d.ts +123 -217
- package/dist/{plugins → stores-sql}/retention-store-sql.js +66 -190
- package/dist/{plugins → stores-sql}/session-event-payload.d.ts +1 -1
- package/dist/{plugins → stores-sql}/session-event-payload.js +1 -1
- package/dist/stores-sql/session-policy-store-sql.d.ts +1 -1
- package/dist/stores-sql/session-write-hooks.d.ts +59 -0
- package/dist/stores-sql/session-write-hooks.js +2 -0
- package/dist/{plugins → stores-sql}/tidb-session-storage.d.ts +10 -11
- package/dist/{plugins → stores-sql}/tidb-session-storage.js +10 -21
- package/dist/{plugins → stores-sql}/tidb-session-store.d.ts +32 -122
- package/dist/{plugins → stores-sql}/tidb-session-store.js +71 -171
- package/dist/stores-sql/tool-result-store-sql.d.ts +1 -1
- package/dist/stores-sql/tool-result-store-sql.js +1 -1
- package/dist/stores-sql/windowed-session-storage.d.ts +56 -0
- package/dist/stores-sql/windowed-session-storage.js +61 -0
- package/dist/task-a2a.d.ts +7 -1
- package/dist/task-a2a.js +15 -14
- package/dist/task-cwd.d.ts +11 -3
- package/dist/task-cwd.js +17 -1
- package/dist/task-mcp.d.ts +10 -2
- package/dist/task-mcp.js +13 -16
- package/dist/task-settings.d.ts +9 -4
- package/dist/task-settings.js +17 -6
- package/dist/tool-approval.d.ts +21 -8
- package/dist/tool-approval.js +10 -6
- package/dist/trace/core-keyset-guard.d.ts +9 -3
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/exit-seat.d.ts +23 -1
- package/dist/trace/exit-seat.js +3 -0
- package/dist/trace/project.d.ts +33 -16
- package/dist/trace/project.js +12 -9
- package/dist/trace/redact.d.ts +1 -1
- package/dist/trace/redact.js +61 -73
- package/dist/trace/self-minted-wire.d.ts +263 -10
- package/dist/trace/self-minted-wire.js +90 -2
- package/dist/trace/sema-provenance.d.ts +45 -41
- package/dist/trace/sema-provenance.js +81 -10
- package/dist/trace/task-notification-facets.d.ts +70 -2
- package/dist/trace/task-notification-facets.js +71 -1
- package/dist/trace/wire-projection-faces.d.ts +38 -2
- package/dist/trace/wire-projection-faces.js +26 -1
- package/dist/unread-request-members.d.ts +66 -0
- package/dist/unread-request-members.js +41 -0
- package/dist/user-input-ledger.d.ts +2 -2
- package/dist/web-admin-client/apply-effective.js +22 -26
- package/dist/web-admin-client/candidate-gate.d.ts +35 -3
- package/dist/web-admin-client/candidate-gate.js +53 -5
- package/dist/web-admin-client/center-request.d.ts +4 -1
- package/dist/web-admin-client/center-request.js +2 -1
- package/dist/web-admin-client/effective-keys.js +0 -1
- package/dist/web-admin-client/facade.d.ts +1 -1
- package/dist/web-admin-client/http-client.d.ts +1 -0
- package/dist/web-admin-client/http-client.js +17 -9
- package/dist/web-admin-client/restart-signal.js +5 -2
- package/dist/web-admin-client/skills-mcp.d.ts +20 -6
- package/dist/web-admin-client/skills-mcp.js +26 -21
- package/dist/web-admin-client/types.d.ts +34 -49
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +2 -2
- package/package.json +13 -12
- package/scripts/drain-check-local.mjs +2 -28
- package/scripts/drain-check.mysql.sql +2 -18
- package/scripts/drain-check.pg.sql +2 -18
- package/wire-changes/server@7.147.0.json +813 -0
|
@@ -2,7 +2,7 @@ import { realpathSync } from "node:fs";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { NodeExecutionEnv, QUESTION_AWAITS_RESUME, deriveAskEffective, expandTiers, resolveAskSeamForm } from "@sema-agent/core";
|
|
4
4
|
import { cappedCeiling } from "../budget.js";
|
|
5
|
-
import {
|
|
5
|
+
import { unreadRequestMembers, unreadRequestMembersRefusal } from "../unread-request-members.js";
|
|
6
6
|
import { SessionEnvironmentSelection, selectEnvironmentTool } from "../capabilities/select-environment-tool.js";
|
|
7
7
|
import { sendUserFileTool } from "../capabilities/send-user-file-tool.js";
|
|
8
8
|
import { buildExcludeToolsSeat, buildPromptSeats, buildRunSkills, createScenarioGate, selectScenario } from "../capabilities/scenarios.js";
|
|
@@ -27,6 +27,7 @@ import { routeServiceTask, supPostureOverrides } from "../router/route-orchestra
|
|
|
27
27
|
import { tightenGoverned } from "../governance-overrides.js";
|
|
28
28
|
import { applyRuntimeGovernance } from "../runtime-governance.js";
|
|
29
29
|
import { HttpError, createCodedHttpError, encodeCheckpointScope } from "../security.js";
|
|
30
|
+
import { resolveHistoryAnchor } from "../history-anchor.js";
|
|
30
31
|
import { headReadOf, sessionFaceOfHead } from "../session-incarnation.js";
|
|
31
32
|
import { legProjectIdOf, sessionWorkspaceStoreOf } from "../session-workspace.js";
|
|
32
33
|
import { memorySpecForRequest } from "../memory-scope.js";
|
|
@@ -71,11 +72,11 @@ export function createResolveSpec(ctx) {
|
|
|
71
72
|
approvalSeat: durableEnabled ? "durable" : "absent",
|
|
72
73
|
singleUserAutoAcceptBaseline: singleUserAutoAcceptBaselineApplies(config),
|
|
73
74
|
});
|
|
74
|
-
const realTaskRootOf = (
|
|
75
|
+
const realTaskRootOf = (root) => {
|
|
75
76
|
if (DEPLOYMENT_SHAPE_PREDICATES.sandboxPathAdjudication.holds(config))
|
|
76
77
|
return undefined;
|
|
77
|
-
const sessionCwd =
|
|
78
|
-
return sessionCwd ?? (
|
|
78
|
+
const sessionCwd = effectiveHostWorkspace(perSessionCwd.get(root), {});
|
|
79
|
+
return sessionCwd ?? (laneWiresExecutionEnv(config.remoteExec.provider) ? undefined : process.cwd());
|
|
79
80
|
};
|
|
80
81
|
const memoryProjectLayers = createMemoryProjectLayers({ stores: memoryEngine, syncRunner: memorySyncRunner, log: logger });
|
|
81
82
|
if (onlySensitiveBaseline)
|
|
@@ -84,6 +85,7 @@ export function createResolveSpec(ctx) {
|
|
|
84
85
|
if (approvalGrantNotice)
|
|
85
86
|
logger.info(approvalGrantNotice.event, approvalGrantNotice.fields);
|
|
86
87
|
const resolveSpec = async (body, req, auth, opts) => {
|
|
88
|
+
const root = opts.execution.root;
|
|
87
89
|
const seatRefusal = gateIntentUnserviceableReason(config, checkpointStore !== undefined);
|
|
88
90
|
if (seatRefusal !== undefined)
|
|
89
91
|
throw createCodedHttpError(501, "capability.checkpoint_store_required", seatRefusal);
|
|
@@ -102,7 +104,7 @@ export function createResolveSpec(ctx) {
|
|
|
102
104
|
cwd: body.cwd,
|
|
103
105
|
shellScratchpadDir: body.scratchpadDir,
|
|
104
106
|
localDataRoot: config.localDataRoot ?? localRoot,
|
|
105
|
-
sessionId:
|
|
107
|
+
sessionId: root,
|
|
106
108
|
requirePrincipal: config.requirePrincipal,
|
|
107
109
|
callerOwnsWorkerDisk: DEPLOYMENT_SHAPE_PREDICATES.callerOwnsWorkerDisk.holds(config),
|
|
108
110
|
});
|
|
@@ -119,15 +121,13 @@ export function createResolveSpec(ctx) {
|
|
|
119
121
|
if (inheritEnvIssue)
|
|
120
122
|
throw new HttpError(400, inheritEnvIssue.message, { code: "request.field_invalid", extra: inheritEnvIssue.facts });
|
|
121
123
|
if (body.inheritEnv === "all") {
|
|
122
|
-
const lane =
|
|
124
|
+
const lane = config.remoteExec.provider;
|
|
123
125
|
if (lane !== "host") {
|
|
124
126
|
throw new HttpError(400, `inheritEnv:"all" applies to the host lane only (this deployment runs ${lane}) — only the host lane builds the model-driven shell's environment from this machine's own, so the declaration has no effect here; omit it (or send "scrub", the default, which every lane accepts)`, { code: "request.field_invalid", extra: inheritEnvFacts("lane_not_host") });
|
|
125
127
|
}
|
|
126
128
|
const why = taskInheritEnvRefusal(config);
|
|
127
129
|
if (why !== undefined)
|
|
128
130
|
throw new HttpError(422, why, { code: HOST_POSTURE_REFUSED_CODE });
|
|
129
|
-
if (!auth?.sessionId)
|
|
130
|
-
throw new HttpError(400, `inheritEnv:"all" requires a session-resolving deployment (no authorizer session) — the host shell's environment is bound per session`, { code: "request.field_invalid", extra: inheritEnvFacts("no_authorizer_session") });
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
{
|
|
@@ -151,7 +151,7 @@ export function createResolveSpec(ctx) {
|
|
|
151
151
|
dropped[e.match]++;
|
|
152
152
|
logger.warn("settings_env_credentials_dropped", {
|
|
153
153
|
migration: "M38",
|
|
154
|
-
sessionId:
|
|
154
|
+
sessionId: root,
|
|
155
155
|
dropped,
|
|
156
156
|
note: "this replayed request was stored before the upgrade and its settings.env carries credentials (a credential variable name of this engine, or a value shaped like a secret); while one-time migration M38 is open they are dropped from what the session's shell and hooks receive and the task resumes — the engine's own credentials come from its process environment and are unaffected; once the window closes the same request is refused",
|
|
157
157
|
});
|
|
@@ -169,7 +169,7 @@ export function createResolveSpec(ctx) {
|
|
|
169
169
|
const stale = inertToolListEntryOf(body, ["allow"]);
|
|
170
170
|
if (stale !== undefined) {
|
|
171
171
|
logger.warn("stored_allow_list_inert_resumed", {
|
|
172
|
-
sessionId:
|
|
172
|
+
sessionId: root,
|
|
173
173
|
layer: stale.layer,
|
|
174
174
|
sentence: stale.message,
|
|
175
175
|
note: "this resumed task's stored request carries an allow-list entry the engine reads as nothing (a retired name, a case twin, an unreadable spelling or a content form): the entry stays as written and grants nothing — the task ran that way before the upgrade, so it continues; fix the entry in a new submission to get what it was meant to allow",
|
|
@@ -179,54 +179,54 @@ export function createResolveSpec(ctx) {
|
|
|
179
179
|
}
|
|
180
180
|
if (opts?.leg === "fresh")
|
|
181
181
|
assertRequestA2aEntries(a2aPeers);
|
|
182
|
+
{
|
|
183
|
+
const unread = unreadRequestMembers({ settings: body.settings, mcpServers: body.mcpServers, a2aPeers }, config, opts?.leg === "fresh" ? { replay: false, settingsEnv } : { replay: true, today: new Date().toISOString().slice(0, 10), storedToolAxes, settingsEnv });
|
|
184
|
+
if (unread.length > 0) {
|
|
185
|
+
const refusal = unreadRequestMembersRefusal(unread);
|
|
186
|
+
throw new HttpError(400, refusal.message, { code: refusal.errorCode, ...(refusal.facts !== undefined ? { extra: { ...refusal.facts } } : {}) });
|
|
187
|
+
}
|
|
188
|
+
}
|
|
182
189
|
if (opts?.leg === "fresh")
|
|
183
190
|
assertRequestImageUrls(body.images);
|
|
184
|
-
const gated = await gateScenarioAndAppend(body, auth, opts, settingsEnv);
|
|
191
|
+
const gated = await gateScenarioAndAppend(body, auth, root, opts, settingsEnv);
|
|
185
192
|
const effMode = effectivePermissionMode(body, gated.parsedSettings.settings);
|
|
186
193
|
{
|
|
187
194
|
const why = permissionModeWriteFaceRefusal(effMode, config);
|
|
188
195
|
if (why !== undefined)
|
|
189
196
|
throw new HttpError(422, why, { code: HOST_POSTURE_REFUSED_CODE });
|
|
190
197
|
}
|
|
191
|
-
const lane = bindSettingsCwdEnvAndModel(body, auth, gated, opts);
|
|
192
|
-
const anchors = await resolveHistoryAnchors(body, auth);
|
|
193
|
-
const projectKey = memoryEngine ? await memoryProjectLayers.prepare(config, auth?.memoryScope, realTaskRootOf(
|
|
198
|
+
const lane = bindSettingsCwdEnvAndModel(body, auth, root, gated, opts);
|
|
199
|
+
const anchors = await resolveHistoryAnchors(body, auth, root);
|
|
200
|
+
const projectKey = memoryEngine ? await memoryProjectLayers.prepare(config, auth?.memoryScope, realTaskRootOf(root)) : undefined;
|
|
194
201
|
const runSkills = buildRunSkills({ scenario: gated.cap.skills, request: body.skills, disable: body.disableSkills === true, deploymentSources: deploymentSkillSources }, logger);
|
|
195
|
-
const spec = assembleSpecLiteral(body, auth, req, opts, { ...gated, ...lane, ...anchors, projectKey, a2aPeers, storedToolAxes, runSkills }, effMode);
|
|
196
|
-
const folded = await foldGovernanceAndSettings(body, auth, spec, gated);
|
|
197
|
-
const final = await applyImageFactsAndRouting(body, auth, folded.governed, {
|
|
202
|
+
const spec = assembleSpecLiteral(body, auth, root, req, opts, { ...gated, ...lane, ...anchors, projectKey, a2aPeers, storedToolAxes, runSkills }, effMode);
|
|
203
|
+
const folded = await foldGovernanceAndSettings(body, auth, root, spec, gated);
|
|
204
|
+
const final = await applyImageFactsAndRouting(body, auth, root, folded.governed, {
|
|
198
205
|
scenarioName: gated.scenarioName,
|
|
199
206
|
scratchpadDir: folded.scratchpadDir,
|
|
200
207
|
hostSemanticsLane: folded.hostSemanticsLane,
|
|
201
208
|
});
|
|
202
209
|
return { spec: final, facts: { hands: gated.hands, skills: runSkills.roster, sessionWitness: gated.sessionWitness } };
|
|
203
210
|
};
|
|
204
|
-
const gateScenarioAndAppend = async (body, auth, opts, settingsEnv) => {
|
|
211
|
+
const gateScenarioAndAppend = async (body, auth, root, opts, settingsEnv) => {
|
|
205
212
|
const scenarioName = await scenarioGate(auth?.principal, body.scenario);
|
|
206
|
-
const root = opts.execution.root;
|
|
207
213
|
const rootFace = sessionHeadOf === undefined ? undefined : sessionFaceOfHead(root, await sessionHeadOf(root));
|
|
208
214
|
const sessionWitness = { sessionId: root, owner: rootFace?.owner ?? null, incarnation: rootFace?.incarnation ?? null };
|
|
209
215
|
const cap = selectScenario(scenarios, scenarioName)(body, auth?.principal, { sessionId: sessionWitness.sessionId, delegationRoot: sessionWitness });
|
|
210
|
-
const acceptedAppend = acceptAppendSystemPrompt(body.appendSystemPrompt, (detail) => logger.warn("append_system_prompt_dropped", { detail, sessionId:
|
|
216
|
+
const acceptedAppend = acceptAppendSystemPrompt(body.appendSystemPrompt, (detail) => logger.warn("append_system_prompt_dropped", { detail, sessionId: root }));
|
|
211
217
|
const objective = typeof body.objective === "string" ? body.objective : "";
|
|
212
218
|
const parsedSettings = parseTaskSettings(body.settings, {
|
|
213
219
|
...(opts?.leg === "fresh" || !taskHooksHonored(config) ? {} : { storedHooksReread: storedHooksRereadM20(new Date().toISOString().slice(0, 10)) }),
|
|
214
220
|
settingsEnv,
|
|
215
221
|
});
|
|
216
|
-
if (parsedSettings.deferred.length > 0) {
|
|
217
|
-
logger.warn("task_settings_deferred", { fields: parsedSettings.deferred, sessionId: auth?.sessionId ?? null });
|
|
218
|
-
}
|
|
219
222
|
if (parsedSettings.hooksReread !== undefined) {
|
|
220
223
|
logger.warn("hooks_read_as_before_upgrade", {
|
|
221
224
|
migration: "M20",
|
|
222
|
-
sessionId:
|
|
225
|
+
sessionId: root,
|
|
223
226
|
stripped: parsedSettings.hooksReread.stripped,
|
|
224
|
-
note: "this replayed request was stored before the upgrade and its settings.hooks carries a shape the hooks reader now refuses (a key the reader does not know that hides a guard-event member, or a JSON `__proto__` event key); while one-time migration M20 is open the keys named in `stripped` are dropped — what the pre-upgrade reader dropped — and the rest goes through the same reader again, so the guard hooks keep running; once the window closes the same request
|
|
227
|
+
note: "this replayed request was stored before the upgrade and its settings.hooks carries a shape the hooks reader now refuses (a key the reader does not know that hides a guard-event member, or a JSON `__proto__` event key); while one-time migration M20 is open the keys named in `stripped` are dropped — what the pre-upgrade reader dropped — and the rest goes through the same reader again, so the guard hooks keep running; once the window closes the same request is refused on resume (409 resume_blocked_by_policy)",
|
|
225
228
|
});
|
|
226
229
|
}
|
|
227
|
-
if (parsedSettings.deferred.includes("hooks") && taskHooksHonored(config)) {
|
|
228
|
-
recordFailOpen("server.hooks.resume-reader-refused", `leg=${opts?.leg ?? "resume"}`);
|
|
229
|
-
}
|
|
230
230
|
let attachmentNotice;
|
|
231
231
|
{
|
|
232
232
|
const reqAtt = body.attachmentIds;
|
|
@@ -239,28 +239,25 @@ export function createResolveSpec(ctx) {
|
|
|
239
239
|
if (reqAtt.length > 0) {
|
|
240
240
|
if (!taskAttachmentStore)
|
|
241
241
|
throw new HttpError(501, "attachmentIds require a store backend (DB_BACKEND=mysql|pg|local)");
|
|
242
|
-
if (!auth?.sessionId)
|
|
243
|
-
throw new HttpError(400, "`attachmentIds` requires a session-resolving deployment (no authorizer session)");
|
|
244
|
-
const sid = auth.sessionId;
|
|
245
242
|
const lane = opts.execution.lane;
|
|
246
243
|
const r = await bindAttachmentsForTask({
|
|
247
244
|
store: taskAttachmentStore,
|
|
248
245
|
owner: auth?.principal ?? "default",
|
|
249
246
|
ids: reqAtt,
|
|
250
|
-
sessionId:
|
|
247
|
+
sessionId: root,
|
|
251
248
|
lane: { word: lane, isolated: laneIsolated(lane) },
|
|
252
249
|
leg: opts?.leg === "fresh" ? "fresh" : "resume",
|
|
253
250
|
nowMs: Date.now(),
|
|
254
251
|
onMissing: (id) => {
|
|
255
252
|
if (opts?.leg === "fresh")
|
|
256
253
|
throw new HttpError(400, `attachment not found: ${id}`);
|
|
257
|
-
logger.warn("attachment_missing_on_resume", { sessionId:
|
|
254
|
+
logger.warn("attachment_missing_on_resume", { sessionId: root, id });
|
|
258
255
|
},
|
|
259
256
|
onRefused: (refusal) => {
|
|
260
257
|
const answer = attachmentBindRefusalAnswer(refusal);
|
|
261
258
|
if (opts?.leg === "fresh")
|
|
262
259
|
throw createCodedHttpError(answer.status, answer.errorCode, answer.message, answer.extra);
|
|
263
|
-
logger.warn("attachment_refused_on_resume", { sessionId:
|
|
260
|
+
logger.warn("attachment_refused_on_resume", { sessionId: root, errorCode: answer.errorCode, ...answer.extra });
|
|
264
261
|
},
|
|
265
262
|
});
|
|
266
263
|
attachmentNotice = r.notice;
|
|
@@ -269,46 +266,45 @@ export function createResolveSpec(ctx) {
|
|
|
269
266
|
}
|
|
270
267
|
return { scenarioName, cap, hands: cap.hands, acceptedAppend, objective, parsedSettings, attachmentNotice, sessionWitness };
|
|
271
268
|
};
|
|
272
|
-
const bindSettingsCwdEnvAndModel = (body, auth, gated, opts) => {
|
|
269
|
+
const bindSettingsCwdEnvAndModel = (body, auth, root, gated, opts) => {
|
|
273
270
|
const { objective, parsedSettings } = gated;
|
|
274
271
|
const cwdWriteGate = DEPLOYMENT_SHAPE_PREDICATES.callerCwd.holds(config);
|
|
275
|
-
const execLane =
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
if (typeof body.cwd === "string" && body.cwd.length > 0 && auth?.sessionId) {
|
|
272
|
+
const execLane = config.remoteExec.provider;
|
|
273
|
+
fenceSessionOwner(root, auth?.principal ?? null);
|
|
274
|
+
if (typeof body.cwd === "string" && body.cwd.length > 0) {
|
|
279
275
|
if (cwdWriteGate && isAbsoluteHostPath(body.cwd))
|
|
280
|
-
setSessionCwd(
|
|
281
|
-
else if (DEPLOYMENT_SHAPE_PREDICATES.
|
|
282
|
-
logger.debug("task_cwd_inherited", { lane: execLane, sessionId:
|
|
276
|
+
setSessionCwd(root, body.cwd);
|
|
277
|
+
else if (DEPLOYMENT_SHAPE_PREDICATES.noHandsSingleUser.holds(config) && isAbsoluteHostPath(body.cwd) && satisfiedByProcessCwd(body.cwd, realpathSync))
|
|
278
|
+
logger.debug("task_cwd_inherited", { lane: execLane, sessionId: root });
|
|
283
279
|
else
|
|
284
|
-
logger.warn("task_cwd_ignored", { honored: cwdWriteGate, lane: execLane, sessionId:
|
|
280
|
+
logger.warn("task_cwd_ignored", { honored: cwdWriteGate, lane: execLane, sessionId: root });
|
|
285
281
|
}
|
|
286
|
-
if (parsedSettings.settings?.shellEnv
|
|
282
|
+
if (parsedSettings.settings?.shellEnv) {
|
|
287
283
|
if (cwdWriteGate)
|
|
288
|
-
setSessionShellEnv(
|
|
289
|
-
else if (DEPLOYMENT_SHAPE_PREDICATES.
|
|
284
|
+
setSessionShellEnv(root, parsedSettings.settings.shellEnv);
|
|
285
|
+
else if (DEPLOYMENT_SHAPE_PREDICATES.noHandsSingleUser.holds(config)) {
|
|
290
286
|
const requested = parsedSettings.settings.shellEnv;
|
|
291
287
|
const mismatched = shellEnvMismatchCount(requested, process.env);
|
|
292
288
|
if (mismatched === 0)
|
|
293
|
-
logger.debug("task_shell_env_inherited", { lane: execLane, keys: Object.keys(requested).length, sessionId:
|
|
289
|
+
logger.debug("task_shell_env_inherited", { lane: execLane, keys: Object.keys(requested).length, sessionId: root });
|
|
294
290
|
else
|
|
295
|
-
logger.warn("task_shell_env_ignored", { honored: false, lane: execLane, mismatchedKeys: mismatched, sessionId:
|
|
291
|
+
logger.warn("task_shell_env_ignored", { honored: false, lane: execLane, mismatchedKeys: mismatched, sessionId: root });
|
|
296
292
|
}
|
|
297
293
|
else
|
|
298
|
-
logger.warn("task_shell_env_ignored", { honored: false, lane: execLane, sessionId:
|
|
294
|
+
logger.warn("task_shell_env_ignored", { honored: false, lane: execLane, sessionId: root });
|
|
299
295
|
}
|
|
300
296
|
const taskHooks = (() => {
|
|
301
297
|
const hc = parsedSettings.settings?.hooks;
|
|
302
298
|
if (!hc)
|
|
303
299
|
return [];
|
|
304
300
|
if (!taskHooksHonored(config)) {
|
|
305
|
-
logger.warn("task_hooks_ignored", { honored: false, sessionId:
|
|
301
|
+
logger.warn("task_hooks_ignored", { honored: false, sessionId: root });
|
|
306
302
|
return [];
|
|
307
303
|
}
|
|
308
304
|
return createSettingsHooksRegistrations(hc, {
|
|
309
305
|
logger,
|
|
310
|
-
sessionId:
|
|
311
|
-
cwd:
|
|
306
|
+
sessionId: root,
|
|
307
|
+
cwd: perSessionCwd.get(root) ?? process.cwd(),
|
|
312
308
|
...(parsedSettings.settings?.shellEnv ? { shellEnv: parsedSettings.settings.shellEnv } : {}),
|
|
313
309
|
httpHookAllowlistLayers: parsedSettings.settings?.httpHookAllowlist !== undefined ? [parsedSettings.settings.httpHookAllowlist] : [],
|
|
314
310
|
belowTaskChainPatterns,
|
|
@@ -317,28 +313,24 @@ export function createResolveSpec(ctx) {
|
|
|
317
313
|
onHookNotice: (n) => fleetBus.publishHookNotice({
|
|
318
314
|
...n,
|
|
319
315
|
...(auth?.principal ? { ownerScope: auth.principal } : {}),
|
|
320
|
-
|
|
316
|
+
ownerSessionId: root,
|
|
321
317
|
}),
|
|
322
|
-
|
|
323
|
-
?
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
hookWakeBus.deliver(auth.sessionId, `[hook asyncRewake] ${redactSecrets(text)}`)
|
|
327
|
-
: false,
|
|
328
|
-
}
|
|
329
|
-
: {}),
|
|
318
|
+
wake: async (text) => hookWakeBus.deliver
|
|
319
|
+
?
|
|
320
|
+
hookWakeBus.deliver(root, `[hook asyncRewake] ${redactSecrets(text)}`)
|
|
321
|
+
: false,
|
|
330
322
|
}, settingsHooksBudgetMs(config));
|
|
331
323
|
})();
|
|
332
324
|
const rawAddDirs = body.additionalDirectories;
|
|
333
325
|
const callerOwnsWorkerDisk = DEPLOYMENT_SHAPE_PREDICATES.callerOwnsWorkerDisk.holds(config);
|
|
334
326
|
const additionalDirectories = callerOwnsWorkerDisk ? parseAdditionalDirectories(rawAddDirs) : undefined;
|
|
335
327
|
if (rawAddDirs !== undefined && !callerOwnsWorkerDisk) {
|
|
336
|
-
logger.warn("task_additional_directories_ignored", { honored: false, sessionId:
|
|
328
|
+
logger.warn("task_additional_directories_ignored", { honored: false, sessionId: root });
|
|
337
329
|
}
|
|
338
330
|
const rawAddReadDirs = body.additionalReadDirectories;
|
|
339
331
|
const additionalReadDirectories = callerOwnsWorkerDisk ? parseAdditionalDirectories(rawAddReadDirs) : undefined;
|
|
340
332
|
if (rawAddReadDirs !== undefined && !callerOwnsWorkerDisk) {
|
|
341
|
-
logger.warn("task_additional_read_directories_ignored", { honored: false, sessionId:
|
|
333
|
+
logger.warn("task_additional_read_directories_ignored", { honored: false, sessionId: root });
|
|
342
334
|
}
|
|
343
335
|
const wireCatalog = selectableCatalog(config.models, config.tiers, config.modelRefusals);
|
|
344
336
|
const picked = resolveTaskModel(body.model ?? parsedSettings.settings?.model, objective, wireCatalog, config.atMention, config.modelRefusals);
|
|
@@ -348,7 +340,7 @@ export function createResolveSpec(ctx) {
|
|
|
348
340
|
throw new HttpError(400, modelUnavailableMessage(source === "mention" ? "@-mention" : "model", requested, name, refusal), { code: "request.model_unavailable" });
|
|
349
341
|
}
|
|
350
342
|
metrics.inc("task_model_unavailable_fallback_total");
|
|
351
|
-
logger.warn("task_model_unavailable_fallback", { requested: echoModelRef(requested), name, code: refusal.code, source, fallback: picked.model, sessionId:
|
|
343
|
+
logger.warn("task_model_unavailable_fallback", { requested: echoModelRef(requested), name, code: refusal.code, source, fallback: picked.model, sessionId: root });
|
|
352
344
|
}
|
|
353
345
|
if (picked.notAllowed !== undefined) {
|
|
354
346
|
const { requested, resolved, source } = picked.notAllowed;
|
|
@@ -356,39 +348,30 @@ export function createResolveSpec(ctx) {
|
|
|
356
348
|
throw new HttpError(400, `model "${echoModelRef(requested)}" is not @-mentionable on this deployment (it resolves to catalog model "${resolved}") — which models can be @-mentioned is configured by the operator (models.atMention)`, { code: "request.model_not_allowed" });
|
|
357
349
|
}
|
|
358
350
|
metrics.inc("task_model_not_allowlisted_resume_total");
|
|
359
|
-
logger.warn("task_model_not_allowlisted_resume", { requested: echoModelRef(requested), resolved, source, sessionId:
|
|
351
|
+
logger.warn("task_model_not_allowlisted_resume", { requested: echoModelRef(requested), resolved, source, sessionId: root, note: "resumed leg keeps running the model it was started on — the allowlist gates fresh picks only" });
|
|
360
352
|
}
|
|
361
353
|
if (picked.unknownExplicit !== undefined) {
|
|
362
354
|
metrics.inc("task_model_unknown_fallback_total");
|
|
363
|
-
logger.warn("task_model_unknown_fallback", { requested: echoModelRef(picked.unknownExplicit), fallback: picked.model, sessionId:
|
|
355
|
+
logger.warn("task_model_unknown_fallback", { requested: echoModelRef(picked.unknownExplicit), fallback: picked.model, sessionId: root });
|
|
364
356
|
}
|
|
365
357
|
return { taskHooks, additionalDirectories, additionalReadDirectories, wireCatalog, picked };
|
|
366
358
|
};
|
|
367
|
-
const
|
|
368
|
-
const resolveHistoryAnchors = async (body, auth) => {
|
|
359
|
+
const resolveHistoryAnchors = async (body, auth, root) => {
|
|
369
360
|
let resumeAtEntryId;
|
|
370
361
|
if (typeof body.resumeAt === "string" && body.resumeAt.length > 0) {
|
|
371
|
-
if (!auth?.sessionId)
|
|
372
|
-
throw new HttpError(422, "resumeAt requires a session to branch (resume_at.no_session)", { code: "resume_at.no_session" });
|
|
373
362
|
if (!resumeAnchorStore || !sessionHeadOf)
|
|
374
363
|
throw new HttpError(501, "resume-at is not available on this worker (no session-store backend for the anchor map)");
|
|
375
|
-
resumeAtEntryId = await
|
|
376
|
-
if (resumeAtEntryId === undefined)
|
|
377
|
-
throw new HttpError(404, `resumeAt: no such message in this session (resume_at.unknown_event) — ${NO_ANCHOR_HINT}; give an explicit resumeAt`, { code: "resume_at.unknown_event" });
|
|
364
|
+
resumeAtEntryId = await resolveHistoryAnchor("resumeAt", resumeAnchorStore, root, body.resumeAt, auth?.principal ?? null, "resumeAt");
|
|
378
365
|
}
|
|
379
366
|
let rewindFilesToEntryId;
|
|
380
367
|
if (resumeAtEntryId === undefined && typeof body.rewindFilesTo === "string" && body.rewindFilesTo.length > 0) {
|
|
381
|
-
if (!auth?.sessionId)
|
|
382
|
-
throw new HttpError(422, "rewindFilesTo requires a session (rewind_files_to.no_session)", { code: "rewind_files_to.no_session" });
|
|
383
368
|
if (!resumeAnchorStore || !sessionHeadOf)
|
|
384
369
|
throw new HttpError(501, "rewind-files-to is not available on this worker (no session-store backend for the anchor map)");
|
|
385
|
-
rewindFilesToEntryId = await
|
|
386
|
-
if (rewindFilesToEntryId === undefined)
|
|
387
|
-
throw new HttpError(404, `rewindFilesTo: no such message in this session (rewind_files_to.unknown_event) — ${NO_ANCHOR_HINT}; name another prompt`, { code: "rewind_files_to.unknown_event" });
|
|
370
|
+
rewindFilesToEntryId = await resolveHistoryAnchor("rewindFilesTo", resumeAnchorStore, root, body.rewindFilesTo, auth?.principal ?? null, "rewindFilesTo");
|
|
388
371
|
}
|
|
389
372
|
const submittedProjectId = auth?.resolvedProjectId ?? (typeof body.projectId === "string" && body.projectId ? body.projectId.toLowerCase() : undefined);
|
|
390
373
|
const s4DefaultScopes = submittedProjectId ? config.projects[submittedProjectId]?.defaultScopes : undefined;
|
|
391
|
-
const legProjectId = await legProjectIdOf(submittedProjectId, sessionWorkspace,
|
|
374
|
+
const legProjectId = await legProjectIdOf(submittedProjectId, sessionWorkspace, root);
|
|
392
375
|
return { resumeAtEntryId, rewindFilesToEntryId, s4DefaultScopes, legProjectId };
|
|
393
376
|
};
|
|
394
377
|
const declaresInteractivePosture = (body, req, opts) => {
|
|
@@ -405,7 +388,7 @@ export function createResolveSpec(ctx) {
|
|
|
405
388
|
const askForm = resolveAskSeamForm(body.approvalReach !== undefined ? { approvalReach: body.approvalReach } : {}, approverSeat !== undefined ? { onAsk: approverSeat } : {});
|
|
406
389
|
return deriveAskEffective(askForm.form, "unresolved") === "human_reachable";
|
|
407
390
|
};
|
|
408
|
-
const assembleSpecLiteral = (body, auth, req, opts, parts, effMode) => {
|
|
391
|
+
const assembleSpecLiteral = (body, auth, root, req, opts, parts, effMode) => {
|
|
409
392
|
const { scenarioName, cap, hands, acceptedAppend, parsedSettings, attachmentNotice, taskHooks, additionalDirectories, additionalReadDirectories, wireCatalog, picked, resumeAtEntryId, rewindFilesToEntryId, s4DefaultScopes, legProjectId, projectKey, a2aPeers, storedToolAxes, runSkills, } = parts;
|
|
410
393
|
const spec = {
|
|
411
394
|
objective: attachmentNotice ? `${picked.cleanedObjective}\n\n${attachmentNotice}` : picked.cleanedObjective,
|
|
@@ -439,8 +422,8 @@ export function createResolveSpec(ctx) {
|
|
|
439
422
|
selfOrchestration: selfOrchestrationFromBody({ selfOrchestration: body.selfOrchestration === true || parsedSettings.settings?.ultracode === true }, config, Boolean(centerRuntimeCapsResolver)),
|
|
440
423
|
forwardSubagentEvents: body.forwardSubagentEvents === true ? true : undefined,
|
|
441
424
|
retainSubagentSessions: normalizeRetainSubagentSessions(body.retainSubagentSessions),
|
|
442
|
-
...taskAgentsSpecFragment(body.agents, config.requirePrincipal, (event, fields) => logger.warn(event, { ...fields, sessionId:
|
|
443
|
-
...(retainBackgroundProcessesFromBody(body.retainBackgroundProcesses, config.requirePrincipal, (event, fields) => logger.warn(event, { ...fields, sessionId:
|
|
425
|
+
...taskAgentsSpecFragment(body.agents, config.requirePrincipal, (event, fields) => logger.warn(event, { ...fields, sessionId: root })),
|
|
426
|
+
...(retainBackgroundProcessesFromBody(body.retainBackgroundProcesses, config.requirePrincipal, (event, fields) => logger.warn(event, { ...fields, sessionId: root })) === true
|
|
444
427
|
? { retainBackgroundProcesses: true }
|
|
445
428
|
: {}),
|
|
446
429
|
...(body.excludeAllTools === true ? { excludeAllTools: true } : {}),
|
|
@@ -471,7 +454,7 @@ export function createResolveSpec(ctx) {
|
|
|
471
454
|
throw new HttpError(400, `unknown compactionModel "${echoModelRef(body.compactionModel)}" — not in the configured catalog (name, tier word, or id; a catalog refresh may have removed it mid-request)`);
|
|
472
455
|
}
|
|
473
456
|
metrics.inc("task_model_unknown_fallback_total");
|
|
474
|
-
logger.warn("compaction_model_unknown_fallback", { requested: echoModelRef(body.compactionModel), sessionId:
|
|
457
|
+
logger.warn("compaction_model_unknown_fallback", { requested: echoModelRef(body.compactionModel), sessionId: root });
|
|
475
458
|
return {};
|
|
476
459
|
}
|
|
477
460
|
if (!isAtMentionable(cm, wireCatalog, config.atMention, config.modelRefusals)) {
|
|
@@ -480,14 +463,14 @@ export function createResolveSpec(ctx) {
|
|
|
480
463
|
throw new HttpError(400, `compactionModel "${echoModelRef(body.compactionModel)}" is not @-mentionable on this deployment (it resolves to catalog model "${terminal}") — which models can be @-mentioned is configured by the operator (models.atMention)`, { code: "request.model_not_allowed" });
|
|
481
464
|
}
|
|
482
465
|
metrics.inc("task_model_not_allowlisted_resume_total");
|
|
483
|
-
logger.warn("task_model_not_allowlisted_resume", { requested: echoModelRef(body.compactionModel), resolved: terminal, source: "compaction", sessionId:
|
|
466
|
+
logger.warn("task_model_not_allowlisted_resume", { requested: echoModelRef(body.compactionModel), resolved: terminal, source: "compaction", sessionId: root, note: "resumed leg keeps the compaction model it was started with — the allowlist gates fresh picks only" });
|
|
484
467
|
}
|
|
485
468
|
return { compactionModel: cm };
|
|
486
469
|
})()),
|
|
487
470
|
thinking: effectiveThinking(body.reasoningEffort, parsedSettings.settings?.ultracode === true),
|
|
488
471
|
getApiKeyAndHeaders: getKeyResolver(),
|
|
489
472
|
...(() => {
|
|
490
|
-
const limits = resolveTaskLimits(body.limits, taskLimitCaps, taskTimeoutSec, config.requirePrincipal, (event, fields) => logger.warn(event, { ...fields, sessionId:
|
|
473
|
+
const limits = resolveTaskLimits(body.limits, taskLimitCaps, taskTimeoutSec, config.requirePrincipal, (event, fields) => logger.warn(event, { ...fields, sessionId: root }));
|
|
491
474
|
const declarations = [];
|
|
492
475
|
if (taskLimitCaps.timeoutSec !== undefined)
|
|
493
476
|
declarations.push({ key: "server.limits.timeoutSecCap", value: String(taskLimitCaps.timeoutSec), reason: "env TASK_TIMEOUT_MAX_SEC (seconds; operator ceiling applied to caller limits.maxWalltimeMs as cap×1000)" });
|
|
@@ -535,13 +518,13 @@ export function createResolveSpec(ctx) {
|
|
|
535
518
|
...(() => { const v = toolNameListFromBody(body.userInvokedSkills); return v ? { userInvokedSkills: v } : {}; })(),
|
|
536
519
|
...(parsedSettings.settings?.skillListingBudgetFraction !== undefined ? { skillListingBudgetFraction: parsedSettings.settings.skillListingBudgetFraction } : {}),
|
|
537
520
|
...(parsedSettings.settings?.skillListingMaxDescChars !== undefined ? { skillListingMaxDescChars: parsedSettings.settings.skillListingMaxDescChars } : {}),
|
|
538
|
-
mcp: resolveRequestMcp(mcpForScenario(config.mcpServers, scenarioName), body.mcpServers, config, peerDesk, opts.lease, logger, opts?.onNotice !== undefined ? { sessionId:
|
|
521
|
+
mcp: resolveRequestMcp(mcpForScenario(config.mcpServers, scenarioName), body.mcpServers, config, peerDesk, opts.lease, logger, opts?.onNotice !== undefined ? { sessionId: root, emit: opts.onNotice } : undefined, storedToolAxes),
|
|
539
522
|
a2a: resolveRequestA2a(a2aForScenario(config.a2aPeers, scenarioName), a2aPeers, config, peerDesk, opts.lease, logger, opts?.leg === "fresh" ? "fresh" : "resume", storedToolAxes),
|
|
540
523
|
toolPolicy: toolPolicyForHands(hands, durableEnabled
|
|
541
524
|
? createApprovalBaselinePolicy(config, {
|
|
542
525
|
kind: "durable",
|
|
543
526
|
question: liveQuestionFace,
|
|
544
|
-
...(approvalExemptionStore !== undefined
|
|
527
|
+
...(approvalExemptionStore !== undefined ? { exemption: createDeploymentListExemption(approvalExemptionStore, root, logger) } : {}),
|
|
545
528
|
})
|
|
546
529
|
: singleUserAutoAcceptBaselineApplies(config)
|
|
547
530
|
? createApprovalBaselinePolicy(config, { kind: "absent" })
|
|
@@ -568,7 +551,7 @@ export function createResolveSpec(ctx) {
|
|
|
568
551
|
};
|
|
569
552
|
return spec;
|
|
570
553
|
};
|
|
571
|
-
const foldGovernanceAndSettings = async (body, auth, spec, gated) => {
|
|
554
|
+
const foldGovernanceAndSettings = async (body, auth, root, spec, gated) => {
|
|
572
555
|
const { acceptedAppend, parsedSettings } = gated;
|
|
573
556
|
const hostSemanticsLane = !DEPLOYMENT_SHAPE_PREDICATES.sandboxPathAdjudication.holds(config);
|
|
574
557
|
const laneHomeBase = () => {
|
|
@@ -577,7 +560,7 @@ export function createResolveSpec(ctx) {
|
|
|
577
560
|
};
|
|
578
561
|
const pathAdjudication = hostSemanticsLane
|
|
579
562
|
? (() => {
|
|
580
|
-
const realRoot = realTaskRootOf(
|
|
563
|
+
const realRoot = realTaskRootOf(root);
|
|
581
564
|
const gateCwd = realRoot ?? join(config.localDataRoot ?? localRoot, "fs-write-gate-unrooted");
|
|
582
565
|
return {
|
|
583
566
|
env: new NodeExecutionEnv({ cwd: gateCwd }),
|
|
@@ -588,9 +571,9 @@ export function createResolveSpec(ctx) {
|
|
|
588
571
|
})()
|
|
589
572
|
: {
|
|
590
573
|
env: new DeferredSandboxPathEnv({
|
|
591
|
-
sessionId:
|
|
574
|
+
sessionId: root,
|
|
592
575
|
slots: sandboxPathEnvSlots,
|
|
593
|
-
logger: { warn: (event, fields) => logger.warn(event, { ...(fields ?? {}), lane: config.remoteExec
|
|
576
|
+
logger: { warn: (event, fields) => logger.warn(event, { ...(fields ?? {}), lane: config.remoteExec.provider }) },
|
|
594
577
|
}),
|
|
595
578
|
...laneHomeBase(),
|
|
596
579
|
};
|
|
@@ -598,18 +581,18 @@ export function createResolveSpec(ctx) {
|
|
|
598
581
|
let governed = governedBase;
|
|
599
582
|
let effectiveSettings = parsedSettings.settings;
|
|
600
583
|
if (effectiveSettings?.outputStyle && acceptedAppend && acceptedAppend.length + 2 + effectiveSettings.outputStyle.length > MAX_SETTINGS_OUTPUT_STYLE_CHARS) {
|
|
601
|
-
logger.warn("output_style_dropped", { detail: `combined append carriers exceed the ${MAX_SETTINGS_OUTPUT_STYLE_CHARS} cap (rider ${acceptedAppend.length} + style ${effectiveSettings.outputStyle.length}) — style dropped (pre-cap stored body on a resume leg?)`, sessionId:
|
|
584
|
+
logger.warn("output_style_dropped", { detail: `combined append carriers exceed the ${MAX_SETTINGS_OUTPUT_STYLE_CHARS} cap (rider ${acceptedAppend.length} + style ${effectiveSettings.outputStyle.length}) — style dropped (pre-cap stored body on a resume leg?)`, sessionId: root });
|
|
602
585
|
const { outputStyle: _dropped2, ...rest2 } = effectiveSettings;
|
|
603
586
|
effectiveSettings = Object.keys(rest2).length > 0 ? rest2 : undefined;
|
|
604
587
|
}
|
|
605
588
|
const shellScratchpad = await acceptShellScratchpadDir(body.scratchpadDir, {
|
|
606
589
|
requirePrincipal: config.requirePrincipal,
|
|
607
590
|
hostSemanticsLane,
|
|
608
|
-
warn: (msg, meta) => logger.warn(msg, { ...(meta ?? {}), sessionId:
|
|
591
|
+
warn: (msg, meta) => logger.warn(msg, { ...(meta ?? {}), sessionId: root }),
|
|
609
592
|
});
|
|
610
593
|
const scratchpadDir = shellScratchpad ??
|
|
611
|
-
(hostSemanticsLane
|
|
612
|
-
? await ensureScratchpadDir(config.localDataRoot ?? localRoot,
|
|
594
|
+
(hostSemanticsLane
|
|
595
|
+
? await ensureScratchpadDir(config.localDataRoot ?? localRoot, root, (msg, meta) => logger.warn(msg, { ...(meta ?? {}), sessionId: root }))
|
|
613
596
|
: undefined);
|
|
614
597
|
if (effectiveSettings) {
|
|
615
598
|
const configRoot = executionConfigRootOf(config);
|
|
@@ -629,11 +612,11 @@ export function createResolveSpec(ctx) {
|
|
|
629
612
|
}
|
|
630
613
|
if (governed.selfOrchestration === true) {
|
|
631
614
|
governed = tightenGoverned(governed, {
|
|
632
|
-
toolPolicy: createWorkflowAskPolicy(approvalExemptionStore
|
|
615
|
+
toolPolicy: createWorkflowAskPolicy(approvalExemptionStore
|
|
633
616
|
? async (toolName) => {
|
|
634
|
-
const hit = await approvalExemptionStore.has(
|
|
617
|
+
const hit = await approvalExemptionStore.has(root, toolName);
|
|
635
618
|
if (hit)
|
|
636
|
-
logger.info("workflow_gate_exempted", { toolName, sessionId:
|
|
619
|
+
logger.info("workflow_gate_exempted", { toolName, sessionId: root });
|
|
637
620
|
return hit;
|
|
638
621
|
}
|
|
639
622
|
: undefined),
|
|
@@ -641,40 +624,37 @@ export function createResolveSpec(ctx) {
|
|
|
641
624
|
}
|
|
642
625
|
return { governed, scratchpadDir, hostSemanticsLane };
|
|
643
626
|
};
|
|
644
|
-
const applyImageFactsAndRouting = async (body, auth, governed, folded) => {
|
|
627
|
+
const applyImageFactsAndRouting = async (body, auth, root, governed, folded) => {
|
|
645
628
|
const { scenarioName, scratchpadDir, hostSemanticsLane } = folded;
|
|
646
629
|
const bodyProfile = typeof body.sandboxImageProfile === "string" && body.sandboxImageProfile.length > 0 ? body.sandboxImageProfile : undefined;
|
|
647
|
-
const taskImageProfile = bodyProfile ?? (body.cascade === true || body.verify === true ? undefined : sessionEnvSelection.get(
|
|
630
|
+
const taskImageProfile = bodyProfile ?? (body.cascade === true || body.verify === true ? undefined : sessionEnvSelection.get(root));
|
|
648
631
|
let resolvedImageCaps;
|
|
649
632
|
if (taskImageProfile !== undefined) {
|
|
650
|
-
if (config.remoteExec
|
|
633
|
+
if (config.remoteExec.provider !== "k8s") {
|
|
651
634
|
throw createCodedHttpError(501, "capability.k8s_lane_required", "sandboxImageProfile is only supported on the k8s sandbox backend");
|
|
652
635
|
}
|
|
653
636
|
if (!imageIndex) {
|
|
654
637
|
throw createCodedHttpError(501, "capability.image_index_required", "sandboxImageProfile requires the sandbox-image-pool, which needs a SQL store backend (DB_BACKEND=mysql|pg) — this deployment's store wires no image index");
|
|
655
638
|
}
|
|
656
|
-
if (!auth?.sessionId) {
|
|
657
|
-
throw createCodedHttpError(400, "request.precondition_unmet", "sandboxImageProfile requires a resolved session");
|
|
658
|
-
}
|
|
659
639
|
const capsNeeded = Array.isArray(body.capabilitiesNeeded)
|
|
660
640
|
? body.capabilitiesNeeded.filter((c) => typeof c === "string")
|
|
661
641
|
: undefined;
|
|
662
642
|
const resolved = await resolveSandboxImageRef({
|
|
663
643
|
profile: taskImageProfile,
|
|
664
644
|
...(capsNeeded && capsNeeded.length > 0 ? { capabilitiesNeeded: capsNeeded } : {}),
|
|
665
|
-
viewer: { operator: explicitOperatorOk(auth
|
|
645
|
+
viewer: { operator: explicitOperatorOk(auth?.principal, config), tenantId: auth?.principal ?? null },
|
|
666
646
|
index: imageIndex,
|
|
667
647
|
});
|
|
668
648
|
if (!resolved.ok)
|
|
669
649
|
throw createCodedHttpError(resolved.status, resolved.errorCode, resolved.message);
|
|
670
|
-
perTaskImage.set(
|
|
650
|
+
perTaskImage.set(root, resolved.ref);
|
|
671
651
|
resolvedImageCaps = resolved.capabilities;
|
|
672
652
|
}
|
|
673
653
|
const remoteScratchpadDir = !hostSemanticsLane && DEPLOYMENT_SHAPE_PREDICATES.remoteScratchpad.holds(config)
|
|
674
|
-
? remoteScratchpadDirFor(
|
|
654
|
+
? remoteScratchpadDirFor(root)
|
|
675
655
|
: undefined;
|
|
676
656
|
const declaredScratchpadDir = scratchpadDir ?? remoteScratchpadDir;
|
|
677
|
-
const pkgSourceLane = config.remoteExec
|
|
657
|
+
const pkgSourceLane = config.remoteExec.provider === "e2b" || config.remoteExec.provider === "k8s";
|
|
678
658
|
const facts = buildEnvFacts({
|
|
679
659
|
...(declaredScratchpadDir ? { scratchpadDir: declaredScratchpadDir } : {}),
|
|
680
660
|
...(config.envFactsEnabled
|
|
@@ -683,7 +663,7 @@ export function createResolveSpec(ctx) {
|
|
|
683
663
|
capabilities: resolvedImageCaps,
|
|
684
664
|
...(pkgSourceLane ? { pkgSource: config.sandboxPkgSource } : {}),
|
|
685
665
|
egress: egressForRemoteExec(config.remoteExec),
|
|
686
|
-
resumeFacts: resumeFactsForLane(config.remoteExec
|
|
666
|
+
resumeFacts: resumeFactsForLane(config.remoteExec.provider, config.remoteExec.provider === "k8s" ? { k8sSnapshot: Boolean(config.remoteExec.s3Snapshot) } : undefined),
|
|
687
667
|
}
|
|
688
668
|
: {}),
|
|
689
669
|
});
|
|
@@ -692,10 +672,10 @@ export function createResolveSpec(ctx) {
|
|
|
692
672
|
if (config.routerEnabled) {
|
|
693
673
|
const decision = routeServiceTask({
|
|
694
674
|
vmIsolatedExecEnv: DEPLOYMENT_SHAPE_PREDICATES.vmIsolatedHands.holds(config),
|
|
695
|
-
hasExecutionEnv: laneWiresExecutionEnv(
|
|
675
|
+
hasExecutionEnv: laneWiresExecutionEnv(config.remoteExec.provider),
|
|
696
676
|
...(config.autonomy ? { autonomy: config.autonomy } : {}),
|
|
697
677
|
});
|
|
698
|
-
logger.info("orchestration_routed", { mode: decision.mode, reason: decision.reason, sessionId:
|
|
678
|
+
logger.info("orchestration_routed", { mode: decision.mode, reason: decision.reason, sessionId: root });
|
|
699
679
|
if (decision.mode === "supervisor") {
|
|
700
680
|
return tightenGoverned(governed, supPostureOverrides());
|
|
701
681
|
}
|
|
@@ -29,47 +29,16 @@
|
|
|
29
29
|
* (车1 已实现)。lane **不补记**它们 —— 补记 = 「删了但审计没落地」的窗口重新打开。receipt 在本文件里
|
|
30
30
|
* 只做两件事:二次确认(日志/指标)与「本轮到底动了多少」的读数。
|
|
31
31
|
*/
|
|
32
|
-
import type { RetentionPolicy
|
|
32
|
+
import type { RetentionPolicy } from "@sema-agent/core";
|
|
33
33
|
import type { RetentionMode } from "../config-types.js";
|
|
34
|
-
import type {
|
|
34
|
+
import type { SpaceReclaimer } from "../workspace-space.js";
|
|
35
|
+
import type { RetentionExecutor } from "../plugins/retention-deployment.js";
|
|
35
36
|
/** 同 domain 连续失败多少次算「卡住了」(fail-loud 的阈值)。`5` 与 reaper 家族的
|
|
36
37
|
* `REAPER_FAILURE_WARN_THRESHOLD` 同值同理由:一次抖动(一次重连、一次超时)正是容错要吸收的,
|
|
37
38
|
* 只有**连败**才越过「可诊断」这条线。 */
|
|
38
39
|
export declare const RETENTION_SWEEP_STUCK_THRESHOLD = 5;
|
|
39
40
|
/** 租约 TTL = 本倍数 × sweep 间隔(设计稿 §3)。`2` = 允许一轮跑满一个完整间隔还有余量,再多就该让位。 */
|
|
40
41
|
export declare const RETENTION_LEASE_TTL_FACTOR = 2;
|
|
41
|
-
/**
|
|
42
|
-
* lane 消费的**执行器**面 —— core `ManagedRetentionCapability` 的三方法 + 车1 的非契约窄读口
|
|
43
|
-
* `previewRetention`(audit-only 档的读数源;core 契约无 count 面)+ 声明位。
|
|
44
|
-
*
|
|
45
|
-
* 🔴 三方法的入参是 core 契约形的**超集**(多一个 `audit`):车1 的店在运行期对缺席的审计上下文
|
|
46
|
-
* fail-closed 抛错,所以这里把它写进类型 —— 让「忘了传」变成编译错,而不是一次运行期的破坏性调用被拒。
|
|
47
|
-
*/
|
|
48
|
-
export interface RetentionExecutor {
|
|
49
|
-
readonly retention?: "managed" | "none";
|
|
50
|
-
listRetentionDomains(): Promise<readonly string[]>;
|
|
51
|
-
previewRetention(input: {
|
|
52
|
-
domain: string;
|
|
53
|
-
cutoffMs: number;
|
|
54
|
-
}): Promise<{
|
|
55
|
-
checkpoints: number;
|
|
56
|
-
sessions: number;
|
|
57
|
-
toolResults: number;
|
|
58
|
-
}>;
|
|
59
|
-
expireCheckpoints(input: RetentionDestructiveInput): Promise<RetentionReceipt>;
|
|
60
|
-
deleteExpiredSessions(input: RetentionDestructiveInput): Promise<RetentionSessionsReceipt>;
|
|
61
|
-
deleteOrphanToolResults(input: RetentionDestructiveInput): Promise<RetentionReceipt>;
|
|
62
|
-
}
|
|
63
|
-
/** 破坏性调用的入参(判定时点的三格随行 —— 理由逐字见车1 `RetentionAuditContext` 的头注)。 */
|
|
64
|
-
export interface RetentionDestructiveInput {
|
|
65
|
-
domain: string;
|
|
66
|
-
cutoffMs: number;
|
|
67
|
-
audit: {
|
|
68
|
-
mode: RetentionMode;
|
|
69
|
-
policyDays: number;
|
|
70
|
-
fencingToken: number | null;
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
42
|
/** 非破坏性审计行的写口(lane 侧属主的那五个词)。 */
|
|
74
43
|
export interface RetentionAuditSink {
|
|
75
44
|
append(row: {
|
|
@@ -132,13 +101,6 @@ export interface RetentionSweepCtx {
|
|
|
132
101
|
* (缓存卷、`space/` 快照、该会话停驻车道的快照一并回收)。它从不抛(失败 = 一行 + fail-open 计数);缺席 = 本部署没有可回收的东西。 */
|
|
133
102
|
spaceReclaimer?: SpaceReclaimer;
|
|
134
103
|
}
|
|
135
|
-
/**
|
|
136
|
-
* 会话树 sweep 的回执 = core 契约的 `RetentionReceipt` + 本仓一位:`endedSpaces` = 本次删掉的会话树里**结束了的空间**(会话 id + 住客空间键 = 会话化身;
|
|
137
|
-
* 读不出住客的空化身不算),present-iff 非空。lane 把它交给空间的回收座(与会话删除协调器同一只),缓存卷与快照随空间的终结回收。
|
|
138
|
-
*/
|
|
139
|
-
export type RetentionSessionsReceipt = RetentionReceipt & {
|
|
140
|
-
readonly endedSpaces?: readonly EndedSpace[];
|
|
141
|
-
};
|
|
142
104
|
/** 一轮的读数(给日志与判据用;lane 自己不做任何决策依赖它)。 */
|
|
143
105
|
export interface RetentionSweepOutcome {
|
|
144
106
|
/** 本轮真正处理完的 domain 数(丢租中止时 = 中止之前那些)。 */
|
|
@@ -168,7 +130,7 @@ export interface RetentionSweepOutcome {
|
|
|
168
130
|
* 为什么本道必须存在:引擎的门不拦
|
|
169
131
|
* · 没锁时,执行器在场 × 一只 `"none"` 的店 —— 部署于是**广告了一个不执行的留存面**:能力位说
|
|
170
132
|
* `{mode,maxAgeDays}`、审计表也在长,而那只店的行谁都没在删。
|
|
171
|
-
* 本仓的 SQL 后端按同一个事实(扫车道开不开,`plugins/retention-
|
|
133
|
+
* 本仓的 SQL 后端按同一个事实(扫车道开不开,`plugins/retention-declaration.ts` 的 `retentionSweepRuns`)给它铸的三只店声明词,所以 lane 开着时
|
|
172
134
|
* 这三只店在这一格上恒是 `managed`;这一格防的是声明与 lane 脱钩的店(别的后端、替身)。
|
|
173
135
|
* 这些都在**启动期**拒(安全控件不得半开),不是让运维从一台"启动成功、什么也没删"的机器上猜。
|
|
174
136
|
*
|