@sema-agent/server 7.136.0 → 7.138.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 +501 -139
- package/README.md +1 -0
- package/README.zh-CN.md +1 -0
- package/USAGE.md +149 -34
- package/deploy/sema-up/README.md +14 -0
- package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +7 -1
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +7 -1
- package/dist/approval-card.d.ts +21 -14
- package/dist/approval-card.js +1 -0
- package/dist/approval-content-kind.d.ts +6 -0
- package/dist/approval-content-kind.js +7 -0
- package/dist/approval-gate-currency.d.ts +48 -6
- package/dist/approval-gate-currency.js +16 -9
- package/dist/approval-hmac.d.ts +13 -1
- package/dist/approval-hmac.js +1 -1
- package/dist/approval.js +3 -3
- package/dist/audit.js +1 -0
- package/dist/auth-bridge.js +2 -2
- package/dist/background-agent-name.d.ts +5 -0
- package/dist/background-agent-name.js +5 -0
- package/dist/boot/budget-tracing.d.ts +1 -12
- package/dist/boot/deployment-mods.d.ts +46 -16
- package/dist/boot/deployment-mods.js +82 -6
- package/dist/boot/execution-env.d.ts +24 -1
- package/dist/boot/execution-env.js +69 -6
- package/dist/boot/governance-seams.d.ts +10 -17
- package/dist/boot/governance-seams.js +5 -17
- package/dist/boot/leader.d.ts +3 -0
- package/dist/boot/leader.js +1 -0
- package/dist/boot/org-delivery.js +15 -2
- package/dist/boot/reapers.d.ts +3 -0
- package/dist/boot/reapers.js +15 -1
- package/dist/boot/resolve-spec.d.ts +7 -0
- package/dist/boot/resolve-spec.js +36 -26
- package/dist/boot/retention-lane.d.ts +11 -5
- package/dist/boot/retention-lane.js +2 -2
- package/dist/boot/runner-deps.d.ts +7 -3
- package/dist/boot/runner-deps.js +1 -0
- package/dist/boot/stage-03-store-backend.d.ts +1 -1
- package/dist/boot/stage-04-stores.d.ts +2 -13
- package/dist/boot/stage-05-execution-env.d.ts +6 -13
- package/dist/boot/stage-05-execution-env.js +17 -5
- package/dist/boot/stage-06-runners.d.ts +6 -13
- package/dist/boot/stage-06-runners.js +10 -3
- package/dist/boot/stage-07-capability-layer.d.ts +7 -13
- package/dist/boot/stage-07-capability-layer.js +3 -3
- package/dist/boot/stage-08-reapers.d.ts +7 -13
- package/dist/boot/stage-08-reapers.js +2 -1
- package/dist/boot/stage-09-leader.d.ts +7 -13
- package/dist/boot/stage-09-leader.js +2 -2
- package/dist/boot/stage-10-http-server.d.ts +7 -13
- package/dist/boot/stage-10-http-server.js +6 -3
- package/dist/boot/stores.d.ts +1 -1
- package/dist/boot/web-admin.d.ts +5 -2
- package/dist/boot/web-admin.js +3 -3
- package/dist/brain.js +5 -5
- package/dist/broker/broker.d.ts +89 -0
- package/dist/broker/broker.js +287 -0
- package/dist/broker/constants.d.ts +39 -0
- package/dist/broker/constants.js +15 -0
- package/dist/broker/http1.d.ts +111 -0
- package/dist/broker/http1.js +256 -0
- package/dist/broker/lease-book.d.ts +87 -0
- package/dist/broker/lease-book.js +142 -0
- package/dist/broker/lease-file.d.ts +60 -0
- package/dist/broker/lease-file.js +127 -0
- package/dist/broker/main.d.ts +2 -0
- package/dist/broker/main.js +20 -0
- package/dist/budget.d.ts +17 -15
- package/dist/budget.js +2 -2
- package/dist/capabilities/composite-members.d.ts +2 -1
- package/dist/capabilities/composite-members.js +2 -1
- package/dist/capabilities/engine-capabilities.js +1 -0
- package/dist/capabilities/mcp-probe.d.ts +36 -11
- package/dist/capabilities/mcp-probe.js +44 -5
- package/dist/capabilities/scenarios.d.ts +23 -8
- package/dist/capabilities/scenarios.js +13 -8
- package/dist/capabilities/skills.d.ts +28 -5
- package/dist/capabilities/skills.js +8 -0
- package/dist/capability-facts.d.ts +6 -0
- package/dist/capability-facts.js +5 -0
- package/dist/center-credential-renewer.js +5 -1
- package/dist/checkpoint-ctx-seal-m28.d.ts +3 -10
- package/dist/checkpoint-ctx-seal-m28.js +1 -1
- package/dist/checkpoint-identity.d.ts +13 -6
- package/dist/config-catalog.js +16 -7
- package/dist/config-types.d.ts +24 -7
- package/dist/config.d.ts +1 -1
- package/dist/config.js +42 -13
- package/dist/deployment-governance.d.ts +2 -2
- package/dist/deployment-governance.js +7 -9
- package/dist/deployment-shape.d.ts +6 -6
- package/dist/device-ws-protocol.d.ts +1 -0
- package/dist/device-ws-protocol.js +2 -1
- package/dist/file-history-disclosure.d.ts +4 -2
- package/dist/file-history-disclosure.js +2 -0
- package/dist/gate-settlement.d.ts +71 -0
- package/dist/gate-settlement.js +40 -0
- package/dist/hooks/classic-stations.d.ts +12 -54
- package/dist/hooks/classic-stations.js +1 -0
- package/dist/hooks/command-spawn.d.ts +2 -2
- package/dist/hooks/hook-runner.js +14 -14
- package/dist/http/admission.js +14 -9
- package/dist/http/approval-sweeps.js +4 -3
- package/dist/http/caller-trust.d.ts +2 -1
- package/dist/http/caller-trust.js +1 -3
- package/dist/http/checkpoint-ctx.d.ts +48 -7
- package/dist/http/checkpoint-ctx.js +40 -0
- package/dist/http/dispatch.d.ts +4 -0
- package/dist/http/dispatch.js +18 -10
- package/dist/http/durable-run-leg.d.ts +5 -1
- package/dist/http/durable-run-leg.js +5 -3
- package/dist/http/health-self-report.d.ts +2 -2
- package/dist/http/memory-compliance-failure-reply.js +3 -0
- package/dist/http/principal-gate.d.ts +15 -10
- package/dist/http/principal-gate.js +48 -9
- package/dist/http/resume-legs.d.ts +7 -31
- package/dist/http/resume-legs.js +185 -126
- package/dist/http/route-ctx.d.ts +38 -53
- package/dist/http/route-ctx.js +2 -5
- package/dist/http/routes/a2a-serve.js +10 -4
- package/dist/http/routes/agents-roster.d.ts +1 -1
- package/dist/http/routes/agents-roster.js +5 -1
- package/dist/http/routes/approvals-assistant.js +24 -10
- package/dist/http/routes/capabilities.js +23 -11
- package/dist/http/routes/mcp-reconnect.d.ts +3 -2
- package/dist/http/routes/mcp-reconnect.js +7 -7
- package/dist/http/routes/memory-consolidation.d.ts +1 -1
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/rules.js +3 -3
- package/dist/http/routes/runs.js +13 -8
- package/dist/http/routes/session-sync.js +42 -6
- package/dist/http/routes/sessions.js +6 -3
- package/dist/http/routes/side-query.js +2 -3
- package/dist/http/routes/tasks.js +794 -780
- package/dist/http/server.d.ts +35 -25
- package/dist/http/stored-body-replay.d.ts +3 -3
- package/dist/http/stored-body-replay.js +6 -1
- package/dist/http/wire-types.d.ts +66 -33
- package/dist/identity-source.d.ts +65 -0
- package/dist/identity-source.js +45 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/leader/wire.d.ts +7 -0
- package/dist/leader/wire.js +5 -4
- package/dist/mcp-assertion-header.d.ts +51 -40
- package/dist/mcp-assertion-header.js +10 -11
- package/dist/mcp-authorization-face.d.ts +27 -0
- package/dist/mcp-authorization-face.js +15 -0
- package/dist/memory-operator-faces.d.ts +13 -4
- package/dist/memory-operator-faces.js +1 -17
- package/dist/memory-store-refusal.d.ts +3 -3
- package/dist/memory-sync-client.js +72 -57
- package/dist/memory-sync.d.ts +1 -1
- package/dist/model-entry-refusal.d.ts +2 -0
- package/dist/model-entry-refusal.js +11 -0
- package/dist/model-route-gap.d.ts +6 -22
- package/dist/model-route-gap.js +7 -5
- package/dist/model-select.d.ts +6 -17
- package/dist/model-select.js +0 -3
- package/dist/mods-declaration.d.ts +110 -0
- package/dist/mods-declaration.js +109 -0
- package/dist/namespaced-rule-name.d.ts +1 -1
- package/dist/observability/err-text.d.ts +5 -0
- package/dist/observability/err-text.js +9 -0
- package/dist/observability/fail-open.d.ts +17 -1
- package/dist/observability/fail-open.js +17 -1
- package/dist/observability/metrics.js +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/operator-ask.d.ts +2 -2
- package/dist/org-delivery-gate.js +1 -1
- package/dist/org-memory-admission.d.ts +2 -2
- package/dist/org-memory-admission.js +39 -2
- package/dist/parked-decide.d.ts +15 -2
- package/dist/parked-decide.js +17 -10
- package/dist/peer-directory.js +2 -0
- package/dist/peer-seat.d.ts +150 -0
- package/dist/peer-seat.js +239 -0
- package/dist/permission-rule-list.d.ts +2 -2
- package/dist/permission-rule-vocab.d.ts +7 -7
- package/dist/permission-rule-vocab.js +3 -3
- package/dist/plain-string-record.d.ts +38 -0
- package/dist/plain-string-record.js +38 -0
- package/dist/plugins/background-agent-store-sql.js +6 -3
- package/dist/plugins/caching-session-store.d.ts +5 -0
- package/dist/plugins/caching-session-store.js +6 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +34 -29
- package/dist/plugins/checkpoint-store-sql.js +14 -14
- package/dist/plugins/file-history-store-sql.js +10 -16
- package/dist/plugins/file-run-store.js +8 -2
- package/dist/plugins/k8s-exec-protocol.d.ts +69 -13
- package/dist/plugins/k8s-exec-protocol.js +116 -28
- package/dist/plugins/k8s-pod-delete-failure.d.ts +25 -0
- package/dist/plugins/k8s-pod-delete-failure.js +17 -0
- package/dist/plugins/k8s-pod-reaper.d.ts +106 -0
- package/dist/plugins/k8s-pod-reaper.js +122 -0
- package/dist/plugins/local-checkpoint-store.d.ts +4 -17
- package/dist/plugins/local-checkpoint-store.js +3 -4
- package/dist/plugins/local-session-store.d.ts +66 -27
- package/dist/plugins/local-session-store.js +60 -28
- package/dist/plugins/mailbox-store-sql.d.ts +11 -3
- package/dist/plugins/mailbox-store-sql.js +103 -15
- package/dist/plugins/memory-run-store.js +2 -0
- package/dist/plugins/memory-sync-store-pg.d.ts +16 -5
- package/dist/plugins/memory-sync-store-tidb.d.ts +3 -3
- package/dist/plugins/one-time-migrations.d.ts +34 -12
- package/dist/plugins/one-time-migrations.js +51 -9
- package/dist/plugins/permission-rule-store-file.js +2 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +17 -17
- package/dist/plugins/permission-rule-store-sql.js +37 -30
- package/dist/plugins/pg-pool.js +4 -0
- package/dist/plugins/pg-session-storage.d.ts +10 -2
- package/dist/plugins/pg-session-storage.js +20 -7
- package/dist/plugins/remote-env-adb.d.ts +6 -1
- package/dist/plugins/remote-env-adb.js +2 -1
- package/dist/plugins/remote-env-device.d.ts +6 -1
- package/dist/plugins/remote-env-device.js +5 -1
- package/dist/plugins/remote-env-e2b.d.ts +5 -0
- package/dist/plugins/remote-env-e2b.js +2 -1
- package/dist/plugins/remote-env-file-error.d.ts +8 -1
- package/dist/plugins/remote-env-file-error.js +7 -1
- package/dist/plugins/remote-env-host.d.ts +10 -2
- package/dist/plugins/remote-env-host.js +8 -2
- package/dist/plugins/remote-env-k8s.d.ts +140 -11
- package/dist/plugins/remote-env-k8s.js +277 -15
- package/dist/plugins/remote-env-local-docker.d.ts +5 -0
- package/dist/plugins/remote-env-local-docker.js +2 -1
- package/dist/plugins/remote-env-ssh.d.ts +6 -1
- package/dist/plugins/remote-env-ssh.js +2 -1
- package/dist/plugins/retention-store-sql.d.ts +14 -2
- package/dist/plugins/retention-store-sql.js +6 -0
- package/dist/plugins/run-store-sql.js +10 -4
- package/dist/plugins/session-fork.d.ts +10 -13
- package/dist/plugins/session-fork.js +5 -25
- package/dist/plugins/session-ownership.d.ts +24 -3
- package/dist/plugins/session-ownership.js +24 -5
- package/dist/plugins/session-workspace-cell.d.ts +17 -0
- package/dist/plugins/session-workspace-cell.js +38 -0
- package/dist/plugins/sql-errors.d.ts +23 -2
- package/dist/plugins/sql-errors.js +15 -0
- package/dist/plugins/store-backend.js +7 -7
- package/dist/plugins/store-contracts.d.ts +10 -1
- package/dist/plugins/store-fault.d.ts +2 -2
- package/dist/plugins/store-fault.js +4 -2
- package/dist/plugins/tidb-pool.js +13 -0
- package/dist/plugins/tidb-session-store.d.ts +17 -2
- package/dist/plugins/tidb-session-store.js +18 -7
- package/dist/plugins/tool-result-store-sql.d.ts +13 -6
- package/dist/plugins/tool-result-store-sql.js +8 -7
- package/dist/plugins/worktree-isolation.d.ts +3 -2
- package/dist/plugins/worktree-isolation.js +1 -7
- package/dist/project-identity.d.ts +1 -14
- package/dist/project-identity.js +0 -4
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +31 -2
- package/dist/request-value-closure.js +7 -1
- package/dist/rule-entry-list.d.ts +3 -2
- package/dist/rule-entry-list.js +2 -2
- package/dist/rules-consent.js +12 -7
- package/dist/run-local.d.ts +2 -2
- package/dist/run-local.js +12 -6
- package/dist/runs.d.ts +7 -1
- package/dist/runs.js +8 -2
- package/dist/runtime-governance.d.ts +5 -5
- package/dist/sandbox-git-lease.d.ts +49 -0
- package/dist/sandbox-git-lease.js +60 -0
- package/dist/sandbox-git-plane.d.ts +84 -0
- package/dist/sandbox-git-plane.js +105 -0
- package/dist/security.d.ts +16 -4
- package/dist/security.js +8 -3
- package/dist/server-secret-env.d.ts +12 -3
- package/dist/server-secret-env.js +18 -2
- package/dist/session-error-wire.d.ts +14 -6
- package/dist/session-error-wire.js +2 -1
- package/dist/session-incarnation.d.ts +4 -5
- package/dist/session-incarnation.js +2 -2
- package/dist/session-policy-wire.d.ts +1 -1
- package/dist/session-policy-wire.js +2 -2
- package/dist/session-sync.d.ts +1 -1
- package/dist/session-workspace.d.ts +130 -0
- package/dist/session-workspace.js +83 -0
- package/dist/spec-fields.d.ts +44 -14
- package/dist/spec-fields.js +33 -12
- package/dist/standing-answer-grant.d.ts +2 -13
- package/dist/standing-answer-grant.js +0 -7
- package/dist/stored-request-prompt-profile-m30.d.ts +49 -0
- package/dist/stored-request-prompt-profile-m30.js +25 -0
- package/dist/task-a2a.d.ts +44 -14
- package/dist/task-a2a.js +46 -20
- package/dist/task-mcp.d.ts +34 -21
- package/dist/task-mcp.js +46 -22
- package/dist/task-settings.d.ts +2 -2
- package/dist/tool-approval.d.ts +43 -9
- package/dist/tool-approval.js +57 -15
- package/dist/tool-rule-names.d.ts +5 -0
- package/dist/trace/core-keyset-guard.d.ts +34 -19
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +4 -0
- package/dist/trace/exit-seat.d.ts +20 -1
- package/dist/trace/exit-seat.js +5 -2
- package/dist/trace/extension-call-face.d.ts +33 -0
- package/dist/trace/extension-call-face.js +39 -0
- package/dist/trace/ledger-sink.d.ts +4 -5
- package/dist/trace/ledger-sink.js +3 -7
- package/dist/trace/project.d.ts +62 -10
- package/dist/trace/project.js +49 -9
- package/dist/trace/redact.d.ts +18 -6
- package/dist/trace/redact.js +154 -60
- package/dist/trace/self-minted-wire.d.ts +500 -7
- package/dist/trace/self-minted-wire.js +182 -1
- package/dist/trace/wire-projection-faces.d.ts +7 -5
- package/dist/trace/wire-projection-faces.js +9 -4
- package/dist/user-authored-text.d.ts +2 -2
- package/dist/user-authored-text.js +16 -1
- package/dist/web-admin-client/apply-effective.js +0 -1
- package/dist/web-admin-client/center-request.d.ts +23 -4
- package/dist/web-admin-client/center-request.js +42 -8
- package/dist/web-admin-client/http-client.js +6 -6
- package/dist/web-admin-client/skills-mcp.d.ts +8 -4
- package/dist/web-admin-client/skills-mcp.js +31 -18
- package/dist/web-admin-client/types.d.ts +10 -5
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +11 -5
- package/package.json +3 -3
- package/wire-changes/server@7.137.0.json +825 -0
- package/wire-changes/server@7.138.0.json +446 -0
package/dist/http/resume-legs.js
CHANGED
|
@@ -4,12 +4,13 @@ import { uuidv7, resumeWithVerification, CheckpointError, defaultTaskRegistry, t
|
|
|
4
4
|
import { decideParkedAgent, denyWorkflowParkForked, denyWorkflowParksUnreadable, findParkOrigin, heldWorkflowParkDecisions, planWorkflowParkedDecide } from "../parked-decide.js";
|
|
5
5
|
import { parkDecisionFingerprint } from "../orchestration/workflow-park-decision.js";
|
|
6
6
|
import { headReadOf } from "../session-incarnation.js";
|
|
7
|
+
import { createSessionWorkspaceRecorder, legSessionWitnessOf, sessionWorkspaceStoreOf } from "../session-workspace.js";
|
|
7
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";
|
|
8
9
|
const headUnavailable = async (sessionId) => {
|
|
9
10
|
throw new Error(`parked decide cannot verify which occupant session ${sessionId} belongs to: this deployment's session store has no head read (headOf; every built-in store has one) — refusing rather than resuming unverified`);
|
|
10
11
|
};
|
|
11
12
|
import { HttpError, decodeCheckpointScope, CHECKPOINT_PUBLIC_SCOPE } from "../security.js";
|
|
12
|
-
import { parkToolCallId, TurnAnchorCapture, HEARTBEAT_MS, markChildrenStoppedByUserOnAbort } from "../runs.js";
|
|
13
|
+
import { graftParkToolCallId, parkToolCallId, TurnAnchorCapture, HEARTBEAT_MS, markChildrenStoppedByUserOnAbort } from "../runs.js";
|
|
13
14
|
import { failureCodeOf, nestedPauseOf, sealResultForExit, outwardPlane } from "../terminal.js";
|
|
14
15
|
import { buildCancelledLedgerRow, createRunAbort, mintCancelledResult } from "../run-cancel-context.js";
|
|
15
16
|
import { isTerminalRunStatus } from "../plugins/store-contracts.js";
|
|
@@ -18,16 +19,17 @@ import { recordResumeResourceWindow } from "../resource-window.js";
|
|
|
18
19
|
import { emitPendingWorkflowCompletions, taskNotificationInboxEntry, taskNotificationStreamKeyOf, NotifiedKeys } from "../orchestration/workflow-completion-inbox.js";
|
|
19
20
|
import { fleetRunPublisher, fleetRunLabels, fleetRunResiduals, isFleetAgentTerminalNotification } from "../fleet/fleet-bus.js";
|
|
20
21
|
import { defaultSubagentTailBus } from "../fleet/subagent-tail-bus.js";
|
|
21
|
-
import { currentApprovalGateToken } from "../approval-gate-currency.js";
|
|
22
|
-
import { createApprovalCardEmitter, declaredApprovalFrameFamilies, parkRowStandingAnswerFacts, resolveApprovalLeg, resolveStreamApprovalGate, standingAnswerDurablyRecordable } from "../tool-approval.js";
|
|
22
|
+
import { currentApprovalGateToken, currentGateFacesOf, sightsCurrentGate } from "../approval-gate-currency.js";
|
|
23
|
+
import { approverFacingArgs, createApprovalCardEmitter, declaredApprovalFrameFamilies, parkRowStandingAnswerFacts, resolveApprovalLeg, resolveStreamApprovalGate, standingAnswerDurablyRecordable } from "../tool-approval.js";
|
|
23
24
|
import { buildCheckpointAnchorHash } from "../approval-ask-audit-store.js";
|
|
24
25
|
import { APPROVAL_ENDING_CAUSES } from "../approval-deny-reasons.js";
|
|
25
26
|
import { serviceVersion } from "../service-version.js";
|
|
26
27
|
import { TERMINAL_PARK_GATE_KINDS } from "../plugins/checkpoint-store-sql.js";
|
|
27
28
|
import { withPrincipal } from "../observability/principal-context.js";
|
|
28
29
|
import { withModelReachScope } from "../model-reach-scope.js";
|
|
30
|
+
import { runSkillsOf } from "../capabilities/skills.js";
|
|
29
31
|
import { createInstructionSelectionLeg } from "../instruction-selection.js";
|
|
30
|
-
import { modelTextEventData, turnEndEventData, contextUsageEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskStartedEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, compactionStartedEventData, workspaceChangedEventData, wiringManifestEventData, toolRosterDeltaEventData, toolDisclosureEventData, humanInputEventData, appendModelUsageDelta, appendPromptManifest, attachModelUsage } from "../trace/project.js";
|
|
32
|
+
import { modelTextEventData, parkEventData, turnEndEventData, contextUsageEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskStartedEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, compactionStartedEventData, workspaceChangedEventData, wiringManifestEventData, toolRosterDeltaEventData, toolDisclosureEventData, humanInputEventData, appendModelUsageDelta, appendPromptManifest, attachModelUsage } from "../trace/project.js";
|
|
31
33
|
import { redactSecrets } from "../trace/redact.js";
|
|
32
34
|
import { buildRunObjectivePreview } from "../user-authored-text.js";
|
|
33
35
|
import { createForwardAppendFailedNote, createLedgerSink, createSerialLedgerAppend } from "../trace/ledger-sink.js";
|
|
@@ -37,17 +39,20 @@ import { errorText } from "../observability/err-text.js";
|
|
|
37
39
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
38
40
|
import { verifyRoundsFromBody } from "./verify-rounds.js";
|
|
39
41
|
import { planReviewDecisionExitsPlan, storedBodyPermissionMode } from "../task-settings.js";
|
|
40
|
-
import { acceptedResumingReceipt, acceptedTaskIdOf
|
|
42
|
+
import { acceptedResumingReceipt, acceptedTaskIdOf } from "./route-ctx.js";
|
|
43
|
+
import { heldFor } from "../peer-seat.js";
|
|
44
|
+
import { NO_SETTLEMENT_EVIDENCE, buildSettlementEvidence, decisionCommittedOf } from "../gate-settlement.js";
|
|
45
|
+
import { durableRowIdentity } from "../checkpoint-identity.js";
|
|
41
46
|
import { mintAndDriveDurableRun } from "./durable-run-leg.js";
|
|
42
47
|
import { createSessionsLocal } from "./routes/sessions.js";
|
|
43
48
|
import { createSessionSyncLocal } from "./routes/session-sync.js";
|
|
44
49
|
import { createImagesLocal } from "./routes/images.js";
|
|
45
50
|
import { createCapabilitiesLocal } from "./routes/capabilities.js";
|
|
46
|
-
import { gatedPrincipal, explicitOperatorOk } from "./principal-gate.js";
|
|
51
|
+
import { gatedPrincipal, explicitOperatorOk, runIdentityOf } from "./principal-gate.js";
|
|
47
52
|
import { buildActiveRunConflict, resumeEntryForGate } from "./active-run-conflict.js";
|
|
48
53
|
import { commitPlacement, devicePlacementErrorBody } from "./device-placement.js";
|
|
49
54
|
import { commitSessionInheritEnv } from "./session-inherit-env.js";
|
|
50
|
-
import { ASK_USER_QUESTION_TOOL_NAME, isApprovalGateKind } from "../approval-content-kind.js";
|
|
55
|
+
import { ASK_USER_QUESTION_TOOL_NAME, isApprovalGateKind, isEngineQuestionRow } from "../approval-content-kind.js";
|
|
51
56
|
import { deploymentListAsks } from "../approval.js";
|
|
52
57
|
import { readResumeCtx, resumeCtxCorruptAnswer, resumeCtxUnsealableAnswer } from "./resume-ctx-read.js";
|
|
53
58
|
import { buildCheckpointVersionKeys, resumeBlockedByPolicyAnswer, resumeRefusalWithCard, sealCheckpointCtx, storedBodyReplayAnswer, storedBodyReplayLogFields, withPermissionModeRewritten } from "./checkpoint-ctx.js";
|
|
@@ -74,11 +79,14 @@ const WORKER_SWAP_REDEEMABLE = {
|
|
|
74
79
|
ledger_event_unknown: true,
|
|
75
80
|
real_approval_damaged: false,
|
|
76
81
|
real_approval_forged: false,
|
|
82
|
+
tool_identity_missing: true,
|
|
83
|
+
bound_input_hash_missing: false,
|
|
77
84
|
requirements_damaged: false,
|
|
78
85
|
read_face_damaged: false,
|
|
79
86
|
read_face_forged: false,
|
|
80
87
|
write_face_damaged: false,
|
|
81
88
|
skill_grants_damaged: false,
|
|
89
|
+
skill_scopes_damaged: false,
|
|
82
90
|
constraint_chain_missing: false,
|
|
83
91
|
hands_coordinates_damaged: false,
|
|
84
92
|
installation_record_absent: true,
|
|
@@ -111,6 +119,7 @@ const CHECKPOINT_ERROR_DISPOSITION = {
|
|
|
111
119
|
"resume.principal_mismatch": "retriable",
|
|
112
120
|
"resume.placement_mismatch": "retriable",
|
|
113
121
|
"resume.preflight_rejected": "retriable",
|
|
122
|
+
"resume.holder_superseded": "retriable",
|
|
114
123
|
"wake.gate_pending": "retriable",
|
|
115
124
|
"wake.nothing_to_deliver": "retriable",
|
|
116
125
|
"checkpoint.config_refused": "retriable",
|
|
@@ -122,9 +131,9 @@ const CHECKPOINT_ERROR_DISPOSITION = {
|
|
|
122
131
|
"checkpoint.gate_mismatch": "terminal",
|
|
123
132
|
"checkpoint.reopen_failed": "terminal",
|
|
124
133
|
"checkpoint.cwd_conflicts_restore": "terminal",
|
|
134
|
+
"steering.duplicate_input_id": "retriable",
|
|
125
135
|
"checkpoint.already_exists": "terminal",
|
|
126
136
|
"checkpoint.execution_outcome_conflict": "terminal",
|
|
127
|
-
"steering.duplicate_input_id": "terminal",
|
|
128
137
|
"steering.invalid_content": "terminal",
|
|
129
138
|
"steering.queue_full": "terminal",
|
|
130
139
|
};
|
|
@@ -156,6 +165,10 @@ const CHECKPOINT_ERROR_FIELD_ROLE = {
|
|
|
156
165
|
hostDecision: "outcome_cell",
|
|
157
166
|
approver: "outcome_cell",
|
|
158
167
|
feedback: "outcome_cell",
|
|
168
|
+
outcome: "outcome_cell",
|
|
169
|
+
updatedInput: "outcome_cell",
|
|
170
|
+
decision: "outcome_cell",
|
|
171
|
+
reason: "outcome_cell",
|
|
159
172
|
taskConfig: "config",
|
|
160
173
|
deps: "config",
|
|
161
174
|
inheritedGate: "config",
|
|
@@ -183,6 +196,26 @@ function decisionRefusalCauseOf(e, gate) {
|
|
|
183
196
|
function notResumableAnswer() {
|
|
184
197
|
return { status: 409, body: refusalBody({ errorCode: "conflict.not_resumable", message: "run is not in a resumable (suspended) state (already resumed, decided, or expired)" }) };
|
|
185
198
|
}
|
|
199
|
+
function approvalStaleAnswer(facts) {
|
|
200
|
+
return {
|
|
201
|
+
status: 409,
|
|
202
|
+
body: refusalBody({
|
|
203
|
+
errorCode: "approval_stale",
|
|
204
|
+
message: "the approval you are deciding is no longer current (already resolved or superseded since you viewed it)",
|
|
205
|
+
facts: {
|
|
206
|
+
...(facts.terminal !== undefined ? { terminal: facts.terminal } : {}),
|
|
207
|
+
...(facts.currentPending !== undefined ? { currentPending: facts.currentPending } : {}),
|
|
208
|
+
},
|
|
209
|
+
}),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function acceptableFormFacts(detail) {
|
|
213
|
+
const rewritten = detail !== null && typeof detail === "object" ? detail.editRewritten : undefined;
|
|
214
|
+
if (rewritten === null || typeof rewritten !== "object" || !Object.hasOwn(rewritten, "acceptableForm"))
|
|
215
|
+
return {};
|
|
216
|
+
const shown = approverFacingArgs(rewritten.acceptableForm);
|
|
217
|
+
return shown === undefined ? {} : { acceptableForm: shown };
|
|
218
|
+
}
|
|
186
219
|
export function checkpointRefusalAnswer(e, at) {
|
|
187
220
|
const refusalCause = e.code === "checkpoint.invalid_outcome" ? decisionRefusalCauseOf(e, at.gate) : undefined;
|
|
188
221
|
const detail = e.detail;
|
|
@@ -198,6 +231,7 @@ export function checkpointRefusalAnswer(e, at) {
|
|
|
198
231
|
? { retryAfterSec: Math.max(1, Math.ceil(detail.retryAfterMs / 1000)) }
|
|
199
232
|
: {}),
|
|
200
233
|
...at.versionKeys,
|
|
234
|
+
...(e.code === "resume.constraint_rejected" ? acceptableFormFacts(detail) : {}),
|
|
201
235
|
},
|
|
202
236
|
}),
|
|
203
237
|
}, at.retriable);
|
|
@@ -209,7 +243,7 @@ export function createResumeLegs(ctx) {
|
|
|
209
243
|
async function resumeCheckpoint(sessionId, decision, reason, hostDecision, req, answer, binding, onResumeCommitted, acceptEarly, decider) {
|
|
210
244
|
const cs = deps.checkpointStore;
|
|
211
245
|
const token = await currentApprovalGateToken(cs, sessionId);
|
|
212
|
-
if (binding?.checkpointToken && binding.checkpointToken
|
|
246
|
+
if (binding?.checkpointToken && !sightsCurrentGate({ face: "checkpointToken", value: binding.checkpointToken }, token ? { checkpointToken: token } : null)) {
|
|
213
247
|
let seenUnreadable = false;
|
|
214
248
|
const seen = await cs.get(binding.checkpointToken).catch((e) => {
|
|
215
249
|
seenUnreadable = true;
|
|
@@ -245,17 +279,7 @@ export function createResumeLegs(ctx) {
|
|
|
245
279
|
};
|
|
246
280
|
}
|
|
247
281
|
}
|
|
248
|
-
return {
|
|
249
|
-
status: 409,
|
|
250
|
-
body: refusalBody({
|
|
251
|
-
errorCode: "approval_stale",
|
|
252
|
-
message: "the approval you are deciding is no longer current (already resolved or superseded since you viewed it)",
|
|
253
|
-
facts: {
|
|
254
|
-
...(attributable ? { terminal: "resolved" } : {}),
|
|
255
|
-
...(currentPending ? { currentPending } : {}),
|
|
256
|
-
},
|
|
257
|
-
}),
|
|
258
|
-
};
|
|
282
|
+
return approvalStaleAnswer({ ...(attributable ? { terminal: "resolved" } : {}), ...(currentPending ? { currentPending } : {}) });
|
|
259
283
|
}
|
|
260
284
|
if (!token) {
|
|
261
285
|
deps.logger?.info?.("approval_decide_no_pending", { sessionId });
|
|
@@ -330,16 +354,7 @@ export function createResumeLegs(ctx) {
|
|
|
330
354
|
...(cp.pendingAction.boundInputHash ? { boundInputHash: cp.pendingAction.boundInputHash } : {}),
|
|
331
355
|
};
|
|
332
356
|
}
|
|
333
|
-
return {
|
|
334
|
-
status: 409,
|
|
335
|
-
body: refusalBody({
|
|
336
|
-
errorCode: "approval_stale",
|
|
337
|
-
message: "the approval you are deciding is no longer current (already resolved or superseded since you viewed it)",
|
|
338
|
-
facts: {
|
|
339
|
-
...(s57CurrentPending ? { currentPending: s57CurrentPending } : {}),
|
|
340
|
-
},
|
|
341
|
-
}),
|
|
342
|
-
};
|
|
357
|
+
return approvalStaleAnswer(s57CurrentPending ? { currentPending: s57CurrentPending } : {});
|
|
343
358
|
}
|
|
344
359
|
const paForGrant = cp.pendingAction.kind === "tool_approval" ? cp.pendingAction : undefined;
|
|
345
360
|
const rememberableTool = paForGrant !== undefined &&
|
|
@@ -360,9 +375,7 @@ export function createResumeLegs(ctx) {
|
|
|
360
375
|
}
|
|
361
376
|
: undefined;
|
|
362
377
|
const noteLateSettleIfAccepted = (out) => {
|
|
363
|
-
if (lateSettleSink === undefined || lateSettleAnchor === undefined || out
|
|
364
|
-
return;
|
|
365
|
-
if (out.body?.errorCode === "cancelled" && out.decisionCommitted !== true)
|
|
378
|
+
if (lateSettleSink === undefined || lateSettleAnchor === undefined || !decisionCommittedOf(out))
|
|
366
379
|
return;
|
|
367
380
|
try {
|
|
368
381
|
lateSettleSink.recordLateSettle({ ...lateSettleAnchor, outcome: decision === "approve" ? "allowed" : "denied", decidedBy: hostDecision.decidedBy, ...(hostDecision.approver !== undefined ? { approver: hostDecision.approver } : {}), settledAtMs: Date.now() });
|
|
@@ -378,6 +391,7 @@ export function createResumeLegs(ctx) {
|
|
|
378
391
|
if (parkedForkLeaseDenial)
|
|
379
392
|
return parkedForkLeaseDenial;
|
|
380
393
|
const ownerLeaseAdmittedHere = req !== undefined;
|
|
394
|
+
const captureSelectedGate = () => durableRowIdentity("decision-receipt", cp.checkpointId, token);
|
|
381
395
|
if (req !== undefined) {
|
|
382
396
|
const parkedAgentStore = deps.backgroundAgentStore;
|
|
383
397
|
const parkedSurface = deps.parkedReviveSurface;
|
|
@@ -407,7 +421,7 @@ export function createResumeLegs(ctx) {
|
|
|
407
421
|
...(deps.parkedReviveInheritedGate ? { rebuildInheritedGate: deps.parkedReviveInheritedGate } : {}),
|
|
408
422
|
...(deps.toolApproval ? { approverSeatFor: windowZeroSeatOf(deps.toolApproval) } : {}),
|
|
409
423
|
...(deps.logger ? { warn: parkWarn } : {}),
|
|
410
|
-
}, parkedReq, { handle: origin.handle, row: origin.row }));
|
|
424
|
+
}, { ...parkedReq, selectedGate: captureSelectedGate() }, { handle: origin.handle, row: origin.row }));
|
|
411
425
|
void ctxPromise.catch(() => { });
|
|
412
426
|
noteLateSettleIfAccepted(parked);
|
|
413
427
|
return parked;
|
|
@@ -435,7 +449,7 @@ export function createResumeLegs(ctx) {
|
|
|
435
449
|
if (held === null || held.fingerprint !== fingerprint)
|
|
436
450
|
return undefined;
|
|
437
451
|
const run = await runStore.getRun(held.deliveredTaskId);
|
|
438
|
-
return run != null && !isTerminalRunStatus(run.status) ? acceptedResumingReceipt(held.deliveredTaskId, held.hostSessionId) : undefined;
|
|
452
|
+
return run != null && !isTerminalRunStatus(run.status) ? acceptedResumingReceipt(held.deliveredTaskId, held.hostSessionId, NO_SETTLEMENT_EVIDENCE) : undefined;
|
|
439
453
|
};
|
|
440
454
|
const replay = await liveReceiptOf(await decisions.get(token));
|
|
441
455
|
if (replay !== undefined)
|
|
@@ -481,42 +495,48 @@ export function createResumeLegs(ctx) {
|
|
|
481
495
|
const resolved = await resolveResumeSpecOrBlocked(ctx, req, auth);
|
|
482
496
|
if (!resolved.ok)
|
|
483
497
|
return resolved.answer;
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
498
|
+
try {
|
|
499
|
+
const { spec, engineNotices } = resolved;
|
|
500
|
+
const pendingTool = cp.pendingAction.toolName;
|
|
501
|
+
if (decision === "approve" && pendingTool === ASK_USER_QUESTION_TOOL_NAME && !answer) {
|
|
502
|
+
return { status: 400, body: refusalBody({ errorCode: "request.field_conflict", message: "pending action is AskUserQuestion — approve must carry body.answer ({ answers: [{ header, selected: string[], note? }] })", facts: { ...fieldConflictFacts("ask_answer", ["decision", "answer"]) } }) };
|
|
503
|
+
}
|
|
504
|
+
if (answer && (decision !== "approve" || pendingTool !== ASK_USER_QUESTION_TOOL_NAME)) {
|
|
505
|
+
return { status: 400, body: refusalBody({ errorCode: "request.field_conflict", message: `body.answer is only valid when approving a pending AskUserQuestion (decision: "${decision}", pending: "${pendingTool ?? "unknown"}")`, facts: { ...fieldConflictFacts("ask_answer", ["answer", "decision"]) } }) };
|
|
506
|
+
}
|
|
507
|
+
const { objective: resumeObjective, sessionId: _sessionId, ...taskConfig } = spec;
|
|
508
|
+
const pa = cp.pendingAction;
|
|
509
|
+
const persistedCallId = pa.kind === "tool_approval" ? pa.toolCallId : "";
|
|
510
|
+
const persistedHash = pa.kind === "tool_approval" ? (pa.boundInputHash ?? "") : "";
|
|
511
|
+
const outcome = {
|
|
512
|
+
gate: "policy_ask",
|
|
513
|
+
boundCallId: binding?.boundCallId ?? persistedCallId,
|
|
514
|
+
boundInputHash: binding?.boundInputHash ?? persistedHash,
|
|
515
|
+
decision: decision === "approve" ? "allow" : "deny",
|
|
516
|
+
...(decision === "approve" && !isEngineQuestionRow(pa) && binding?.updatedInput !== undefined ? { updatedInput: binding.updatedInput } : {}),
|
|
517
|
+
...(reason ? { reason } : {}),
|
|
518
|
+
...(binding?.feedback !== undefined ? { feedback: binding.feedback } : {}),
|
|
519
|
+
...(answer !== undefined ? { answer } : {}),
|
|
520
|
+
hostDecision,
|
|
521
|
+
};
|
|
522
|
+
const verifyRounds = verifyRoundsFromBody(ctx.body);
|
|
523
|
+
const driven = await driveResumeIntoRunLog({ peerLease: resolved.peerLease, runner: runnerFor(spec), token, sessionId: cp.sessionId, principal: auth.principal, fleetScope: resumeFleetScope(req, auth), taskConfig, resumeObjective, outcome, commitment: { kind: "gate_resolved", ...captureSelectedGate() }, verifyRounds, resumeCtx: { sessionId, ctx }, ...(engineNotices.length > 0 ? { engineNotices } : {}), ...(boundGrant ? { onResumeCommitted: boundGrant } : {}), ...(acceptEarly === true ? { acceptEarly: true } : {}), ...(req !== undefined ? { callerInitiated: true } : {}), ...(ownerLeaseAdmittedHere ? { ownerLeaseAdmitted: true } : {}) });
|
|
524
|
+
noteLateSettleIfAccepted(driven);
|
|
525
|
+
return driven;
|
|
488
526
|
}
|
|
489
|
-
|
|
490
|
-
|
|
527
|
+
finally {
|
|
528
|
+
resolved.peerLease.release();
|
|
491
529
|
}
|
|
492
|
-
const { objective: resumeObjective, sessionId: _sessionId, ...taskConfig } = spec;
|
|
493
|
-
const pa = cp.pendingAction;
|
|
494
|
-
const persistedCallId = pa.kind === "tool_approval" ? pa.toolCallId : "";
|
|
495
|
-
const persistedHash = pa.kind === "tool_approval" ? (pa.boundInputHash ?? "") : "";
|
|
496
|
-
const outcome = {
|
|
497
|
-
gate: "policy_ask",
|
|
498
|
-
boundCallId: binding?.boundCallId ?? persistedCallId,
|
|
499
|
-
boundInputHash: binding?.boundInputHash ?? persistedHash,
|
|
500
|
-
decision: decision === "approve" ? "allow" : "deny",
|
|
501
|
-
...(decision === "approve" && binding?.updatedInput !== undefined ? { updatedInput: binding.updatedInput } : {}),
|
|
502
|
-
...(reason ? { reason } : {}),
|
|
503
|
-
...(binding?.feedback !== undefined ? { feedback: binding.feedback } : {}),
|
|
504
|
-
...(answer !== undefined ? { answer } : {}),
|
|
505
|
-
hostDecision,
|
|
506
|
-
};
|
|
507
|
-
const verifyRounds = verifyRoundsFromBody(ctx.body);
|
|
508
|
-
const driven = await driveResumeIntoRunLog({ runner: runnerFor(spec), token, sessionId: cp.sessionId, principal: auth.principal, fleetScope: resumeFleetScope(req, auth), taskConfig, resumeObjective, outcome, verifyRounds, resumeCtx: { sessionId, ctx }, ...(engineNotices.length > 0 ? { engineNotices } : {}), ...(boundGrant ? { onResumeCommitted: boundGrant } : {}), ...(acceptEarly === true ? { acceptEarly: true } : {}), ...(req !== undefined ? { callerInitiated: true } : {}), ...(ownerLeaseAdmittedHere ? { ownerLeaseAdmitted: true } : {}) });
|
|
509
|
-
noteLateSettleIfAccepted(driven);
|
|
510
|
-
return driven;
|
|
511
530
|
}
|
|
512
531
|
const ONE_SHOT_SUBMIT_KEYS = ["resumeAt", "restoreFiles", "acceptPartialRestore", "rewindFilesTo", "rewindFiles", "userAttachments", "images"];
|
|
513
532
|
const ONE_SHOT_SUBMIT_STRIP = Object.fromEntries(ONE_SHOT_SUBMIT_KEYS.map((k) => [k, undefined]));
|
|
514
|
-
const resolveResumeSpec = async (ctx, req, auth) => {
|
|
533
|
+
const resolveResumeSpec = async (ctx, req, auth, lease) => {
|
|
515
534
|
const engineNotices = [];
|
|
516
535
|
const spec = await deps.resolveSpec({ ...ctx.body, ...ONE_SHOT_SUBMIT_STRIP }, req, auth, {
|
|
517
536
|
leg: "resume",
|
|
518
537
|
onNotice: (n) => engineNotices.push(n),
|
|
519
538
|
...(ctx.unattendedLeg === true ? { unattendedLeg: true } : {}),
|
|
539
|
+
lease,
|
|
520
540
|
});
|
|
521
541
|
return { spec, engineNotices };
|
|
522
542
|
};
|
|
@@ -528,11 +548,13 @@ export function createResumeLegs(ctx) {
|
|
|
528
548
|
const replay = storedBodyReplayRefusal(ctx, deps.config);
|
|
529
549
|
if (replay !== undefined)
|
|
530
550
|
return { ok: false, answer: refuseStoredBodyReplay(auth.sessionId, replay) };
|
|
551
|
+
const lease = deps.peerDesk.lease("resume");
|
|
531
552
|
try {
|
|
532
|
-
const { spec, engineNotices } = await resolveResumeSpec(ctx, req, auth);
|
|
533
|
-
return { ok: true, spec, engineNotices };
|
|
553
|
+
const { spec, engineNotices } = await resolveResumeSpec(ctx, req, auth, lease);
|
|
554
|
+
return { ok: true, spec, engineNotices, peerLease: lease };
|
|
534
555
|
}
|
|
535
556
|
catch (e) {
|
|
557
|
+
lease.release();
|
|
536
558
|
if (e instanceof HttpError) {
|
|
537
559
|
return { ok: false, answer: resumeRefusalWithCard(resumeBlockedByPolicyAnswer(httpErrorRefusal(e)), true) };
|
|
538
560
|
}
|
|
@@ -541,11 +563,11 @@ export function createResumeLegs(ctx) {
|
|
|
541
563
|
};
|
|
542
564
|
async function driveResumeIntoRunLog(args) {
|
|
543
565
|
if (args.acceptEarly !== true)
|
|
544
|
-
return await driveResumeLeg(args);
|
|
566
|
+
return await heldFor(args.peerLease, () => driveResumeLeg(args));
|
|
545
567
|
let settleAccepted;
|
|
546
568
|
let wasAccepted = false;
|
|
547
569
|
const accepted = new Promise((resolve) => { settleAccepted = resolve; });
|
|
548
|
-
const leg = driveResumeLeg(args, (receipt) => { wasAccepted = true; settleAccepted?.(receipt); });
|
|
570
|
+
const leg = heldFor(args.peerLease, () => driveResumeLeg(args, (receipt) => { wasAccepted = true; settleAccepted?.(receipt); }));
|
|
549
571
|
void leg.then((out) => {
|
|
550
572
|
if (wasAccepted && out.status >= 400) {
|
|
551
573
|
deps.logger?.warn?.("resume_leg_failed_after_accept", { sessionId: args.sessionId, status: out.status, body: out.body });
|
|
@@ -599,6 +621,7 @@ export function createResumeLegs(ctx) {
|
|
|
599
621
|
const freshId = uuidv7();
|
|
600
622
|
const created = await deps.runStore.createRun(freshId, sessionId, principal ?? null, deps.instanceId ?? "default", {
|
|
601
623
|
source: args.mintFreshRun.source,
|
|
624
|
+
identity: args.mintFreshRun.identity,
|
|
602
625
|
objectivePreview: buildRunObjectivePreview(resumeObjective ?? ""),
|
|
603
626
|
});
|
|
604
627
|
if (created.existing) {
|
|
@@ -725,6 +748,7 @@ export function createResumeLegs(ctx) {
|
|
|
725
748
|
let unregisterEngineNotice;
|
|
726
749
|
try {
|
|
727
750
|
const instructionLeg = createInstructionSelectionLeg();
|
|
751
|
+
const legWiringSections = () => ({ instructions: instructionLeg.segment(), skills: runSkillsOf(taskConfig) });
|
|
728
752
|
result = await instructionLeg.run(sessionId, () => withModelReachScope({ sessionId, taskId }, () => withPrincipal(principal, async () => {
|
|
729
753
|
const resumeNotifiedKeys = new NotifiedKeys();
|
|
730
754
|
if (deps.runStore && taskId) {
|
|
@@ -748,7 +772,7 @@ export function createResumeLegs(ctx) {
|
|
|
748
772
|
persistThinking: deps.config.traceThinking,
|
|
749
773
|
notifiedKeys: resumeNotifiedKeys,
|
|
750
774
|
...(taskId ? { onActivity: () => recordTurnActivity(taskId) } : {}),
|
|
751
|
-
|
|
775
|
+
legSections: legWiringSections,
|
|
752
776
|
});
|
|
753
777
|
const vAppend = (type, data) => verifySink.append(type, data);
|
|
754
778
|
cancelLedgerAppend = vAppend;
|
|
@@ -820,7 +844,7 @@ export function createResumeLegs(ctx) {
|
|
|
820
844
|
if (reSuspended || vrReopened) {
|
|
821
845
|
await appendModelUsageDelta(ap, deps.modelUsage, taskId);
|
|
822
846
|
const vrParkCallId = vrNested !== undefined ? await parkToolCallId({ terminal: vrNested }, deps.checkpointStore) : undefined;
|
|
823
|
-
await ap(reParkStatus ?? reparkStatus, {
|
|
847
|
+
await ap(reParkStatus ?? reparkStatus, parkEventData({ terminal: vrNested, ...(vrParkCallId !== undefined ? { toolCallId: vrParkCallId } : {}) }, vrReopened ? (failureCodeOf(vr.terminal) ?? null) : undefined));
|
|
824
848
|
}
|
|
825
849
|
else {
|
|
826
850
|
safe = await attachModelUsage(safe, { append: ap, getEvents: (id, a) => rs2.getEvents(id, a), modelUsage: deps.modelUsage, taskId });
|
|
@@ -882,6 +906,7 @@ export function createResumeLegs(ctx) {
|
|
|
882
906
|
const driveResume = async () => {
|
|
883
907
|
resumeLegLive = true;
|
|
884
908
|
const tailContentMode = resumeTaskConfig.forwardSubagentEvents === true ? "on" : "progress_only";
|
|
909
|
+
const resumeWorkspace = createSessionWorkspaceRecorder(sessionWorkspaceStoreOf(deps.sessionStorage), legSessionWitnessOf(resumeTaskConfig));
|
|
885
910
|
const stream = await legRunner.resumeStream(token, outcome, { ...resumeTaskConfig, signal: cancelCtrl.signal, preemptSignal: preemptCtrl.signal }, {
|
|
886
911
|
...launchInternals,
|
|
887
912
|
onForwardEvent: (e) => {
|
|
@@ -944,12 +969,14 @@ export function createResumeLegs(ctx) {
|
|
|
944
969
|
if (taskId)
|
|
945
970
|
steerableRuns.set(taskId, stream);
|
|
946
971
|
if (!taskId || !rs) {
|
|
972
|
+
for await (const ev of stream)
|
|
973
|
+
await resumeWorkspace.observe(ev);
|
|
947
974
|
const rNoRow = await stream.result();
|
|
948
975
|
if (await reopenedAfterLeg(rNoRow, cancelCtrl.cause() !== undefined))
|
|
949
976
|
reopenConfirmedPark = true;
|
|
950
977
|
return sealResultForExit(rNoRow);
|
|
951
978
|
}
|
|
952
|
-
onAccepted?.(acceptedResumingReceipt(taskId, sessionId));
|
|
979
|
+
onAccepted?.(acceptedResumingReceipt(taskId, sessionId, buildSettlementEvidence({ at: "engine_accepted", commitment: args.commitment })));
|
|
953
980
|
let causeAtDone;
|
|
954
981
|
for await (const ev of stream) {
|
|
955
982
|
if (ev.type === "done")
|
|
@@ -957,6 +984,7 @@ export function createResumeLegs(ctx) {
|
|
|
957
984
|
recordTurnActivity(taskId);
|
|
958
985
|
fleetPub?.onEvent(ev);
|
|
959
986
|
await deps.userInputLedger?.observeLegEvent(stream, ev);
|
|
987
|
+
await resumeWorkspace.observe(ev);
|
|
960
988
|
await appendPromptManifest(append, deps.promptManifests, taskId);
|
|
961
989
|
switch (ev.type) {
|
|
962
990
|
case "text_delta":
|
|
@@ -1017,7 +1045,7 @@ export function createResumeLegs(ctx) {
|
|
|
1017
1045
|
break;
|
|
1018
1046
|
case "wiring_manifest":
|
|
1019
1047
|
await flush();
|
|
1020
|
-
await append("wiring_manifest", wiringManifestEventData(ev,
|
|
1048
|
+
await append("wiring_manifest", wiringManifestEventData(ev, legWiringSections()));
|
|
1021
1049
|
break;
|
|
1022
1050
|
case "tool_roster_delta": {
|
|
1023
1051
|
await flush();
|
|
@@ -1074,20 +1102,19 @@ export function createResumeLegs(ctx) {
|
|
|
1074
1102
|
const r = causeAtDone !== undefined ? mintCancelledResult({ taskId, sessionId, startedAtMs: resumeLegStartedAt, message: "cancelled by user", engineResult: rEngine, cause: causeAtDone }) : rEngine;
|
|
1075
1103
|
const rPark = r.terminal.kind === "paused" ? outwardPlane(r.terminal).status : undefined;
|
|
1076
1104
|
if (rPark === "suspended") {
|
|
1077
|
-
|
|
1078
|
-
await append("suspended", { gate: r.terminal.kind === "paused" ? r.terminal.gate : null, ...(parkCallId !== undefined ? { toolCallId: parkCallId } : {}) });
|
|
1105
|
+
await append("suspended", parkEventData(await graftParkToolCallId(r, deps.checkpointStore)));
|
|
1079
1106
|
await appendModelUsageDelta(append, deps.modelUsage, taskId);
|
|
1080
1107
|
return r;
|
|
1081
1108
|
}
|
|
1082
1109
|
if (rPark === "needs_review") {
|
|
1083
|
-
await append("needs_review",
|
|
1110
|
+
await append("needs_review", parkEventData(r));
|
|
1084
1111
|
await appendModelUsageDelta(append, deps.modelUsage, taskId);
|
|
1085
1112
|
return r;
|
|
1086
1113
|
}
|
|
1087
1114
|
if (await reopenedAfterLeg(r, causeAtDone !== undefined)) {
|
|
1088
1115
|
reopenConfirmedPark = true;
|
|
1089
1116
|
try {
|
|
1090
|
-
await append(reparkStatus,
|
|
1117
|
+
await append(reparkStatus, parkEventData(r, failureCodeOf(r.terminal) ?? null));
|
|
1091
1118
|
await appendModelUsageDelta(append, deps.modelUsage, taskId);
|
|
1092
1119
|
}
|
|
1093
1120
|
catch {
|
|
@@ -1215,13 +1242,13 @@ export function createResumeLegs(ctx) {
|
|
|
1215
1242
|
settleFleet(checkpointReopened ? reparkStatus : resumePlane.status, fleetRunResiduals(sealed));
|
|
1216
1243
|
return {
|
|
1217
1244
|
status: 200,
|
|
1218
|
-
decisionCommitted: true,
|
|
1219
1245
|
body: {
|
|
1220
1246
|
taskId, sessionId, status: resumePlane.status,
|
|
1221
1247
|
bindingEnforced: true,
|
|
1222
1248
|
...(resumePlane.errorCode ? { errorCode: resumePlane.errorCode } : {}),
|
|
1223
1249
|
...(resumePlane.errorMessage ? { errorMessage: redactErrorMessage(resumePlane.errorMessage) ?? "" } : {}),
|
|
1224
1250
|
...(checkpointReopened ? { retriable: true } : {}),
|
|
1251
|
+
...buildSettlementEvidence({ at: "engine_terminal", commitment: args.commitment }),
|
|
1225
1252
|
},
|
|
1226
1253
|
};
|
|
1227
1254
|
}
|
|
@@ -1296,10 +1323,16 @@ export function createResumeLegs(ctx) {
|
|
|
1296
1323
|
const resolved = await resolveResumeSpecOrBlocked(ctx, req, auth);
|
|
1297
1324
|
if (!resolved.ok)
|
|
1298
1325
|
return resolved.answer;
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1326
|
+
try {
|
|
1327
|
+
const { spec, engineNotices } = resolved;
|
|
1328
|
+
const { objective: resumeObjective, sessionId: _sessionId, ...taskConfig } = spec;
|
|
1329
|
+
const verifyRounds = verifyRoundsFromBody(ctx.body);
|
|
1330
|
+
const selectedGate = durableRowIdentity("decision-receipt", cp.checkpointId, token);
|
|
1331
|
+
return await driveResumeIntoRunLog({ peerLease: resolved.peerLease, runner: runnerFor(spec), token, sessionId: cp.sessionId, principal: auth.principal, fleetScope: resumeFleetScope(req, auth), taskConfig, resumeObjective, outcome: { gate: "resource_limit", decision: "continue" }, commitment: { kind: "gate_resolved", ...selectedGate }, verifyRounds, resumeCtx: { sessionId, ctx }, ...(engineNotices.length > 0 ? { engineNotices } : {}), ...(acceptEarly === true ? { acceptEarly: true } : {}), ...(req !== undefined ? { callerInitiated: true } : {}) });
|
|
1332
|
+
}
|
|
1333
|
+
finally {
|
|
1334
|
+
resolved.peerLease.release();
|
|
1335
|
+
}
|
|
1303
1336
|
}
|
|
1304
1337
|
async function startFreshHostTurn(sessionId, objective, principal, req, workflowDecision, runId) {
|
|
1305
1338
|
const cs = deps.checkpointStore;
|
|
@@ -1332,22 +1365,28 @@ export function createResumeLegs(ctx) {
|
|
|
1332
1365
|
const resolved = await resolveResumeSpecOrBlocked(ctx, req, auth);
|
|
1333
1366
|
if (!resolved.ok)
|
|
1334
1367
|
return resolved.answer;
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1368
|
+
try {
|
|
1369
|
+
const { spec, engineNotices } = resolved;
|
|
1370
|
+
const hostSpec = { ...spec, objective, sessionId };
|
|
1371
|
+
const out = await mintAndDriveDurableRun(routeCtxBase, deps.runStore, {
|
|
1372
|
+
prepared: { spec: hostSpec, runner: runnerFor(hostSpec), auth, body: ctx.body, acceptance: createRunAcceptance({}, { objective }), peerLease: resolved.peerLease, ...(engineNotices.length > 0 ? { engineNotices } : {}) },
|
|
1373
|
+
fleetScope: resumeFleetScope(req, auth),
|
|
1374
|
+
elicitOwner: principal ?? null,
|
|
1375
|
+
source: "workflow_parked_decide",
|
|
1376
|
+
identity: runIdentityOf(req, deps.config, principal ?? null),
|
|
1377
|
+
workflowDecision,
|
|
1378
|
+
});
|
|
1379
|
+
if (out.existing) {
|
|
1380
|
+
throw new Error(`decide host turn: createRun observed an existing row ${out.existing.taskId} for a freshly minted taskId (no idempotency key was sent)`);
|
|
1381
|
+
}
|
|
1382
|
+
if (out.status !== 202)
|
|
1383
|
+
return { status: out.status, body: out.body };
|
|
1384
|
+
const minted = out.body;
|
|
1385
|
+
return acceptedResumingReceipt(minted.taskId, minted.sessionId, NO_SETTLEMENT_EVIDENCE);
|
|
1386
|
+
}
|
|
1387
|
+
finally {
|
|
1388
|
+
resolved.peerLease.release();
|
|
1346
1389
|
}
|
|
1347
|
-
if (out.status !== 202)
|
|
1348
|
-
return { status: out.status, body: out.body };
|
|
1349
|
-
const minted = out.body;
|
|
1350
|
-
return acceptedResumingReceipt(minted.taskId, minted.sessionId);
|
|
1351
1390
|
}
|
|
1352
1391
|
async function resumeWake(sessionId, message, caller, req, acceptEarly, workflowDecision, ownerLeaseAdmittedFor) {
|
|
1353
1392
|
const cs = deps.checkpointStore;
|
|
@@ -1411,28 +1450,35 @@ export function createResumeLegs(ctx) {
|
|
|
1411
1450
|
const resolved = await resolveResumeSpecOrBlocked(ctx, req, auth);
|
|
1412
1451
|
if (!resolved.ok)
|
|
1413
1452
|
return resolved.answer;
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1453
|
+
try {
|
|
1454
|
+
const { spec, engineNotices } = resolved;
|
|
1455
|
+
const { objective: resumeObjective, sessionId: _sessionId, ...taskConfig } = spec;
|
|
1456
|
+
return await driveResumeIntoRunLog({
|
|
1457
|
+
peerLease: resolved.peerLease,
|
|
1458
|
+
runner: runnerFor(spec),
|
|
1459
|
+
token,
|
|
1460
|
+
sessionId: cp.sessionId,
|
|
1461
|
+
principal: auth.principal,
|
|
1462
|
+
fleetScope: resumeFleetScope(req, auth),
|
|
1463
|
+
taskConfig,
|
|
1464
|
+
resumeObjective,
|
|
1465
|
+
outcome: { gate: "wake", ...(message !== undefined ? { message: { text: message, trusted } } : {}) },
|
|
1466
|
+
commitment: { kind: "delivered" },
|
|
1467
|
+
verifyRounds: undefined,
|
|
1468
|
+
resumeCtx: { sessionId, ctx },
|
|
1469
|
+
mintFreshRun: { source: "wake", identity: runIdentityOf(req, deps.config, auth.principal ?? null) },
|
|
1470
|
+
...(workflowDecision !== undefined ? { workflowDecision } : {}),
|
|
1471
|
+
...(engineNotices.length > 0 ? { engineNotices } : {}),
|
|
1472
|
+
...(acceptEarly === true ? { acceptEarly: true } : {}),
|
|
1473
|
+
...(req !== undefined ? { callerInitiated: true } : {}),
|
|
1474
|
+
...(ownerLeaseAdmittedFor !== undefined && auth.principal === ownerLeaseAdmittedFor ? { ownerLeaseAdmitted: true } : {}),
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
finally {
|
|
1478
|
+
resolved.peerLease.release();
|
|
1479
|
+
}
|
|
1434
1480
|
}
|
|
1435
|
-
async function preparePlanReview(sessionId, log, decider) {
|
|
1481
|
+
async function preparePlanReview(sessionId, log, decider, sighting) {
|
|
1436
1482
|
const cs = deps.checkpointStore;
|
|
1437
1483
|
const refuse = (answer) => ({ ok: false, answer });
|
|
1438
1484
|
const log404 = (r) => deps.logger?.info?.("decide_404", {
|
|
@@ -1490,6 +1536,13 @@ export function createResumeLegs(ctx) {
|
|
|
1490
1536
|
}),
|
|
1491
1537
|
});
|
|
1492
1538
|
}
|
|
1539
|
+
if (sighting !== undefined) {
|
|
1540
|
+
const current = currentGateFacesOf(token, cp);
|
|
1541
|
+
if (!sightsCurrentGate(sighting, current)) {
|
|
1542
|
+
const currentId = decider !== undefined && cp.status === "pending" ? current.checkpointId : undefined;
|
|
1543
|
+
return refuse(approvalStaleAnswer(currentId !== undefined ? { currentPending: { checkpointId: currentId } } : {}));
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1493
1546
|
const ctxRead = await readResumeCtx(cs.getCtx(sessionId), ctxOpening(sessionId));
|
|
1494
1547
|
if (ctxRead.kind === "corrupt")
|
|
1495
1548
|
return refuse(resumeCtxCorruptAnswer(ctxRead.where));
|
|
@@ -1516,18 +1569,24 @@ export function createResumeLegs(ctx) {
|
|
|
1516
1569
|
const resolved = await resolveResumeSpecOrBlocked(rebuildCtx, req, auth);
|
|
1517
1570
|
if (!resolved.ok)
|
|
1518
1571
|
return resolved.answer;
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1572
|
+
try {
|
|
1573
|
+
const { spec, engineNotices } = resolved;
|
|
1574
|
+
const { objective: resumeObjective, sessionId: _sessionId, ...taskConfig } = spec;
|
|
1575
|
+
const verifyRounds = verifyRoundsFromBody(ctx.body);
|
|
1576
|
+
const outcome = {
|
|
1577
|
+
gate: "plan_review",
|
|
1578
|
+
decision,
|
|
1579
|
+
...(editedPlan !== undefined ? { editedPlan } : {}),
|
|
1580
|
+
...(reason ? { reason } : {}),
|
|
1581
|
+
hostDecision,
|
|
1582
|
+
};
|
|
1583
|
+
const selectedGate = durableRowIdentity("decision-receipt", cp.checkpointId, token);
|
|
1584
|
+
const out = await driveResumeIntoRunLog({ peerLease: resolved.peerLease, runner: runnerFor(spec), token, sessionId: cp.sessionId, principal: auth.principal, fleetScope: resumeFleetScope(req, auth), taskConfig, resumeObjective, outcome, commitment: { kind: "gate_resolved", ...selectedGate }, verifyRounds, resumeCtx: { sessionId, ctx: rebuildCtx }, ...(engineNotices.length > 0 ? { engineNotices } : {}), ...(acceptEarly === true ? { acceptEarly: true } : {}), ...(req !== undefined ? { callerInitiated: true } : {}) });
|
|
1585
|
+
return out;
|
|
1586
|
+
}
|
|
1587
|
+
finally {
|
|
1588
|
+
resolved.peerLease.release();
|
|
1589
|
+
}
|
|
1531
1590
|
}
|
|
1532
1591
|
const routeCtxBase = {
|
|
1533
1592
|
deps,
|