@sema-agent/server 7.132.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 +266 -0
- package/README.md +8 -9
- package/README.zh-CN.md +7 -6
- package/USAGE.md +174 -55
- 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 +79 -19
- package/dist/approval-card.js +44 -13
- 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 +27 -10
- package/dist/audit.js +12 -16
- package/dist/bake-runner/main.js +3 -2
- package/dist/boot/deferred-sandbox-path-env.js +1 -1
- package/dist/boot/execution-env.js +9 -7
- package/dist/boot/execution-lane.js +11 -0
- package/dist/boot/leader.js +2 -0
- 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/reapers.d.ts +3 -0
- package/dist/boot/reapers.js +21 -1
- package/dist/boot/resolve-spec.d.ts +3 -0
- package/dist/boot/resolve-spec.js +60 -81
- package/dist/boot/runner-deps.js +1 -0
- package/dist/boot/session-faces.d.ts +1 -0
- package/dist/boot/session-faces.js +4 -2
- package/dist/boot/stage-02-web-admin-pull.js +4 -1
- package/dist/boot/stage-06-runners.d.ts +2 -0
- package/dist/boot/stage-06-runners.js +6 -3
- package/dist/boot/stage-07-capability-layer.d.ts +2 -0
- package/dist/boot/stage-07-capability-layer.js +24 -3
- package/dist/boot/stage-08-reapers.d.ts +2 -0
- package/dist/boot/stage-08-reapers.js +2 -2
- package/dist/boot/stage-09-leader.d.ts +3 -0
- package/dist/boot/stage-10-http-server.d.ts +3 -0
- package/dist/boot/stage-10-http-server.js +5 -6
- package/dist/boot/stores.js +2 -2
- package/dist/boot/web-admin.d.ts +4 -0
- package/dist/boot/web-admin.js +151 -63
- package/dist/boot/workflow-orchestration.d.ts +2 -0
- package/dist/boot/workflow-orchestration.js +2 -1
- package/dist/brain.js +8 -3
- package/dist/breaker-key.d.ts +6 -0
- package/dist/breaker-key.js +29 -0
- package/dist/caller-text-echo.d.ts +9 -6
- package/dist/caller-text-echo.js +8 -11
- package/dist/capabilities/center-plugins.d.ts +7 -0
- package/dist/capabilities/center-plugins.js +1 -1
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/capabilities/execution-lane.js +2 -2
- package/dist/capabilities/hands-lane.d.ts +21 -0
- package/dist/capabilities/hands-lane.js +10 -0
- package/dist/capabilities/mcp-probe.d.ts +36 -4
- package/dist/capabilities/mcp-probe.js +27 -4
- package/dist/capabilities/scenarios.d.ts +63 -7
- package/dist/capabilities/scenarios.js +39 -7
- 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 +43 -28
- 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-provider.d.ts +6 -1
- package/dist/config-provider.js +6 -2
- package/dist/config-types.d.ts +71 -14
- package/dist/config-types.js +8 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.js +121 -59
- 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 -23
- package/dist/elicitation.js +3 -2
- package/dist/entry-problems.d.ts +34 -0
- package/dist/entry-problems.js +14 -0
- package/dist/execution-lane-caps.d.ts +49 -10
- package/dist/execution-lane-caps.js +43 -4
- 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 +10 -5
- package/dist/hooks/classic-stations.js +4 -4
- package/dist/hooks/command-spawn.d.ts +57 -0
- package/dist/hooks/command-spawn.js +139 -0
- package/dist/hooks/hook-llm.js +2 -2
- package/dist/hooks/hook-runner.d.ts +127 -25
- package/dist/hooks/hook-runner.js +668 -287
- 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.js +103 -60
- package/dist/http/approval-sweeps.js +55 -18
- package/dist/http/caller-trust.d.ts +77 -0
- package/dist/http/caller-trust.js +143 -0
- package/dist/http/checkpoint-ctx.d.ts +16 -16
- package/dist/http/checkpoint-ctx.js +13 -10
- package/dist/http/claimed-run.d.ts +4 -3
- package/dist/http/device-placement.d.ts +2 -4
- package/dist/http/device-placement.js +2 -1
- package/dist/http/dispatch.js +10 -4
- package/dist/http/durable-run-leg.d.ts +4 -32
- package/dist/http/durable-run-leg.js +34 -10
- package/dist/http/owner-access.d.ts +56 -0
- package/dist/http/owner-access.js +42 -0
- package/dist/http/principal-gate.d.ts +48 -23
- package/dist/http/principal-gate.js +39 -12
- package/dist/http/readiness.d.ts +11 -5
- package/dist/http/readiness.js +10 -3
- package/dist/http/request-guards.d.ts +16 -23
- package/dist/http/request-guards.js +30 -15
- 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 +3 -4
- package/dist/http/resume-legs.js +126 -69
- 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 +20 -4
- 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 +5 -1
- 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 +33 -106
- package/dist/http/routes/session-sync.js +15 -28
- package/dist/http/routes/sessions.js +30 -40
- package/dist/http/routes/side-query.js +6 -4
- package/dist/http/routes/tasks.js +50 -14
- package/dist/http/routes/workflows.d.ts +351 -0
- package/dist/http/routes/workflows.js +153 -119
- package/dist/http/send.d.ts +24 -3
- package/dist/http/send.js +14 -2
- package/dist/http/server.d.ts +17 -18
- package/dist/http/server.js +15 -13
- package/dist/http/stored-body-replay.js +17 -4
- package/dist/http/submit-ctx.js +4 -3
- package/dist/http/submit-replay.d.ts +4 -3
- package/dist/http/submit-replay.js +5 -4
- package/dist/http/wire-types.d.ts +10 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +0 -1
- package/dist/lane-home-probe.d.ts +78 -9
- package/dist/lane-home-probe.js +78 -12
- package/dist/leader/endpoint.d.ts +4 -1
- package/dist/leader/endpoint.js +11 -10
- package/dist/limit-refusal.d.ts +17 -5
- package/dist/limit-refusal.js +4 -1
- package/dist/mcp-assertion-header.d.ts +31 -10
- package/dist/mcp-assertion-header.js +10 -3
- package/dist/mcp-tool-faces.js +1 -3
- package/dist/memory-project-layer.d.ts +37 -0
- package/dist/memory-project-layer.js +46 -0
- package/dist/memory-scope.d.ts +23 -16
- 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 +5 -0
- package/dist/model-provider.js +4 -2
- package/dist/model-route-endpoint.d.ts +8 -11
- package/dist/model-route-endpoint.js +4 -7
- 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/err-text.d.ts +6 -0
- package/dist/observability/err-text.js +18 -4
- package/dist/observability/fail-open.d.ts +35 -9
- package/dist/observability/fail-open.js +35 -9
- package/dist/observability/metrics.js +1 -0
- package/dist/observability/prompt-manifest.d.ts +3 -17
- package/dist/observability/prompt-manifest.js +45 -42
- package/dist/observability/tool-trace.js +9 -9
- 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/permission-rule-list.d.ts +1 -1
- package/dist/permission-rule-list.js +2 -2
- 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 +38 -25
- package/dist/plugins/blob-backend.js +29 -19
- 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 +14 -0
- package/dist/plugins/checkpoint-store-sql.js +20 -2
- 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/local-checkpoint-store.d.ts +2 -0
- package/dist/plugins/local-checkpoint-store.js +6 -1
- package/dist/plugins/local-session-store.d.ts +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 +110 -5
- package/dist/plugins/one-time-migrations.js +320 -8
- package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
- package/dist/plugins/org-delivery-quota-store.js +228 -0
- package/dist/plugins/pg-pool.js +39 -7
- package/dist/plugins/pg-session-storage.d.ts +17 -4
- package/dist/plugins/pg-session-storage.js +29 -6
- package/dist/plugins/remote-env-adb.d.ts +6 -12
- package/dist/plugins/remote-env-adb.js +12 -2
- package/dist/plugins/remote-env-k8s.d.ts +8 -12
- package/dist/plugins/remote-env-k8s.js +23 -5
- package/dist/plugins/remote-env-local-docker.d.ts +10 -15
- package/dist/plugins/remote-env-local-docker.js +12 -9
- package/dist/plugins/remote-env-ssh.d.ts +10 -16
- package/dist/plugins/remote-env-ssh.js +17 -11
- package/dist/plugins/run-store-sql.d.ts +16 -14
- package/dist/plugins/run-store-sql.js +22 -2
- 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 +32 -6
- package/dist/plugins/session-epoch-anchor.js +2 -3
- package/dist/plugins/session-store.d.ts +18 -8
- package/dist/plugins/session-store.js +15 -4
- package/dist/plugins/sql-driver.d.ts +74 -11
- package/dist/plugins/sql-driver.js +210 -12
- package/dist/plugins/sql-errors.d.ts +23 -0
- package/dist/plugins/sql-errors.js +21 -0
- package/dist/plugins/store-backend.d.ts +36 -1
- package/dist/plugins/store-backend.js +40 -14
- 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 +3 -2
- package/dist/plugins/tidb-session-storage.js +2 -2
- package/dist/plugins/tidb-session-store.d.ts +24 -4
- package/dist/plugins/tidb-session-store.js +28 -4
- 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/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 +7 -0
- package/dist/request-key-closure.js +9 -1
- package/dist/request-value-closure.d.ts +5 -0
- package/dist/request-value-closure.js +11 -3
- package/dist/rule-entry-list.d.ts +26 -2
- package/dist/rule-entry-list.js +72 -12
- 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 +36 -6
- package/dist/runs.d.ts +10 -9
- package/dist/runs.js +21 -3
- 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/session-error-wire.d.ts +19 -2
- package/dist/session-error-wire.js +5 -1
- 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 +15 -4
- package/dist/spec-fields.js +21 -2
- package/dist/sql-engine-posture.d.ts +3 -1
- package/dist/task-cwd.d.ts +1 -1
- package/dist/task-mcp.d.ts +3 -3
- package/dist/task-mcp.js +7 -66
- package/dist/task-settings.d.ts +89 -88
- package/dist/task-settings.js +71 -63
- package/dist/text-bidi.d.ts +0 -4
- package/dist/text-bidi.js +1 -3
- package/dist/tighten-only-seats.d.ts +150 -0
- package/dist/tighten-only-seats.js +196 -0
- package/dist/tool-approval.d.ts +303 -87
- package/dist/tool-approval.js +623 -239
- package/dist/trace/core-keyset-guard.d.ts +104 -22
- package/dist/trace/exit-seat.d.ts +28 -0
- package/dist/trace/exit-seat.js +76 -0
- package/dist/trace/ledger-events.d.ts +3 -2
- package/dist/trace/project.d.ts +80 -12
- package/dist/trace/project.js +41 -28
- 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 +298 -2
- package/dist/trace/wire-projection-faces.js +154 -13
- 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/facade.d.ts +1 -1
- package/dist/web-admin-client/facade.js +1 -1
- package/dist/web-admin-client/read-face.js +5 -9
- package/dist/web-admin-client/skills-mcp.js +4 -5
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -9
- package/package.json +7 -3
package/dist/http/route-ctx.d.ts
CHANGED
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
18
18
|
import type { HostDecision } from "../host-decision.js";
|
|
19
|
+
import type { EntryProblem } from "../entry-problems.js";
|
|
20
|
+
import type { SessionOwnerCell } from "../security.js";
|
|
19
21
|
import type { TaskStream, TaskSpec, TaskResult, QuestionAnswer, Checkpoint, CheckpointToken, ResumeOutcome, RunInternals, Runner, EngineNotice } from "@sema-agent/core";
|
|
20
22
|
import type { FlatServiceDeps, RequestAuth } from "./server.js";
|
|
21
23
|
import type { TaskRequestBody, DecideBinding } from "./wire-types.js";
|
|
@@ -75,8 +77,9 @@ export interface RouteHelpers {
|
|
|
75
77
|
/** run 面的属主门(谓词 `runOwnerReadable`;非属主 ⇒ 404 `not_found.run` + 长文,与 run 读口的 unknown 臂同码同串,[ref])。 */
|
|
76
78
|
runOwnerOk(req: IncomingMessage, res: ServerResponse, owner: string | null): boolean;
|
|
77
79
|
/** 会话面的属主门(谓词 `sessionOwnerReadable`,S-1452:没有身份边界的部署不钉人,与会话列表同读;非属主 ⇒ 404 `not_found.session` +
|
|
78
|
-
* {@link SESSION_NOT_FOUND_MESSAGE},与会话读口的 unknown 臂同码同串 —— G52 [ref] / S-989)。每一个按会话寻址的属主判都走它。
|
|
79
|
-
|
|
80
|
+
* {@link SESSION_NOT_FOUND_MESSAGE},与会话读口的 unknown 臂同码同串 —— G52 [ref] / S-989)。每一个按会话寻址的属主判都走它。
|
|
81
|
+
* `cell` = 调用点经 `security.ts` 的 `sessionOwnerCellOf` 读出的那一格(S-1770:无主的委派子代 placed 行只对 fleet 调用方放行,判据 `ownerlessRowOpen`)。 */
|
|
82
|
+
sessionOwnerOk(req: IncomingMessage, res: ServerResponse, cell: SessionOwnerCell): boolean;
|
|
80
83
|
sessionOwnerScope(req: IncomingMessage): {
|
|
81
84
|
fleetWide: boolean;
|
|
82
85
|
gateOwner: string | null;
|
|
@@ -132,6 +135,12 @@ export interface PreparedTaskSubmission {
|
|
|
132
135
|
* 装配跑在这条腿的通告口开张之前,所以铸点交不出去 —— 由腿在 `registerEngineNoticeLeg` 那一拍
|
|
133
136
|
* 经 `pending` 一起投(投递单点仍是那一只注册助手,不新开第二条机制)。缺席 = 本次装配没铸下任何通告。 */
|
|
134
137
|
engineNotices?: readonly EngineNotice[];
|
|
138
|
+
/**
|
|
139
|
+
* 受理时对**放行侧选择器清单**(根 `allowTools`、子代定义的 `allowTools`)的告知(`rule-entry-list.ts` 的 `allowSelectorWarningsOf`):受理了、没拒,但这几条条目什么也不放
|
|
140
|
+
* (引擎读不出,或名字不在名册)。三条提交腿在各自的受理应答里原样带成 `warnings`(同步腿 200 体 · 流式腿 `meta` 帧 · 异步腿 202 回执);缺席 = 没有话说。
|
|
141
|
+
* 判的是**这一次提交**的体:幂等重放从 run 记录答,不重判、不带。
|
|
142
|
+
*/
|
|
143
|
+
warnings?: readonly EntryProblem[];
|
|
135
144
|
/**
|
|
136
145
|
* S-470(device lane 首绑写协议,design §4.3.2 两阶段 placement)—— **已校验、未写库**的 placement 意图。
|
|
137
146
|
*
|
|
@@ -191,6 +200,28 @@ export interface CheckpointCtx {
|
|
|
191
200
|
*/
|
|
192
201
|
writerVersion?: string;
|
|
193
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* `/decide` 第三条车道交给宿主投递腿(wake:`DriveResumeArgs` / fresh:`DurableRunLegArgs`)的**一件**:这一跑在内存里带着的决定,
|
|
205
|
+
* 与开跑之前落行的那一笔。两位只能一起给 —— 型上拆不开:送出一条决定的那一跑,开跑之前一定已经把它落成行(律的属主 =
|
|
206
|
+
* `orchestration/workflow-park-decision.ts` 文件头「先落行、后开跑」)。
|
|
207
|
+
* 🔴 **TRUSTED**:绝不是 `TaskSpec` 字段、也绝不是工具参数(模型不能决定一次审批)。
|
|
208
|
+
*/
|
|
209
|
+
export interface WorkflowDecisionDelivery {
|
|
210
|
+
/**
|
|
211
|
+
* 这一跑在内存里带着的那条决定(`RunInternals.workflowParkedResume` 的元素形,直接取 core 的那一位 —— 手抄一份结构等价的字面会让更宽的
|
|
212
|
+
* `token: string` 悄悄通过)。为什么要随腿带:起跑读者(`parked-decide.ts` 的 `heldWorkflowParkDecisions`)在落行**之前**读行(wake 腿的
|
|
213
|
+
* internals 在引擎的 pre-CAS 守卫之前就交进去了),读不到这一笔;读者把两者按 token 合并,同一张卡以它为准(与随后落的是同一条)。
|
|
214
|
+
*/
|
|
215
|
+
readonly carried: NonNullable<RunInternals["workflowParkedResume"]>;
|
|
216
|
+
/**
|
|
217
|
+
* 落行:宿主会话的认领在手、这一跑再没有任何会变成拒绝的判定之后、**开跑之前**调一次,`taskId` = 这一跑(行上的 `deliveredTaskId`)。
|
|
218
|
+
* wake 腿挂在引擎的 `afterCheckpointResolve` 座(resolve CAS 赢下之后、续跑那一腿开跑之前);fresh 腿在建行、落点、续跑输入之后、起跑之前。
|
|
219
|
+
* 写在决定店所绑 run 店的认领栅栏里:`taskId` 那一拍已不持有宿主会话的认领(被收割 / 已归别人)⇒ 不写、抛。担保止于栅栏那一拍 —— 写提交之后
|
|
220
|
+
* 这一跑才失去认领(提交确认迟到 / 进程停顿),它照样开跑、带着这一份(引擎 checkpoint 先 resolve 者赢;店头注「不承诺的半句」)。
|
|
221
|
+
* 抛 ⇒ 这一跑不开、认领放掉、响亮 500(wake:引擎把抛原样带出 `resumeStream`,普通异常臂终结合成行;fresh:`releaseClaimedRun` 撤行)。
|
|
222
|
+
*/
|
|
223
|
+
readonly commitBeforeLaunch: (taskId: string) => Promise<void>;
|
|
224
|
+
}
|
|
194
225
|
/** B4①(命名化):`driveResumeIntoRunLog` 的入参形(resume 家族共用)——原为 9 成员内联匿名对象。 */
|
|
195
226
|
export interface DriveResumeArgs {
|
|
196
227
|
token: CheckpointToken;
|
|
@@ -265,27 +296,8 @@ export interface DriveResumeArgs {
|
|
|
265
296
|
mintFreshRun?: {
|
|
266
297
|
source: string;
|
|
267
298
|
};
|
|
268
|
-
/**
|
|
269
|
-
|
|
270
|
-
* (`RunInternals.workflowParkedResume`)。
|
|
271
|
-
*
|
|
272
|
-
* 为什么是这里、为什么是这个形:core 给部署方留的**唯一**通道就是它(d.ts 逐字:「A host that decided a
|
|
273
|
-
* workflow child's parked checkpoint **launches the run that re-invokes** `Workflow({resumeFromRunId})`
|
|
274
|
-
* with the decision here」)。宿主这一跑的模型再调一次 `Workflow({resumeFromRunId})` 时,工具的
|
|
275
|
-
* `parkedResume` dep 只挑出 `runId` 命中这次 resume 源的条目,交给 `RunWorkflowOptions.parkedResume`,
|
|
276
|
-
* 于是那个 parked ordinal 带着人的决定继续,而不是再 park 一次。
|
|
277
|
-
*
|
|
278
|
-
* 🔴 **TRUSTED**:它绝不是 `TaskSpec` 字段、也绝不是工具参数(模型不能决定一次审批)。唯一的铸点是
|
|
279
|
-
* `/decide` 的第三条车道(判据属主 = `parked-decide.ts` 的 `planWorkflowParkedDecide` 顶注)。
|
|
280
|
-
* 缺席 ⇒ 本位对这条腿是完整 no-op,与本批之前逐字相同。
|
|
281
|
-
*
|
|
282
|
-
* 🔴 **形不手抄:直接是 core 的那一位**(`NonNullable<RunInternals["workflowParkedResume"]>`)。手抄一份
|
|
283
|
-
* 结构等价的字面(本位 7.73.0 及以前就是)会让 `token: string` / `inheritedGate: unknown` 这种**更宽**的
|
|
284
|
-
* 形悄悄通过,再靠下游一个 `as NonNullable<RunInternals[...]>` 把它洗进 core 的 branded 位 —— 那个转型
|
|
285
|
-
* 正是「边界必 schema、禁自铸」要挡的东西(裸 string 当赎回键传进去,编译期一个字都不响)。派生之后
|
|
286
|
-
* core 改这一位(本版就把 `WorkflowParkedResume.outcome` 改成了可选)在本仓是**编译事件**,不是靠人去
|
|
287
|
-
* 对表的一行注。 */
|
|
288
|
-
workflowParkedResume?: NonNullable<RunInternals["workflowParkedResume"]>;
|
|
299
|
+
/** `/decide` 第三条车道交给本腿的那一件决定投递(语义属主 = {@link WorkflowDecisionDelivery} 顶注)。缺席 ⇒ 只摊决定行(其余四条 resume 腿恒缺席)。 */
|
|
300
|
+
workflowDecision?: WorkflowDecisionDelivery;
|
|
289
301
|
/** [ref]([ref] Inkglow 案 → [ref]① 定谳):**200 受理语义**——调用方声明「我的消费方按 poll/SSE 跟
|
|
290
302
|
* 终态,别让 HTTP 等模型往返」。在场为 `true` 时本腿在**受理点**(`resumeStream` 解析之后)立刻把
|
|
291
303
|
* `200 {taskId, status:"resuming", bindingEnforced:true}` 交回调用方,模型腿(流迭代 + 行驱动)继续
|
|
@@ -435,11 +447,9 @@ export interface RouteLegs {
|
|
|
435
447
|
/** [ref] 件 S-1:透传给 {@link DriveResumeArgs.acceptEarly}(200 受理语义)。HTTP `/wake` 腿传 `true`
|
|
436
448
|
* —— 本腿走 `mintFreshRun`,受理体里的 `taskId` 因此是**新铸的**那个(壳的 poll 锚)。 */
|
|
437
449
|
acceptEarly?: boolean,
|
|
438
|
-
/**
|
|
439
|
-
*
|
|
440
|
-
|
|
441
|
-
* 路径」的成文纪律。 */
|
|
442
|
-
workflowParkedResume?: DriveResumeArgs["workflowParkedResume"]): Promise<HostLegOutcome>;
|
|
450
|
+
/** 透传给 {@link DriveResumeArgs.workflowDecision}。HTTP `/wake` 腿**不设**此位 —— 它是 `/decide` 第三条车道投递腿的专用席,
|
|
451
|
+
* 而两条腿共用这一条驱动路径正是 `notify-wake.ts` 那条「wake 会烧模型,所以复用 resume 家族的同一条腿」的成文纪律。 */
|
|
452
|
+
workflowDecision?: WorkflowDecisionDelivery): Promise<HostLegOutcome>;
|
|
443
453
|
/**
|
|
444
454
|
* assistant plan_review 三态腿的**纯读段**(S-609,7.97.0):选卡 → 属主轻读 → 载入 → 行级 scope → 门类 → 这条决断
|
|
445
455
|
* 唯一的一次 ctx 读。任何一步拒 ⇒ `{ok:false, answer}`(不改任何状态;端点在消费一次性 nonce **之前**把它答出去);
|
|
@@ -722,6 +732,12 @@ export declare function acceptedResumingReceipt(taskId: string, sessionId: strin
|
|
|
722
732
|
status: number;
|
|
723
733
|
body: object;
|
|
724
734
|
};
|
|
735
|
+
/** 一条腿的结局是不是一张「已受理」回执,是 ⇒ 回执上那一跑的 `taskId`(同一张回执的读法与 {@link acceptedResumingReceipt} 住在一起;
|
|
736
|
+
* `/decide` 的 workflow 车道据它把投递那一跑记在决定行上)。 */
|
|
737
|
+
export declare function acceptedTaskIdOf(out: {
|
|
738
|
+
status: number;
|
|
739
|
+
body: object;
|
|
740
|
+
}): string | undefined;
|
|
725
741
|
export declare const RUN_NOT_FOUND_MESSAGE = "run not found \u2014 the id belongs to no run in this deployment's run store (a run from another server process, or an in-memory store that did not survive a restart, is not visible here)";
|
|
726
742
|
/**
|
|
727
743
|
* 会话资源面 404 的**唯一一句**(与 {@link RUN_NOT_FOUND_MESSAGE} 同一冻结纪律,常量锚在 `test/api-error-text-freeze.test.ts`)。
|
package/dist/http/route-ctx.js
CHANGED
|
@@ -27,6 +27,10 @@ export function buildHostLegOutcome(out) {
|
|
|
27
27
|
export function acceptedResumingReceipt(taskId, sessionId) {
|
|
28
28
|
return { status: 200, body: { taskId, sessionId, status: "resuming", bindingEnforced: true } };
|
|
29
29
|
}
|
|
30
|
+
export function acceptedTaskIdOf(out) {
|
|
31
|
+
const body = out.body;
|
|
32
|
+
return out.status === 200 && "taskId" in body && typeof body.taskId === "string" && body.taskId !== "" ? body.taskId : undefined;
|
|
33
|
+
}
|
|
30
34
|
export const RUN_NOT_FOUND_MESSAGE = "run not found — the id belongs to no run in this deployment's run store (a run from another server process, or an in-memory store that did not survive a restart, is not visible here)";
|
|
31
35
|
export const SESSION_NOT_FOUND_MESSAGE = "session not found";
|
|
32
36
|
export function runNotFoundMessage(id) {
|
package/dist/http/route-table.js
CHANGED
|
@@ -14,6 +14,7 @@ import { handleMemoryCompliance, MEMORY_COMPLIANCE_ROUTES } from "./routes/memor
|
|
|
14
14
|
import { handleMemoryOrigin, MEMORY_ORIGIN_ROUTES } from "./routes/memory-origin.js";
|
|
15
15
|
import { handleMemoryConsolidation, MEMORY_CONSOLIDATION_ROUTES } from "./routes/memory-consolidation.js";
|
|
16
16
|
import { handleSharedMemory, SHARED_MEMORY_ROUTES } from "./routes/shared-memory.js";
|
|
17
|
+
import { handlePrincipalInbox, PRINCIPAL_INBOX_ROUTES } from "./routes/principal-inbox.js";
|
|
17
18
|
import { handleRules, RULES_ROUTES } from "./routes/rules.js";
|
|
18
19
|
import { handleSessionsList, SESSIONS_LIST_ROUTES } from "./routes/sessions-list.js";
|
|
19
20
|
import { handleAgentRoster, AGENT_ROSTER_ROUTES } from "./routes/agents-roster.js";
|
|
@@ -71,6 +72,7 @@ export const ROUTES = [
|
|
|
71
72
|
row({ handler: handleMemoryConsolidation, decls: MEMORY_CONSOLIDATION_ROUTES, position: "post-credential", label: "memory-consolidation" }),
|
|
72
73
|
row({ handler: handleRules, decls: RULES_ROUTES, position: "post-credential", label: "rules" }),
|
|
73
74
|
row({ handler: handleSharedMemory, decls: SHARED_MEMORY_ROUTES, position: "post-credential", label: "shared-memory" }),
|
|
75
|
+
row({ handler: handlePrincipalInbox, decls: PRINCIPAL_INBOX_ROUTES, position: "post-credential", label: "principal-inbox" }),
|
|
74
76
|
row({ handler: handleSessionsList, decls: SESSIONS_LIST_ROUTES, position: "post-credential", label: "sessions-list" }),
|
|
75
77
|
row({ handler: handleAgentRoster, decls: AGENT_ROSTER_ROUTES, position: "post-credential", label: "agent-roster" }),
|
|
76
78
|
row({ handler: handleSessions, decls: SESSIONS_ROUTES, position: "post-credential", label: "sessions" }),
|
|
@@ -9,6 +9,7 @@ import { isActiveRunConflictBody } from "../active-run-conflict.js";
|
|
|
9
9
|
import { sendJson, sendError } from "../send.js";
|
|
10
10
|
import { admissionRefusalOf, readinessOf, sendBillableRefusal } from "../readiness.js";
|
|
11
11
|
import { gatedPrincipal, sendPrincipalRefusal } from "../principal-gate.js";
|
|
12
|
+
import { readOwnedRun } from "../owner-access.js";
|
|
12
13
|
import { assertNever } from "../route-ctx.js";
|
|
13
14
|
import * as facts from "../../capability-facts.js";
|
|
14
15
|
import { createDurableRun } from "./runs.js";
|
|
@@ -241,7 +242,7 @@ async function handleMessageSend({ req, res, ctx, params, serve, runStore }) {
|
|
|
241
242
|
.update(contextId ?? "").update("\x1f")
|
|
242
243
|
.update(skillId ?? "")
|
|
243
244
|
.digest("hex");
|
|
244
|
-
const submitter =
|
|
245
|
+
const submitter = gatedPrincipal(req, deps.config);
|
|
245
246
|
const idem = { key: idemKeyOf(fingerprint, caller, "run"), bodyFingerprint: fingerprint };
|
|
246
247
|
const body = {
|
|
247
248
|
objective,
|
|
@@ -315,11 +316,9 @@ function durableIdempotencyTaskId(scope, messageId) {
|
|
|
315
316
|
async function handleTasksGet({ req, ctx, params, runStore }) {
|
|
316
317
|
const { deps } = ctx;
|
|
317
318
|
const id = asNonEmptyString(params.id, "params.id", MAX_TASK_ID_CHARS);
|
|
318
|
-
const run = await runStore.
|
|
319
|
+
const run = await readOwnedRun(deps.config, runStore, gatedPrincipal(req, deps.config), id, "owner");
|
|
319
320
|
if (!run)
|
|
320
321
|
throw new RpcError(A2A_TASK_NOT_FOUND, A2A_TASK_NOT_FOUND_MESSAGE);
|
|
321
|
-
if (run.owner !== null && gatedPrincipal(req, deps.config) !== run.owner)
|
|
322
|
-
throw new RpcError(A2A_TASK_NOT_FOUND, A2A_TASK_NOT_FOUND_MESSAGE);
|
|
323
322
|
return taskFromRun(run, isStaleRun(run, deps.config.runStaleSec));
|
|
324
323
|
}
|
|
325
324
|
const A2A_METHODS = {
|
|
@@ -17,7 +17,7 @@ export async function handleAdminConfigRefresh(req, res, match, ctx) {
|
|
|
17
17
|
sendOperatorPrincipalsRequired(res);
|
|
18
18
|
return;
|
|
19
19
|
}
|
|
20
|
-
if (!explicitOperatorOk(principal, deps.config
|
|
20
|
+
if (!explicitOperatorOk(principal, deps.config)) {
|
|
21
21
|
sendError(res, 403, "auth.operator_only", OPERATOR_ONLY_MESSAGE);
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
@@ -21,7 +21,7 @@ export async function handleAdminDrain(req, res, match, ctx) {
|
|
|
21
21
|
sendOperatorPrincipalsRequired(res);
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
|
-
if (!explicitOperatorOk(principal, deps.config
|
|
24
|
+
if (!explicitOperatorOk(principal, deps.config)) {
|
|
25
25
|
sendError(res, 403, "auth.operator_only", OPERATOR_ONLY_MESSAGE);
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
@@ -21,7 +21,7 @@ export async function handleMemoryOptOut(req, res, match, ctx) {
|
|
|
21
21
|
sendOperatorPrincipalsRequired(res);
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
|
-
if (!explicitOperatorOk(principal, deps.config
|
|
24
|
+
if (!explicitOperatorOk(principal, deps.config)) {
|
|
25
25
|
sendError(res, 403, "auth.operator_only", "memory opt-out grant administration is operator-only: the caller principal is not in OPERATOR_PRINCIPALS");
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
@@ -52,6 +52,10 @@ export async function handleMemoryOptOut(req, res, match, ctx) {
|
|
|
52
52
|
return;
|
|
53
53
|
case "memory-optout-put-default":
|
|
54
54
|
case "memory-optout-put-override":
|
|
55
|
+
if (operator === undefined) {
|
|
56
|
+
sendPrincipalRefusal(res, req, deps.config);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
55
59
|
break;
|
|
56
60
|
default:
|
|
57
61
|
return assertNever(match.decl.id);
|
|
@@ -52,7 +52,7 @@ export async function handleAdoption(req, res, match, ctx) {
|
|
|
52
52
|
sendOperatorPrincipalsRequired(res);
|
|
53
53
|
return;
|
|
54
54
|
}
|
|
55
|
-
if (!explicitOperatorOk(principal, deps.config
|
|
55
|
+
if (!explicitOperatorOk(principal, deps.config)) {
|
|
56
56
|
sendError(res, 403, "auth.operator_only", "adoption is an operator-only deployment action");
|
|
57
57
|
return;
|
|
58
58
|
}
|
|
@@ -86,14 +86,7 @@ export async function handleAdoption(req, res, match, ctx) {
|
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
88
88
|
case "adoption-submit": {
|
|
89
|
-
|
|
90
|
-
try {
|
|
91
|
-
raw = await readJson(req);
|
|
92
|
-
}
|
|
93
|
-
catch {
|
|
94
|
-
sendError(res, 400, "request.invalid_json", "invalid JSON body");
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
89
|
+
const raw = await readJson(req);
|
|
97
90
|
const parsed = AdoptionRequestSchema.safeParse(raw);
|
|
98
91
|
if (!parsed.success) {
|
|
99
92
|
sendError(res, 400, "request.body_shape", "invalid adoption body — expected {fromPrincipal, toPrincipal} as non-empty strings");
|
|
@@ -4,7 +4,7 @@ import { sameExecutionRecord } from "@sema-agent/core";
|
|
|
4
4
|
import { DECIDED_REPLAY_SCAN_CAP, approvalPayloadFingerprint } from "../../plugins/checkpoint-store-sql.js";
|
|
5
5
|
import { APPROVAL_GATE_KINDS, carriesDeploymentListQuestion, standingAnswerDurablyRecordable } from "../../tool-approval.js";
|
|
6
6
|
import { isParkedRunStatus } from "../../plugins/store-contracts.js";
|
|
7
|
-
import { principalFrom, decodeCheckpointScope, PRINCIPAL_TOKEN_HEADER, APPROVAL_MAC_HEADER, APPROVAL_MAC_KID_HEADER } from "../../security.js";
|
|
7
|
+
import { principalFrom, decodeCheckpointScope, ownerOfCheckpointScope, CHECKPOINT_PUBLIC_SCOPE, PRINCIPAL_TOKEN_HEADER, APPROVAL_MAC_HEADER, APPROVAL_MAC_KID_HEADER } from "../../security.js";
|
|
8
8
|
import { editedPlanBinding, isWellFormedUnicode, verifyDirectDoorProof } from "../../principal-jwt.js";
|
|
9
9
|
import { MAX_APPROVAL_REASON_CHARS, projectQuestionAnswer, questionAnswerFromProjection } from "../../approval-hmac.js";
|
|
10
10
|
import { PLAN_APPROVE_PERMISSION_MODES_AFTER, isPlanApprovePermissionModeAfter, planReviewDecisionExitsPlan, storedBodyPermissionMode } from "../../task-settings.js";
|
|
@@ -15,7 +15,8 @@ import { buildRunName } from "../../fleet/fleet-bus.js";
|
|
|
15
15
|
import { sleep } from "../sse-log.js";
|
|
16
16
|
import { bindSseLifecycle } from "../sse-lifecycle.js";
|
|
17
17
|
import { sendJson, sendError, sseHeaders, SSE_MAX_STREAM_MS, SSE_HEARTBEAT_IDLE_MS } from "../send.js";
|
|
18
|
-
import { gatedPrincipal, explicitOperatorOk,
|
|
18
|
+
import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal, sessionCallerOf } from "../principal-gate.js";
|
|
19
|
+
import { readOwnedRun, readOwnedSession } from "../owner-access.js";
|
|
19
20
|
import { governanceOriginOf } from "../../runtime-governance.js";
|
|
20
21
|
import { deploymentListAsks } from "../../approval.js";
|
|
21
22
|
import { callGrantBindingOf, questionGrantBindingOf } from "../../standing-answer-grant.js";
|
|
@@ -23,8 +24,11 @@ import { sendResumeOutcome } from "../route-ctx.js";
|
|
|
23
24
|
import { assertNever } from "../route-ctx.js";
|
|
24
25
|
import * as facts from "../../capability-facts.js";
|
|
25
26
|
import { readResumeCtx } from "../resume-ctx-read.js";
|
|
27
|
+
import { StoreCorruptError } from "../../plugins/sql-json-column.js";
|
|
26
28
|
import { recordFailOpen } from "../../observability/fail-open.js";
|
|
29
|
+
import { durableRowIdentity } from "../../checkpoint-identity.js";
|
|
27
30
|
import { MAX_KEY_ECHO, keyClosureClause, scanKeyClosure } from "../../request-key-closure.js";
|
|
31
|
+
import { fieldConflictFacts } from "../../field-conflict.js";
|
|
28
32
|
const DECIDE_BODY_DECLARED_KEYS = [
|
|
29
33
|
"answer", "boundCallId", "boundInputHash", "checkpointToken", "decidedBy", "decision", "reason", "remember", "updatedInput",
|
|
30
34
|
];
|
|
@@ -268,18 +272,19 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
268
272
|
}
|
|
269
273
|
const cs = park.checkpointStore;
|
|
270
274
|
const principal = gatedPrincipal(req, deps.config);
|
|
271
|
-
const operator =
|
|
275
|
+
const operator = explicitOperatorOk(principal, deps.config);
|
|
276
|
+
const ownScope = principal ?? CHECKPOINT_PUBLIC_SCOPE;
|
|
272
277
|
if (match.decl.id === "approvals-stream") {
|
|
273
278
|
const scope = operator
|
|
274
279
|
? (new URLSearchParams(match.search).get("owner") ?? undefined)
|
|
275
|
-
:
|
|
280
|
+
: ownScope;
|
|
276
281
|
await streamApprovals(req, res, cs, deps.toolApproval, scope, deps.config);
|
|
277
282
|
return;
|
|
278
283
|
}
|
|
279
284
|
if (match.decl.id === "approvals-list") {
|
|
280
285
|
const scope = operator
|
|
281
286
|
? (new URLSearchParams(match.search).get("owner") ?? undefined)
|
|
282
|
-
:
|
|
287
|
+
: ownScope;
|
|
283
288
|
sendJson(res, 200, {
|
|
284
289
|
pending: (await cs.listPending(scope)).map((r) => projectPendingForWire(r, deps.config)),
|
|
285
290
|
serverNowMs: Date.now(),
|
|
@@ -300,17 +305,13 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
300
305
|
sendError(res, 400, "request.path_malformed", "malformed id (invalid percent-encoding)");
|
|
301
306
|
return;
|
|
302
307
|
}
|
|
303
|
-
|
|
304
|
-
const isExplicitOperator = explicitOperatorOk(principal, operators);
|
|
305
|
-
if (!isExplicitOperator) {
|
|
308
|
+
if (!explicitOperatorOk(principal, deps.config)) {
|
|
306
309
|
const owned = facts.sessionOwnership(deps);
|
|
307
310
|
if (!owned.available) {
|
|
308
311
|
sendError(res, 501, "capability.session_store_required", "approval exemptions require a session-store backend");
|
|
309
312
|
return;
|
|
310
313
|
}
|
|
311
|
-
|
|
312
|
-
const owner = await ownerOf(exSessionId);
|
|
313
|
-
if (owner === undefined || (owner !== null && owner !== principal)) {
|
|
314
|
+
if ((await readOwnedSession(deps, owned.sessionStorage, sessionCallerOf(req, deps), exSessionId, "owner")) === undefined) {
|
|
314
315
|
sendError(res, 404, "not_found.session", "not found");
|
|
315
316
|
return;
|
|
316
317
|
}
|
|
@@ -329,13 +330,16 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
329
330
|
return;
|
|
330
331
|
}
|
|
331
332
|
const revoked = await deps.approvalExemptionStore.revoke(exSessionId, exToolName);
|
|
332
|
-
|
|
333
|
+
if (revoked)
|
|
334
|
+
sendJson(res, 200, { revoked: true });
|
|
335
|
+
else
|
|
336
|
+
sendError(res, 404, "not_found.exemption", "not found");
|
|
333
337
|
return;
|
|
334
338
|
}
|
|
335
339
|
}
|
|
336
340
|
if (match.decl.id === "assistant-inbox") {
|
|
337
341
|
const ownerParam = new URLSearchParams(match.search).get("owner") || undefined;
|
|
338
|
-
const scope = operator && ownerParam ? ownerParam :
|
|
342
|
+
const scope = operator && ownerParam ? ownerParam : ownScope;
|
|
339
343
|
const summaries = await cs.listByScope(scope);
|
|
340
344
|
const inbox = (await Promise.all(summaries.map(async (s) => {
|
|
341
345
|
const ctxRead = await readResumeCtx(cs.getCtx(s.sessionId));
|
|
@@ -345,6 +349,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
345
349
|
const input = s.toolInput != null ? redactedPreview(s.toolInput) : null;
|
|
346
350
|
return {
|
|
347
351
|
sessionId: s.sessionId,
|
|
352
|
+
...durableRowIdentity("assistant-inbox", s.checkpointId, s.token),
|
|
348
353
|
scope: s.scope,
|
|
349
354
|
createdAt: s.createdAt,
|
|
350
355
|
...(s.gateKind !== undefined ? { gateKind: s.gateKind } : {}),
|
|
@@ -364,13 +369,14 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
364
369
|
objective,
|
|
365
370
|
input,
|
|
366
371
|
};
|
|
367
|
-
})))
|
|
372
|
+
})))
|
|
373
|
+
.sort((a, b) => (b.severity ?? 0) - (a.severity ?? 0) || (a.createdAt ?? 0) - (b.createdAt ?? 0));
|
|
368
374
|
sendJson(res, 200, { inbox });
|
|
369
375
|
return;
|
|
370
376
|
}
|
|
371
377
|
if (match.decl.id === "assistant-tasks") {
|
|
372
378
|
const ownerParam = new URLSearchParams(match.search).get("owner") || undefined;
|
|
373
|
-
const scope = operator && ownerParam ? ownerParam :
|
|
379
|
+
const scope = operator && ownerParam ? ownerParam : ownScope;
|
|
374
380
|
const ledger = facts.durableRuns(deps);
|
|
375
381
|
if (!ledger.available) {
|
|
376
382
|
sendJson(res, 200, { tasks: [] });
|
|
@@ -379,7 +385,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
379
385
|
const runStore = ledger.runStore;
|
|
380
386
|
const summaries = await cs.listByScope(scope);
|
|
381
387
|
const byGate = new Map(summaries.map((s) => [s.sessionId, s]));
|
|
382
|
-
const runs = await runStore.listRuns({ owner: scope, limit: 100 });
|
|
388
|
+
const runs = await runStore.listRuns({ owner: ownerOfCheckpointScope(scope), limit: 100 });
|
|
383
389
|
const tasks = runs
|
|
384
390
|
.filter((r) => r.status === "running" || isParkedRunStatus(r.status))
|
|
385
391
|
.map((r) => {
|
|
@@ -416,17 +422,11 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
416
422
|
return;
|
|
417
423
|
}
|
|
418
424
|
const taskId = match.params.taskId;
|
|
419
|
-
const run = await runStore
|
|
425
|
+
const run = await readOwnedRun(deps.config, runStore, principal, taskId, "owner_or_operator");
|
|
420
426
|
if (!run) {
|
|
421
427
|
sendError(res, 404, "not_found.run", "task not found");
|
|
422
428
|
return;
|
|
423
429
|
}
|
|
424
|
-
const operators = deps.config.operatorPrincipals;
|
|
425
|
-
const explicitOperator = explicitOperatorOk(principal, operators);
|
|
426
|
-
if (!explicitOperator && run.owner !== null && run.owner !== principal) {
|
|
427
|
-
sendError(res, 404, "not_found.run", "task not found");
|
|
428
|
-
return;
|
|
429
|
-
}
|
|
430
430
|
if (run.status === "running") {
|
|
431
431
|
const ownedHere = run.instanceId != null && run.instanceId === deps.instanceId;
|
|
432
432
|
if (ownedHere && !preemptableRuns.has(taskId)) {
|
|
@@ -482,8 +482,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
482
482
|
sendError(res, 404, "not_found.run", "task not found");
|
|
483
483
|
return;
|
|
484
484
|
}
|
|
485
|
-
const
|
|
486
|
-
const explicitOperator = explicitOperatorOk(principal, operators);
|
|
485
|
+
const explicitOperator = explicitOperatorOk(principal, deps.config);
|
|
487
486
|
if (!explicitOperator && run.owner !== null && run.owner !== principal) {
|
|
488
487
|
sendError(res, 404, "not_found.run", "task not found");
|
|
489
488
|
return;
|
|
@@ -520,7 +519,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
520
519
|
}
|
|
521
520
|
}
|
|
522
521
|
if (decision === "edit" && (typeof body.editedPlan !== "string" || body.editedPlan.length === 0)) {
|
|
523
|
-
sendError(res, 400, "request.field_conflict", "decision 'edit' requires a non-empty editedPlan (the operator's revised plan)");
|
|
522
|
+
sendError(res, 400, "request.field_conflict", "decision 'edit' requires a non-empty editedPlan (the operator's revised plan)", fieldConflictFacts("plan_edit", ["decision", "editedPlan"]));
|
|
524
523
|
return;
|
|
525
524
|
}
|
|
526
525
|
const decidedByReading = readDecidedBy(body.decidedBy, deps.config.directDoorActive);
|
|
@@ -543,7 +542,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
543
542
|
return;
|
|
544
543
|
}
|
|
545
544
|
if (decision !== "edit" && body.editedPlan !== undefined) {
|
|
546
|
-
sendError(res, 400, "request.field_conflict", `editedPlan is only valid with decision 'edit' (got '${decision}')
|
|
545
|
+
sendError(res, 400, "request.field_conflict", `editedPlan is only valid with decision 'edit' (got '${decision}')`, fieldConflictFacts("plan_edit", ["editedPlan", "decision"]));
|
|
547
546
|
return;
|
|
548
547
|
}
|
|
549
548
|
if (body.permissionModeAfter !== undefined && !isPlanApprovePermissionModeAfter(body.permissionModeAfter)) {
|
|
@@ -551,7 +550,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
551
550
|
return;
|
|
552
551
|
}
|
|
553
552
|
if (!planReviewDecisionExitsPlan(decision) && body.permissionModeAfter !== undefined) {
|
|
554
|
-
sendError(res, 400, "request.field_conflict", `permissionModeAfter is only valid with a decision that carries the plan out ('approve' or 'edit'; got '${decision}')
|
|
553
|
+
sendError(res, 400, "request.field_conflict", `permissionModeAfter is only valid with a decision that carries the plan out ('approve' or 'edit'; got '${decision}')`, fieldConflictFacts("plan_mode_after", ["permissionModeAfter", "decision"]));
|
|
555
554
|
return;
|
|
556
555
|
}
|
|
557
556
|
if (body.reason !== undefined && typeof body.reason !== "string") {
|
|
@@ -572,7 +571,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
572
571
|
return;
|
|
573
572
|
}
|
|
574
573
|
if (!deps.config.directDoorActive) {
|
|
575
|
-
sendError(res, 400, "request.field_conflict", "boundCallId (the plan_review nonce) is only valid on a direct-door worker — a BFF worker carries no decision proof to bind it to");
|
|
574
|
+
sendError(res, 400, "request.field_conflict", "boundCallId (the plan_review nonce) is only valid on a direct-door worker — a BFF worker carries no decision proof to bind it to", fieldConflictFacts("bound_call_door", ["boundCallId"]));
|
|
576
575
|
return;
|
|
577
576
|
}
|
|
578
577
|
}
|
|
@@ -611,8 +610,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
611
610
|
deciderPrincipal = proof.principal;
|
|
612
611
|
singleUse = proof.singleUse === undefined ? undefined : { proof: proof.singleUse, store };
|
|
613
612
|
}
|
|
614
|
-
const
|
|
615
|
-
const explicitOperator = explicitOperatorOk(deciderPrincipal, operators);
|
|
613
|
+
const explicitOperator = explicitOperatorOk(deciderPrincipal, deps.config);
|
|
616
614
|
if (!explicitOperator && run.owner !== null && run.owner !== deciderPrincipal) {
|
|
617
615
|
deps.logger?.info?.("decide_404", { reason: "owner-mismatch", taskId, principalPresent: principal !== undefined });
|
|
618
616
|
sendError(res, 404, "not_found.run", "task not found");
|
|
@@ -626,7 +624,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
626
624
|
if (body.permissionModeAfter !== undefined) {
|
|
627
625
|
const storedCtx = plan.prepared.ctx;
|
|
628
626
|
if (storedCtx.body !== undefined && storedBodyPermissionMode(storedCtx.body) !== "plan") {
|
|
629
|
-
sendError(res, 400, "request.field_conflict", "permissionModeAfter does not apply to this task: it was not started in plan mode (its stored permission mode is not \"plan\"), so approving the plan returns it to the mode it was in before planning");
|
|
627
|
+
sendError(res, 400, "request.field_conflict", "permissionModeAfter does not apply to this task: it was not started in plan mode (its stored permission mode is not \"plan\"), so approving the plan returns it to the mode it was in before planning", fieldConflictFacts("plan_mode_after", ["permissionModeAfter"]));
|
|
630
628
|
return;
|
|
631
629
|
}
|
|
632
630
|
}
|
|
@@ -683,7 +681,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
683
681
|
return;
|
|
684
682
|
}
|
|
685
683
|
if (decision !== "approve") {
|
|
686
|
-
sendError(res, 400, "request.field_conflict", "remember requires decision 'approve'");
|
|
684
|
+
sendError(res, 400, "request.field_conflict", "remember requires decision 'approve'", fieldConflictFacts("remember_decision", ["remember", "decision"]));
|
|
687
685
|
return;
|
|
688
686
|
}
|
|
689
687
|
if (deps.config.directDoorActive) {
|
|
@@ -770,8 +768,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
770
768
|
}
|
|
771
769
|
deciderPrincipal = proof.principal;
|
|
772
770
|
}
|
|
773
|
-
const
|
|
774
|
-
const explicitOperator = explicitOperatorOk(deciderPrincipal, operators);
|
|
771
|
+
const explicitOperator = explicitOperatorOk(deciderPrincipal, deps.config);
|
|
775
772
|
if (!explicitOperator) {
|
|
776
773
|
const cpScope = await cs
|
|
777
774
|
.peekPendingScope(sessionId, { gateKinds: APPROVAL_GATE_KINDS })
|
|
@@ -895,23 +892,27 @@ export async function streamApprovals(req, res, cs, live, scope, governance, pol
|
|
|
895
892
|
});
|
|
896
893
|
let first = true;
|
|
897
894
|
while (!closed) {
|
|
898
|
-
let
|
|
899
|
-
let livePending;
|
|
895
|
+
let snapshot;
|
|
900
896
|
try {
|
|
901
|
-
pending = (await cs.listPending(scope)).map((r) => projectPendingForWire(r, governance));
|
|
902
|
-
|
|
897
|
+
const pending = (await cs.listPending(scope)).map((r) => projectPendingForWire(r, governance));
|
|
898
|
+
snapshot = { pending, livePending: live ? live.listLivePending(scope) : [] };
|
|
903
899
|
}
|
|
904
|
-
catch {
|
|
900
|
+
catch (err) {
|
|
901
|
+
if (err instanceof StoreCorruptError) {
|
|
902
|
+
if (!res.writableEnded)
|
|
903
|
+
res.write(`event: error\ndata: ${JSON.stringify({ type: "error", errorCode: "approvals.read_corrupt", message: "a stored approval row cannot be read - this stream is closing, and reconnecting will fail the same way until an operator repairs or removes the row" })}\n\n`);
|
|
904
|
+
break;
|
|
905
|
+
}
|
|
905
906
|
if (!res.writableEnded)
|
|
906
|
-
res.write(`event:
|
|
907
|
-
await sleep(pollMs);
|
|
908
|
-
continue;
|
|
907
|
+
res.write(`event: error\ndata: ${JSON.stringify({ type: "error", errorCode: "approvals.read_unavailable", message: "the approvals queue could not be read - this stream stays open and retries on its next poll; until a read succeeds, silence here does not mean nothing is pending" })}\n\n`);
|
|
909
908
|
}
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
909
|
+
if (snapshot !== undefined) {
|
|
910
|
+
durableLane.tick(snapshot.pending);
|
|
911
|
+
liveLane.tick(snapshot.livePending);
|
|
912
|
+
if (first) {
|
|
913
|
+
res.write(`event: synced\ndata: ${JSON.stringify({ type: "synced", count: snapshot.pending.length })}\n\n`);
|
|
914
|
+
first = false;
|
|
915
|
+
}
|
|
915
916
|
}
|
|
916
917
|
if (Date.now() - start > SSE_MAX_STREAM_MS) {
|
|
917
918
|
res.write(`event: error\ndata: ${JSON.stringify({ type: "error", errorCode: "STREAM_MAX_DURATION", message: "approvals stream reached its 15-minute cap — reconnect to continue" })}\n\n`);
|
|
@@ -7,6 +7,7 @@ import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal } from "../pri
|
|
|
7
7
|
import {} from "../route-ctx.js";
|
|
8
8
|
import { assertNever, SESSION_NOT_FOUND_MESSAGE } from "../route-ctx.js";
|
|
9
9
|
import * as facts from "../../capability-facts.js";
|
|
10
|
+
import { sessionOwnerCellOf } from "../../security.js";
|
|
10
11
|
const LIST_LIMIT = 500;
|
|
11
12
|
export const DESCRIPTION_MAX = 500;
|
|
12
13
|
const ROW_KEY_DISPOSITION = {
|
|
@@ -67,8 +68,8 @@ export async function handleBackground(req, res, match, ctx) {
|
|
|
67
68
|
sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
|
|
68
69
|
return;
|
|
69
70
|
}
|
|
70
|
-
const
|
|
71
|
-
if (!
|
|
71
|
+
const operator = explicitOperatorOk(principal, deps.config);
|
|
72
|
+
if (!operator && !ctx.helpers.sessionOwnerOk(req, res, await sessionOwnerCellOf(owned.sessionStorage, sessionId, owner)))
|
|
72
73
|
return;
|
|
73
74
|
const scope = owner ?? "default";
|
|
74
75
|
switch (id) {
|