@sema-agent/server 7.148.0 → 7.150.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 +551 -9
- package/README.md +17 -2
- package/README.zh-CN.md +5 -1
- package/USAGE.md +126 -68
- package/dist/adoption/wire.d.ts +3 -3
- package/dist/approval-card.d.ts +33 -33
- package/dist/approval-gate-currency.d.ts +1 -1
- package/dist/approval-leg-origin.d.ts +33 -0
- package/dist/approval-leg-origin.js +4 -0
- package/dist/audit.d.ts +1 -1
- package/dist/audit.js +2 -2
- package/dist/auth-bridge.d.ts +9 -1
- package/dist/auth-bridge.js +4 -4
- package/dist/auth-keys.d.ts +10 -1
- package/dist/auth-keys.js +8 -0
- package/dist/background-session-reap.d.ts +1 -1
- package/dist/boot/deferred-sandbox-path-env.d.ts +5 -3
- package/dist/boot/deferred-sandbox-path-env.js +1 -2
- package/dist/boot/execution-env.js +10 -11
- package/dist/boot/execution-lane.d.ts +6 -4
- package/dist/boot/execution-lane.js +3 -1
- package/dist/boot/org-delivery.d.ts +3 -2
- package/dist/boot/parked-revive-gate.d.ts +5 -5
- package/dist/boot/parked-revive-gate.js +2 -3
- package/dist/boot/resolve-spec.d.ts +4 -5
- package/dist/boot/resolve-spec.js +66 -28
- package/dist/boot/retention-lane.d.ts +1 -1
- package/dist/boot/runner-deps.js +3 -1
- package/dist/boot/session-faces.js +21 -21
- package/dist/boot/stage-01-config.d.ts +1 -0
- package/dist/boot/stage-01-config.js +4 -3
- package/dist/boot/stage-02-web-admin-pull.d.ts +1 -0
- package/dist/boot/stage-02-web-admin-pull.js +10 -2
- package/dist/boot/stage-03-store-backend.d.ts +1 -0
- package/dist/boot/stage-03-store-backend.js +4 -4
- package/dist/boot/stage-04-stores.d.ts +1 -0
- package/dist/boot/stage-05-execution-env.d.ts +1 -0
- package/dist/boot/stage-06-runners.d.ts +2 -1
- package/dist/boot/stage-06-runners.js +1 -2
- package/dist/boot/stage-07-capability-layer.d.ts +2 -1
- package/dist/boot/stage-07-capability-layer.js +1 -1
- package/dist/boot/stage-08-reapers.d.ts +2 -1
- package/dist/boot/stage-09-leader.d.ts +2 -1
- package/dist/boot/stage-10-http-server.d.ts +35 -2
- package/dist/boot/stage-10-http-server.js +9 -4
- package/dist/boot/stores.d.ts +3 -0
- package/dist/boot/stores.js +22 -19
- package/dist/boot/web-admin.d.ts +1 -1
- package/dist/capabilities/tool-defer.d.ts +1 -1
- package/dist/capability-facts.d.ts +70 -60
- package/dist/capability-facts.js +45 -49
- package/dist/card-settle-stored-scope.d.ts +56 -0
- package/dist/card-settle-stored-scope.js +27 -0
- package/dist/card-void.d.ts +7 -12
- package/dist/card-void.js +2 -7
- package/dist/config-catalog.d.ts +12 -0
- package/dist/config-catalog.js +37 -33
- package/dist/config-invariants.d.ts +5 -4
- package/dist/config-invariants.js +4 -4
- package/dist/config-types.d.ts +49 -16
- package/dist/config.d.ts +6 -5
- package/dist/config.js +35 -24
- package/dist/context-window-notice.d.ts +31 -0
- package/dist/context-window-notice.js +28 -0
- package/dist/deployment-governance.d.ts +7 -28
- package/dist/deployment-governance.js +1 -14
- package/dist/deployment-shape.d.ts +20 -11
- package/dist/deployment-shape.js +1 -0
- package/dist/device-ws-hub.d.ts +1 -0
- package/dist/device-ws-hub.js +64 -28
- package/dist/device-ws-protocol.d.ts +20 -6
- package/dist/device-ws-protocol.js +9 -2
- package/dist/engine-identity.d.ts +7 -1
- package/dist/engine-identity.js +5 -0
- package/dist/env-name-allowlist-knobs.d.ts +6 -5
- package/dist/env-name-allowlist-knobs.js +5 -0
- package/dist/execution-lane-caps.d.ts +20 -5
- package/dist/execution-lane-caps.js +18 -4
- package/dist/field-conflict.d.ts +2 -2
- package/dist/fleet/engine-signal.d.ts +14 -1
- package/dist/fleet/engine-signal.js +5 -1
- package/dist/fleet/fleet-reconciler.d.ts +1 -1
- package/dist/fleet/serving-lease.d.ts +18 -3
- package/dist/fleet/serving-lease.js +81 -35
- package/dist/fleet-client.d.ts +13 -11
- package/dist/fleet-client.js +53 -33
- package/dist/history-anchor.js +1 -1
- package/dist/hitl-delivery.d.ts +1 -3
- package/dist/hitl-delivery.js +1 -1
- package/dist/hooks/command-spawn.d.ts +7 -2
- package/dist/hooks/command-spawn.js +13 -6
- package/dist/hooks/hook-runner.d.ts +5 -0
- package/dist/hooks/hook-runner.js +11 -7
- package/dist/http/active-run-conflict.d.ts +3 -7
- package/dist/http/active-run-conflict.js +2 -2
- package/dist/http/admission.js +5 -5
- package/dist/http/approval-sweeps.js +5 -3
- package/dist/http/caller-trust.d.ts +2 -2
- package/dist/http/caller-trust.js +3 -3
- package/dist/http/checkpoint-ctx.d.ts +18 -63
- package/dist/http/checkpoint-ctx.js +1 -24
- package/dist/http/claim-heartbeat.d.ts +6 -6
- package/dist/http/claim-heartbeat.js +6 -6
- package/dist/http/claimed-run.d.ts +16 -9
- package/dist/http/claimed-run.js +8 -0
- package/dist/http/dispatch.js +7 -5
- package/dist/http/durable-run-leg.d.ts +8 -1
- package/dist/http/durable-run-leg.js +34 -15
- package/dist/http/execution-context.d.ts +115 -14
- package/dist/http/execution-context.js +130 -40
- package/dist/http/owner-access.d.ts +246 -21
- package/dist/http/owner-access.js +186 -8
- package/dist/http/principal-gate.d.ts +18 -11
- package/dist/http/principal-gate.js +3 -1
- package/dist/http/readiness.d.ts +4 -2
- package/dist/http/resume-ctx-read.d.ts +14 -3
- package/dist/http/resume-ctx-read.js +24 -3
- package/dist/http/resume-legs.d.ts +35 -3
- package/dist/http/resume-legs.js +262 -106
- package/dist/http/route-ctx.d.ts +29 -11
- package/dist/http/routes/a2a-serve.js +17 -14
- package/dist/http/routes/approvals-assistant.d.ts +3 -2
- package/dist/http/routes/approvals-assistant.js +11 -11
- package/dist/http/routes/capabilities.js +5 -4
- package/dist/http/routes/config-catalog.d.ts +1 -1
- package/dist/http/routes/diagnostics.d.ts +3 -1
- package/dist/http/routes/diagnostics.js +30 -5
- package/dist/http/routes/mcp-reconnect.js +2 -2
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/notify-wake.js +2 -3
- package/dist/http/routes/principal-inbox.d.ts +3 -1
- package/dist/http/routes/principal-inbox.js +3 -2
- package/dist/http/routes/projects.d.ts +1 -0
- package/dist/http/routes/projects.js +5 -3
- package/dist/http/routes/retention-ops.d.ts +1 -1
- package/dist/http/routes/run-permission-mode.d.ts +1 -1
- package/dist/http/routes/run-permission-mode.js +2 -2
- package/dist/http/routes/runs.d.ts +1 -1
- package/dist/http/routes/runs.js +33 -37
- package/dist/http/routes/session-memory-sync.js +4 -5
- package/dist/http/routes/session-sync.d.ts +24 -5
- package/dist/http/routes/session-sync.js +45 -37
- package/dist/http/routes/sessions-list.d.ts +1 -1
- package/dist/http/routes/sessions.d.ts +1 -1
- package/dist/http/routes/sessions.js +18 -44
- package/dist/http/routes/tasks.js +136 -101
- package/dist/http/routes/trace-usage.js +14 -14
- package/dist/http/routes/workflows.d.ts +1 -0
- package/dist/http/routes/workflows.js +20 -38
- package/dist/http/server.d.ts +12 -9
- package/dist/http/server.js +35 -6
- package/dist/http/stored-body-replay.d.ts +3 -24
- package/dist/http/stored-body-replay.js +2 -12
- package/dist/http/submit-ctx.d.ts +2 -2
- package/dist/http/submit-ctx.js +5 -5
- package/dist/http/submit-replay.d.ts +15 -2
- package/dist/http/submit-replay.js +10 -4
- package/dist/http/wire-types.d.ts +6 -3
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -0
- package/dist/leader/endpoint.js +9 -8
- package/dist/leg-facts.d.ts +13 -2
- package/dist/leg-facts.js +2 -0
- package/dist/local-store-declaration.d.ts +54 -0
- package/dist/local-store-declaration.js +59 -0
- package/dist/mcp-assertion-header.d.ts +1 -1
- package/dist/mcp-assertion-header.js +1 -1
- package/dist/mcp-authorization-face.d.ts +18 -14
- package/dist/mcp-authorization-face.js +3 -2
- package/dist/memory-project-layer.js +1 -1
- package/dist/memory-scope.d.ts +4 -4
- package/dist/memory-scope.js +4 -4
- package/dist/memory-store-refusal.d.ts +1 -1
- package/dist/memory-sync-client.js +2 -2
- package/dist/model-context-window.d.ts +50 -11
- package/dist/model-context-window.js +20 -1
- package/dist/model-entry-refusal.d.ts +5 -4
- package/dist/model-entry-refusal.js +17 -3
- package/dist/model-reach-scope.d.ts +2 -1
- package/dist/observability/corrupt-read-seat.d.ts +1 -1
- package/dist/observability/fail-open.d.ts +19 -7
- package/dist/observability/fail-open.js +19 -7
- package/dist/observability/logger.d.ts +7 -0
- package/dist/observability/logger.js +3 -1
- package/dist/observability/metrics.js +1 -1
- package/dist/observability/run-terminal.d.ts +1 -1
- package/dist/observability/run-terminal.js +1 -0
- package/dist/observability/secret-env-scrub.d.ts +1 -1
- package/dist/observability/secret-env-scrub.js +1 -1
- package/dist/org-delivery-gate.d.ts +31 -6
- package/dist/org-delivery-gate.js +7 -4
- package/dist/owner-faces.d.ts +30 -5
- package/dist/owner-faces.js +2 -0
- package/dist/park-row-commit.d.ts +67 -0
- package/dist/park-row-commit.js +76 -0
- package/dist/parked-decide.d.ts +9 -7
- package/dist/parked-decide.js +25 -6
- package/dist/peer-directory.d.ts +1 -1
- package/dist/peer-seat.d.ts +1 -1
- package/dist/peer-seat.js +52 -59
- package/dist/plugins/adoption-log-sql.d.ts +3 -3
- package/dist/plugins/adoption-log-sql.js +19 -19
- package/dist/plugins/approval-ask-store-sql.d.ts +1 -1
- package/dist/plugins/approval-ask-store-sql.js +3 -5
- package/dist/plugins/approval-exemption-skill-cutoff.d.ts +64 -0
- package/dist/plugins/approval-exemption-skill-cutoff.js +122 -0
- package/dist/plugins/approval-exemption-skill-m46.d.ts +0 -6
- package/dist/plugins/approval-exemption-skill-m46.js +6 -10
- package/dist/plugins/approval-exemption-store.d.ts +26 -1
- package/dist/plugins/approval-exemption-store.js +28 -19
- package/dist/plugins/ensure-schema-lock-policy.d.ts +36 -3
- package/dist/plugins/ensure-schema-lock-policy.js +75 -9
- package/dist/plugins/exec-path-law.d.ts +34 -0
- package/dist/plugins/exec-path-law.js +13 -0
- package/dist/plugins/file-run-store.d.ts +22 -9
- package/dist/plugins/file-run-store.js +51 -23
- package/dist/plugins/local-checkpoint-store.d.ts +8 -1
- package/dist/plugins/local-checkpoint-store.js +5 -1
- package/dist/plugins/local-data-root-admission.d.ts +52 -0
- package/dist/plugins/local-data-root-admission.js +100 -0
- package/dist/plugins/local-engine-high-water.d.ts +28 -7
- package/dist/plugins/local-engine-high-water.js +27 -22
- package/dist/plugins/local-session-store.d.ts +134 -49
- package/dist/plugins/local-session-store.js +149 -108
- package/dist/plugins/memory-run-store.d.ts +14 -9
- package/dist/plugins/memory-run-store.js +48 -22
- package/dist/plugins/one-time-migration-marker.d.ts +19 -3
- package/dist/plugins/one-time-migration-marker.js +7 -1
- package/dist/plugins/one-time-migrations.d.ts +110 -59
- package/dist/plugins/one-time-migrations.js +224 -136
- package/dist/plugins/org-delivery-quota-store.d.ts +34 -11
- package/dist/plugins/org-delivery-quota-store.js +29 -14
- package/dist/plugins/permission-rule-store-sql.d.ts +1 -1
- package/dist/plugins/permission-rule-store-sql.js +5 -9
- package/dist/plugins/pg-pool.d.ts +1 -1
- package/dist/plugins/pg-pool.js +14 -12
- package/dist/plugins/posix-shell-fs.js +4 -2
- package/dist/plugins/remote-env-adb.js +3 -2
- package/dist/plugins/remote-env-device.d.ts +3 -2
- package/dist/plugins/remote-env-device.js +8 -6
- package/dist/plugins/remote-env-e2b.d.ts +4 -8
- package/dist/plugins/remote-env-e2b.js +21 -15
- package/dist/plugins/remote-env-host.d.ts +51 -10
- package/dist/plugins/remote-env-host.js +97 -31
- package/dist/plugins/remote-env-k8s.js +7 -4
- package/dist/plugins/remote-env-local-docker.d.ts +6 -3
- package/dist/plugins/remote-env-local-docker.js +11 -25
- package/dist/plugins/remote-env-ssh.js +4 -3
- package/dist/plugins/remote-shell.d.ts +3 -1
- package/dist/plugins/remote-shell.js +3 -3
- package/dist/plugins/replica-registration.d.ts +35 -0
- package/dist/plugins/replica-registration.js +48 -0
- package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
- package/dist/plugins/run-store-sql.d.ts +27 -8
- package/dist/plugins/run-store-sql.js +46 -18
- package/dist/plugins/scenario-prefix-switch-m42.d.ts +8 -12
- package/dist/plugins/scenario-prefix-switch-m42.js +9 -6
- package/dist/plugins/schema-consistency.d.ts +91 -5
- package/dist/plugins/schema-consistency.js +189 -7
- package/dist/plugins/schema-drift-sentence.d.ts +6 -5
- package/dist/plugins/schema-drift-sentence.js +13 -5
- package/dist/plugins/serving-requirement.d.ts +49 -0
- package/dist/plugins/serving-requirement.js +53 -0
- package/dist/plugins/session-placement.d.ts +5 -4
- package/dist/plugins/shell-sentinel-owner-m48.d.ts +22 -0
- package/dist/plugins/shell-sentinel-owner-m48.js +6 -0
- package/dist/plugins/stop-then-start-sentence.d.ts +55 -0
- package/dist/plugins/stop-then-start-sentence.js +51 -0
- package/dist/plugins/store-backend.d.ts +23 -9
- package/dist/plugins/store-backend.js +58 -24
- package/dist/plugins/store-contracts.d.ts +45 -5
- package/dist/plugins/store-contracts.js +19 -0
- package/dist/plugins/tidb-pool.d.ts +11 -6
- package/dist/plugins/tidb-pool.js +22 -12
- package/dist/plugins/workspace-custody.d.ts +44 -0
- package/dist/plugins/workspace-custody.js +47 -0
- package/dist/process-instance.d.ts +3 -0
- package/dist/process-instance.js +7 -0
- package/dist/project-context.d.ts +66 -0
- package/dist/project-context.js +70 -0
- package/dist/project-identity.d.ts +8 -7
- package/dist/project-identity.js +40 -17
- package/dist/project-layer-key.d.ts +13 -2
- package/dist/project-layer-key.js +9 -1
- package/dist/question.d.ts +9 -21
- package/dist/question.js +28 -19
- package/dist/read-deny-floor-notice.d.ts +36 -0
- package/dist/read-deny-floor-notice.js +40 -0
- package/dist/{plain-string-record.d.ts → request-declaration-disposition.d.ts} +9 -23
- package/dist/request-declaration-disposition.js +39 -0
- package/dist/run-cancel-card.d.ts +28 -0
- package/dist/run-cancel-card.js +20 -0
- package/dist/run-cancel-context.d.ts +10 -0
- package/dist/run-cancel-context.js +1 -0
- package/dist/run-local.js +28 -13
- package/dist/runs.d.ts +31 -7
- package/dist/runs.js +34 -16
- package/dist/security.d.ts +3 -3
- package/dist/server-secret-env.d.ts +34 -20
- package/dist/server-secret-env.js +61 -18
- package/dist/session-agent.d.ts +4 -12
- package/dist/session-agent.js +0 -6
- package/dist/session-children-retire.d.ts +6 -3
- package/dist/session-children-retire.js +2 -5
- package/dist/session-incarnation.d.ts +18 -4
- package/dist/session-incarnation.js +4 -1
- package/dist/session-notify-door.d.ts +4 -4
- package/dist/session-notify-door.js +5 -6
- package/dist/session-rules-seat.d.ts +4 -3
- package/dist/session-rules-seat.js +3 -11
- package/dist/session-sync.js +3 -3
- package/dist/session-workspace.d.ts +3 -3
- package/dist/store-admission.d.ts +33 -0
- package/dist/store-admission.js +49 -0
- package/dist/store-posture.d.ts +5 -0
- package/dist/store-posture.js +18 -1
- package/dist/stores-sql/checkpoint-store-sql.d.ts +22 -3
- package/dist/stores-sql/checkpoint-store-sql.js +109 -23
- package/dist/stores-sql/file-history-store-sql.d.ts +1 -1
- package/dist/stores-sql/file-history-store-sql.js +3 -5
- package/dist/stores-sql/retention-store-sql.d.ts +1 -1
- package/dist/stores-sql/tool-result-store-sql.d.ts +1 -1
- package/dist/stores-sql/tool-result-store-sql.js +4 -6
- package/dist/task-a2a.d.ts +3 -8
- package/dist/task-a2a.js +25 -27
- package/dist/task-cwd.d.ts +27 -10
- package/dist/task-cwd.js +3 -0
- package/dist/task-mcp.d.ts +3 -3
- package/dist/task-mcp.js +1 -1
- package/dist/task-settings.d.ts +13 -0
- package/dist/task-settings.js +14 -7
- package/dist/terminal.d.ts +2 -0
- package/dist/terminal.js +21 -6
- package/dist/tool-approval.d.ts +50 -41
- package/dist/tool-approval.js +96 -73
- package/dist/trace/engine-notice-wire.d.ts +38 -21
- package/dist/trace/engine-notice-wire.js +25 -4
- package/dist/trace/ledger-sink.d.ts +3 -1
- package/dist/trace/project.d.ts +8 -5
- package/dist/trace/project.js +11 -9
- package/dist/trace/projection-table.d.ts +33 -2
- package/dist/trace/redact.d.ts +12 -0
- package/dist/trace/redact.js +5 -1
- package/dist/trace/self-minted-wire.d.ts +268 -56
- package/dist/trace/self-minted-wire.js +110 -40
- package/dist/trace/tool-card.d.ts +3 -0
- package/dist/trace/tool-card.js +24 -0
- package/dist/trace/tool-output-media.d.ts +2 -1
- package/dist/unattended-permission-mode.d.ts +1 -1
- package/dist/web-admin-client/apply-effective.d.ts +1 -1
- package/dist/web-admin-client/apply-effective.js +22 -9
- package/dist/web-admin-client/effective-keys.d.ts +1 -1
- package/dist/web-admin-client/skills-mcp.d.ts +1 -1
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -29
- package/docs/error-text-lexicon.json +317 -0
- package/package.json +4 -2
- package/scripts/embed-minimal.mjs +183 -0
- package/wire-changes/server@7.149.0.json +372 -0
- package/wire-changes/server@7.150.0.json +335 -0
- package/dist/plain-string-record.js +0 -70
package/dist/http/resume-legs.js
CHANGED
|
@@ -3,18 +3,19 @@ import { createHash } from "node:crypto";
|
|
|
3
3
|
import { uuidv7, resumeWithVerification, resumeCascade, CheckpointError, judgeCheckpointRow, defaultTaskRegistry, taskNotificationDedupKey, validatePendingSteer, GLOBAL_USAGE_KEY } from "@sema-agent/core";
|
|
4
4
|
import { decideParkedAgent, deliverToHoldingRun, denyWorkflowParkForked, denyWorkflowParksUnreadable, findParkOrigin, heldWorkflowParkDecisions, planWorkflowParkedDecide } from "../parked-decide.js";
|
|
5
5
|
import { parkDecisionFingerprint } from "../orchestration/workflow-park-decision.js";
|
|
6
|
-
import {
|
|
6
|
+
import { runFactsOf, sealRouteDeps, sessionFactsReadOf } from "./owner-access.js";
|
|
7
7
|
import { createSessionWorkspaceRecorder, sessionWorkspaceStoreOf } from "../session-workspace.js";
|
|
8
8
|
const DELIVERY_NOT_RECORDED = "workflow park decide: this delivery no longer holds the host session (its claim was released) — the decision was not recorded and this delivery was not started";
|
|
9
9
|
import { HttpError, checkpointPartsOf, decodeCheckpointScope, scopeCellOf, CHECKPOINT_PUBLIC_SCOPE } from "../security.js";
|
|
10
10
|
import { keyAdmits } from "../owner-faces.js";
|
|
11
11
|
import { personOf } from "../owner-brands.js";
|
|
12
12
|
import { recoveredSubject } from "../owner-faces.js";
|
|
13
|
-
import { beatRunHeartbeat, graftParkToolCallId, parkToolCallId, TurnAnchorCapture, HEARTBEAT_MS, markChildrenStoppedByUserOnAbort, voidHeldParkCard } from "../runs.js";
|
|
13
|
+
import { beatRunHeartbeat, graftParkToolCallId, heldParkOf, parkToolCallId, TurnAnchorCapture, HEARTBEAT_MS, markChildrenStoppedByUserOnAbort, voidHeldParkCard } from "../runs.js";
|
|
14
|
+
import { commitParkRow } from "../park-row-commit.js";
|
|
14
15
|
import { atHostBoundary, failureCodeOf, nestedPauseOf, sealResultForExit, outwardPlane, outwardThrownMessage } from "../terminal.js";
|
|
15
16
|
import { voidVerifierPauseCard } from "../verifier-pause-card.js";
|
|
16
|
-
import { buildCancelledLedgerRow, CARD_SETTLED_BY_CANCEL_MESSAGE, createRunAbort, mintCancelledResult, withCardSettledByCancelMessage } from "../run-cancel-context.js";
|
|
17
|
-
import {
|
|
17
|
+
import { buildCancelledLedgerRow, CANCELLED_CODE, CARD_SETTLED_BY_CANCEL_MESSAGE, createRunAbort, mintCancelledResult, withCardSettledByCancelMessage } from "../run-cancel-context.js";
|
|
18
|
+
import { createLegCtxClaim, isTerminalRunStatus } from "../plugins/store-contracts.js";
|
|
18
19
|
import { readTurnActivityMs, recordTurnActivity } from "../turn-activity.js";
|
|
19
20
|
import { recordResumeResourceWindow } from "../resource-window.js";
|
|
20
21
|
import { emitPendingWorkflowCompletions, taskNotificationInboxEntry, taskNotificationStreamKeyOf, NotifiedKeys } from "../orchestration/workflow-completion-inbox.js";
|
|
@@ -27,15 +28,19 @@ import { buildCheckpointAnchorHash } from "../approval-ask-audit-store.js";
|
|
|
27
28
|
import { APPROVAL_ENDING_CAUSES } from "../approval-deny-reasons.js";
|
|
28
29
|
import { serviceVersion } from "../service-version.js";
|
|
29
30
|
import { TERMINAL_PARK_GATE_KINDS, UnreadableCheckpointRowError } from "../plugins/checkpoint-store-face.js";
|
|
31
|
+
import { cancelSettlesCard } from "../run-cancel-card.js";
|
|
32
|
+
import { CARD_EXPIRE_OUTCOME, expireCardUnderStoredScope } from "../card-settle-stored-scope.js";
|
|
30
33
|
import { withSubject } from "../observability/principal-context.js";
|
|
31
34
|
import { withModelReachScope } from "../model-reach-scope.js";
|
|
35
|
+
import { approvalLegOriginOf } from "../approval-leg-origin.js";
|
|
32
36
|
import { legFactsOf } from "../leg-facts.js";
|
|
37
|
+
import { compositionLegRoot } from "../task-cwd.js";
|
|
33
38
|
import { createInstructionSelectionLeg } from "../instruction-selection.js";
|
|
34
39
|
import { modelTextEventData, appendParkRow, turnEndEventData, contextUsageEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskStartedEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, compactionStartedEventData, workspaceChangedEventData, wiringManifestEventData, toolRosterDeltaEventData, toolDisclosureEventData, humanInputEventData, appendModelUsageDelta, attachModelUsage, createPromptManifestSeat } from "../trace/project.js";
|
|
35
40
|
import { redactSecrets } from "../trace/redact.js";
|
|
36
41
|
import { buildRunObjectivePreview } from "../user-authored-text.js";
|
|
37
42
|
import { createForwardAppendFailedNote, createLedgerSink, createSerialLedgerAppend } from "../trace/ledger-sink.js";
|
|
38
|
-
import { registerEngineNoticeLeg } from "../trace/engine-notice-wire.js";
|
|
43
|
+
import { defaultEngineNoticeRouter, registerEngineNoticeLeg } from "../trace/engine-notice-wire.js";
|
|
39
44
|
import { blockText, reasoningDeltaBytes, reasoningSegmentEventId } from "../trace/model-segment.js";
|
|
40
45
|
import { errorText } from "../observability/err-text.js";
|
|
41
46
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
@@ -52,15 +57,16 @@ import { createImagesLocal } from "./routes/images.js";
|
|
|
52
57
|
import { createCapabilitiesLocal } from "./routes/capabilities.js";
|
|
53
58
|
import { gatedSubject, explicitOperatorOk, runIdentityOf } from "./principal-gate.js";
|
|
54
59
|
import { buildActiveRunConflict, resumeEntryForGate } from "./active-run-conflict.js";
|
|
55
|
-
import {
|
|
60
|
+
import { refusalAfterLostClaim } from "./claim-heartbeat.js";
|
|
61
|
+
import { CONTINUATION_CLAIM_FACE, ClaimFaultAnswer, commitExecutionContext, faultedAnswerOf, isRootSessionGoneError, resolveBeforeClaim, rootSessionAbsentAnswer, stampSpecRoot, withdrawClaim } from "./execution-context.js";
|
|
56
62
|
import { timeClaim } from "./claim-latency.js";
|
|
57
63
|
import { commitSessionInheritEnv } from "./session-inherit-env.js";
|
|
58
64
|
import { ASK_USER_QUESTION_TOOL_NAME, isApprovalGateKind, isEngineQuestionRow } from "../approval-content-kind.js";
|
|
59
65
|
import { deploymentListAsks } from "../approval.js";
|
|
60
66
|
import { isParkLedgerEventType } from "../trace/ledger-events.js";
|
|
61
|
-
import { readResumeCtx, resumeCtxCorruptAnswer, resumeCtxUnreadableAnswer, resumeCtxUnsealableAnswer,
|
|
67
|
+
import { readResumeCtx, resumeCtxCorruptAnswer, resumeCtxUnreadableAnswer, resumeCtxUnsealableAnswer, resumeStoreFailureOf } from "./resume-ctx-read.js";
|
|
62
68
|
import { objectiveWithheldIn } from "./submit-ctx.js";
|
|
63
|
-
import { buildCheckpointVersionKeys, resumeAssemblyRefusalAnswer, resumeRefusalWithCard, sealCheckpointCtx, storedBodyReplayAnswer, storedBodyReplayLogFields
|
|
69
|
+
import { buildCheckpointVersionKeys, resumeAssemblyRefusalAnswer, resumeRefusalWithCard, sealCheckpointCtx, storedBodyReplayAnswer, storedBodyReplayLogFields } from "./checkpoint-ctx.js";
|
|
64
70
|
import { refusalBody, resumeRefusalFacts } from "./refusal-body.js";
|
|
65
71
|
import { storedBodyReplayRefusal } from "./stored-body-replay.js";
|
|
66
72
|
import { restateResumeCtx } from "./resume-restatement.js";
|
|
@@ -204,6 +210,9 @@ function decisionRefusalCauseOf(e, gate) {
|
|
|
204
210
|
function notResumableAnswer() {
|
|
205
211
|
return { status: 409, body: refusalBody({ errorCode: "conflict.not_resumable", message: "run is not in a resumable (suspended) state (already resumed, decided, or expired)" }) };
|
|
206
212
|
}
|
|
213
|
+
function resumeClaimFaultAnswerOf(e) {
|
|
214
|
+
return faultedAnswerOf(e, CONTINUATION_CLAIM_FACE.faulted);
|
|
215
|
+
}
|
|
207
216
|
function approvalStaleAnswer(facts) {
|
|
208
217
|
return {
|
|
209
218
|
status: 409,
|
|
@@ -217,13 +226,41 @@ function approvalStaleAnswer(facts) {
|
|
|
217
226
|
}),
|
|
218
227
|
};
|
|
219
228
|
}
|
|
220
|
-
function rowRefusalAnswer(verdict, diagnostic, ctx) {
|
|
229
|
+
function rowRefusalAnswer(verdict, diagnostic, ctx, wayOut) {
|
|
221
230
|
const refusal = new CheckpointError(verdict.code, diagnostic === undefined ? verdict.sentence : `${verdict.sentence} Diagnostic: ${diagnostic}`, verdict.reason === undefined ? undefined : { reason: verdict.reason });
|
|
222
|
-
return checkpointRefusalAnswer(refusal, { gate: "policy_ask", retriable: resumeRefusalDisposition(refusal) === "retriable", versionKeys: refusalVersionKeys(refusal, ctx) });
|
|
231
|
+
return checkpointRefusalAnswer(refusal, { gate: "policy_ask", retriable: resumeRefusalDisposition(refusal) === "retriable", versionKeys: refusalVersionKeys(refusal, ctx), ...(wayOut !== undefined ? { wayOut } : {}) });
|
|
232
|
+
}
|
|
233
|
+
export async function rowWayOutOf(seat, kind) {
|
|
234
|
+
switch (kind) {
|
|
235
|
+
case "lacking":
|
|
236
|
+
return "newer_worker";
|
|
237
|
+
case "damaged":
|
|
238
|
+
try {
|
|
239
|
+
return (await cancelSettlesCard(seat.cs, seat.runs, seat.token)) ? "cancel_run" : undefined;
|
|
240
|
+
}
|
|
241
|
+
catch (e) {
|
|
242
|
+
seat.logger?.warn?.("row_way_out_probe_failed", { note: "the store could not answer whether cancel would settle this card — no wayOut offered", err: errorText(e) });
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
default: {
|
|
246
|
+
const unhandled = kind;
|
|
247
|
+
throw new Error(`row verdict ${String(unhandled)} has no way out`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
async function loadedRowWayOut(cp, seat) {
|
|
252
|
+
const verdict = judgeCheckpointRow(cp);
|
|
253
|
+
return verdict.kind === "ok" ? undefined : rowWayOutOf(seat, verdict.kind);
|
|
254
|
+
}
|
|
255
|
+
async function loadedRowRefusal(cp, seat, writer) {
|
|
256
|
+
const verdict = judgeCheckpointRow(cp);
|
|
257
|
+
if (verdict.kind === "ok")
|
|
258
|
+
return undefined;
|
|
259
|
+
return rowRefusalAnswer(verdict, undefined, verdict.code === "checkpoint.unsupported_version" ? await writer() : {}, await rowWayOutOf(seat, verdict.kind));
|
|
223
260
|
}
|
|
224
|
-
export function rowReadRefusalAnswer(e) {
|
|
261
|
+
export async function rowReadRefusalAnswer(e, seat) {
|
|
225
262
|
if (e instanceof UnreadableCheckpointRowError && e.rowVerdict.kind !== "ok")
|
|
226
|
-
return rowRefusalAnswer(e.rowVerdict, errorText(e), {});
|
|
263
|
+
return rowRefusalAnswer(e.rowVerdict, errorText(e), {}, seat === undefined ? undefined : await rowWayOutOf(seat, e.rowVerdict.kind));
|
|
227
264
|
return { status: 409, body: refusalBody({ errorCode: "conflict.checkpoint_unreadable", message: errorText(e) }) };
|
|
228
265
|
}
|
|
229
266
|
function refusalVersionKeys(e, ctx) {
|
|
@@ -252,6 +289,7 @@ export function checkpointRefusalAnswer(e, at) {
|
|
|
252
289
|
: {}),
|
|
253
290
|
...at.versionKeys,
|
|
254
291
|
...(e.code === "resume.constraint_rejected" ? acceptableFormFacts(detail) : {}),
|
|
292
|
+
...(at.wayOut !== undefined ? { wayOut: at.wayOut } : {}),
|
|
255
293
|
},
|
|
256
294
|
}),
|
|
257
295
|
}, at.retriable);
|
|
@@ -335,7 +373,7 @@ export function createResumeLegs(ctx) {
|
|
|
335
373
|
return { status: 404, body: refusalBody({ errorCode: "not_found.approval", message: "approval not found" }) };
|
|
336
374
|
}
|
|
337
375
|
const cpPromise = cs.get(token);
|
|
338
|
-
const runSessionPromise = cs.hostSessionOfCard(token).then((id) => (typeof id === "string" ? { kind: "owned", id } : { kind: "unowned" }), (e) => ({ kind: "failed", failure:
|
|
376
|
+
const runSessionPromise = cs.hostSessionOfCard(token).then((id) => (typeof id === "string" ? { kind: "owned", id } : { kind: "unowned" }), (e) => ({ kind: "failed", failure: resumeStoreFailureOf(e) }));
|
|
339
377
|
const runCtxOf = async () => {
|
|
340
378
|
const owner = await runSessionPromise;
|
|
341
379
|
if (owner.kind === "unowned")
|
|
@@ -352,7 +390,6 @@ export function createResumeLegs(ctx) {
|
|
|
352
390
|
const ctxPromise = runCtxOf();
|
|
353
391
|
void ctxPromise.catch(() => { });
|
|
354
392
|
const noApproval = { status: 404, body: refusalBody({ errorCode: "not_found.approval", message: "approval not found" }) };
|
|
355
|
-
const rowOwnRefusal = async (verdict) => rowRefusalAnswer(verdict, undefined, verdict.code === "checkpoint.unsupported_version" ? await ctxPromise.then((r) => (r !== undefined && "ctx" in r ? (r.ctx ?? {}) : {}), () => ({})) : {});
|
|
356
393
|
let cp;
|
|
357
394
|
try {
|
|
358
395
|
cp = await cpPromise;
|
|
@@ -363,7 +400,7 @@ export function createResumeLegs(ctx) {
|
|
|
363
400
|
deps.logger?.warn?.("approval_decide_unreadable_row_withheld", { sessionId, note: "row unreadable and the caller's ownership of THAT token is unproven — folded into the uniform 404" });
|
|
364
401
|
return noApproval;
|
|
365
402
|
}
|
|
366
|
-
return rowReadRefusalAnswer(e);
|
|
403
|
+
return rowReadRefusalAnswer(e, { cs, runs: deps.runStore, token, logger: deps.logger });
|
|
367
404
|
}
|
|
368
405
|
if (!cp) {
|
|
369
406
|
if (!(await mayDiscloseRowError(cs, token, decider)))
|
|
@@ -374,9 +411,9 @@ export function createResumeLegs(ctx) {
|
|
|
374
411
|
deps.logger?.warn?.("approval_decide_row_scope_mismatch", { sessionId, note: "loaded pending row is foreign to the verified caller — TOCTOU fold" });
|
|
375
412
|
return { status: 404, body: refusalBody({ errorCode: "not_found.approval", message: "approval not found" }) };
|
|
376
413
|
}
|
|
377
|
-
const
|
|
378
|
-
if (
|
|
379
|
-
return
|
|
414
|
+
const rowOwn = await loadedRowRefusal(cp, { cs, runs: deps.runStore, token, logger: deps.logger }, () => ctxPromise.then((r) => (r !== undefined && "ctx" in r ? (r.ctx ?? {}) : {}), () => ({})));
|
|
415
|
+
if (rowOwn !== undefined)
|
|
416
|
+
return rowOwn;
|
|
380
417
|
const decideGateKind = cp.gate?.kind;
|
|
381
418
|
if (!isApprovalGateKind(decideGateKind)) {
|
|
382
419
|
if (typeof decideGateKind !== "string" || decideGateKind === "") {
|
|
@@ -491,12 +528,14 @@ export function createResumeLegs(ctx) {
|
|
|
491
528
|
...(deps.parkedReviveInheritedGate ? { rebuildInheritedGate: deps.parkedReviveInheritedGate } : {}),
|
|
492
529
|
...(deps.toolApproval ? { approverSeatFor: windowZeroSeatOf(deps.toolApproval) } : {}),
|
|
493
530
|
execution: {
|
|
494
|
-
resolve: async (root) => {
|
|
531
|
+
resolve: async (root, face) => {
|
|
495
532
|
let ctx;
|
|
496
533
|
try {
|
|
497
|
-
ctx = await
|
|
534
|
+
ctx = await resolveBeforeClaim(deps, { kind: "continuation", root, principal: checkpointPartsOf(cp.scope)?.person }, face);
|
|
498
535
|
}
|
|
499
536
|
catch (e) {
|
|
537
|
+
if (e instanceof ClaimFaultAnswer)
|
|
538
|
+
return { ok: false, gone: false, answer: e.answer };
|
|
500
539
|
if (isRootSessionGoneError(e))
|
|
501
540
|
return { ok: false, gone: true };
|
|
502
541
|
if (e instanceof HttpError)
|
|
@@ -541,36 +580,59 @@ export function createResumeLegs(ctx) {
|
|
|
541
580
|
const liveReceiptOf = async (held) => {
|
|
542
581
|
if (held === null || held.fingerprint !== fingerprint)
|
|
543
582
|
return undefined;
|
|
544
|
-
const run = await runStore
|
|
583
|
+
const run = await runFactsOf(runStore, held.deliveredTaskId);
|
|
545
584
|
return run != null && !isTerminalRunStatus(run.status) ? acceptedResumingReceipt(held.deliveredTaskId, held.hostSessionId, NO_SETTLEMENT_EVIDENCE) : undefined;
|
|
546
585
|
};
|
|
547
586
|
const replay = await liveReceiptOf(await decisions.get(token));
|
|
548
587
|
if (replay !== undefined)
|
|
549
588
|
return replay;
|
|
550
589
|
let recordFailure;
|
|
590
|
+
const answerOfRecordFailure = async (failed) => {
|
|
591
|
+
if (failed.kind === "faulted")
|
|
592
|
+
return faultedAnswerOf(failed.err, CONTINUATION_CLAIM_FACE.faulted);
|
|
593
|
+
try {
|
|
594
|
+
return await refusalAfterLostClaim(deps, runStore, plan.hostSessionId, failed.deliveredTaskId);
|
|
595
|
+
}
|
|
596
|
+
catch (e) {
|
|
597
|
+
return faultedAnswerOf(e, CONTINUATION_CLAIM_FACE.faulted);
|
|
598
|
+
}
|
|
599
|
+
};
|
|
551
600
|
const delivery = {
|
|
552
601
|
carried: [{ runId: plan.runId, token, outcome: plan.outcome }],
|
|
553
602
|
commitBeforeLaunch: async (deliveredTaskId) => {
|
|
603
|
+
let recorded;
|
|
554
604
|
try {
|
|
555
|
-
|
|
556
|
-
if (!recorded)
|
|
557
|
-
throw new Error(DELIVERY_NOT_RECORDED);
|
|
605
|
+
recorded = await decisions.record({ token, runId: plan.runId, hostSessionId: plan.hostSessionId, outcome: plan.outcome, fingerprint, deliveredTaskId, acceptedAtMs: Date.now() });
|
|
558
606
|
}
|
|
559
607
|
catch (err) {
|
|
560
|
-
recordFailure = { err };
|
|
608
|
+
recordFailure = { kind: "faulted", err };
|
|
561
609
|
throw err;
|
|
562
610
|
}
|
|
611
|
+
if (!recorded) {
|
|
612
|
+
recordFailure = { kind: "not_recorded", deliveredTaskId };
|
|
613
|
+
throw new Error(DELIVERY_NOT_RECORDED);
|
|
614
|
+
}
|
|
563
615
|
},
|
|
564
616
|
};
|
|
565
617
|
const hostToken = await cs
|
|
566
618
|
.findPendingTokenBySession(plan.hostSessionId, undefined, { gateKinds: TERMINAL_PARK_GATE_KINDS, pick: "oldest" })
|
|
567
619
|
.catch(() => undefined);
|
|
568
620
|
const admittedPayer = decodeCheckpointScope(cp.scope);
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
621
|
+
let out;
|
|
622
|
+
try {
|
|
623
|
+
out = hostToken
|
|
624
|
+
? await resumeWake(plan.hostSessionId, plan.message, decider?.subject, req, acceptEarly, delivery, admittedPayer, restatement)
|
|
625
|
+
: await startFreshHostTurn(plan.hostSessionId, plan.message.text, admittedPayer, req, delivery, plan.runId, restatement);
|
|
626
|
+
}
|
|
627
|
+
catch (err) {
|
|
628
|
+
const failed = recordFailure;
|
|
629
|
+
if (failed === undefined)
|
|
630
|
+
throw err;
|
|
631
|
+
return await answerOfRecordFailure(failed);
|
|
632
|
+
}
|
|
633
|
+
const failed = recordFailure;
|
|
634
|
+
if (failed !== undefined)
|
|
635
|
+
return await answerOfRecordFailure(failed);
|
|
574
636
|
if (acceptedTaskIdOf(out) === undefined)
|
|
575
637
|
return (await liveReceiptOf(await decisions.get(token))) ?? out;
|
|
576
638
|
return out;
|
|
@@ -623,17 +685,18 @@ export function createResumeLegs(ctx) {
|
|
|
623
685
|
const ONE_SHOT_SUBMIT_STRIP = Object.fromEntries(ONE_SHOT_SUBMIT_KEYS.map((k) => [k, undefined]));
|
|
624
686
|
const resolveResumeSpec = async (ctx, req, auth, lease) => {
|
|
625
687
|
const engineNotices = [];
|
|
626
|
-
const execution = await
|
|
688
|
+
const execution = await resolveBeforeClaim(deps, { kind: "continuation", root: auth.sessionId, principal: auth.subject === undefined ? undefined : personOf(recoveredSubject(auth.subject)) }, CONTINUATION_CLAIM_FACE);
|
|
627
689
|
const resolved = await deps.resolveSpec({ ...ctx.body, ...ONE_SHOT_SUBMIT_STRIP }, req, auth, {
|
|
628
690
|
leg: "resume",
|
|
629
691
|
onNotice: (n) => engineNotices.push(n),
|
|
630
692
|
...(ctx.unattendedLeg === true ? { unattendedLeg: true } : {}),
|
|
693
|
+
...(ctx.projectContext !== undefined ? { projectContext: ctx.projectContext } : {}),
|
|
631
694
|
lease,
|
|
632
695
|
execution,
|
|
633
696
|
});
|
|
634
697
|
const legFacts = legFactsOf(resolved);
|
|
635
698
|
const runner = runnerFor(resolved);
|
|
636
|
-
const spec = stampSpecRoot(resolved, execution, ctx.body);
|
|
699
|
+
const spec = stampSpecRoot(resolved, execution, { use: "session", requireExistingSession: ctx.body.requireExistingSession });
|
|
637
700
|
return { spec, runner, legFacts, engineNotices, execution };
|
|
638
701
|
};
|
|
639
702
|
const refuseStoredBodyReplay = (sessionId, refusal) => {
|
|
@@ -651,6 +714,8 @@ export function createResumeLegs(ctx) {
|
|
|
651
714
|
}
|
|
652
715
|
catch (e) {
|
|
653
716
|
lease.release();
|
|
717
|
+
if (e instanceof ClaimFaultAnswer)
|
|
718
|
+
return { ok: false, answer: e.answer };
|
|
654
719
|
if (e instanceof HttpError) {
|
|
655
720
|
return { ok: false, answer: resumeRefusalWithCard(resumeAssemblyRefusalAnswer(e.status, httpErrorRefusal(e)), true) };
|
|
656
721
|
}
|
|
@@ -684,16 +749,24 @@ export function createResumeLegs(ctx) {
|
|
|
684
749
|
const payer = legSubject === undefined ? undefined : personOf(legSubject);
|
|
685
750
|
const heldObjective = objectiveWithheldIn(resumeCtx.ctx) ? undefined : resumeObjective;
|
|
686
751
|
const reparkStatus = outcome.gate === "plan_review" ? "needs_review" : "suspended";
|
|
752
|
+
const commitResumePark = (runStore, runId, word, parkResult, cardToken) => {
|
|
753
|
+
if (heldLeg === undefined)
|
|
754
|
+
throw new Error(`resume leg: run ${runId} parked without the holding leg its claim handed back — the park cannot be committed`);
|
|
755
|
+
return commitParkRow({
|
|
756
|
+
runStore, taskId: runId, word, result: parkResult, card: { token: cardToken, sessionId }, cards: deps.checkpointStore, leg: "resume",
|
|
757
|
+
legId: heldLeg, staleWindowMs: deps.config?.runStaleSec === undefined ? undefined : deps.config.runStaleSec * 1000,
|
|
758
|
+
});
|
|
759
|
+
};
|
|
687
760
|
const resumeCtxNotPersisted = (why) => {
|
|
688
761
|
deps.metrics?.inc("resume_ctx_not_persisted_total");
|
|
689
762
|
deps.logger?.warn?.("resume_ctx_not_persisted", { sessionId: resumeCtx.sessionId, gate: outcome.gate, error: why, note: "this continuation runs with the body it was given; the durable rebuild input still holds the PREVIOUS body, so the NEXT continuation of this session rebuilds from that one — its permission mode is never wider than this leg's, but if this leg restated its MCP / A2A peer tables (mcpServers / a2aPeers on the resume request), a later continuation that does not restate them runs with the previous tables again" });
|
|
690
763
|
};
|
|
691
764
|
const commitResumeCtx = () => Promise.resolve().then(async () => {
|
|
692
765
|
const sealed = sealCheckpointCtx({ ...resumeCtx.ctx, writerVersion: serviceVersion() }, deps.checkpointCtxSealing, resumeCtx.sessionId);
|
|
693
|
-
const claim =
|
|
766
|
+
const claim = heldLeg !== undefined && taskId !== undefined && deps.runStore !== undefined ? createLegCtxClaim(deps.runStore, taskId, heldLeg) : undefined;
|
|
694
767
|
const landed = await deps.checkpointStore.putCtx(resumeCtx.sessionId, sealed, claim);
|
|
695
768
|
if (landed === "claim_released")
|
|
696
|
-
resumeCtxNotPersisted("claim_released: this
|
|
769
|
+
resumeCtxNotPersisted("claim_released: this leg no longer holds the run (settled, reaped, or claimed again by a later leg before the write-back landed) — nothing written");
|
|
697
770
|
}).catch((e) => resumeCtxNotPersisted(errorText(e)));
|
|
698
771
|
const legKey = createHash("sha256").update(String(token)).digest("hex");
|
|
699
772
|
const streamApprovalOn = resolveStreamApprovalGate({
|
|
@@ -720,16 +793,27 @@ export function createResumeLegs(ctx) {
|
|
|
720
793
|
const heldDecisions = await heldWorkflowParkDecisions(deps, sessionId, args.workflowDecision?.carried);
|
|
721
794
|
let taskId = await deps.runStore?.getActiveTaskId(sessionId);
|
|
722
795
|
let freshRunClaimed = false;
|
|
796
|
+
let heldLeg;
|
|
797
|
+
let legClaim;
|
|
798
|
+
let engineHandedOff = false;
|
|
799
|
+
let restored;
|
|
800
|
+
const cancelledInClaimWindow = () => restored?.kind === "ended" && restored.row?.errorCode === CANCELLED_CODE;
|
|
723
801
|
if (args.mintFreshRun && taskId && deps.runStore) {
|
|
724
802
|
return { status: 409, body: await buildActiveRunConflict({ runStore: deps.runStore, checkpointStore: deps.checkpointStore, governance: deps.config, turnActivity: readTurnActivityMs }, sessionId, taskId) };
|
|
725
803
|
}
|
|
726
804
|
if (!taskId && args.mintFreshRun && deps.runStore) {
|
|
727
805
|
const freshId = uuidv7();
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
806
|
+
let created;
|
|
807
|
+
try {
|
|
808
|
+
created = await timeClaim(deps.metrics, "run_claim", deps.runStore.createRun(freshId, sessionId, subject ?? null, deps.instanceId ?? "default", {
|
|
809
|
+
source: args.mintFreshRun.source,
|
|
810
|
+
identity: args.mintFreshRun.identity,
|
|
811
|
+
objectivePreview: heldObjective === undefined ? null : buildRunObjectivePreview(heldObjective),
|
|
812
|
+
}));
|
|
813
|
+
}
|
|
814
|
+
catch (e) {
|
|
815
|
+
return resumeClaimFaultAnswerOf(e);
|
|
816
|
+
}
|
|
733
817
|
if (created.existing) {
|
|
734
818
|
throw new Error(`wake fresh run: createRun observed an existing row for the freshly minted taskId ${freshId} (no idempotency key was sent) — refusing to treat it as a busy session`);
|
|
735
819
|
}
|
|
@@ -738,11 +822,20 @@ export function createResumeLegs(ctx) {
|
|
|
738
822
|
if (!created.ok) {
|
|
739
823
|
return { status: 409, body: await buildActiveRunConflict({ runStore: deps.runStore, checkpointStore: deps.checkpointStore, governance: deps.config, turnActivity: readTurnActivityMs }, sessionId, created.activeTaskId) };
|
|
740
824
|
}
|
|
741
|
-
|
|
825
|
+
legClaim = { kind: "run", runStore: deps.runStore, taskId: freshId, legId: created.legId };
|
|
826
|
+
let placementReject;
|
|
827
|
+
try {
|
|
828
|
+
const refusal = await commitExecutionContext(deps, legClaim, execution);
|
|
829
|
+
placementReject = refusal === null ? null : CONTINUATION_CLAIM_FACE.refused(refusal);
|
|
830
|
+
}
|
|
831
|
+
catch (e) {
|
|
832
|
+
placementReject = resumeClaimFaultAnswerOf(e);
|
|
833
|
+
}
|
|
742
834
|
if (placementReject)
|
|
743
835
|
return placementReject;
|
|
744
836
|
taskId = freshId;
|
|
745
837
|
freshRunClaimed = true;
|
|
838
|
+
heldLeg = created.legId;
|
|
746
839
|
}
|
|
747
840
|
const fleetPub = taskId && deps.fleetBus
|
|
748
841
|
? fleetRunPublisher(deps.fleetBus, { runId: taskId, scope: fleetScope, rootTaskId: taskId, sessionId, ...fleetRunLabels(heldObjective) })
|
|
@@ -751,12 +844,12 @@ export function createResumeLegs(ctx) {
|
|
|
751
844
|
if (deps.toolApproval && taskId) {
|
|
752
845
|
const toolApproval = deps.toolApproval;
|
|
753
846
|
resumeTaskConfig.onAsk = approvalLeg.unattended
|
|
754
|
-
? toolApproval.boundUnattendedAsk({ owner: subject ?? null, taskId, sessionId,
|
|
847
|
+
? toolApproval.boundUnattendedAsk({ owner: subject ?? null, taskId, sessionId, ...approvalLegOriginOf(execution) }, approvalLeg.unattended)
|
|
755
848
|
: toolApproval.boundAsk({
|
|
756
849
|
owner: subject ?? null,
|
|
757
850
|
taskId,
|
|
758
851
|
sessionId,
|
|
759
|
-
|
|
852
|
+
...approvalLegOriginOf(execution),
|
|
760
853
|
...(approvalLeg.active ? { legKey, ...(legDeadlineMonotonic !== undefined ? { legDeadlineMonotonic } : {}) } : {}),
|
|
761
854
|
});
|
|
762
855
|
}
|
|
@@ -791,12 +884,9 @@ export function createResumeLegs(ctx) {
|
|
|
791
884
|
if (!cs2)
|
|
792
885
|
return false;
|
|
793
886
|
try {
|
|
794
|
-
|
|
795
|
-
if (live?.status !== "pending")
|
|
796
|
-
return false;
|
|
797
|
-
if (await cs2.expire(token, live.scope))
|
|
887
|
+
if ((await expireCardUnderStoredScope(cs2, token)) === CARD_EXPIRE_OUTCOME.expired)
|
|
798
888
|
return true;
|
|
799
|
-
deps.logger?.
|
|
889
|
+
deps.logger?.info?.("resume_cancel_checkpoint_not_settled", { taskId, sessionId });
|
|
800
890
|
return false;
|
|
801
891
|
}
|
|
802
892
|
catch (cancelSettleErr) {
|
|
@@ -826,19 +916,45 @@ export function createResumeLegs(ctx) {
|
|
|
826
916
|
let cancelLedgerAppend;
|
|
827
917
|
const preemptCtrl = new AbortController();
|
|
828
918
|
if (taskId && deps.runStore) {
|
|
829
|
-
|
|
919
|
+
if (freshRunClaimed)
|
|
920
|
+
claimedRow = true;
|
|
921
|
+
else {
|
|
922
|
+
try {
|
|
923
|
+
heldLeg = await deps.runStore.markResuming(taskId, deps.instanceId ?? "default");
|
|
924
|
+
}
|
|
925
|
+
catch (e) {
|
|
926
|
+
return resumeClaimFaultAnswerOf(e);
|
|
927
|
+
}
|
|
928
|
+
claimedRow = heldLeg !== undefined;
|
|
929
|
+
}
|
|
830
930
|
if (!claimedRow)
|
|
831
931
|
return notResumableAnswer();
|
|
932
|
+
inflightRuns.set(taskId, cancelCtrl);
|
|
832
933
|
if (!freshRunClaimed) {
|
|
833
|
-
const
|
|
834
|
-
|
|
835
|
-
|
|
934
|
+
const rs0 = deps.runStore;
|
|
935
|
+
const claimedTask = taskId;
|
|
936
|
+
const restoreClaim = async () => {
|
|
937
|
+
restored = await commitResumePark(rs0, claimedTask, reparkStatus, null, token);
|
|
938
|
+
};
|
|
939
|
+
legClaim = { kind: "resumed", runStore: rs0, taskId: claimedTask, restore: restoreClaim };
|
|
940
|
+
let placementReject;
|
|
941
|
+
try {
|
|
942
|
+
const refusal = await commitExecutionContext(deps, legClaim, execution);
|
|
943
|
+
placementReject = refusal === null ? null : CONTINUATION_CLAIM_FACE.refused(refusal);
|
|
944
|
+
}
|
|
945
|
+
catch (e) {
|
|
946
|
+
placementReject = resumeClaimFaultAnswerOf(e);
|
|
947
|
+
}
|
|
948
|
+
if (placementReject) {
|
|
949
|
+
if (inflightRuns.get(claimedTask) === cancelCtrl)
|
|
950
|
+
inflightRuns.delete(claimedTask);
|
|
951
|
+
return cancelledInClaimWindow() ? { status: 200, body: { taskId: claimedTask, sessionId, status: "failed", errorCode: "cancelled" } } : placementReject;
|
|
952
|
+
}
|
|
836
953
|
}
|
|
837
954
|
markChildrenStoppedByUserOnAbort(cancelCtrl.signal, taskId, subject);
|
|
838
955
|
fleetPub?.onStart();
|
|
839
956
|
const rs = deps.runStore;
|
|
840
957
|
const owner = subject ?? null;
|
|
841
|
-
inflightRuns.set(taskId, cancelCtrl);
|
|
842
958
|
preemptableRuns.set(taskId, preemptCtrl);
|
|
843
959
|
resumeHeartbeat = setInterval(() => {
|
|
844
960
|
beatRunHeartbeat(rs, taskId, owner, () => cancelCtrl.abort("stall_verdict"), () => undefined);
|
|
@@ -867,6 +983,10 @@ export function createResumeLegs(ctx) {
|
|
|
867
983
|
if (args.onResumeCommitted)
|
|
868
984
|
await args.onResumeCommitted();
|
|
869
985
|
let unregisterEngineNotice;
|
|
986
|
+
const handToEngine = (start) => {
|
|
987
|
+
engineHandedOff = true;
|
|
988
|
+
return start();
|
|
989
|
+
};
|
|
870
990
|
try {
|
|
871
991
|
const instructionLeg = createInstructionSelectionLeg();
|
|
872
992
|
const legWiringSections = () => ({ instructions: instructionLeg.segment(), skills: args.legFacts?.skills });
|
|
@@ -885,6 +1005,21 @@ export function createResumeLegs(ctx) {
|
|
|
885
1005
|
return write;
|
|
886
1006
|
}, { route: "resume-open", connection: "durable-append", log: (m, x) => deps.logger?.info?.(m, x) });
|
|
887
1007
|
}
|
|
1008
|
+
const openEngineNoticePort = async (append) => {
|
|
1009
|
+
unregisterEngineNotice = registerEngineNoticeLeg({
|
|
1010
|
+
sessionId,
|
|
1011
|
+
...(taskId !== undefined ? { taskId } : {}),
|
|
1012
|
+
durable: (row) => append("engine_notice", row).then(() => true, (err) => {
|
|
1013
|
+
recordFailOpen("server.engine-notice.durable-append-failed", `leg=resume code=${row.code} task=${taskId ?? ""}`);
|
|
1014
|
+
deps.logger?.warn?.("engine_notice_append_failed", { taskId, noticeCode: row.code, sessionId: row.sessionId, err: err instanceof Error ? err.message : String(err) });
|
|
1015
|
+
return false;
|
|
1016
|
+
}),
|
|
1017
|
+
});
|
|
1018
|
+
for (const notice of args.engineNotices ?? [])
|
|
1019
|
+
await defaultEngineNoticeRouter.routeConfirmed(notice);
|
|
1020
|
+
if (deps.userInputLedger && taskId)
|
|
1021
|
+
await deps.userInputLedger.announceUndrained({ sessionId, taskId });
|
|
1022
|
+
};
|
|
888
1023
|
if (composition !== undefined) {
|
|
889
1024
|
const rsV = deps.runStore;
|
|
890
1025
|
const vSeqBase = rsV && taskId ? await rsV.maxSeq(taskId) : 0;
|
|
@@ -897,9 +1032,11 @@ export function createResumeLegs(ctx) {
|
|
|
897
1032
|
});
|
|
898
1033
|
const vAppend = (type, data) => verifySink.append(type, data);
|
|
899
1034
|
cancelLedgerAppend = vAppend;
|
|
1035
|
+
await openEngineNoticePort(vAppend);
|
|
900
1036
|
const verifyTailContentMode = resumeTaskConfig.forwardSubagentEvents === true ? "on" : "progress_only";
|
|
901
1037
|
const verifyInternals = {
|
|
902
1038
|
...launchInternals,
|
|
1039
|
+
...compositionLegRoot(args.legFacts?.registeredCwd),
|
|
903
1040
|
...(taskId ? { onActivity: () => recordTurnActivity(taskId) } : {}),
|
|
904
1041
|
onForwardEvent: (e) => {
|
|
905
1042
|
fleetPub?.onForwardEvent(e);
|
|
@@ -949,10 +1086,10 @@ export function createResumeLegs(ctx) {
|
|
|
949
1086
|
let vrEngine;
|
|
950
1087
|
switch (composition.entry) {
|
|
951
1088
|
case "verify":
|
|
952
|
-
vrEngine = await resumeWithVerification(legRunner, token, outcome, legSpec, resumeObjective, composition.rounds, verifyInternals);
|
|
1089
|
+
vrEngine = await handToEngine(() => resumeWithVerification(legRunner, token, outcome, legSpec, resumeObjective, composition.rounds, verifyInternals));
|
|
953
1090
|
break;
|
|
954
1091
|
case "cascade":
|
|
955
|
-
vrEngine = await resumeCascade(legRunner, token, outcome, stampSpecRoot({ ...legSpec, ...composition.objectiveInputs, objective: resumeObjective }, execution,
|
|
1092
|
+
vrEngine = await handToEngine(() => resumeCascade(legRunner, token, outcome, stampSpecRoot({ ...legSpec, ...composition.objectiveInputs, objective: resumeObjective }, execution, { use: "ladder_host" }), composition.config, composition.parkedLeg, verifyInternals));
|
|
956
1093
|
break;
|
|
957
1094
|
default: {
|
|
958
1095
|
const unhandled = composition;
|
|
@@ -989,8 +1126,9 @@ export function createResumeLegs(ctx) {
|
|
|
989
1126
|
}
|
|
990
1127
|
}
|
|
991
1128
|
catch (e) {
|
|
992
|
-
if (!vrReopened)
|
|
1129
|
+
if (!reSuspended && !vrReopened)
|
|
993
1130
|
throw e;
|
|
1131
|
+
recordFailOpen("server.runs.terminal-ledger-write-failed", `arm=resume-park-projection ${errorText(e)}`);
|
|
994
1132
|
}
|
|
995
1133
|
}
|
|
996
1134
|
if (reSuspended)
|
|
@@ -1009,21 +1147,11 @@ export function createResumeLegs(ctx) {
|
|
|
1009
1147
|
const serialAppend = createSerialLedgerAppend((s, type, data) => rs.appendEvent(taskId, s, type, data), startSeq);
|
|
1010
1148
|
const append = (type, data) => (rs && taskId ? serialAppend(type, data) : Promise.resolve());
|
|
1011
1149
|
cancelLedgerAppend = append;
|
|
1012
|
-
|
|
1013
|
-
sessionId,
|
|
1014
|
-
...(args.engineNotices !== undefined && args.engineNotices.length > 0 ? { pending: [...args.engineNotices] } : {}),
|
|
1015
|
-
durable: (row) => append("engine_notice", row).then(() => true, (err) => {
|
|
1016
|
-
recordFailOpen("server.engine-notice.durable-append-failed", `leg=resume code=${row.code} task=${taskId ?? ""}`);
|
|
1017
|
-
deps.logger?.warn?.("engine_notice_append_failed", { taskId, noticeCode: row.code, sessionId: row.sessionId, err: err instanceof Error ? err.message : String(err) });
|
|
1018
|
-
return false;
|
|
1019
|
-
}),
|
|
1020
|
-
});
|
|
1021
|
-
if (deps.userInputLedger && taskId)
|
|
1022
|
-
await deps.userInputLedger.announceUndrained({ sessionId, taskId });
|
|
1150
|
+
await openEngineNoticePort(append);
|
|
1023
1151
|
const anchorOwner = subject ?? null;
|
|
1024
|
-
const
|
|
1025
|
-
const captureTurnAnchor = deps.resumeAnchorStore &&
|
|
1026
|
-
? async (eventId) => { const leaf = (await
|
|
1152
|
+
const sessionFactsOf = sessionFactsReadOf(deps.sessionStorage);
|
|
1153
|
+
const captureTurnAnchor = deps.resumeAnchorStore && sessionFactsOf
|
|
1154
|
+
? async (eventId) => { const leaf = (await sessionFactsOf(sessionId))?.leafId; if (leaf)
|
|
1027
1155
|
await deps.resumeAnchorStore.put(sessionId, eventId, leaf, anchorOwner); }
|
|
1028
1156
|
: undefined;
|
|
1029
1157
|
const captureUserMessageAnchor = deps.resumeAnchorStore && taskId && freshRunClaimed
|
|
@@ -1047,7 +1175,7 @@ export function createResumeLegs(ctx) {
|
|
|
1047
1175
|
resumeLegLive = true;
|
|
1048
1176
|
const tailContentMode = resumeTaskConfig.forwardSubagentEvents === true ? "on" : "progress_only";
|
|
1049
1177
|
const resumeWorkspace = createSessionWorkspaceRecorder(sessionWorkspaceStoreOf(deps.sessionStorage), args.legFacts?.sessionWitness);
|
|
1050
|
-
const stream = await legRunner.resumeStream(token, outcome, { ...resumeTaskConfig, signal: cancelCtrl.signal, preemptSignal: preemptCtrl.signal }, {
|
|
1178
|
+
const stream = await handToEngine(() => legRunner.resumeStream(token, outcome, { ...resumeTaskConfig, signal: cancelCtrl.signal, preemptSignal: preemptCtrl.signal }, {
|
|
1051
1179
|
...launchInternals,
|
|
1052
1180
|
onForwardEvent: (e) => {
|
|
1053
1181
|
fleetPub?.onForwardEvent(e);
|
|
@@ -1102,7 +1230,7 @@ export function createResumeLegs(ctx) {
|
|
|
1102
1230
|
},
|
|
1103
1231
|
}
|
|
1104
1232
|
: {}),
|
|
1105
|
-
});
|
|
1233
|
+
}));
|
|
1106
1234
|
await commitResumeCtx();
|
|
1107
1235
|
resumeStreamRef = stream;
|
|
1108
1236
|
if (taskId)
|
|
@@ -1260,11 +1388,7 @@ export function createResumeLegs(ctx) {
|
|
|
1260
1388
|
const settledLeg = await reopenedAfterLeg(r, causeAtDone !== undefined);
|
|
1261
1389
|
if (settledLeg.reopened) {
|
|
1262
1390
|
reopenConfirmedPark = true;
|
|
1263
|
-
|
|
1264
|
-
await appendParkRow(append, { modelUsage: deps.modelUsage, taskId }, reparkStatus, r, failureCodeOf(r.terminal) ?? null);
|
|
1265
|
-
}
|
|
1266
|
-
catch {
|
|
1267
|
-
}
|
|
1391
|
+
await appendParkRow(append, { modelUsage: deps.modelUsage, taskId }, reparkStatus, r, failureCodeOf(r.terminal) ?? null);
|
|
1268
1392
|
return r;
|
|
1269
1393
|
}
|
|
1270
1394
|
const safe = await attachModelUsage(sealResultForExit(settledLeg.leg), { append, getEvents: (id, a) => rs.getEvents(id, a), modelUsage: deps.modelUsage, taskId });
|
|
@@ -1283,7 +1407,7 @@ export function createResumeLegs(ctx) {
|
|
|
1283
1407
|
owner: subject ?? null,
|
|
1284
1408
|
abortSignal: cancelCtrl.signal,
|
|
1285
1409
|
sessionId,
|
|
1286
|
-
|
|
1410
|
+
...approvalLegOriginOf(execution),
|
|
1287
1411
|
family: "approval_request",
|
|
1288
1412
|
transport: hitlTransport,
|
|
1289
1413
|
legKey,
|
|
@@ -1293,9 +1417,12 @@ export function createResumeLegs(ctx) {
|
|
|
1293
1417
|
const withElicitation = () => deps.elicitation && taskId
|
|
1294
1418
|
? deps.elicitation.runWithContext({ taskId, owner: subject ?? null, transport: hitlTransport, abortSignal: cancelCtrl.signal }, withApproval)
|
|
1295
1419
|
: withApproval();
|
|
1420
|
+
const withQuestion = () => deps.question && taskId
|
|
1421
|
+
? deps.question.runWithContext({ taskId, owner: subject ?? null, transport: hitlTransport, abortSignal: cancelCtrl.signal }, withElicitation)
|
|
1422
|
+
: withElicitation();
|
|
1296
1423
|
return await (deps.sendUserFile && taskId
|
|
1297
|
-
? deps.sendUserFile.runWithContext({ taskId, emit: async (frame) => { const { type, ...rest } = frame; await append(type, rest); } },
|
|
1298
|
-
:
|
|
1424
|
+
? deps.sendUserFile.runWithContext({ taskId, emit: async (frame) => { const { type, ...rest } = frame; await append(type, rest); } }, withQuestion)
|
|
1425
|
+
: withQuestion());
|
|
1299
1426
|
})));
|
|
1300
1427
|
}
|
|
1301
1428
|
catch (e) {
|
|
@@ -1315,6 +1442,7 @@ export function createResumeLegs(ctx) {
|
|
|
1315
1442
|
return { status: 200, body: { taskId, sessionId, status: "failed", errorCode: "cancelled" } };
|
|
1316
1443
|
}
|
|
1317
1444
|
const retriable = disposition === "retriable";
|
|
1445
|
+
let reparkEnded = false;
|
|
1318
1446
|
if (claimedRow && taskId && deps.runStore) {
|
|
1319
1447
|
if (retriable && freshRunClaimed) {
|
|
1320
1448
|
const c = { taskId, sessionId, terminal: { kind: "failed", code: e.code, message: e.message }, stats: { turns: 0, tokens: 0, usageMissing: true } };
|
|
@@ -1324,15 +1452,17 @@ export function createResumeLegs(ctx) {
|
|
|
1324
1452
|
settleFleet("failed");
|
|
1325
1453
|
}
|
|
1326
1454
|
else if (retriable) {
|
|
1327
|
-
|
|
1328
|
-
|
|
1455
|
+
const parked = await commitResumePark(deps.runStore, taskId, reparkStatus, null, token);
|
|
1456
|
+
reparkEnded = parked.kind === "ended";
|
|
1457
|
+
settleFleet(reparkEnded ? "failed" : reparkStatus);
|
|
1329
1458
|
}
|
|
1330
1459
|
else {
|
|
1331
1460
|
await deps.runStore.setTerminal(taskId, "failed", null, e.message).catch(() => undefined);
|
|
1332
1461
|
settleFleet("failed");
|
|
1333
1462
|
}
|
|
1334
1463
|
}
|
|
1335
|
-
|
|
1464
|
+
const answerRetriable = retriable && !reparkEnded;
|
|
1465
|
+
return checkpointRefusalAnswer(e, { gate: outcome.gate, retriable: answerRetriable, ...(taskId !== undefined ? { taskId } : {}), versionKeys: refusalVersionKeys(e, resumeCtx.ctx), ...(answerRetriable && args.rowWayOut !== undefined ? { wayOut: args.rowWayOut } : {}) });
|
|
1336
1466
|
}
|
|
1337
1467
|
const thrownCause = cancelCtrl.cause();
|
|
1338
1468
|
if (thrownCause !== undefined) {
|
|
@@ -1345,12 +1475,28 @@ export function createResumeLegs(ctx) {
|
|
|
1345
1475
|
settleFleet("failed");
|
|
1346
1476
|
return { status: 200, body: { taskId, sessionId, status: "failed", errorCode: "cancelled" } };
|
|
1347
1477
|
}
|
|
1348
|
-
if (
|
|
1349
|
-
|
|
1350
|
-
await deps
|
|
1478
|
+
if (!engineHandedOff && legClaim !== undefined) {
|
|
1479
|
+
const claim = legClaim;
|
|
1480
|
+
await withdrawClaim(deps, claim, `the resume could not be handed to the engine: ${outwardThrownMessage(e, errorText(e))}`, "faulted");
|
|
1481
|
+
const parkedAgain = claim.kind === "resumed" && restored?.kind !== "ended";
|
|
1482
|
+
settleFleet(parkedAgain ? reparkStatus : "failed");
|
|
1483
|
+
if (cancelledInClaimWindow())
|
|
1484
|
+
return { status: 200, body: { taskId, sessionId, status: "failed", errorCode: "cancelled" } };
|
|
1485
|
+
return resumeClaimFaultAnswerOf(e);
|
|
1486
|
+
}
|
|
1487
|
+
const heldParkWord = heldPark === undefined ? undefined : heldParkOf(heldPark);
|
|
1488
|
+
if (!(claimedRow && taskId && deps.runStore && heldPark !== undefined && heldParkWord !== undefined)) {
|
|
1489
|
+
if (claimedRow && taskId && deps.runStore) {
|
|
1490
|
+
await voidHeldParkCard(heldPark, sessionId, deps.checkpointStore, "resume");
|
|
1491
|
+
await deps.runStore.setTerminal(taskId, "failed", null, outwardThrownMessage(e, errorText(e))).catch(() => undefined);
|
|
1492
|
+
}
|
|
1493
|
+
settleFleet("failed");
|
|
1494
|
+
throw e;
|
|
1351
1495
|
}
|
|
1352
|
-
|
|
1353
|
-
|
|
1496
|
+
recordFailOpen("server.runs.terminal-ledger-write-failed", `arm=resume-park-held ${errorText(e)}`);
|
|
1497
|
+
if (cancelLedgerAppend !== undefined)
|
|
1498
|
+
await appendParkRow(cancelLedgerAppend, { modelUsage: deps.modelUsage, taskId }, heldParkWord.word, await graftParkToolCallId(heldPark, deps.checkpointStore));
|
|
1499
|
+
result = heldPark;
|
|
1354
1500
|
}
|
|
1355
1501
|
finally {
|
|
1356
1502
|
unregisterEngineNotice?.();
|
|
@@ -1375,25 +1521,32 @@ export function createResumeLegs(ctx) {
|
|
|
1375
1521
|
const checkpointReopened = reopenConfirmedPark;
|
|
1376
1522
|
const sealed = sealResultForExit(result);
|
|
1377
1523
|
const resumePlane = outwardPlane(sealed.terminal);
|
|
1524
|
+
let parkEnded;
|
|
1378
1525
|
if (taskId && deps.runStore) {
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
await deps.runStore
|
|
1526
|
+
const park = checkpointReopened && reparkStatus === "needs_review" ? { word: "needs_review", result: null }
|
|
1527
|
+
: resumePlane.status === "suspended" || checkpointReopened ? { word: "suspended", result: sealed.terminal.kind === "paused" ? sealed : null }
|
|
1528
|
+
: resumePlane.status === "needs_review" ? { word: "needs_review", result: sealed }
|
|
1529
|
+
: undefined;
|
|
1530
|
+
if (park !== undefined) {
|
|
1531
|
+
const parked = await commitResumePark(deps.runStore, taskId, park.word, park.result, heldPark?.terminal.kind === "paused" ? heldPark.terminal.token : token);
|
|
1532
|
+
if (parked.kind === "ended")
|
|
1533
|
+
parkEnded = { row: parked.row };
|
|
1534
|
+
}
|
|
1385
1535
|
else
|
|
1386
1536
|
await deps.runStore.setTerminal(taskId, resumePlane.status, sealed, resumePlane.errorMessage ?? null);
|
|
1387
1537
|
}
|
|
1388
|
-
settleFleet(checkpointReopened ? reparkStatus : resumePlane.status, fleetRunResiduals(sealed, sealed ? failureCodeOf(sealed.terminal) : undefined));
|
|
1538
|
+
settleFleet(parkEnded !== undefined ? "failed" : checkpointReopened ? reparkStatus : resumePlane.status, fleetRunResiduals(sealed, sealed ? failureCodeOf(sealed.terminal) : undefined));
|
|
1539
|
+
const answered = parkEnded !== undefined
|
|
1540
|
+
? { status: parkEnded.row?.status ?? "failed", errorCode: parkEnded.row?.errorCode ?? undefined, errorMessage: parkEnded.row?.error ?? undefined }
|
|
1541
|
+
: { status: resumePlane.status, errorCode: resumePlane.errorCode, errorMessage: resumePlane.errorMessage };
|
|
1389
1542
|
return {
|
|
1390
1543
|
status: 200,
|
|
1391
1544
|
body: {
|
|
1392
|
-
taskId, sessionId, status:
|
|
1545
|
+
taskId, sessionId, status: answered.status,
|
|
1393
1546
|
bindingEnforced: true,
|
|
1394
|
-
...(
|
|
1395
|
-
...(
|
|
1396
|
-
...(checkpointReopened ? { retriable: true } : {}),
|
|
1547
|
+
...(answered.errorCode ? { errorCode: answered.errorCode } : {}),
|
|
1548
|
+
...(answered.errorMessage ? { errorMessage: redactErrorMessage(answered.errorMessage) ?? "" } : {}),
|
|
1549
|
+
...(checkpointReopened && parkEnded === undefined ? { retriable: true } : {}),
|
|
1397
1550
|
...buildSettlementEvidence({ at: "engine_terminal", commitment: args.commitment }),
|
|
1398
1551
|
},
|
|
1399
1552
|
};
|
|
@@ -1446,7 +1599,7 @@ export function createResumeLegs(ctx) {
|
|
|
1446
1599
|
deps.logger?.warn?.("assistant_resume_unreadable_row_withheld", { sessionId, note: "row unreadable and the caller's ownership of THAT token is unproven — folded into the uniform 404" });
|
|
1447
1600
|
return noSuspension;
|
|
1448
1601
|
}
|
|
1449
|
-
return rowReadRefusalAnswer(e);
|
|
1602
|
+
return rowReadRefusalAnswer(e, { cs, runs: deps.runStore, token, logger: deps.logger });
|
|
1450
1603
|
}
|
|
1451
1604
|
if (!cp) {
|
|
1452
1605
|
if (!(await mayDiscloseRowError(cs, token, decider)))
|
|
@@ -1482,7 +1635,8 @@ export function createResumeLegs(ctx) {
|
|
|
1482
1635
|
if (composition?.entry === "cascade_unlinked")
|
|
1483
1636
|
return compositionUnlinkedAnswer();
|
|
1484
1637
|
const selectedGate = durableRowIdentity("decision-receipt", cp.checkpointId, token);
|
|
1485
|
-
|
|
1638
|
+
const rowWayOut = await loadedRowWayOut(cp, { cs, runs: deps.runStore, token, logger: deps.logger });
|
|
1639
|
+
return await driveResumeIntoRunLog({ peerLease: resolved.peerLease, execution: resolved.execution, runner: resolved.runner, legFacts: resolved.legFacts, token, sessionId, subject: auth.subject, fleetScope: resumeFleetScope(req, auth), taskConfig, resumeObjective, outcome: { gate: "resource_limit", decision: "continue" }, commitment: { kind: "gate_resolved", ...selectedGate }, composition, resumeCtx: { sessionId, ctx }, ...(rowWayOut !== undefined ? { rowWayOut } : {}), ...(engineNotices.length > 0 ? { engineNotices } : {}), ...(acceptEarly === true ? { acceptEarly: true } : {}), ...(req !== undefined ? { callerInitiated: true } : {}) });
|
|
1486
1640
|
}
|
|
1487
1641
|
finally {
|
|
1488
1642
|
resolved.peerLease.release();
|
|
@@ -1532,6 +1686,7 @@ export function createResumeLegs(ctx) {
|
|
|
1532
1686
|
source: "workflow_parked_decide",
|
|
1533
1687
|
identity: runIdentityOf(req, deps.config, subject ?? null),
|
|
1534
1688
|
workflowDecision,
|
|
1689
|
+
face: CONTINUATION_CLAIM_FACE,
|
|
1535
1690
|
});
|
|
1536
1691
|
if (out.existing) {
|
|
1537
1692
|
throw new Error(`decide host turn: createRun observed an existing row ${out.existing.taskId} for a freshly minted taskId (no idempotency key was sent)`);
|
|
@@ -1567,7 +1722,7 @@ export function createResumeLegs(ctx) {
|
|
|
1567
1722
|
deps.logger?.warn?.("wake_unreadable_row_withheld", { sessionId, note: "row unreadable and the caller's ownership of THAT token is unproven — folded into the uniform 404" });
|
|
1568
1723
|
return { status: 404, body: refusalBody({ errorCode: "not_found.parked_checkpoint", message: "no parked checkpoint for this session (nothing to wake)" }) };
|
|
1569
1724
|
}
|
|
1570
|
-
return rowReadRefusalAnswer(e);
|
|
1725
|
+
return rowReadRefusalAnswer(e, undefined);
|
|
1571
1726
|
}
|
|
1572
1727
|
if (!cp) {
|
|
1573
1728
|
if (!(await mayDiscloseRowError(cs, token, who))) {
|
|
@@ -1672,7 +1827,7 @@ export function createResumeLegs(ctx) {
|
|
|
1672
1827
|
deps.logger?.warn?.("plan_review_unreadable_row_withheld", { sessionId, note: "row unreadable and the caller's ownership of THAT token is unproven — folded into the uniform 404" });
|
|
1673
1828
|
return refuse(noPending);
|
|
1674
1829
|
}
|
|
1675
|
-
return refuse(rowReadRefusalAnswer(e));
|
|
1830
|
+
return refuse(await rowReadRefusalAnswer(e, { cs, runs: deps.runStore, token, logger: deps.logger }));
|
|
1676
1831
|
}
|
|
1677
1832
|
if (!cp) {
|
|
1678
1833
|
log404("checkpoint-missing");
|
|
@@ -1726,7 +1881,7 @@ export function createResumeLegs(ctx) {
|
|
|
1726
1881
|
throw new Error("drivePlanReview: permissionModeAfter was passed for a task whose stored permission mode is not \"plan\" — the caller must refuse this before any state changes (see the plan_review route's pre-nonce gate)");
|
|
1727
1882
|
}
|
|
1728
1883
|
const approvedMode = planReviewDecisionExitsPlan(decision) && effMode === "plan" ? (permissionModeAfter ?? "default") : undefined;
|
|
1729
|
-
const rebuildCtx = approvedMode === undefined ? ctx :
|
|
1884
|
+
const rebuildCtx = approvedMode === undefined ? ctx : { ...ctx, body: { ...ctx.body, permissionMode: approvedMode } };
|
|
1730
1885
|
const resolved = await resolveResumeSpecOrBlocked(rebuildCtx, req, auth);
|
|
1731
1886
|
if (!resolved.ok)
|
|
1732
1887
|
return resolved.answer;
|
|
@@ -1744,7 +1899,8 @@ export function createResumeLegs(ctx) {
|
|
|
1744
1899
|
hostDecision,
|
|
1745
1900
|
};
|
|
1746
1901
|
const selectedGate = durableRowIdentity("decision-receipt", cp.checkpointId, token);
|
|
1747
|
-
const
|
|
1902
|
+
const rowWayOut = await loadedRowWayOut(cp, { cs: deps.checkpointStore, runs: deps.runStore, token, logger: deps.logger });
|
|
1903
|
+
const out = await driveResumeIntoRunLog({ peerLease: resolved.peerLease, execution: resolved.execution, runner: resolved.runner, legFacts: resolved.legFacts, token, sessionId, subject: auth.subject, fleetScope: resumeFleetScope(req, auth), taskConfig, resumeObjective, outcome, commitment: { kind: "gate_resolved", ...selectedGate }, composition, resumeCtx: { sessionId, ctx: rebuildCtx }, ...(rowWayOut !== undefined ? { rowWayOut } : {}), ...(engineNotices.length > 0 ? { engineNotices } : {}), ...(acceptEarly === true ? { acceptEarly: true } : {}), ...(req !== undefined ? { callerInitiated: true } : {}) });
|
|
1748
1904
|
return out;
|
|
1749
1905
|
}
|
|
1750
1906
|
finally {
|
|
@@ -1755,10 +1911,10 @@ export function createResumeLegs(ctx) {
|
|
|
1755
1911
|
activeTaskIdOf: async (sessionId) => deps.runStore?.getActiveTaskId?.(sessionId),
|
|
1756
1912
|
liveRuns: steerableRuns,
|
|
1757
1913
|
inbox: deps.workflowCompletionInbox,
|
|
1758
|
-
|
|
1914
|
+
sessionStorage: deps.sessionStorage,
|
|
1759
1915
|
});
|
|
1760
1916
|
const routeCtxBase = {
|
|
1761
|
-
deps,
|
|
1917
|
+
deps: sealRouteDeps(deps),
|
|
1762
1918
|
registry: { idemCache, inflightRuns, preemptableRuns, steerableRuns, wakeParkMints, counters },
|
|
1763
1919
|
helpers: { readJson, readRawBody, rateLimited, quotaExceeded, ownerQuotaDenied, leaseDenied, ownerLeaseDenied, usageWindowDenied, admitRun, safeDecode },
|
|
1764
1920
|
local: { images: createImagesLocal(deps), sessions: createSessionsLocal(), sessionSync: createSessionSyncLocal(), capabilities: createCapabilitiesLocal() },
|