@sema-agent/server 7.142.0 → 7.144.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 +608 -0
- package/USAGE.md +63 -36
- package/dist/adoption/plan.js +22 -0
- package/dist/approval-ask-audit-store.d.ts +7 -5
- package/dist/approval-ask-audit-store.js +12 -6
- package/dist/approval-ask-machine.d.ts +15 -7
- package/dist/approval-ask-machine.js +10 -4
- package/dist/approval-card.d.ts +155 -39
- package/dist/approval-card.js +111 -31
- package/dist/approval-queue-kind.d.ts +27 -0
- package/dist/approval-queue-kind.js +6 -0
- package/dist/approval-reconciler.d.ts +8 -8
- package/dist/approval-reconciler.js +3 -3
- package/dist/audit.js +4 -2
- package/dist/boot/budget-tracing.d.ts +1 -1
- package/dist/boot/execution-env.js +1 -1
- package/dist/boot/governance-seams.d.ts +26 -41
- package/dist/boot/governance-seams.js +61 -28
- package/dist/boot/late-binds.d.ts +7 -4
- package/dist/boot/late-binds.js +3 -1
- package/dist/boot/leader.js +2 -4
- package/dist/boot/memory-consolidation.d.ts +0 -8
- package/dist/boot/memory-consolidation.js +3 -3
- package/dist/boot/reapers.js +5 -4
- package/dist/boot/resolve-spec.d.ts +1 -1
- package/dist/boot/resolve-spec.js +8 -8
- package/dist/boot/runner-deps.d.ts +14 -6
- package/dist/boot/runner-deps.js +6 -17
- package/dist/boot/shutdown.d.ts +9 -0
- package/dist/boot/shutdown.js +18 -2
- package/dist/boot/stage-01-config.js +2 -0
- package/dist/boot/stage-02-web-admin-pull.js +3 -0
- package/dist/boot/stage-03-store-backend.d.ts +4 -1
- package/dist/boot/stage-03-store-backend.js +1 -2
- package/dist/boot/stage-04-stores.d.ts +5 -2
- package/dist/boot/stage-04-stores.js +3 -5
- package/dist/boot/stage-05-execution-env.d.ts +5 -2
- package/dist/boot/stage-06-runners.d.ts +5 -2
- package/dist/boot/stage-06-runners.js +1 -3
- package/dist/boot/stage-07-capability-layer.d.ts +5 -2
- package/dist/boot/stage-07-capability-layer.js +6 -2
- package/dist/boot/stage-08-reapers.d.ts +5 -2
- package/dist/boot/stage-09-leader.d.ts +5 -2
- package/dist/boot/stage-10-http-server.d.ts +5 -2
- package/dist/boot/stage-10-http-server.js +4 -1
- package/dist/boot/stores.d.ts +5 -2
- package/dist/boot/stores.js +7 -7
- package/dist/boot/web-admin.d.ts +5 -1
- package/dist/boot/web-admin.js +31 -19
- package/dist/capabilities/hands-lane.d.ts +9 -39
- package/dist/capabilities/hands-lane.js +8 -13
- package/dist/capabilities/mcp-probe.d.ts +3 -2
- package/dist/capabilities/scenarios.d.ts +23 -17
- package/dist/capabilities/scenarios.js +2 -2
- package/dist/capabilities/skills.d.ts +1 -17
- package/dist/capabilities/skills.js +0 -8
- package/dist/capability-facts.d.ts +8 -8
- package/dist/capability-facts.js +4 -4
- package/dist/card-void.d.ts +6 -9
- package/dist/config-catalog.js +1 -1
- package/dist/config-d-migration.d.ts +2 -0
- package/dist/config-dir-trust.js +58 -29
- package/dist/config-invariants.d.ts +7 -1
- package/dist/config-invariants.js +7 -0
- package/dist/config-provider.d.ts +10 -0
- package/dist/config-provider.js +15 -4
- package/dist/config-root-migration.d.ts +13 -0
- package/dist/config-root-migration.js +99 -0
- package/dist/config-types.d.ts +5 -5
- package/dist/config.d.ts +4 -3
- package/dist/config.js +1 -1
- package/dist/delegated-session-owner.d.ts +35 -151
- package/dist/delegated-session-owner.js +1 -83
- package/dist/device-ws-protocol.d.ts +1 -0
- package/dist/device-ws-protocol.js +2 -1
- package/dist/entry-mode-clamp-notice.d.ts +1 -1
- package/dist/env-model-table-gate.d.ts +53 -0
- package/dist/env-model-table-gate.js +53 -0
- package/dist/execution-placement.d.ts +7 -4
- package/dist/fleet/fleet-bus.d.ts +28 -52
- package/dist/fleet/fleet-bus.js +35 -100
- package/dist/fleet/fleet-reconciler.d.ts +4 -4
- package/dist/fleet/fleet-reconciler.js +1 -1
- package/dist/fleet/subagent-tail-bus.d.ts +14 -11
- package/dist/fleet/subagent-tail-bus.js +15 -28
- package/dist/hooks/classic-stations.d.ts +3 -1
- package/dist/hooks/classic-stations.js +2 -0
- package/dist/hooks/hook-runner.js +28 -7
- package/dist/host-decision.d.ts +54 -20
- package/dist/host-decision.js +42 -14
- package/dist/http/admission.d.ts +1 -1
- package/dist/http/admission.js +7 -3
- package/dist/http/approval-sweeps.js +11 -8
- package/dist/http/caller-trust.d.ts +1 -1
- package/dist/http/durable-run-leg.js +2 -2
- package/dist/http/engine-refusal.d.ts +16 -0
- package/dist/http/engine-refusal.js +17 -0
- package/dist/http/memory-compliance-failure-reply.d.ts +1 -3
- package/dist/http/memory-compliance-failure-reply.js +4 -6
- package/dist/http/owner-access.d.ts +11 -0
- package/dist/http/owner-access.js +13 -0
- package/dist/http/principal-gate.d.ts +1 -1
- package/dist/http/refusal-body.d.ts +7 -3
- package/dist/http/refusal-body.js +1 -0
- package/dist/http/resume-legs.d.ts +21 -7
- package/dist/http/resume-legs.js +82 -53
- package/dist/http/resume-restatement.d.ts +39 -0
- package/dist/http/resume-restatement.js +25 -0
- package/dist/http/route-ctx.d.ts +35 -10
- package/dist/http/route-ctx.js +1 -1
- package/dist/http/routes/approvals-assistant.d.ts +9 -1
- package/dist/http/routes/approvals-assistant.js +143 -31
- package/dist/http/routes/capabilities.js +11 -2
- package/dist/http/routes/memory-policy.d.ts +2 -2
- package/dist/http/routes/memory-policy.js +1 -1
- package/dist/http/routes/notify-wake.js +23 -25
- package/dist/http/routes/rules.js +48 -13
- package/dist/http/routes/runs.js +9 -8
- package/dist/http/routes/session-memory-sync.d.ts +34 -6
- package/dist/http/routes/session-memory-sync.js +27 -10
- package/dist/http/routes/session-sync.js +13 -20
- package/dist/http/routes/sessions.d.ts +2 -2
- package/dist/http/routes/sessions.js +22 -23
- package/dist/http/routes/tasks.js +27 -49
- package/dist/http/server.d.ts +13 -7
- package/dist/http/server.js +2 -2
- package/dist/http/stored-body-replay.js +15 -4
- package/dist/http/wire-types.d.ts +17 -7
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lane-home-probe.d.ts +15 -0
- package/dist/lane-home-probe.js +4 -0
- package/dist/leader/leader.js +5 -2
- package/dist/leader/wire.d.ts +7 -1
- package/dist/leader/wire.js +6 -5
- package/dist/leg-facts.d.ts +37 -0
- package/dist/leg-facts.js +15 -0
- package/dist/memory-bundle-engine.d.ts +1 -4
- package/dist/memory-bundle-engine.js +2 -2
- package/dist/memory-operator-faces.d.ts +30 -66
- package/dist/memory-operator-faces.js +17 -88
- package/dist/memory-scope-stores.d.ts +38 -40
- package/dist/memory-scope-stores.js +51 -36
- package/dist/memory-scope.d.ts +0 -9
- package/dist/memory-scope.js +0 -9
- package/dist/memory-sync-client.js +14 -3
- package/dist/memory-sync.d.ts +20 -4
- package/dist/memory-sync.js +23 -4
- package/dist/model-plane-face.d.ts +13 -7
- package/dist/model-plane-face.js +2 -1
- package/dist/observability/corrupt-read-seat.d.ts +5 -9
- package/dist/observability/corrupt-read-seat.js +1 -2
- package/dist/observability/fail-open.d.ts +30 -10
- package/dist/observability/fail-open.js +27 -10
- package/dist/observability/run-terminal.d.ts +1 -1
- package/dist/observability/run-terminal.js +6 -2
- package/dist/orchestration/workflow-completion-inbox.d.ts +5 -19
- package/dist/orchestration/workflow-completion-inbox.js +0 -12
- package/dist/orchestration/workflow-notify-journal.d.ts +3 -2
- package/dist/orchestration/workflow-park-decision.d.ts +8 -3
- package/dist/orchestration/workflow-park-decision.js +5 -3
- package/dist/org-delivery-gate.d.ts +11 -0
- package/dist/org-delivery-gate.js +19 -1
- package/dist/parked-decide.d.ts +13 -9
- package/dist/parked-decide.js +7 -7
- package/dist/parked-revive-surface.d.ts +6 -7
- package/dist/parked-revive-surface.js +1 -1
- package/dist/peer-inbound-face.d.ts +122 -0
- package/dist/peer-inbound-face.js +123 -0
- package/dist/permission-rule-list.d.ts +13 -9
- package/dist/permission-rule-list.js +7 -3
- package/dist/plugins/approval-ask-store-file.js +18 -6
- package/dist/plugins/approval-ask-store-memory.js +8 -6
- package/dist/plugins/approval-ask-store-sql.d.ts +28 -13
- package/dist/plugins/approval-ask-store-sql.js +30 -11
- package/dist/plugins/caching-session-store.d.ts +0 -3
- package/dist/plugins/caching-session-store.js +0 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +45 -38
- package/dist/plugins/checkpoint-store-sql.js +108 -45
- package/dist/plugins/file-history-store-sql.d.ts +24 -18
- package/dist/plugins/file-history-store-sql.js +24 -19
- package/dist/plugins/file-run-store.d.ts +29 -0
- package/dist/plugins/file-run-store.js +97 -8
- package/dist/plugins/fork-routing-session-store.d.ts +8 -1
- package/dist/plugins/fork-routing-session-store.js +6 -0
- package/dist/plugins/imported-layer-root-retirement.d.ts +82 -0
- package/dist/plugins/imported-layer-root-retirement.js +96 -0
- package/dist/plugins/local-checkpoint-store.d.ts +6 -8
- package/dist/plugins/local-checkpoint-store.js +5 -4
- package/dist/plugins/local-session-store.d.ts +69 -30
- package/dist/plugins/local-session-store.js +133 -57
- package/dist/plugins/local-session-window.d.ts +4 -2
- package/dist/plugins/mailbox-recipient-lifecycle.d.ts +9 -31
- package/dist/plugins/mailbox-recipient-lifecycle.js +4 -0
- package/dist/plugins/mailbox-store-sql.d.ts +12 -8
- package/dist/plugins/mailbox-store-sql.js +76 -7
- package/dist/plugins/memory-sync-store-pg.d.ts +15 -0
- package/dist/plugins/memory-sync-store-pg.js +21 -0
- package/dist/plugins/memory-sync-store-tidb.d.ts +2 -0
- package/dist/plugins/memory-sync-store-tidb.js +13 -1
- package/dist/plugins/one-time-migrations.d.ts +44 -14
- package/dist/plugins/one-time-migrations.js +118 -15
- package/dist/plugins/org-delivery-quota-store.d.ts +1 -1
- package/dist/plugins/org-delivery-quota-store.js +2 -12
- package/dist/plugins/park-commit-watch.d.ts +1 -1
- package/dist/plugins/permission-rule-store-file.d.ts +10 -1
- package/dist/plugins/permission-rule-store-file.js +15 -2
- package/dist/plugins/permission-rule-store-sql.d.ts +31 -1
- package/dist/plugins/permission-rule-store-sql.js +35 -2
- package/dist/plugins/pg-session-storage.d.ts +1 -9
- package/dist/plugins/pg-session-storage.js +2 -19
- package/dist/plugins/remote-env-device.d.ts +8 -11
- package/dist/plugins/remote-env-device.js +6 -3
- package/dist/plugins/remote-env-host.d.ts +8 -4
- package/dist/plugins/remote-env-host.js +7 -9
- package/dist/plugins/remote-env-k8s.d.ts +37 -24
- package/dist/plugins/remote-env-k8s.js +50 -17
- package/dist/plugins/remote-shell.js +12 -2
- package/dist/plugins/retention-store-sql.d.ts +2 -2
- package/dist/plugins/sandbox-read-floor.d.ts +5 -7
- package/dist/plugins/sandbox-read-floor.js +2 -7
- package/dist/plugins/schema-consistency.d.ts +5 -1
- package/dist/plugins/session-fork.d.ts +1 -1
- package/dist/plugins/session-ownership.d.ts +9 -0
- package/dist/plugins/session-ownership.js +6 -0
- package/dist/plugins/session-store.d.ts +13 -16
- package/dist/plugins/session-store.js +9 -10
- package/dist/plugins/sql-errors.d.ts +10 -1
- package/dist/plugins/sql-errors.js +13 -0
- package/dist/plugins/sql-json-column.d.ts +24 -2
- package/dist/plugins/sql-json-column.js +38 -3
- package/dist/plugins/store-backend.d.ts +23 -28
- package/dist/plugins/store-backend.js +12 -3
- package/dist/plugins/store-contracts.d.ts +29 -5
- package/dist/plugins/store-contracts.js +4 -1
- package/dist/plugins/task-attachment-store.d.ts +2 -2
- package/dist/plugins/task-attachment-store.js +37 -52
- package/dist/plugins/tidb-session-store.d.ts +2 -14
- package/dist/plugins/tidb-session-store.js +2 -20
- package/dist/plugins/tool-result-store-sql.d.ts +9 -8
- package/dist/plugins/tool-result-store-sql.js +23 -2
- package/dist/plugins/wiring-section-codec.d.ts +32 -0
- package/dist/plugins/wiring-section-codec.js +55 -0
- package/dist/plugins/workspace-fill.d.ts +1 -1
- package/dist/rule-entry-list.d.ts +3 -2
- package/dist/rule-entry-list.js +5 -1
- package/dist/rules-consent.d.ts +28 -5
- package/dist/rules-consent.js +40 -28
- package/dist/run-local.js +11 -6
- package/dist/runs.d.ts +12 -8
- package/dist/runs.js +10 -7
- package/dist/runtime-governance.d.ts +1 -1
- package/dist/security.d.ts +0 -4
- package/dist/server-secret-env.d.ts +4 -0
- package/dist/session-error-wire.d.ts +34 -23
- package/dist/session-error-wire.js +8 -3
- package/dist/session-incarnation.d.ts +3 -3
- package/dist/session-notify-door.d.ts +106 -0
- package/dist/session-notify-door.js +97 -0
- package/dist/session-sync.d.ts +9 -14
- package/dist/session-sync.js +5 -5
- package/dist/session-workspace.d.ts +3 -13
- package/dist/session-workspace.js +0 -9
- package/dist/standing-answer-grant.d.ts +5 -0
- package/dist/standing-answer-grant.js +10 -0
- package/dist/stores-sql/session-policy-store-sql.d.ts +4 -2
- package/dist/stores-sql/session-policy-store-sql.js +3 -13
- package/dist/task-mcp.d.ts +1 -1
- package/dist/task-settings.d.ts +11 -8
- package/dist/task-settings.js +31 -11
- package/dist/tool-approval.d.ts +55 -35
- package/dist/tool-approval.js +112 -74
- package/dist/trace/core-keyset-guard.d.ts +12 -9
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +4 -2
- package/dist/trace/exit-seat.d.ts +7 -1
- package/dist/trace/exit-seat.js +1 -0
- package/dist/trace/ledger-sink.d.ts +2 -2
- package/dist/trace/ledger-sink.js +12 -4
- package/dist/trace/model-segment.d.ts +74 -25
- package/dist/trace/model-segment.js +141 -32
- package/dist/trace/project.d.ts +15 -6
- package/dist/trace/project.js +12 -4
- package/dist/trace/redact.d.ts +72 -9
- package/dist/trace/redact.js +1509 -471
- package/dist/trace/self-minted-wire.d.ts +598 -47
- package/dist/trace/self-minted-wire.js +190 -20
- package/dist/trace/wire-projection-faces.d.ts +1 -1
- package/dist/trace/wire-projection-faces.js +1 -1
- package/dist/verifier-pause-card.d.ts +33 -5
- package/dist/verifier-pause-card.js +15 -10
- package/dist/web-admin-client/apply-effective.d.ts +12 -16
- package/dist/web-admin-client/apply-effective.js +90 -10
- package/dist/workspace-space.d.ts +19 -3
- package/dist/workspace-space.js +8 -4
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -1
- package/package.json +3 -2
- package/wire-changes/server@7.143.0.json +1167 -0
- package/wire-changes/server@7.144.0.json +291 -0
- package/dist/session-records-skipped-notice.d.ts +0 -21
- package/dist/session-records-skipped-notice.js +0 -27
package/dist/http/resume-legs.js
CHANGED
|
@@ -4,7 +4,7 @@ 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,
|
|
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, decodeCheckpointScope, CHECKPOINT_PUBLIC_SCOPE } from "../security.js";
|
|
10
10
|
import { graftParkToolCallId, parkToolCallId, TurnAnchorCapture, HEARTBEAT_MS, markChildrenStoppedByUserOnAbort, voidHeldParkCard } from "../runs.js";
|
|
@@ -15,7 +15,7 @@ import { isTerminalRunStatus } from "../plugins/store-contracts.js";
|
|
|
15
15
|
import { readTurnActivityMs, recordTurnActivity } from "../turn-activity.js";
|
|
16
16
|
import { recordResumeResourceWindow } from "../resource-window.js";
|
|
17
17
|
import { emitPendingWorkflowCompletions, taskNotificationInboxEntry, taskNotificationStreamKeyOf, NotifiedKeys } from "../orchestration/workflow-completion-inbox.js";
|
|
18
|
-
import { fleetRunPublisher, fleetRunLabels, fleetRunResiduals
|
|
18
|
+
import { fleetRunPublisher, fleetRunLabels, fleetRunResiduals } from "../fleet/fleet-bus.js";
|
|
19
19
|
import { defaultSubagentTailBus } from "../fleet/subagent-tail-bus.js";
|
|
20
20
|
import { currentApprovalGateToken, currentGateFacesOf, sightsCurrentGate } from "../approval-gate-currency.js";
|
|
21
21
|
import { approverFacingArgs, createApprovalCardEmitter, declaredApprovalFrameFamilies, parkRowStandingAnswerFacts, resolveApprovalLeg, resolveStreamApprovalGate, standingAnswerDurablyRecordable } from "../tool-approval.js";
|
|
@@ -25,14 +25,14 @@ import { serviceVersion } from "../service-version.js";
|
|
|
25
25
|
import { TERMINAL_PARK_GATE_KINDS } from "../plugins/checkpoint-store-sql.js";
|
|
26
26
|
import { withPrincipal } from "../observability/principal-context.js";
|
|
27
27
|
import { withModelReachScope } from "../model-reach-scope.js";
|
|
28
|
-
import {
|
|
28
|
+
import { legFactsOf } from "../leg-facts.js";
|
|
29
29
|
import { createInstructionSelectionLeg } from "../instruction-selection.js";
|
|
30
30
|
import { modelTextEventData, appendParkRow, 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
31
|
import { redactSecrets } from "../trace/redact.js";
|
|
32
32
|
import { buildRunObjectivePreview } from "../user-authored-text.js";
|
|
33
33
|
import { createForwardAppendFailedNote, createLedgerSink, createSerialLedgerAppend } from "../trace/ledger-sink.js";
|
|
34
34
|
import { registerEngineNoticeLeg } from "../trace/engine-notice-wire.js";
|
|
35
|
-
import { reasoningDeltaBytes, reasoningSegmentEventId } from "../trace/model-segment.js";
|
|
35
|
+
import { blockText, reasoningDeltaBytes, reasoningSegmentEventId } from "../trace/model-segment.js";
|
|
36
36
|
import { errorText } from "../observability/err-text.js";
|
|
37
37
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
38
38
|
import { verifyRoundsFromBody } from "./verify-rounds.js";
|
|
@@ -57,9 +57,11 @@ import { readResumeCtx, resumeCtxCorruptAnswer, resumeCtxUnsealableAnswer } from
|
|
|
57
57
|
import { buildCheckpointVersionKeys, resumeBlockedByPolicyAnswer, resumeRefusalWithCard, sealCheckpointCtx, storedBodyReplayAnswer, storedBodyReplayLogFields, withPermissionModeRewritten } from "./checkpoint-ctx.js";
|
|
58
58
|
import { refusalBody, resumeRefusalFacts } from "./refusal-body.js";
|
|
59
59
|
import { storedBodyReplayRefusal } from "./stored-body-replay.js";
|
|
60
|
+
import { restateResumeCtx } from "./resume-restatement.js";
|
|
60
61
|
import { httpErrorRefusal } from "./send.js";
|
|
61
62
|
import { createRunAcceptance } from "../run-acceptance.js";
|
|
62
63
|
import { fieldConflictFacts } from "../field-conflict.js";
|
|
64
|
+
import { createSessionNotifyDoor } from "../session-notify-door.js";
|
|
63
65
|
function legMayHaveReopenedCheckpoint(r) {
|
|
64
66
|
return r.terminal.kind === "failed" && nestedPauseOf(r.terminal) === undefined;
|
|
65
67
|
}
|
|
@@ -107,6 +109,8 @@ const CHECKPOINT_ERROR_DISPOSITION = {
|
|
|
107
109
|
"checkpoint.reopened_concurrently": "retriable",
|
|
108
110
|
"resume.parent_constraint_missing": "retriable",
|
|
109
111
|
"resume.parent_constraint_mismatch": "retriable",
|
|
112
|
+
"resume.composition_mismatch": "retriable",
|
|
113
|
+
"checkpoint.void_unpin_failed": "terminal",
|
|
110
114
|
"resume.constraint_rejected": "retriable",
|
|
111
115
|
"resume.constraint_unprojectable": "retriable",
|
|
112
116
|
"resume.usage_window_exhausted": "retriable",
|
|
@@ -230,14 +234,19 @@ export function checkpointRefusalAnswer(e, at) {
|
|
|
230
234
|
}),
|
|
231
235
|
}, at.retriable);
|
|
232
236
|
}
|
|
237
|
+
export function decidedActionOf(binding) {
|
|
238
|
+
const { boundCallId, boundInputHash } = binding;
|
|
239
|
+
const missingKeys = [...(typeof boundCallId === "string" && boundCallId.length > 0 ? [] : ["boundCallId"]), ...(typeof boundInputHash === "string" && boundInputHash.length > 0 ? [] : ["boundInputHash"])];
|
|
240
|
+
return missingKeys.length === 0 ? { action: { boundCallId: boundCallId, boundInputHash: boundInputHash } } : { missingKeys };
|
|
241
|
+
}
|
|
233
242
|
export function createResumeLegs(ctx) {
|
|
234
243
|
const { deps, runnerFor, idemCache, inflightRuns, preemptableRuns, steerableRuns, wakeParkMints, counters, readJson, readRawBody, rateLimited, quotaExceeded, ownerQuotaDenied, leaseDenied, ownerLeaseDenied, usageWindowDenied, safeDecode, runOwnerOk, sessionOwnerOk, runSessionAcceptOk, prepareSpec, finalizeTaskResult, ownerCostQuotaDenied, ownerFleetLeaseDenied, usageWindowDenialFor } = ctx;
|
|
235
244
|
const ctxOpening = (sessionId) => ({ sessionId, opener: deps.checkpointCtxSealing });
|
|
236
245
|
const resumeFleetScope = (req, auth) => req ? (gatedPrincipal(req, deps.config) ?? "default") : (auth.principal ?? "default");
|
|
237
|
-
async function resumeCheckpoint(sessionId, decision, reason, hostDecision, req, answer, binding, onResumeCommitted, acceptEarly, decider) {
|
|
246
|
+
async function resumeCheckpoint(sessionId, decision, reason, hostDecision, req, answer, binding, onResumeCommitted, acceptEarly, decider, restatement) {
|
|
238
247
|
const cs = deps.checkpointStore;
|
|
239
248
|
const token = await currentApprovalGateToken(cs, sessionId);
|
|
240
|
-
if (binding
|
|
249
|
+
if (binding.checkpointToken && !sightsCurrentGate({ face: "checkpointToken", value: binding.checkpointToken }, token ? { checkpointToken: token } : null)) {
|
|
241
250
|
let seenUnreadable = false;
|
|
242
251
|
const seen = await cs.get(binding.checkpointToken).catch((e) => {
|
|
243
252
|
seenUnreadable = true;
|
|
@@ -326,20 +335,23 @@ export function createResumeLegs(ctx) {
|
|
|
326
335
|
}),
|
|
327
336
|
};
|
|
328
337
|
}
|
|
329
|
-
|
|
338
|
+
const decided = decidedActionOf(binding);
|
|
339
|
+
if (decided.action === undefined) {
|
|
330
340
|
return {
|
|
331
341
|
status: 400,
|
|
332
342
|
body: refusalBody({
|
|
333
343
|
errorCode: "decide_requires_binding",
|
|
334
|
-
message: "decide requires the decision-action binding — echo
|
|
344
|
+
message: "decide requires the decision-action binding — echo boundCallId and boundInputHash exactly as the pending approval you are deciding shows them (GET /v1/approvals), so a decision on a view that has since been replaced is refused instead of landing on the gate that replaced it",
|
|
335
345
|
facts: {
|
|
336
346
|
bindingEnforced: true,
|
|
347
|
+
missingKeys: decided.missingKeys,
|
|
337
348
|
},
|
|
338
349
|
}),
|
|
339
350
|
};
|
|
340
351
|
}
|
|
352
|
+
const action = decided.action;
|
|
341
353
|
const s57RowCallId = cp.pendingAction.kind === "tool_approval" ? cp.pendingAction.toolCallId : undefined;
|
|
342
|
-
if (
|
|
354
|
+
if (s57RowCallId && action.boundCallId !== s57RowCallId) {
|
|
343
355
|
let s57CurrentPending;
|
|
344
356
|
if (decider !== undefined && cp.status === "pending" && cp.sessionId === sessionId && cp.pendingAction.kind === "tool_approval") {
|
|
345
357
|
s57CurrentPending = {
|
|
@@ -400,8 +412,9 @@ export function createResumeLegs(ctx) {
|
|
|
400
412
|
const parkedReq = {
|
|
401
413
|
token, scope: cp.scope, sessionId: cp.sessionId, pendingAction: cp.pendingAction,
|
|
402
414
|
decision, hostDecision, ...(reason !== undefined ? { reason } : {}),
|
|
403
|
-
|
|
415
|
+
binding: { ...(({ checkpointToken: _staleGuardOnly, ...rest }) => rest)(binding), ...action },
|
|
404
416
|
...(answer !== undefined ? { answer } : {}),
|
|
417
|
+
...(restatement !== undefined ? { restatement } : {}),
|
|
405
418
|
...(boundGrant ? { grantRemember: (rootSessionId) => boundGrant(rootSessionId) } : {}),
|
|
406
419
|
};
|
|
407
420
|
if (origin?.kind === "background" && parkedAgentStore !== undefined && parkedSurface !== undefined) {
|
|
@@ -458,7 +471,7 @@ export function createResumeLegs(ctx) {
|
|
|
458
471
|
if (decisions === undefined || runStore === undefined) {
|
|
459
472
|
return { status: 501, body: refusalBody({ errorCode: "capability.run_store_required", message: "delivering this decision requires a durable run store (DB_BACKEND=mysql|pg|local)" }) };
|
|
460
473
|
}
|
|
461
|
-
const fingerprint = parkDecisionFingerprint(plan.outcome);
|
|
474
|
+
const fingerprint = parkDecisionFingerprint(plan.outcome, restatement);
|
|
462
475
|
const liveReceiptOf = async (held) => {
|
|
463
476
|
if (held === null || held.fingerprint !== fingerprint)
|
|
464
477
|
return undefined;
|
|
@@ -488,8 +501,8 @@ export function createResumeLegs(ctx) {
|
|
|
488
501
|
.catch(() => undefined);
|
|
489
502
|
const admittedPayer = decodeCheckpointScope(cp.scope);
|
|
490
503
|
const out = hostToken
|
|
491
|
-
? await resumeWake(plan.hostSessionId, plan.message, decider?.principal, req, acceptEarly, delivery, admittedPayer)
|
|
492
|
-
: await startFreshHostTurn(plan.hostSessionId, plan.message, admittedPayer, req, delivery, plan.runId);
|
|
504
|
+
? await resumeWake(plan.hostSessionId, plan.message, decider?.principal, req, acceptEarly, delivery, admittedPayer, restatement)
|
|
505
|
+
: await startFreshHostTurn(plan.hostSessionId, plan.message, admittedPayer, req, delivery, plan.runId, restatement);
|
|
493
506
|
if (recordFailure !== undefined)
|
|
494
507
|
throw recordFailure.err;
|
|
495
508
|
if (acceptedTaskIdOf(out) === undefined)
|
|
@@ -502,9 +515,10 @@ export function createResumeLegs(ctx) {
|
|
|
502
515
|
return resumeCtxCorruptAnswer(ctxRead0.where);
|
|
503
516
|
if (ctxRead0.kind === "unsealable")
|
|
504
517
|
return resumeCtxUnsealableAnswer(ctxRead0);
|
|
505
|
-
const
|
|
506
|
-
if (!
|
|
518
|
+
const storedCtx = ctxRead0.kind === "ok" ? ctxRead0.ctx : null;
|
|
519
|
+
if (!storedCtx)
|
|
507
520
|
return { status: 409, body: refusalBody({ errorCode: "conflict.resume_context_unavailable", message: "resume context missing — cannot rebuild task config" }) };
|
|
521
|
+
const ctx = restateResumeCtx(storedCtx, restatement);
|
|
508
522
|
const auth = { sessionId: cp.sessionId, principal: decodeCheckpointScope(cp.scope), memoryScope: ctx.memoryScope };
|
|
509
523
|
const resolved = await resolveResumeSpecOrBlocked(ctx, req, auth);
|
|
510
524
|
if (!resolved.ok)
|
|
@@ -520,21 +534,19 @@ export function createResumeLegs(ctx) {
|
|
|
520
534
|
}
|
|
521
535
|
const { objective: resumeObjective, sessionId: _sessionId, ...taskConfig } = spec;
|
|
522
536
|
const pa = cp.pendingAction;
|
|
523
|
-
const persistedCallId = pa.kind === "tool_approval" ? pa.toolCallId : "";
|
|
524
|
-
const persistedHash = pa.kind === "tool_approval" ? (pa.boundInputHash ?? "") : "";
|
|
525
537
|
const outcome = {
|
|
526
538
|
gate: "policy_ask",
|
|
527
|
-
boundCallId:
|
|
528
|
-
boundInputHash:
|
|
539
|
+
boundCallId: action.boundCallId,
|
|
540
|
+
boundInputHash: action.boundInputHash,
|
|
529
541
|
decision: decision === "approve" ? "allow" : "deny",
|
|
530
|
-
...(decision === "approve" && !isEngineQuestionRow(pa) && binding
|
|
542
|
+
...(decision === "approve" && !isEngineQuestionRow(pa) && binding.updatedInput !== undefined ? { updatedInput: binding.updatedInput } : {}),
|
|
531
543
|
...(reason ? { reason } : {}),
|
|
532
|
-
...(binding
|
|
544
|
+
...(binding.feedback !== undefined ? { feedback: binding.feedback } : {}),
|
|
533
545
|
...(answer !== undefined ? { answer } : {}),
|
|
534
546
|
hostDecision,
|
|
535
547
|
};
|
|
536
548
|
const verifyRounds = verifyRoundsFromBody(ctx.body);
|
|
537
|
-
const driven = await driveResumeIntoRunLog({ peerLease: resolved.peerLease, execution: resolved.execution, runner:
|
|
549
|
+
const driven = await driveResumeIntoRunLog({ peerLease: resolved.peerLease, execution: resolved.execution, runner: resolved.runner, legFacts: resolved.legFacts, 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 } : {}) });
|
|
538
550
|
noteLateSettleIfAccepted(driven);
|
|
539
551
|
return driven;
|
|
540
552
|
}
|
|
@@ -547,14 +559,17 @@ export function createResumeLegs(ctx) {
|
|
|
547
559
|
const resolveResumeSpec = async (ctx, req, auth, lease) => {
|
|
548
560
|
const engineNotices = [];
|
|
549
561
|
const execution = await resolveExecutionContext(deps, { kind: "continuation", root: auth.sessionId, principal: auth.principal });
|
|
550
|
-
const
|
|
562
|
+
const resolved = await deps.resolveSpec({ ...ctx.body, ...ONE_SHOT_SUBMIT_STRIP }, req, auth, {
|
|
551
563
|
leg: "resume",
|
|
552
564
|
onNotice: (n) => engineNotices.push(n),
|
|
553
565
|
...(ctx.unattendedLeg === true ? { unattendedLeg: true } : {}),
|
|
554
566
|
lease,
|
|
555
567
|
execution,
|
|
556
|
-
})
|
|
557
|
-
|
|
568
|
+
});
|
|
569
|
+
const legFacts = legFactsOf(resolved);
|
|
570
|
+
const runner = runnerFor(resolved);
|
|
571
|
+
const spec = stampSpecRoot(resolved, execution);
|
|
572
|
+
return { spec, runner, legFacts, engineNotices, execution };
|
|
558
573
|
};
|
|
559
574
|
const refuseStoredBodyReplay = (sessionId, refusal) => {
|
|
560
575
|
deps.logger?.warn?.("resume_refused_stored_body", { sessionId, ...storedBodyReplayLogFields(refusal) });
|
|
@@ -566,8 +581,8 @@ export function createResumeLegs(ctx) {
|
|
|
566
581
|
return { ok: false, answer: refuseStoredBodyReplay(auth.sessionId, replay) };
|
|
567
582
|
const lease = deps.peerDesk.lease("resume");
|
|
568
583
|
try {
|
|
569
|
-
const { spec, engineNotices, execution } = await resolveResumeSpec(ctx, req, auth, lease);
|
|
570
|
-
return { ok: true, spec, engineNotices, execution, peerLease: lease };
|
|
584
|
+
const { spec, runner, legFacts, engineNotices, execution } = await resolveResumeSpec(ctx, req, auth, lease);
|
|
585
|
+
return { ok: true, spec, runner, legFacts, engineNotices, execution, peerLease: lease };
|
|
571
586
|
}
|
|
572
587
|
catch (e) {
|
|
573
588
|
lease.release();
|
|
@@ -603,7 +618,7 @@ export function createResumeLegs(ctx) {
|
|
|
603
618
|
const reparkStatus = outcome.gate === "plan_review" ? "needs_review" : "suspended";
|
|
604
619
|
const commitResumeCtx = () => Promise.resolve().then(() => deps.checkpointStore.putCtx(resumeCtx.sessionId, sealCheckpointCtx({ ...resumeCtx.ctx, writerVersion: serviceVersion() }, deps.checkpointCtxSealing, resumeCtx.sessionId))).catch((e) => {
|
|
605
620
|
deps.metrics?.inc("resume_ctx_not_persisted_total");
|
|
606
|
-
deps.logger?.warn?.("resume_ctx_not_persisted", { sessionId: resumeCtx.sessionId, gate: outcome.gate, error: errorText(e), 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
|
|
621
|
+
deps.logger?.warn?.("resume_ctx_not_persisted", { sessionId: resumeCtx.sessionId, gate: outcome.gate, error: errorText(e), 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" });
|
|
607
622
|
});
|
|
608
623
|
const legKey = createHash("sha256").update(String(token)).digest("hex");
|
|
609
624
|
const streamApprovalOn = resolveStreamApprovalGate({
|
|
@@ -777,7 +792,7 @@ export function createResumeLegs(ctx) {
|
|
|
777
792
|
let unregisterEngineNotice;
|
|
778
793
|
try {
|
|
779
794
|
const instructionLeg = createInstructionSelectionLeg();
|
|
780
|
-
const legWiringSections = () => ({ instructions: instructionLeg.segment(), skills:
|
|
795
|
+
const legWiringSections = () => ({ instructions: instructionLeg.segment(), skills: args.legFacts?.skills });
|
|
781
796
|
result = await instructionLeg.run(sessionId, () => withModelReachScope({ sessionId, taskId }, () => withPrincipal(principal, async () => {
|
|
782
797
|
const resumeNotifiedKeys = new NotifiedKeys();
|
|
783
798
|
if (deps.runStore && taskId) {
|
|
@@ -832,9 +847,8 @@ export function createResumeLegs(ctx) {
|
|
|
832
847
|
if (defaultSubagentTailBus.hasSubscribers(n.task_id)) {
|
|
833
848
|
defaultSubagentTailBus.publish(n.task_id, { type: "task_settled", taskId: n.task_id, status: n.status, ...(typeof n.seq === "number" ? { seq: n.seq } : {}), ...(n.summary ? { summary: redactSecrets(n.summary) } : {}) });
|
|
834
849
|
}
|
|
835
|
-
const hadRow = isFleetAgentTerminalNotification(n) ? (fleetPub?.onChildTerminal(n.sessionId ?? n.task_id, n.status, n.task_id, n.toolUseId) ?? false) : false;
|
|
836
850
|
const parked = !resumeLegLive && Boolean(deps.workflowCompletionInbox && sessionId);
|
|
837
|
-
deps.logger?.info?.("task_notification_observed", { route: "resume-verify", taskId: n.task_id, taskType: n.task_type, status: n.status,
|
|
851
|
+
deps.logger?.info?.("task_notification_observed", { route: "resume-verify", taskId: n.task_id, taskType: n.task_type, status: n.status, legLive: resumeLegLive, parkedDurable: parked });
|
|
838
852
|
if (parked) {
|
|
839
853
|
void deps.workflowCompletionInbox.enqueue(taskNotificationInboxEntry(sessionId, principal ?? null, n, Date.now(), taskId, opts?.priority)).catch((err) => deps.logger?.warn?.("park_enqueue_failed", { route: "resume-verify", taskId: n.task_id, err: err instanceof Error ? err.message : String(err) }));
|
|
840
854
|
}
|
|
@@ -856,7 +870,7 @@ export function createResumeLegs(ctx) {
|
|
|
856
870
|
resumeLegLive = true;
|
|
857
871
|
const vrEngine = await resumeWithVerification(legRunner, token, outcome, { ...resumeTaskConfig, signal: cancelCtrl.signal, preemptSignal: preemptCtrl.signal }, resumeObjective, verifyRounds, verifyInternals);
|
|
858
872
|
const vrCause = cancelCtrl.cause();
|
|
859
|
-
await voidVerifierPauseCard(vrEngine,
|
|
873
|
+
await voidVerifierPauseCard(vrEngine, legRunner);
|
|
860
874
|
const vrJudged = atHostBoundary(vrEngine, sessionId);
|
|
861
875
|
if (vrJudged.terminal.kind === "paused")
|
|
862
876
|
heldPark = vrJudged;
|
|
@@ -898,6 +912,7 @@ export function createResumeLegs(ctx) {
|
|
|
898
912
|
const rs = deps.runStore;
|
|
899
913
|
const startSeq = rs && taskId ? await rs.maxSeq(taskId) : 0;
|
|
900
914
|
let text = "";
|
|
915
|
+
let block = "";
|
|
901
916
|
let reasoning = "";
|
|
902
917
|
let reasoningEventId;
|
|
903
918
|
const persistThinking = deps.config.traceThinking;
|
|
@@ -931,15 +946,17 @@ export function createResumeLegs(ctx) {
|
|
|
931
946
|
reasoning = "";
|
|
932
947
|
reasoningEventId = undefined;
|
|
933
948
|
}
|
|
934
|
-
|
|
935
|
-
|
|
949
|
+
const segment = text + blockText(block);
|
|
950
|
+
if (segment) {
|
|
951
|
+
await append("text", modelTextEventData({ text: segment, eventId: anchor.firstTextEventId }));
|
|
936
952
|
text = "";
|
|
953
|
+
block = "";
|
|
937
954
|
}
|
|
938
955
|
};
|
|
939
956
|
const driveResume = async () => {
|
|
940
957
|
resumeLegLive = true;
|
|
941
958
|
const tailContentMode = resumeTaskConfig.forwardSubagentEvents === true ? "on" : "progress_only";
|
|
942
|
-
const resumeWorkspace = createSessionWorkspaceRecorder(sessionWorkspaceStoreOf(deps.sessionStorage),
|
|
959
|
+
const resumeWorkspace = createSessionWorkspaceRecorder(sessionWorkspaceStoreOf(deps.sessionStorage), args.legFacts?.sessionWitness);
|
|
943
960
|
const stream = await legRunner.resumeStream(token, outcome, { ...resumeTaskConfig, signal: cancelCtrl.signal, preemptSignal: preemptCtrl.signal }, {
|
|
944
961
|
...launchInternals,
|
|
945
962
|
onForwardEvent: (e) => {
|
|
@@ -976,9 +993,8 @@ export function createResumeLegs(ctx) {
|
|
|
976
993
|
if (defaultSubagentTailBus.hasSubscribers(n.task_id)) {
|
|
977
994
|
defaultSubagentTailBus.publish(n.task_id, { type: "task_settled", taskId: n.task_id, status: n.status, ...(typeof n.seq === "number" ? { seq: n.seq } : {}), ...(n.summary ? { summary: redactSecrets(n.summary) } : {}) });
|
|
978
995
|
}
|
|
979
|
-
const hadRow = isFleetAgentTerminalNotification(n) ? (fleetPub?.onChildTerminal(n.sessionId ?? n.task_id, n.status, n.task_id, n.toolUseId) ?? false) : false;
|
|
980
996
|
const parked = !resumeLegLive && Boolean(deps.workflowCompletionInbox && sessionId);
|
|
981
|
-
deps.logger?.info?.("task_notification_observed", { route: "resume", taskId: n.task_id, taskType: n.task_type, status: n.status,
|
|
997
|
+
deps.logger?.info?.("task_notification_observed", { route: "resume", taskId: n.task_id, taskType: n.task_type, status: n.status, legLive: resumeLegLive, parkedDurable: parked });
|
|
982
998
|
if (parked) {
|
|
983
999
|
void deps.workflowCompletionInbox.enqueue(taskNotificationInboxEntry(sessionId, principal ?? null, n, Date.now(), taskId, opts?.priority)).catch((err) => deps.logger?.warn?.("park_enqueue_failed", { route: "resume", taskId: n.task_id, err: err instanceof Error ? err.message : String(err) }));
|
|
984
1000
|
}
|
|
@@ -1024,9 +1040,13 @@ export function createResumeLegs(ctx) {
|
|
|
1024
1040
|
await appendPromptManifest(append, deps.promptManifests, taskId);
|
|
1025
1041
|
switch (ev.type) {
|
|
1026
1042
|
case "text_delta":
|
|
1027
|
-
|
|
1043
|
+
block += ev.delta;
|
|
1028
1044
|
anchor.onText(ev.eventId);
|
|
1029
1045
|
break;
|
|
1046
|
+
case "text_end":
|
|
1047
|
+
text += blockText(block, ev);
|
|
1048
|
+
block = "";
|
|
1049
|
+
break;
|
|
1030
1050
|
case "reasoning_delta": {
|
|
1031
1051
|
const rb = reasoningDeltaBytes(ev);
|
|
1032
1052
|
if (persistThinking && rb !== undefined) {
|
|
@@ -1307,7 +1327,7 @@ export function createResumeLegs(ctx) {
|
|
|
1307
1327
|
const owner = decodeCheckpointScope(scope ?? CHECKPOINT_PUBLIC_SCOPE);
|
|
1308
1328
|
return owner === undefined || owner === decider.principal;
|
|
1309
1329
|
}
|
|
1310
|
-
async function resumePreempted(sessionId, req, acceptEarly, decider) {
|
|
1330
|
+
async function resumePreempted(sessionId, req, acceptEarly, decider, restatement) {
|
|
1311
1331
|
const cs = deps.checkpointStore;
|
|
1312
1332
|
const RESUMABLE_GATE_KIND = "resource_limit";
|
|
1313
1333
|
const preemptBinding = { gateKinds: [RESUMABLE_GATE_KIND] };
|
|
@@ -1357,7 +1377,7 @@ export function createResumeLegs(ctx) {
|
|
|
1357
1377
|
return resumeCtxUnsealableAnswer(ctxRead);
|
|
1358
1378
|
if (ctxRead.kind === "absent")
|
|
1359
1379
|
return { status: 409, body: refusalBody({ errorCode: "conflict.resume_context_unavailable", message: "resume context missing — cannot rebuild task config" }) };
|
|
1360
|
-
const ctx = ctxRead.ctx;
|
|
1380
|
+
const ctx = restateResumeCtx(ctxRead.ctx, restatement);
|
|
1361
1381
|
const auth = { sessionId: cp.sessionId, principal: decodeCheckpointScope(cp.scope), memoryScope: ctx.memoryScope };
|
|
1362
1382
|
const resolved = await resolveResumeSpecOrBlocked(ctx, req, auth);
|
|
1363
1383
|
if (!resolved.ok)
|
|
@@ -1367,13 +1387,13 @@ export function createResumeLegs(ctx) {
|
|
|
1367
1387
|
const { objective: resumeObjective, sessionId: _sessionId, ...taskConfig } = spec;
|
|
1368
1388
|
const verifyRounds = verifyRoundsFromBody(ctx.body);
|
|
1369
1389
|
const selectedGate = durableRowIdentity("decision-receipt", cp.checkpointId, token);
|
|
1370
|
-
return await driveResumeIntoRunLog({ peerLease: resolved.peerLease, execution: resolved.execution, runner:
|
|
1390
|
+
return await driveResumeIntoRunLog({ peerLease: resolved.peerLease, execution: resolved.execution, runner: resolved.runner, legFacts: resolved.legFacts, 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 } : {}) });
|
|
1371
1391
|
}
|
|
1372
1392
|
finally {
|
|
1373
1393
|
resolved.peerLease.release();
|
|
1374
1394
|
}
|
|
1375
1395
|
}
|
|
1376
|
-
async function startFreshHostTurn(sessionId, objective, principal, req, workflowDecision, runId) {
|
|
1396
|
+
async function startFreshHostTurn(sessionId, objective, principal, req, workflowDecision, runId, restatement) {
|
|
1377
1397
|
const cs = deps.checkpointStore;
|
|
1378
1398
|
if (!deps.runStore) {
|
|
1379
1399
|
return { status: 501, body: refusalBody({ errorCode: "capability.run_store_required", message: "delivering this decision requires a durable run store (DB_BACKEND=mysql|pg|local)" }) };
|
|
@@ -1383,8 +1403,8 @@ export function createResumeLegs(ctx) {
|
|
|
1383
1403
|
return resumeCtxCorruptAnswer(ctxRead.where);
|
|
1384
1404
|
if (ctxRead.kind === "unsealable")
|
|
1385
1405
|
return resumeCtxUnsealableAnswer(ctxRead);
|
|
1386
|
-
const
|
|
1387
|
-
if (!
|
|
1406
|
+
const storedCtx = ctxRead.kind === "ok" ? ctxRead.ctx : null;
|
|
1407
|
+
if (!storedCtx) {
|
|
1388
1408
|
return {
|
|
1389
1409
|
status: 409,
|
|
1390
1410
|
body: refusalBody({
|
|
@@ -1397,6 +1417,7 @@ export function createResumeLegs(ctx) {
|
|
|
1397
1417
|
}),
|
|
1398
1418
|
};
|
|
1399
1419
|
}
|
|
1420
|
+
const ctx = restateResumeCtx(storedCtx, restatement);
|
|
1400
1421
|
const windowDenial = await usageWindowDenialFor(principal || GLOBAL_USAGE_KEY);
|
|
1401
1422
|
if (windowDenial)
|
|
1402
1423
|
return { status: windowDenial.status, body: windowDenial.body };
|
|
@@ -1408,7 +1429,7 @@ export function createResumeLegs(ctx) {
|
|
|
1408
1429
|
const { spec, engineNotices } = resolved;
|
|
1409
1430
|
const hostSpec = { ...spec, objective };
|
|
1410
1431
|
const out = await mintAndDriveDurableRun(routeCtxBase, deps.runStore, {
|
|
1411
|
-
prepared: { spec: hostSpec, runner:
|
|
1432
|
+
prepared: { spec: hostSpec, runner: resolved.runner, legFacts: resolved.legFacts, auth, body: ctx.body, acceptance: createRunAcceptance({}, { objective }), peerLease: resolved.peerLease, execution: resolved.execution, ...(engineNotices.length > 0 ? { engineNotices } : {}) },
|
|
1412
1433
|
fleetScope: resumeFleetScope(req, auth),
|
|
1413
1434
|
elicitOwner: principal ?? null,
|
|
1414
1435
|
source: "workflow_parked_decide",
|
|
@@ -1427,7 +1448,7 @@ export function createResumeLegs(ctx) {
|
|
|
1427
1448
|
resolved.peerLease.release();
|
|
1428
1449
|
}
|
|
1429
1450
|
}
|
|
1430
|
-
async function resumeWake(sessionId, message, caller, req, acceptEarly, workflowDecision, ownerLeaseAdmittedFor) {
|
|
1451
|
+
async function resumeWake(sessionId, message, caller, req, acceptEarly, workflowDecision, ownerLeaseAdmittedFor, restatement) {
|
|
1431
1452
|
const cs = deps.checkpointStore;
|
|
1432
1453
|
const wakeBinding = { gateKinds: TERMINAL_PARK_GATE_KINDS, pick: "oldest" };
|
|
1433
1454
|
const token = (await cs.findPendingTokenBySession(sessionId, undefined, wakeBinding)) ?? (await cs.findPendingTokenBySession(sessionId));
|
|
@@ -1484,7 +1505,7 @@ export function createResumeLegs(ctx) {
|
|
|
1484
1505
|
return resumeCtxUnsealableAnswer(ctxRead);
|
|
1485
1506
|
if (ctxRead.kind === "absent")
|
|
1486
1507
|
return { status: 409, body: refusalBody({ errorCode: "conflict.resume_context_unavailable", message: "resume context missing — cannot rebuild task config" }) };
|
|
1487
|
-
const ctx = ctxRead.ctx;
|
|
1508
|
+
const ctx = restateResumeCtx(ctxRead.ctx, restatement);
|
|
1488
1509
|
const auth = { sessionId: cp.sessionId, principal: decodeCheckpointScope(cp.scope), memoryScope: ctx.memoryScope };
|
|
1489
1510
|
const resolved = await resolveResumeSpecOrBlocked(ctx, req, auth);
|
|
1490
1511
|
if (!resolved.ok)
|
|
@@ -1495,7 +1516,8 @@ export function createResumeLegs(ctx) {
|
|
|
1495
1516
|
return await driveResumeIntoRunLog({
|
|
1496
1517
|
peerLease: resolved.peerLease,
|
|
1497
1518
|
execution: resolved.execution,
|
|
1498
|
-
runner:
|
|
1519
|
+
runner: resolved.runner,
|
|
1520
|
+
legFacts: resolved.legFacts,
|
|
1499
1521
|
token,
|
|
1500
1522
|
sessionId: cp.sessionId,
|
|
1501
1523
|
principal: auth.principal,
|
|
@@ -1595,8 +1617,9 @@ export function createResumeLegs(ctx) {
|
|
|
1595
1617
|
return refuse(refuseStoredBodyReplay(sessionId, replay));
|
|
1596
1618
|
return { ok: true, prepared: { sessionId, token, cp, ctx: ctxRead.ctx } };
|
|
1597
1619
|
}
|
|
1598
|
-
async function drivePlanReview(prepared, decision, editedPlan, reason, hostDecision, req, acceptEarly, permissionModeAfter) {
|
|
1599
|
-
const { sessionId, token, cp
|
|
1620
|
+
async function drivePlanReview(prepared, decision, editedPlan, reason, hostDecision, req, acceptEarly, permissionModeAfter, restatement) {
|
|
1621
|
+
const { sessionId, token, cp } = prepared;
|
|
1622
|
+
const ctx = restateResumeCtx(prepared.ctx, restatement);
|
|
1600
1623
|
if ((await deps.checkpointStore.findPendingTokenBySession(sessionId, undefined, { gateKinds: ["plan_review"] })) !== token)
|
|
1601
1624
|
return notResumableAnswer();
|
|
1602
1625
|
const auth = { sessionId: cp.sessionId, principal: decodeCheckpointScope(cp.scope), memoryScope: ctx.memoryScope };
|
|
@@ -1621,20 +1644,26 @@ export function createResumeLegs(ctx) {
|
|
|
1621
1644
|
hostDecision,
|
|
1622
1645
|
};
|
|
1623
1646
|
const selectedGate = durableRowIdentity("decision-receipt", cp.checkpointId, token);
|
|
1624
|
-
const out = await driveResumeIntoRunLog({ peerLease: resolved.peerLease, execution: resolved.execution, runner:
|
|
1647
|
+
const out = await driveResumeIntoRunLog({ peerLease: resolved.peerLease, execution: resolved.execution, runner: resolved.runner, legFacts: resolved.legFacts, 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 } : {}) });
|
|
1625
1648
|
return out;
|
|
1626
1649
|
}
|
|
1627
1650
|
finally {
|
|
1628
1651
|
resolved.peerLease.release();
|
|
1629
1652
|
}
|
|
1630
1653
|
}
|
|
1654
|
+
const sessionNotifyDoor = createSessionNotifyDoor({
|
|
1655
|
+
activeTaskIdOf: async (sessionId) => deps.runStore?.getActiveTaskId?.(sessionId),
|
|
1656
|
+
liveRuns: steerableRuns,
|
|
1657
|
+
inbox: deps.workflowCompletionInbox,
|
|
1658
|
+
headOf: headReadOf(deps.sessionStorage),
|
|
1659
|
+
});
|
|
1631
1660
|
const routeCtxBase = {
|
|
1632
1661
|
deps,
|
|
1633
1662
|
registry: { idemCache, inflightRuns, preemptableRuns, steerableRuns, wakeParkMints, counters },
|
|
1634
1663
|
helpers: { readJson, readRawBody, rateLimited, quotaExceeded, ownerQuotaDenied, leaseDenied, ownerLeaseDenied, usageWindowDenied, safeDecode, runOwnerOk, sessionOwnerOk, runSessionAcceptOk },
|
|
1635
1664
|
local: { images: createImagesLocal(deps), sessions: createSessionsLocal(), sessionSync: createSessionSyncLocal(), capabilities: createCapabilitiesLocal() },
|
|
1636
|
-
legs: { prepareSpec, finalizeTaskResult, resumeCheckpoint, driveResumeIntoRunLog, resumePreempted, resumeWake, preparePlanReview, drivePlanReview },
|
|
1665
|
+
legs: { prepareSpec, finalizeTaskResult, resumeCheckpoint, driveResumeIntoRunLog, resumePreempted, resumeWake, preparePlanReview, drivePlanReview, sessionNotify: sessionNotifyDoor },
|
|
1637
1666
|
};
|
|
1638
|
-
return { routeCtxBase, resumeCheckpoint, driveResumeIntoRunLog, driveResumeLeg, mayDiscloseRowError, resumePreempted, startFreshHostTurn, resumeWake, preparePlanReview, drivePlanReview };
|
|
1667
|
+
return { routeCtxBase, resumeCheckpoint, driveResumeIntoRunLog, driveResumeLeg, mayDiscloseRowError, resumePreempted, startFreshHostTurn, resumeWake, preparePlanReview, drivePlanReview, sessionNotifyDoor };
|
|
1639
1668
|
}
|
|
1640
1669
|
//# sourceMappingURL=resume-legs.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 续跑请求的**重述键** —— 「我此刻的对端表」随续跑请求一起说出来(唯一属主)。
|
|
3
|
+
*
|
|
4
|
+
* ## 律(一条)
|
|
5
|
+
* 续跑请求体可带 {@link RESUME_RESTATABLE_KEYS} 里的键(今天两只:`mcpServers` / `a2aPeers`),键名与值形 = 提交体(`POST /v1/tasks`)的同一键:
|
|
6
|
+
* · **在场**(值不是 `undefined` / `null`)⇒ 先过提交腿**同一只**判官(`assertRequestMcpEntries` / `assertRequestA2aEntries`;坏形 = 与提交腿同码同句的
|
|
7
|
+
* 400,判在续跑腿任何状态改动之前),再**取代**续跑重建输入(`checkpoint_ctx` 体)里的那一键:本次重建读它,续跑赢下 CAS 之后随重建输入一起写回
|
|
8
|
+
* (`DriveResumeArgs.resumeCtx` 那一只写点)⇒ 之后的续跑在没有新重述时重放的也是它;
|
|
9
|
+
* · **缺席**(或 `null`,与提交体「缺席或 `null` = 没声明」同一读法)⇒ 存量体那一键原样重放(冻结读法)。
|
|
10
|
+
* 重建之后的路与存量体逐字同一条(`resolveSpec` 的续跑腿:部署锁、闸、部署保留名、合并、对端座登记、用户面通告),所以一份重述在本部署上能挂上什么,
|
|
11
|
+
* 与它作为一次新提交能挂上什么是同一个答案;引擎从 `ResumeTaskConfig.mcp` / `.a2a`(与 `TaskSpec` 同键)收到的就是这张表。
|
|
12
|
+
*
|
|
13
|
+
* ## 不在本仓判的
|
|
14
|
+
* 「停驻快照里那一只调用的目标台还在不在当前表里」是引擎续跑准入的判(引擎 7.61.0 起三码各答各形,以 core 为准:工具不在了 ⇒ `resume.tool_unavailable`、同名而已不是批准时那一只 ⇒ `resume.tool_contract_mismatch`(两者重开检查点)、还是那一只而面或声明变了 ⇒ `resume.target_moved`(否决);本服务逐字过境)—— 本服务只负责把当前表送到,不自判、不预拒。
|
|
15
|
+
*
|
|
16
|
+
* ## 为什么是一张闭表
|
|
17
|
+
* 与提交腿的一次性动作那张闭表(`resume-legs.ts` 的 `ONE_SHOT_SUBMIT_KEYS`:重建时剥掉)对称 —— 那张说「哪些提交键不随重建走」,这张说「哪些提交键由续跑请求重述」。
|
|
18
|
+
* 加一键 = 改这条律本身:判官表 {@link RESTATEMENT_JUDGES} 缺行即编译红,接收它的续跑门各自在键闭集里声明它。
|
|
19
|
+
*/
|
|
20
|
+
import type { TaskRequestBody } from "./wire-types.js";
|
|
21
|
+
import type { CheckpointCtx } from "./route-ctx.js";
|
|
22
|
+
/** 续跑请求可重述的提交键(闭集;`satisfies` 钉在提交体的具名键上 —— 写一个提交体上没有的词 = 编译红)。 */
|
|
23
|
+
export declare const RESUME_RESTATABLE_KEYS: readonly ["a2aPeers", "mcpServers"];
|
|
24
|
+
export type ResumeRestatableKey = (typeof RESUME_RESTATABLE_KEYS)[number];
|
|
25
|
+
/** 一次续跑请求读出的重述(只含在场的键;读者 {@link readResumeRestatement},用者 {@link restateResumeCtx})。 */
|
|
26
|
+
export type ResumeRestatement = {
|
|
27
|
+
readonly [K in ResumeRestatableKey]?: TaskRequestBody[K];
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* 从一份续跑请求体里读出重述:在场的键逐一过判官,全部过 ⇒ 交回只含在场键的重述;一键都不在 ⇒ `undefined`(冻结读法)。
|
|
31
|
+
* 判官的拒原样抛出(调用方是路由,`HttpError` 由分发器按提交腿同一只渲染器落 wire)。体不是对象 ⇒ `undefined`(体形由各门自己的根形门答)。
|
|
32
|
+
*/
|
|
33
|
+
export declare function readResumeRestatement(body: unknown): ResumeRestatement | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* 把重述盖进续跑重建输入:在场的键取代体里的同名键,其余位(记忆域 / 无人值守标 / 读法记号 / 写者版本)原样随行。`undefined` ⇒ 原 ctx 原样(同一个对象)。
|
|
36
|
+
* 各续跑腿在读出 ctx 的那一拍调一次,之后重建(`resolveResumeSpecOrBlocked`)与写回(`resumeCtx`)读的都是这一份。
|
|
37
|
+
*/
|
|
38
|
+
export declare function restateResumeCtx(ctx: CheckpointCtx, restatement: ResumeRestatement | undefined): CheckpointCtx;
|
|
39
|
+
//# sourceMappingURL=resume-restatement.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { assertRequestMcpEntries } from "../task-mcp.js";
|
|
2
|
+
import { assertRequestA2aEntries } from "../task-a2a.js";
|
|
3
|
+
export const RESUME_RESTATABLE_KEYS = ["a2aPeers", "mcpServers"];
|
|
4
|
+
const RESTATEMENT_JUDGES = {
|
|
5
|
+
a2aPeers: assertRequestA2aEntries,
|
|
6
|
+
mcpServers: assertRequestMcpEntries,
|
|
7
|
+
};
|
|
8
|
+
export function readResumeRestatement(body) {
|
|
9
|
+
if (body === null || typeof body !== "object" || Array.isArray(body))
|
|
10
|
+
return undefined;
|
|
11
|
+
const raw = body;
|
|
12
|
+
let out;
|
|
13
|
+
for (const key of RESUME_RESTATABLE_KEYS) {
|
|
14
|
+
const value = Object.hasOwn(raw, key) ? raw[key] : undefined;
|
|
15
|
+
if (value === undefined || value === null)
|
|
16
|
+
continue;
|
|
17
|
+
RESTATEMENT_JUDGES[key](value);
|
|
18
|
+
(out ??= {})[key] = value;
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
export function restateResumeCtx(ctx, restatement) {
|
|
23
|
+
return restatement === undefined ? ctx : { ...ctx, body: { ...ctx.body, ...restatement } };
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=resume-restatement.js.map
|