@sema-agent/server 7.137.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 +328 -139
- package/README.md +1 -0
- package/README.zh-CN.md +1 -0
- package/USAGE.md +67 -20
- package/dist/approval-card.d.ts +21 -14
- package/dist/approval-card.js +1 -0
- package/dist/audit.js +1 -0
- 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/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/resolve-spec.d.ts +3 -0
- package/dist/boot/resolve-spec.js +23 -12
- 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-04-stores.d.ts +1 -12
- package/dist/boot/stage-05-execution-env.d.ts +3 -12
- package/dist/boot/stage-05-execution-env.js +7 -4
- package/dist/boot/stage-06-runners.d.ts +3 -12
- package/dist/boot/stage-06-runners.js +5 -2
- package/dist/boot/stage-07-capability-layer.d.ts +3 -12
- package/dist/boot/stage-07-capability-layer.js +2 -2
- package/dist/boot/stage-08-reapers.d.ts +3 -12
- package/dist/boot/stage-09-leader.d.ts +3 -12
- package/dist/boot/stage-09-leader.js +2 -2
- package/dist/boot/stage-10-http-server.d.ts +3 -12
- package/dist/boot/stage-10-http-server.js +4 -2
- 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/budget.d.ts +17 -15
- package/dist/budget.js +2 -2
- package/dist/capabilities/mcp-probe.d.ts +36 -11
- package/dist/capabilities/mcp-probe.js +44 -5
- package/dist/capability-facts.d.ts +6 -0
- package/dist/capability-facts.js +5 -0
- package/dist/checkpoint-identity.d.ts +13 -6
- package/dist/config-catalog.js +7 -1
- package/dist/config-types.d.ts +15 -7
- package/dist/config.js +8 -5
- package/dist/deployment-shape.d.ts +6 -6
- package/dist/gate-settlement.d.ts +71 -0
- package/dist/gate-settlement.js +40 -0
- package/dist/hooks/classic-stations.d.ts +1 -0
- 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 +4 -2
- package/dist/http/dispatch.d.ts +4 -0
- package/dist/http/dispatch.js +3 -0
- package/dist/http/durable-run-leg.js +4 -2
- package/dist/http/memory-compliance-failure-reply.js +3 -0
- package/dist/http/resume-legs.d.ts +5 -11
- package/dist/http/resume-legs.js +136 -91
- package/dist/http/route-ctx.d.ts +30 -51
- 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 +6 -6
- package/dist/http/routes/capabilities.js +12 -10
- package/dist/http/routes/mcp-reconnect.d.ts +3 -2
- package/dist/http/routes/mcp-reconnect.js +7 -5
- 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 +11 -7
- package/dist/http/routes/sessions.js +6 -4
- package/dist/http/routes/side-query.js +2 -3
- package/dist/http/routes/tasks.js +792 -780
- package/dist/http/server.d.ts +31 -25
- package/dist/http/wire-types.d.ts +14 -6
- package/dist/identity-source.d.ts +1 -1
- 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-sync-client.js +72 -57
- package/dist/memory-sync.d.ts +1 -1
- package/dist/model-route-gap.d.ts +6 -22
- package/dist/model-route-gap.js +7 -5
- package/dist/mods-declaration.d.ts +110 -0
- package/dist/mods-declaration.js +109 -0
- package/dist/observability/err-text.d.ts +5 -0
- package/dist/observability/err-text.js +9 -0
- package/dist/observability/fail-open.d.ts +5 -1
- package/dist/observability/fail-open.js +5 -1
- package/dist/observability/secret-env-scrub.d.ts +1 -1
- package/dist/observability/secret-env-scrub.js +1 -1
- package/dist/parked-decide.d.ts +15 -2
- package/dist/parked-decide.js +14 -8
- package/dist/peer-seat.d.ts +150 -0
- package/dist/peer-seat.js +239 -0
- 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 +15 -20
- package/dist/plugins/checkpoint-store-sql.js +8 -8
- package/dist/plugins/file-history-store-sql.js +3 -2
- package/dist/plugins/k8s-pod-reaper.d.ts +2 -8
- package/dist/plugins/k8s-pod-reaper.js +3 -3
- package/dist/plugins/local-checkpoint-store.d.ts +1 -11
- package/dist/plugins/local-checkpoint-store.js +0 -1
- 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-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 +6 -3
- package/dist/plugins/one-time-migrations.js +3 -4
- package/dist/plugins/permission-rule-store-sql.js +21 -13
- package/dist/plugins/pg-session-storage.d.ts +10 -2
- package/dist/plugins/pg-session-storage.js +18 -5
- package/dist/plugins/remote-env-adb.d.ts +3 -1
- package/dist/plugins/remote-env-adb.js +1 -1
- package/dist/plugins/remote-env-device.d.ts +3 -1
- package/dist/plugins/remote-env-device.js +1 -1
- package/dist/plugins/remote-env-e2b.d.ts +2 -0
- package/dist/plugins/remote-env-e2b.js +1 -1
- package/dist/plugins/remote-env-host.d.ts +3 -1
- package/dist/plugins/remote-env-host.js +1 -1
- package/dist/plugins/remote-env-k8s.d.ts +3 -1
- package/dist/plugins/remote-env-k8s.js +1 -1
- package/dist/plugins/remote-env-local-docker.d.ts +2 -0
- package/dist/plugins/remote-env-local-docker.js +1 -1
- package/dist/plugins/remote-env-ssh.d.ts +3 -1
- package/dist/plugins/remote-env-ssh.js +1 -1
- package/dist/plugins/retention-store-sql.d.ts +14 -2
- package/dist/plugins/retention-store-sql.js +6 -0
- package/dist/plugins/session-fork.d.ts +10 -13
- package/dist/plugins/session-fork.js +5 -25
- package/dist/plugins/session-ownership.d.ts +7 -0
- package/dist/plugins/session-ownership.js +5 -0
- package/dist/plugins/session-workspace-cell.d.ts +17 -0
- package/dist/plugins/session-workspace-cell.js +38 -0
- package/dist/plugins/store-backend.js +7 -7
- package/dist/plugins/tidb-pool.js +6 -0
- package/dist/plugins/tidb-session-store.d.ts +17 -2
- package/dist/plugins/tidb-session-store.js +16 -5
- 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/rules-consent.js +6 -4
- package/dist/run-local.js +12 -6
- package/dist/runs.d.ts +7 -1
- package/dist/runs.js +6 -1
- package/dist/sandbox-git-plane.d.ts +2 -2
- package/dist/server-secret-env.d.ts +6 -3
- package/dist/server-secret-env.js +4 -2
- package/dist/session-incarnation.d.ts +4 -5
- package/dist/session-incarnation.js +2 -2
- package/dist/session-workspace.d.ts +130 -0
- package/dist/session-workspace.js +83 -0
- package/dist/spec-fields.d.ts +1 -1
- package/dist/standing-answer-grant.d.ts +2 -13
- package/dist/standing-answer-grant.js +0 -7
- package/dist/task-a2a.d.ts +44 -14
- package/dist/task-a2a.js +46 -20
- package/dist/task-mcp.d.ts +33 -20
- package/dist/task-mcp.js +46 -22
- package/dist/tool-approval.d.ts +32 -8
- package/dist/tool-approval.js +49 -12
- package/dist/trace/core-keyset-guard.d.ts +33 -18
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/exit-seat.d.ts +20 -1
- package/dist/trace/exit-seat.js +3 -0
- package/dist/trace/extension-call-face.d.ts +33 -0
- package/dist/trace/extension-call-face.js +39 -0
- package/dist/trace/project.d.ts +25 -7
- package/dist/trace/project.js +29 -3
- package/dist/trace/redact.js +42 -13
- package/dist/trace/self-minted-wire.d.ts +129 -10
- package/dist/trace/self-minted-wire.js +62 -3
- package/dist/trace/wire-projection-faces.d.ts +6 -6
- package/dist/trace/wire-projection-faces.js +6 -5
- package/dist/user-authored-text.d.ts +2 -2
- package/dist/user-authored-text.js +16 -1
- package/dist/web-admin-client/center-request.d.ts +3 -2
- package/dist/web-admin-client/center-request.js +2 -3
- 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 +5 -0
- package/package.json +3 -3
- package/wire-changes/server@7.138.0.json +446 -0
- package/dist/http/mcp-remote-text.d.ts +0 -5
- package/dist/http/mcp-remote-text.js +0 -7
package/dist/http/dispatch.js
CHANGED
|
@@ -9,6 +9,7 @@ import { sendJson, sendError, isSseResponse, endSseWithError } from "./send.js";
|
|
|
9
9
|
import { admissionRefusalOf, readinessOf, healthReadinessKeys, sendReadyz, sendBillableRefusal, billableRefusalOf, billableRefusalFrame } from "./readiness.js";
|
|
10
10
|
import { ENGINE_SIGNAL_KEY, buildEngineSignal, fleetMembershipKeys, healthConfigLedgerKeys, healthDrainingKeys, mintEngineSignal, restartActionable } from "../fleet/engine-signal.js";
|
|
11
11
|
import { buildHealthSelfReport } from "./health-self-report.js";
|
|
12
|
+
import { deploymentModPackages as deploymentModPackagesFact } from "../capability-facts.js";
|
|
12
13
|
import { actsForDeployment, admitRunIdentity, authorized, systemFor, gatedPrincipal, sendPrincipalRefusal, sendUnauthorized, traceTokenPresented, verifiedIdentitySource, hasServiceAuth, devOpenDeployment } from "./principal-gate.js";
|
|
13
14
|
const PROCESS_STARTED_AT_MS = Date.now() - Math.round(process.uptime() * 1000);
|
|
14
15
|
export function readCredentialOk(req, config) {
|
|
@@ -127,6 +128,7 @@ export function createDispatch(ctx) {
|
|
|
127
128
|
if (req.method === "GET" && url === "/health") {
|
|
128
129
|
const signal = mintEngineSignal(deps);
|
|
129
130
|
const engineSignal = buildEngineSignal(signal);
|
|
131
|
+
const declaredMods = deploymentModPackagesFact(deps);
|
|
130
132
|
const configHash = createHash("sha256")
|
|
131
133
|
.update(JSON.stringify({ model: deps.config.model.id, sessionBackend: deps.config.sessionBackend, dbBackend: deps.config.dbBackend, dataRoot: deps.config.localDataRoot, configProvider: deps.config.configProvider, remoteExec: deps.config.remoteExec?.provider, port: deps.config.port }))
|
|
132
134
|
.digest("hex")
|
|
@@ -149,6 +151,7 @@ export function createDispatch(ctx) {
|
|
|
149
151
|
startedAt: PROCESS_STARTED_AT_MS,
|
|
150
152
|
port: req.socket.localPort,
|
|
151
153
|
...(deps.config.directDoorActive ? { directDoorActive: true } : {}),
|
|
154
|
+
...(declaredMods.available ? { mods: { deploymentPackages: declaredMods.count } } : {}),
|
|
152
155
|
...buildHealthSelfReport(deps),
|
|
153
156
|
...(signal.restart ? { ...(restartActionable(signal) ? { restartRequired: true } : {}), restart: signal.restart } : {}),
|
|
154
157
|
...(() => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { uuidv7 } from "@sema-agent/core";
|
|
2
2
|
import { heldWorkflowParkDecisions } from "../parked-decide.js";
|
|
3
3
|
import { HEARTBEAT_MS, runInBackground } from "../runs.js";
|
|
4
|
+
import { heldFor } from "../peer-seat.js";
|
|
4
5
|
import { fleetRunPublisher, fleetRunLabels } from "../fleet/fleet-bus.js";
|
|
5
6
|
import { cascadeConfig, runMeta } from "./run-meta.js";
|
|
6
7
|
import { declaredApprovalFrameFamilies, resolveStreamApprovalGate } from "../tool-approval.js";
|
|
@@ -13,6 +14,7 @@ import { persistSubmitCtx } from "./submit-ctx.js";
|
|
|
13
14
|
import { releaseClaimedRun } from "./claimed-run.js";
|
|
14
15
|
import { serviceVersion } from "../service-version.js";
|
|
15
16
|
import { headReadOf } from "../session-incarnation.js";
|
|
17
|
+
import { createSessionWorkspaceRecorder, legSessionWitnessOf, sessionWorkspaceStoreOf } from "../session-workspace.js";
|
|
16
18
|
export async function mintAndDriveDurableRun(ctx, runStore, args) {
|
|
17
19
|
const { deps } = ctx;
|
|
18
20
|
const { inflightRuns, preemptableRuns, steerableRuns } = ctx.registry;
|
|
@@ -78,7 +80,7 @@ export async function mintAndDriveDurableRun(ctx, runStore, args) {
|
|
|
78
80
|
sessionId,
|
|
79
81
|
...fleetRunLabels(args.prepared.spec.objective),
|
|
80
82
|
});
|
|
81
|
-
void runInBackground(args.prepared.runner, { ...args.prepared.spec, sessionId }, runStore, taskId, deps.metrics, args.prepared.auth?.principal, args.prepared.verify, args.prepared.cascade ? cascadeConfig(deps.config.cascadeLadder, args.prepared.spec.limits?.maxCostUsd) : undefined, deps.instrumentDegenerate, deps.planCacheProbe, deps.config.traceThinking, inflightRuns, preemptableRuns, steerableRuns, deps.modelUsage, deps.elicitation, args.elicitOwner, captureTurnAnchor, fleetPub, captureUserMessageAnchor, deps.question, deps.workflowCompletionInbox, deps.subagentSteerRegistry, (m, x) => deps.logger?.info?.(m, x), deps.sendUserFile, deps.promptManifests, deps.toolApproval
|
|
83
|
+
void heldFor(args.prepared.peerLease, () => runInBackground(args.prepared.runner, { ...args.prepared.spec, sessionId }, runStore, taskId, deps.metrics, args.prepared.auth?.principal, args.prepared.verify, args.prepared.cascade ? cascadeConfig(deps.config.cascadeLadder, args.prepared.spec.limits?.maxCostUsd) : undefined, deps.instrumentDegenerate, deps.planCacheProbe, deps.config.traceThinking, inflightRuns, preemptableRuns, steerableRuns, deps.modelUsage, deps.elicitation, args.elicitOwner, captureTurnAnchor, fleetPub, captureUserMessageAnchor, deps.question, deps.workflowCompletionInbox, deps.subagentSteerRegistry, (m, x) => deps.logger?.info?.(m, x), deps.sendUserFile, deps.promptManifests, deps.toolApproval
|
|
82
84
|
? {
|
|
83
85
|
coordinator: deps.toolApproval,
|
|
84
86
|
streamApprovalOn: resolveStreamApprovalGate({
|
|
@@ -91,7 +93,7 @@ export async function mintAndDriveDurableRun(ctx, runStore, args) {
|
|
|
91
93
|
windowMarginMs: deps.config.streamAskWindowMarginMs,
|
|
92
94
|
declaredFamilies: declaredApprovalFrameFamilies(args.prepared.body.settings),
|
|
93
95
|
}
|
|
94
|
-
: undefined, deps.checkpointStore, args.prepared.engineNotices, trustedInternals, deps.userInputLedger, args.prepared.acceptance);
|
|
96
|
+
: undefined, deps.checkpointStore, args.prepared.engineNotices, trustedInternals, deps.userInputLedger, args.prepared.acceptance, createSessionWorkspaceRecorder(sessionWorkspaceStoreOf(deps.sessionStorage), legSessionWitnessOf(args.prepared.spec))));
|
|
95
97
|
return { status: 202, body: { taskId, sessionId, status: "running", ...(args.prepared.warnings !== undefined ? { warnings: args.prepared.warnings } : {}) } };
|
|
96
98
|
}
|
|
97
99
|
//# sourceMappingURL=durable-run-leg.js.map
|
|
@@ -8,6 +8,9 @@ function sentCoreCode(res, coreCode, coreMessage, audience) {
|
|
|
8
8
|
case "config.memory_erasure_request":
|
|
9
9
|
sendError(res, 400, "config.memory_erasure_request", textFor(audience, coreMessage, "session memory erasure refused — the erasure request is not valid; correct it and resend"));
|
|
10
10
|
return true;
|
|
11
|
+
case "config.memory_erasure_scope":
|
|
12
|
+
sendError(res, 400, "config.memory_erasure_scope", textFor(audience, coreMessage, "session memory erasure refused — the request reaches memory outside the scopes it may erase; nothing was erased"));
|
|
13
|
+
return true;
|
|
11
14
|
case "memory.erasure_evidence_unavailable":
|
|
12
15
|
sendError(res, 409, "memory.erasure_evidence_unavailable", textFor(audience, coreMessage, "session memory erasure refused — this deployment's memory store cannot produce erasure evidence; resend with allowUnevidenced: true to erase without evidence, or ask the operator"));
|
|
13
16
|
return true;
|
|
@@ -18,7 +18,7 @@ import type { CheckpointStoreFull } from "../plugins/store-backend.js";
|
|
|
18
18
|
import type { HostDecision } from "../host-decision.js";
|
|
19
19
|
import { type GateSighting } from "../approval-gate-currency.js";
|
|
20
20
|
import { type PlanApprovePermissionModeAfter } from "../task-settings.js";
|
|
21
|
-
import type { RouteCtxBase, DriveResumeArgs,
|
|
21
|
+
import type { RouteCtxBase, DriveResumeArgs, PreparedPlanReview, ResumeLegOutcome, WorkflowDecisionDelivery } from "./route-ctx.js";
|
|
22
22
|
import type { RunRegistry, RouteHelpers, RouteLegs } from "./route-ctx.js";
|
|
23
23
|
import type { createRequestGuards } from "./request-guards.js";
|
|
24
24
|
import type { FlatServiceDeps } from "./server.js";
|
|
@@ -59,12 +59,9 @@ export declare function createResumeLegs(ctx: {
|
|
|
59
59
|
resumePreempted: (sessionId: string, req: IncomingMessage | undefined, acceptEarly?: boolean, decider?: {
|
|
60
60
|
principal?: string;
|
|
61
61
|
explicitOperator: boolean;
|
|
62
|
-
}) => Promise<
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}>;
|
|
66
|
-
startFreshHostTurn: (sessionId: string, objective: string, principal: string | undefined, req: IncomingMessage, workflowDecision: WorkflowDecisionDelivery, runId: string) => Promise<HostLegOutcome>;
|
|
67
|
-
resumeWake: (sessionId: string, message: string | undefined, caller: string | undefined, req: IncomingMessage | undefined, acceptEarly?: boolean, workflowDecision?: WorkflowDecisionDelivery, ownerLeaseAdmittedFor?: string) => Promise<HostLegOutcome>;
|
|
62
|
+
}) => Promise<ResumeLegOutcome>;
|
|
63
|
+
startFreshHostTurn: (sessionId: string, objective: string, principal: string | undefined, req: IncomingMessage, workflowDecision: WorkflowDecisionDelivery, runId: string) => Promise<ResumeLegOutcome>;
|
|
64
|
+
resumeWake: (sessionId: string, message: string | undefined, caller: string | undefined, req: IncomingMessage | undefined, acceptEarly?: boolean, workflowDecision?: WorkflowDecisionDelivery, ownerLeaseAdmittedFor?: string) => Promise<ResumeLegOutcome>;
|
|
68
65
|
preparePlanReview: (sessionId: string, log?: {
|
|
69
66
|
taskId?: string;
|
|
70
67
|
principalPresent?: boolean;
|
|
@@ -81,9 +78,6 @@ export declare function createResumeLegs(ctx: {
|
|
|
81
78
|
readonly ok: true;
|
|
82
79
|
readonly prepared: PreparedPlanReview;
|
|
83
80
|
}>;
|
|
84
|
-
drivePlanReview: (prepared: PreparedPlanReview, decision: "approve" | "edit" | "reject", editedPlan: string | undefined, reason: string | undefined, hostDecision: HostDecision, req: IncomingMessage | undefined, acceptEarly?: boolean, permissionModeAfter?: PlanApprovePermissionModeAfter) => Promise<
|
|
85
|
-
status: number;
|
|
86
|
-
body: object;
|
|
87
|
-
}>;
|
|
81
|
+
drivePlanReview: (prepared: PreparedPlanReview, decision: "approve" | "edit" | "reject", editedPlan: string | undefined, reason: string | undefined, hostDecision: HostDecision, req: IncomingMessage | undefined, acceptEarly?: boolean, permissionModeAfter?: PlanApprovePermissionModeAfter) => Promise<ResumeLegOutcome>;
|
|
88
82
|
};
|
|
89
83
|
//# sourceMappingURL=resume-legs.d.ts.map
|
package/dist/http/resume-legs.js
CHANGED
|
@@ -4,6 +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, 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`);
|
|
@@ -38,7 +39,10 @@ import { errorText } from "../observability/err-text.js";
|
|
|
38
39
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
39
40
|
import { verifyRoundsFromBody } from "./verify-rounds.js";
|
|
40
41
|
import { planReviewDecisionExitsPlan, storedBodyPermissionMode } from "../task-settings.js";
|
|
41
|
-
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";
|
|
42
46
|
import { mintAndDriveDurableRun } from "./durable-run-leg.js";
|
|
43
47
|
import { createSessionsLocal } from "./routes/sessions.js";
|
|
44
48
|
import { createSessionSyncLocal } from "./routes/session-sync.js";
|
|
@@ -75,6 +79,8 @@ const WORKER_SWAP_REDEEMABLE = {
|
|
|
75
79
|
ledger_event_unknown: true,
|
|
76
80
|
real_approval_damaged: false,
|
|
77
81
|
real_approval_forged: false,
|
|
82
|
+
tool_identity_missing: true,
|
|
83
|
+
bound_input_hash_missing: false,
|
|
78
84
|
requirements_damaged: false,
|
|
79
85
|
read_face_damaged: false,
|
|
80
86
|
read_face_forged: false,
|
|
@@ -125,9 +131,9 @@ const CHECKPOINT_ERROR_DISPOSITION = {
|
|
|
125
131
|
"checkpoint.gate_mismatch": "terminal",
|
|
126
132
|
"checkpoint.reopen_failed": "terminal",
|
|
127
133
|
"checkpoint.cwd_conflicts_restore": "terminal",
|
|
134
|
+
"steering.duplicate_input_id": "retriable",
|
|
128
135
|
"checkpoint.already_exists": "terminal",
|
|
129
136
|
"checkpoint.execution_outcome_conflict": "terminal",
|
|
130
|
-
"steering.duplicate_input_id": "terminal",
|
|
131
137
|
"steering.invalid_content": "terminal",
|
|
132
138
|
"steering.queue_full": "terminal",
|
|
133
139
|
};
|
|
@@ -159,6 +165,10 @@ const CHECKPOINT_ERROR_FIELD_ROLE = {
|
|
|
159
165
|
hostDecision: "outcome_cell",
|
|
160
166
|
approver: "outcome_cell",
|
|
161
167
|
feedback: "outcome_cell",
|
|
168
|
+
outcome: "outcome_cell",
|
|
169
|
+
updatedInput: "outcome_cell",
|
|
170
|
+
decision: "outcome_cell",
|
|
171
|
+
reason: "outcome_cell",
|
|
162
172
|
taskConfig: "config",
|
|
163
173
|
deps: "config",
|
|
164
174
|
inheritedGate: "config",
|
|
@@ -365,9 +375,7 @@ export function createResumeLegs(ctx) {
|
|
|
365
375
|
}
|
|
366
376
|
: undefined;
|
|
367
377
|
const noteLateSettleIfAccepted = (out) => {
|
|
368
|
-
if (lateSettleSink === undefined || lateSettleAnchor === undefined || out
|
|
369
|
-
return;
|
|
370
|
-
if (out.body?.errorCode === "cancelled" && out.decisionCommitted !== true)
|
|
378
|
+
if (lateSettleSink === undefined || lateSettleAnchor === undefined || !decisionCommittedOf(out))
|
|
371
379
|
return;
|
|
372
380
|
try {
|
|
373
381
|
lateSettleSink.recordLateSettle({ ...lateSettleAnchor, outcome: decision === "approve" ? "allowed" : "denied", decidedBy: hostDecision.decidedBy, ...(hostDecision.approver !== undefined ? { approver: hostDecision.approver } : {}), settledAtMs: Date.now() });
|
|
@@ -383,6 +391,7 @@ export function createResumeLegs(ctx) {
|
|
|
383
391
|
if (parkedForkLeaseDenial)
|
|
384
392
|
return parkedForkLeaseDenial;
|
|
385
393
|
const ownerLeaseAdmittedHere = req !== undefined;
|
|
394
|
+
const captureSelectedGate = () => durableRowIdentity("decision-receipt", cp.checkpointId, token);
|
|
386
395
|
if (req !== undefined) {
|
|
387
396
|
const parkedAgentStore = deps.backgroundAgentStore;
|
|
388
397
|
const parkedSurface = deps.parkedReviveSurface;
|
|
@@ -412,7 +421,7 @@ export function createResumeLegs(ctx) {
|
|
|
412
421
|
...(deps.parkedReviveInheritedGate ? { rebuildInheritedGate: deps.parkedReviveInheritedGate } : {}),
|
|
413
422
|
...(deps.toolApproval ? { approverSeatFor: windowZeroSeatOf(deps.toolApproval) } : {}),
|
|
414
423
|
...(deps.logger ? { warn: parkWarn } : {}),
|
|
415
|
-
}, parkedReq, { handle: origin.handle, row: origin.row }));
|
|
424
|
+
}, { ...parkedReq, selectedGate: captureSelectedGate() }, { handle: origin.handle, row: origin.row }));
|
|
416
425
|
void ctxPromise.catch(() => { });
|
|
417
426
|
noteLateSettleIfAccepted(parked);
|
|
418
427
|
return parked;
|
|
@@ -440,7 +449,7 @@ export function createResumeLegs(ctx) {
|
|
|
440
449
|
if (held === null || held.fingerprint !== fingerprint)
|
|
441
450
|
return undefined;
|
|
442
451
|
const run = await runStore.getRun(held.deliveredTaskId);
|
|
443
|
-
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;
|
|
444
453
|
};
|
|
445
454
|
const replay = await liveReceiptOf(await decisions.get(token));
|
|
446
455
|
if (replay !== undefined)
|
|
@@ -486,42 +495,48 @@ export function createResumeLegs(ctx) {
|
|
|
486
495
|
const resolved = await resolveResumeSpecOrBlocked(ctx, req, auth);
|
|
487
496
|
if (!resolved.ok)
|
|
488
497
|
return resolved.answer;
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
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;
|
|
493
526
|
}
|
|
494
|
-
|
|
495
|
-
|
|
527
|
+
finally {
|
|
528
|
+
resolved.peerLease.release();
|
|
496
529
|
}
|
|
497
|
-
const { objective: resumeObjective, sessionId: _sessionId, ...taskConfig } = spec;
|
|
498
|
-
const pa = cp.pendingAction;
|
|
499
|
-
const persistedCallId = pa.kind === "tool_approval" ? pa.toolCallId : "";
|
|
500
|
-
const persistedHash = pa.kind === "tool_approval" ? (pa.boundInputHash ?? "") : "";
|
|
501
|
-
const outcome = {
|
|
502
|
-
gate: "policy_ask",
|
|
503
|
-
boundCallId: binding?.boundCallId ?? persistedCallId,
|
|
504
|
-
boundInputHash: binding?.boundInputHash ?? persistedHash,
|
|
505
|
-
decision: decision === "approve" ? "allow" : "deny",
|
|
506
|
-
...(decision === "approve" && !isEngineQuestionRow(pa) && binding?.updatedInput !== undefined ? { updatedInput: binding.updatedInput } : {}),
|
|
507
|
-
...(reason ? { reason } : {}),
|
|
508
|
-
...(binding?.feedback !== undefined ? { feedback: binding.feedback } : {}),
|
|
509
|
-
...(answer !== undefined ? { answer } : {}),
|
|
510
|
-
hostDecision,
|
|
511
|
-
};
|
|
512
|
-
const verifyRounds = verifyRoundsFromBody(ctx.body);
|
|
513
|
-
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 } : {}) });
|
|
514
|
-
noteLateSettleIfAccepted(driven);
|
|
515
|
-
return driven;
|
|
516
530
|
}
|
|
517
531
|
const ONE_SHOT_SUBMIT_KEYS = ["resumeAt", "restoreFiles", "acceptPartialRestore", "rewindFilesTo", "rewindFiles", "userAttachments", "images"];
|
|
518
532
|
const ONE_SHOT_SUBMIT_STRIP = Object.fromEntries(ONE_SHOT_SUBMIT_KEYS.map((k) => [k, undefined]));
|
|
519
|
-
const resolveResumeSpec = async (ctx, req, auth) => {
|
|
533
|
+
const resolveResumeSpec = async (ctx, req, auth, lease) => {
|
|
520
534
|
const engineNotices = [];
|
|
521
535
|
const spec = await deps.resolveSpec({ ...ctx.body, ...ONE_SHOT_SUBMIT_STRIP }, req, auth, {
|
|
522
536
|
leg: "resume",
|
|
523
537
|
onNotice: (n) => engineNotices.push(n),
|
|
524
538
|
...(ctx.unattendedLeg === true ? { unattendedLeg: true } : {}),
|
|
539
|
+
lease,
|
|
525
540
|
});
|
|
526
541
|
return { spec, engineNotices };
|
|
527
542
|
};
|
|
@@ -533,11 +548,13 @@ export function createResumeLegs(ctx) {
|
|
|
533
548
|
const replay = storedBodyReplayRefusal(ctx, deps.config);
|
|
534
549
|
if (replay !== undefined)
|
|
535
550
|
return { ok: false, answer: refuseStoredBodyReplay(auth.sessionId, replay) };
|
|
551
|
+
const lease = deps.peerDesk.lease("resume");
|
|
536
552
|
try {
|
|
537
|
-
const { spec, engineNotices } = await resolveResumeSpec(ctx, req, auth);
|
|
538
|
-
return { ok: true, spec, engineNotices };
|
|
553
|
+
const { spec, engineNotices } = await resolveResumeSpec(ctx, req, auth, lease);
|
|
554
|
+
return { ok: true, spec, engineNotices, peerLease: lease };
|
|
539
555
|
}
|
|
540
556
|
catch (e) {
|
|
557
|
+
lease.release();
|
|
541
558
|
if (e instanceof HttpError) {
|
|
542
559
|
return { ok: false, answer: resumeRefusalWithCard(resumeBlockedByPolicyAnswer(httpErrorRefusal(e)), true) };
|
|
543
560
|
}
|
|
@@ -546,11 +563,11 @@ export function createResumeLegs(ctx) {
|
|
|
546
563
|
};
|
|
547
564
|
async function driveResumeIntoRunLog(args) {
|
|
548
565
|
if (args.acceptEarly !== true)
|
|
549
|
-
return await driveResumeLeg(args);
|
|
566
|
+
return await heldFor(args.peerLease, () => driveResumeLeg(args));
|
|
550
567
|
let settleAccepted;
|
|
551
568
|
let wasAccepted = false;
|
|
552
569
|
const accepted = new Promise((resolve) => { settleAccepted = resolve; });
|
|
553
|
-
const leg = driveResumeLeg(args, (receipt) => { wasAccepted = true; settleAccepted?.(receipt); });
|
|
570
|
+
const leg = heldFor(args.peerLease, () => driveResumeLeg(args, (receipt) => { wasAccepted = true; settleAccepted?.(receipt); }));
|
|
554
571
|
void leg.then((out) => {
|
|
555
572
|
if (wasAccepted && out.status >= 400) {
|
|
556
573
|
deps.logger?.warn?.("resume_leg_failed_after_accept", { sessionId: args.sessionId, status: out.status, body: out.body });
|
|
@@ -889,6 +906,7 @@ export function createResumeLegs(ctx) {
|
|
|
889
906
|
const driveResume = async () => {
|
|
890
907
|
resumeLegLive = true;
|
|
891
908
|
const tailContentMode = resumeTaskConfig.forwardSubagentEvents === true ? "on" : "progress_only";
|
|
909
|
+
const resumeWorkspace = createSessionWorkspaceRecorder(sessionWorkspaceStoreOf(deps.sessionStorage), legSessionWitnessOf(resumeTaskConfig));
|
|
892
910
|
const stream = await legRunner.resumeStream(token, outcome, { ...resumeTaskConfig, signal: cancelCtrl.signal, preemptSignal: preemptCtrl.signal }, {
|
|
893
911
|
...launchInternals,
|
|
894
912
|
onForwardEvent: (e) => {
|
|
@@ -951,12 +969,14 @@ export function createResumeLegs(ctx) {
|
|
|
951
969
|
if (taskId)
|
|
952
970
|
steerableRuns.set(taskId, stream);
|
|
953
971
|
if (!taskId || !rs) {
|
|
972
|
+
for await (const ev of stream)
|
|
973
|
+
await resumeWorkspace.observe(ev);
|
|
954
974
|
const rNoRow = await stream.result();
|
|
955
975
|
if (await reopenedAfterLeg(rNoRow, cancelCtrl.cause() !== undefined))
|
|
956
976
|
reopenConfirmedPark = true;
|
|
957
977
|
return sealResultForExit(rNoRow);
|
|
958
978
|
}
|
|
959
|
-
onAccepted?.(acceptedResumingReceipt(taskId, sessionId));
|
|
979
|
+
onAccepted?.(acceptedResumingReceipt(taskId, sessionId, buildSettlementEvidence({ at: "engine_accepted", commitment: args.commitment })));
|
|
960
980
|
let causeAtDone;
|
|
961
981
|
for await (const ev of stream) {
|
|
962
982
|
if (ev.type === "done")
|
|
@@ -964,6 +984,7 @@ export function createResumeLegs(ctx) {
|
|
|
964
984
|
recordTurnActivity(taskId);
|
|
965
985
|
fleetPub?.onEvent(ev);
|
|
966
986
|
await deps.userInputLedger?.observeLegEvent(stream, ev);
|
|
987
|
+
await resumeWorkspace.observe(ev);
|
|
967
988
|
await appendPromptManifest(append, deps.promptManifests, taskId);
|
|
968
989
|
switch (ev.type) {
|
|
969
990
|
case "text_delta":
|
|
@@ -1221,13 +1242,13 @@ export function createResumeLegs(ctx) {
|
|
|
1221
1242
|
settleFleet(checkpointReopened ? reparkStatus : resumePlane.status, fleetRunResiduals(sealed));
|
|
1222
1243
|
return {
|
|
1223
1244
|
status: 200,
|
|
1224
|
-
decisionCommitted: true,
|
|
1225
1245
|
body: {
|
|
1226
1246
|
taskId, sessionId, status: resumePlane.status,
|
|
1227
1247
|
bindingEnforced: true,
|
|
1228
1248
|
...(resumePlane.errorCode ? { errorCode: resumePlane.errorCode } : {}),
|
|
1229
1249
|
...(resumePlane.errorMessage ? { errorMessage: redactErrorMessage(resumePlane.errorMessage) ?? "" } : {}),
|
|
1230
1250
|
...(checkpointReopened ? { retriable: true } : {}),
|
|
1251
|
+
...buildSettlementEvidence({ at: "engine_terminal", commitment: args.commitment }),
|
|
1231
1252
|
},
|
|
1232
1253
|
};
|
|
1233
1254
|
}
|
|
@@ -1302,10 +1323,16 @@ export function createResumeLegs(ctx) {
|
|
|
1302
1323
|
const resolved = await resolveResumeSpecOrBlocked(ctx, req, auth);
|
|
1303
1324
|
if (!resolved.ok)
|
|
1304
1325
|
return resolved.answer;
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
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
|
+
}
|
|
1309
1336
|
}
|
|
1310
1337
|
async function startFreshHostTurn(sessionId, objective, principal, req, workflowDecision, runId) {
|
|
1311
1338
|
const cs = deps.checkpointStore;
|
|
@@ -1338,23 +1365,28 @@ export function createResumeLegs(ctx) {
|
|
|
1338
1365
|
const resolved = await resolveResumeSpecOrBlocked(ctx, req, auth);
|
|
1339
1366
|
if (!resolved.ok)
|
|
1340
1367
|
return resolved.answer;
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
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();
|
|
1353
1389
|
}
|
|
1354
|
-
if (out.status !== 202)
|
|
1355
|
-
return { status: out.status, body: out.body };
|
|
1356
|
-
const minted = out.body;
|
|
1357
|
-
return acceptedResumingReceipt(minted.taskId, minted.sessionId);
|
|
1358
1390
|
}
|
|
1359
1391
|
async function resumeWake(sessionId, message, caller, req, acceptEarly, workflowDecision, ownerLeaseAdmittedFor) {
|
|
1360
1392
|
const cs = deps.checkpointStore;
|
|
@@ -1418,26 +1450,33 @@ export function createResumeLegs(ctx) {
|
|
|
1418
1450
|
const resolved = await resolveResumeSpecOrBlocked(ctx, req, auth);
|
|
1419
1451
|
if (!resolved.ok)
|
|
1420
1452
|
return resolved.answer;
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
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
|
+
}
|
|
1441
1480
|
}
|
|
1442
1481
|
async function preparePlanReview(sessionId, log, decider, sighting) {
|
|
1443
1482
|
const cs = deps.checkpointStore;
|
|
@@ -1530,18 +1569,24 @@ export function createResumeLegs(ctx) {
|
|
|
1530
1569
|
const resolved = await resolveResumeSpecOrBlocked(rebuildCtx, req, auth);
|
|
1531
1570
|
if (!resolved.ok)
|
|
1532
1571
|
return resolved.answer;
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
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
|
+
}
|
|
1545
1590
|
}
|
|
1546
1591
|
const routeCtxBase = {
|
|
1547
1592
|
deps,
|