@sema-agent/core 7.12.0 → 7.14.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/CHANGELOG.md +124 -0
- package/dist/agents/subagent.d.ts +4 -9
- package/dist/agents/subagent.js +16 -12
- package/dist/agents/teacher.js +1 -1
- package/dist/brain/reasoning.d.ts +23 -0
- package/dist/brain/reasoning.js +35 -4
- package/dist/brain/stream-engine.js +35 -17
- package/dist/brain/timeout.d.ts +25 -4
- package/dist/brain/timeout.js +1 -1
- package/dist/core/ask-origin.d.ts +83 -9
- package/dist/core/ask-origin.js +31 -5
- package/dist/core/auto-mode.d.ts +3 -3
- package/dist/core/checkpoint-seat.d.ts +18 -0
- package/dist/core/checkpoint-seat.js +6 -0
- package/dist/core/checkpoint-store.d.ts +9 -16
- package/dist/core/checkpoint-store.js +7 -4
- package/dist/core/engine-notice.d.ts +21 -1
- package/dist/core/env-knob-announce.d.ts +16 -0
- package/dist/core/env-knob-announce.js +14 -0
- package/dist/core/gate-fold.js +2 -0
- package/dist/core/gate-lanes.d.ts +0 -40
- package/dist/core/gate-lanes.js +24 -29
- package/dist/core/gate-outcome.d.ts +42 -3
- package/dist/core/gate-outcome.js +22 -0
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +3 -1
- package/dist/core/hooks.d.ts +6 -17
- package/dist/core/hooks.js +7 -5
- package/dist/core/mcp.d.ts +3 -2
- package/dist/core/mcp.js +5 -11
- package/dist/core/memory-engine/engine.d.ts +2 -2
- package/dist/core/runner/advertised-writable-dirs.d.ts +74 -0
- package/dist/core/runner/advertised-writable-dirs.js +48 -0
- package/dist/core/runner/assemble-result.d.ts +50 -1
- package/dist/core/runner/assemble-result.js +4 -1
- package/dist/core/runner/compaction-seams.d.ts +42 -0
- package/dist/core/runner/compaction-seams.js +80 -0
- package/dist/core/runner/contracts.d.ts +44 -6
- package/dist/core/runner/denial-limit-arms.d.ts +7 -9
- package/dist/core/runner/denial-limit-arms.js +11 -12
- package/dist/core/runner/gate-exit.d.ts +15 -3
- package/dist/core/runner/gate-exit.js +6 -4
- package/dist/core/runner/permission-rule-lanes.d.ts +2 -1
- package/dist/core/runner/permission-rule-lanes.js +2 -1
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +34 -4
- package/dist/core/runner/prepare-caps-and-workflow.js +47 -12
- package/dist/core/runner/prepare-gate-stations.d.ts +1 -1
- package/dist/core/runner/prepare-hands-readface.d.ts +10 -4
- package/dist/core/runner/prepare-hands-readface.js +5 -14
- package/dist/core/runner/prepare-inherited-gate.d.ts +5 -3
- package/dist/core/runner/prepare-inherited-gate.js +1 -1
- package/dist/core/runner/prepare-memory.d.ts +31 -34
- package/dist/core/runner/prepare-memory.js +73 -51
- package/dist/core/runner/prepare-policy-chain.js +8 -4
- package/dist/core/runner/prepare-prompt-inputs.d.ts +4 -0
- package/dist/core/runner/prepare-prompt-inputs.js +2 -2
- package/dist/core/runner/prepare-protocol-tools.js +5 -0
- package/dist/core/runner/prepare-question-face.d.ts +10 -8
- package/dist/core/runner/prepare-question-face.js +1 -3
- package/dist/core/runner/prepare-safety-scan.js +11 -16
- package/dist/core/runner/prepare-task.d.ts +9 -1
- package/dist/core/runner/prepare-task.js +63 -49
- package/dist/core/runner/prepare-wiring-manifest.d.ts +2 -2
- package/dist/core/runner/prepare-wiring-manifest.js +1 -1
- package/dist/core/runner/resume-claim.d.ts +2 -2
- package/dist/core/runner/resume-preflight.d.ts +2 -2
- package/dist/core/runner/run-attachment-seats.d.ts +2 -2
- package/dist/core/runner/run-compaction-machinery.js +2 -0
- package/dist/core/runner/run-git-lane.d.ts +1 -1
- package/dist/core/runner/run-harness-handlers.js +5 -1
- package/dist/core/runner/run-identity-wiring.d.ts +7 -0
- package/dist/core/runner/run-identity-wiring.js +3 -1
- package/dist/core/runner/run-leg.d.ts +7 -5
- package/dist/core/runner/run-leg.js +256 -5
- package/dist/core/runner/run-notification-lane.d.ts +4 -3
- package/dist/core/runner/run-recovery-lanes.d.ts +4 -17
- package/dist/core/runner/run-recovery-lanes.js +5 -4
- package/dist/core/runner/run-settle-and-teardown.d.ts +14 -10
- package/dist/core/runner/run-settle-and-teardown.js +112 -4
- package/dist/core/runner/run-stop-and-final-verify.d.ts +2 -2
- package/dist/core/runner/run-terminal-adoption.d.ts +16 -16
- package/dist/core/runner/run-terminal-adoption.js +87 -7
- package/dist/core/runner/run-turn-boundary.js +5 -4
- package/dist/core/runner/runtask.d.ts +10 -90
- package/dist/core/runner/runtask.js +77 -596
- package/dist/core/runner/stream-lifecycle-verbs.js +10 -1
- package/dist/core/runner/stream-settle-backstop.js +1 -1
- package/dist/core/runtime-caps.d.ts +21 -0
- package/dist/core/runtime-caps.js +5 -1
- package/dist/core/task-event.d.ts +11 -2
- package/dist/core/task-registry-shared.js +8 -6
- package/dist/core/task-result.d.ts +15 -0
- package/dist/core/task-stream.d.ts +10 -1
- package/dist/core/terminal-cause.d.ts +6 -2
- package/dist/core/tool-face.d.ts +8 -0
- package/dist/core/tool-face.js +1 -0
- package/dist/core/tool-policy.d.ts +39 -31
- package/dist/core/tool-policy.js +29 -5
- package/dist/core/tool-registry.d.ts +11 -3
- package/dist/core/tool-registry.js +7 -1
- package/dist/core/tool-roster.d.ts +26 -0
- package/dist/core/tool-roster.js +40 -7
- package/dist/core/tool-spec.d.ts +13 -12
- package/dist/core/types.d.ts +2 -1
- package/dist/core/types.js +1 -0
- package/dist/core/wiring-manifest.d.ts +16 -9
- package/dist/core/wiring-manifest.js +8 -3
- package/dist/index.d.ts +8 -7
- package/dist/index.js +7 -6
- package/dist/orchestration/run-workflow-tool.d.ts +8 -8
- package/dist/orchestration/run-workflow-tool.js +1 -1
- package/dist/orchestration/workflow-primitives.d.ts +4 -3
- package/dist/orchestration/workflow-primitives.js +3 -3
- package/dist/orchestration/workflow-types.d.ts +14 -0
- package/dist/orchestration/workflow.d.ts +41 -4
- package/dist/orchestration/workflow.js +23 -5
- package/dist/server/http.js +2 -1
- package/dist/tools/fs/fs-shared.js +9 -3
- package/dist/tools/fs/read-deny.d.ts +24 -8
- package/dist/tools/fs/read-deny.js +20 -1
- package/package.json +2 -1
- package/test/export-surface.snapshot.json +35 -1
|
@@ -41,7 +41,9 @@ export function runIdentityWiring(input) {
|
|
|
41
41
|
};
|
|
42
42
|
prepared.harness.engineInjectionsHeld = () => prepared.batchHaltRef.current !== undefined;
|
|
43
43
|
let undrainedUserAtEnd;
|
|
44
|
+
let userInputLostAtEnd = false;
|
|
44
45
|
prepared.harness.onUndrainedUserInputs = (counts) => {
|
|
46
|
+
userInputLostAtEnd = counts.steer + counts.followUp > 0;
|
|
45
47
|
if (prepared.pausedRef.current !== undefined) {
|
|
46
48
|
undrainedUserAtEnd = counts;
|
|
47
49
|
return;
|
|
@@ -81,5 +83,5 @@ export function runIdentityWiring(input) {
|
|
|
81
83
|
const loopLatch = { ended: false, userInterrupted: false, userHalted: false };
|
|
82
84
|
onReady({ harness: prepared.harness, abortController: prepared.abortController, loop: loopLatch, reminderMark: prepared.reminderMark, sessionId: prepared.sessionId, runId: prepared.runId, hookTimeoutMs: prepared.hookTimeoutMs, hookIdentity: prepared.hookIdentity });
|
|
83
85
|
const stats = { turns: 0, tokens: 0, toolCalls: 0, promptTokens: 0, totalInputTokens: 0, cachedTokens: 0, cacheWriteTokens: 0, cacheWriteTokensLong: 0, outputTokens: 0, costMicroUsd: 0 };
|
|
84
|
-
return { runSourceTaskId, parentToolCallId, ident, emitDelegationLifecycle, loopLatch, stats, undrainedUserAtEnd: { get current() { return undrainedUserAtEnd; } } };
|
|
86
|
+
return { runSourceTaskId, parentToolCallId, ident, emitDelegationLifecycle, loopLatch, stats, undrainedUserAtEnd: { get current() { return undrainedUserAtEnd; } }, userInputLostAtEnd: { get current() { return userInputLostAtEnd; } } };
|
|
85
87
|
}
|
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
* assembly — orphaned background tasks, the git frame, the parked steer queue and the wake message each under its own trust
|
|
6
6
|
* framing and redelivery screen — and the prompt itself) and the OBJECTIVE leg (the UserPromptSubmit screen, the git
|
|
7
7
|
* frame's primary delivery, the first-frame listings, the pre-call budget / token / entry-governance gates, the image
|
|
8
|
-
* conversion, the objective's human-input frame and the prompt itself). The
|
|
8
|
+
* conversion, the objective's human-input frame and the prompt itself). The resumed decision's application
|
|
9
|
+
* (`applyResumeDecision`) and the gated call's resolver (`resolvePendingCall` — the post-CAS belts, the execution record)
|
|
10
|
+
* are the lane's own module-private functions since design/393 S7, verbatim from the Runner's private methods: the resume
|
|
11
|
+
* leg is their one caller, and a sibling file would be a lane-to-lane reach (the S6 legs' reading). The tail captures the abort facts; the catch
|
|
9
12
|
* re-throws the resume-equivalent env failures after a bounded teardown and adopts everything else as the leg's throw;
|
|
10
13
|
* the finally releases the timer, the diagnostics, the signal, the content-ask bindings, flips the notification lane
|
|
11
14
|
* and releases the four subscriptions in their order.
|
|
@@ -79,11 +82,10 @@ export interface RunLegInput<R> {
|
|
|
79
82
|
unsubBoundary: () => void;
|
|
80
83
|
/** borrowed-readonly — the git lane's harness-event release, called third. */
|
|
81
84
|
unsub: () => void;
|
|
82
|
-
/** borrowed-readonly — the Runner's deployment deps, read LIVE (`onError`, `hooks`, `onNotice`, `allowImageUrl
|
|
83
|
-
* why it is a seat and not a
|
|
85
|
+
/** borrowed-readonly — the Runner's deployment deps, read LIVE (`onError`, `hooks`, `onNotice`, `allowImageUrl`; the resumed
|
|
86
|
+
* decision's resolver files its execution record's word through `onNotice` too); the one home of why it is a seat and not a
|
|
87
|
+
* captured object is {@link RunnerDepsSeat}. */
|
|
84
88
|
runner: RunnerDepsSeat;
|
|
85
|
-
/** borrowed-readonly — the Runner's application of the resumed decision (its private method, as a delegate). */
|
|
86
|
-
applyResumeDecision: (prepared: Prepared, resume: ResumeRun, emit: (e: TaskEvent) => void, emitCommitted: (entryId: string, role: "user" | "assistant" | "toolResult", toolCallId?: string) => void, onResolvedToolSuccess?: (toolName: string, details: unknown) => void, onExecuteStart?: (toolCallId: string) => void) => Promise<void>;
|
|
87
89
|
/** borrowed-readonly — the terminal adoption, entered in this lane's last continuation with the leg's facts. */
|
|
88
90
|
next: (leg: RunLegResult) => Promise<R>;
|
|
89
91
|
}
|
|
@@ -1,24 +1,33 @@
|
|
|
1
1
|
import { snapshotActorAssertion } from "../../internal/llm.js";
|
|
2
2
|
import { redactThenCut } from "../../agents/subagent-steps.js";
|
|
3
|
-
import {
|
|
3
|
+
import { ASK_USER_QUESTION_TOOL_NAME } from "../ask-question.js";
|
|
4
|
+
import { CheckpointError, readPendingSteerQueue, realApprovalOrgFact, remainingBudgetMicroUsd } from "../checkpoint-store.js";
|
|
5
|
+
import { normalizePersistedRuleHit } from "../gate-lanes.js";
|
|
4
6
|
import { formatHookFeedback, hookSeatExpiredError, runHookSeat } from "../hooks.js";
|
|
5
7
|
import { buildHumanInputEvent, projectHumanInput } from "../human-input-projection.js";
|
|
8
|
+
import { ORG_ADJUDICATION_TIMEOUT_MS, settleOrgVerdictWithin } from "../permission-rule-org.js";
|
|
9
|
+
import { applyPersistedTightening, disclosedRuleSet } from "../persisted-rule-arms.js";
|
|
6
10
|
import { computeCostMicroUsd } from "../pricing.js";
|
|
7
11
|
import { mintSystemReminder } from "../reminder-mint.js";
|
|
8
12
|
import { hasDestroy } from "../remote-env.js";
|
|
13
|
+
import { refuseOutOfContractDecision } from "../tool-policy.js";
|
|
14
|
+
import { callFaceSeat, judgeParkedToolIdentity, rosterEntryNamed, toolCallFaceOf } from "../tool-roster.js";
|
|
9
15
|
import { deliverEngineNotice } from "../types.js";
|
|
10
|
-
import { delimitUntrusted, inlineUntrusted, sanitizeUntrustedText } from "../untrusted-text.js";
|
|
16
|
+
import { delimitUntrusted, inlineUntrusted, REVIEWER_NOTE_MAX_BODY, sanitizeUntrustedText } from "../untrusted-text.js";
|
|
11
17
|
import { errorCodeOf } from "./assemble-result.js";
|
|
12
18
|
import { DEFAULT_PRECALL_OUTPUT_TOKENS, platformLimitTerminal } from "./clock-and-limits.js";
|
|
13
|
-
import { resumeContinuation } from "./decide-continuation.js";
|
|
19
|
+
import { deepJsonEqual, DEFERRED_REISSUE, resumeContinuation } from "./decide-continuation.js";
|
|
20
|
+
import { settleExecutionRecord } from "./execution-record.js";
|
|
21
|
+
import { mintGateOutcome } from "./gate-exit.js";
|
|
14
22
|
import { resolveGitLegDelivery, wrapGitFrame } from "./git-leg-delivery.js";
|
|
15
23
|
import { GIT_STATUS_ECHO_PREVIEW } from "./git-status-frame.js";
|
|
16
24
|
import { toImageContent } from "./image.js";
|
|
17
25
|
import { nextHumanInputSeq } from "./steer-admission.js";
|
|
18
26
|
import { settleTeardownLeg } from "./teardown-bounded.js";
|
|
27
|
+
import { toolEndBodyFrom, toolResultMsg } from "./tool-end-body.js";
|
|
19
28
|
import { attachmentEnvelopeTags, commitAgentListing, commitSkillsListing, reduceToolEnd, renderAgentListingDelta, renderOrphanedBackgroundTasks, renderSkillsListingDelta, stampWriteAnchor } from "./turn-attachments.js";
|
|
20
29
|
export async function runLeg(input) {
|
|
21
|
-
const { spec, queue, prepared, resume, rs, entryActor, effectiveTimeoutMs, timeout, pushContent, ident, emitCommitted, writeFamilyOf, startedToolCallIds, announceWorkspaceMove, withBrainSinks, flushGitMirror, loopLatch, notificationLane, unsubscribeTaskNotifications, unsubGitRetry, unsubBoundary, unsub, runner,
|
|
30
|
+
const { spec, queue, prepared, resume, rs, entryActor, effectiveTimeoutMs, timeout, pushContent, ident, emitCommitted, writeFamilyOf, startedToolCallIds, announceWorkspaceMove, withBrainSinks, flushGitMirror, loopLatch, notificationLane, unsubscribeTaskNotifications, unsubGitRetry, unsubBoundary, unsub, runner, next } = input;
|
|
22
31
|
let final;
|
|
23
32
|
let threw;
|
|
24
33
|
let abortedLive = false;
|
|
@@ -55,7 +64,7 @@ export async function runLeg(input) {
|
|
|
55
64
|
}
|
|
56
65
|
}
|
|
57
66
|
if (resumeWindowRetryAfterMs === undefined && !walltimeExhaustedResume && resume.outcome.gate !== "wake") {
|
|
58
|
-
await applyResumeDecision(prepared, resume, (e) => pushContent({ ...e, ...ident() }), emitCommitted, (toolName, details) => {
|
|
67
|
+
await applyResumeDecision(runner, prepared, resume, (e) => pushContent({ ...e, ...ident() }), emitCommitted, (toolName, details) => {
|
|
59
68
|
if (rs.attach.attachState === undefined)
|
|
60
69
|
return;
|
|
61
70
|
const family = writeFamilyOf(toolName);
|
|
@@ -460,3 +469,245 @@ export async function runLeg(input) {
|
|
|
460
469
|
}
|
|
461
470
|
return await next({ final, threw, abortedLive, userInterruptedLive, strandedHumanAnswers });
|
|
462
471
|
}
|
|
472
|
+
const ORG_DISCLOSURE_MAX_CHARS = 600;
|
|
473
|
+
async function applyResumeDecision(runner, prepared, resume, emit, emitCommitted, onResolvedToolSuccess, onExecuteStart) {
|
|
474
|
+
const { pendingAction } = resume.cp;
|
|
475
|
+
if (resume.outcome.gate === "dry_run_review")
|
|
476
|
+
return;
|
|
477
|
+
if (resume.outcome.gate === "plan_review")
|
|
478
|
+
return;
|
|
479
|
+
if (pendingAction.kind !== "tool_approval")
|
|
480
|
+
return;
|
|
481
|
+
if (resume.outcome.gate === "policy_ask" &&
|
|
482
|
+
resume.outcome.decision === "allow" &&
|
|
483
|
+
!prepared.tools.some((t) => t.name === pendingAction.toolName)) {
|
|
484
|
+
const e = new Error(`the approved tool "${pendingAction.toolName}" is no longer available on resume — refusing to continue as if it ran; the checkpoint is reopened for a retry with the tool present`);
|
|
485
|
+
e.code = "resume.tool_unavailable";
|
|
486
|
+
throw e;
|
|
487
|
+
}
|
|
488
|
+
const liveRoster = prepared.toolRosterDeltas.current;
|
|
489
|
+
if (pendingAction.kind === "tool_approval" && liveRoster !== undefined && judgeParkedToolIdentity(pendingAction, rosterEntryNamed(liveRoster, pendingAction.toolName)) === "mismatch") {
|
|
490
|
+
const e = new Error(`the approved tool "${pendingAction.toolName}" on this leg is not the tool the approval was minted against (its contract / shape / revision differ) — refusing to execute a replacement wearing the name; the checkpoint is reopened for a retry with the original tool present`);
|
|
491
|
+
e.code = "resume.tool_contract_mismatch";
|
|
492
|
+
throw e;
|
|
493
|
+
}
|
|
494
|
+
const completed = new Set(pendingAction.completedCallIds);
|
|
495
|
+
const deferredIds = pendingAction.batchToolCallIds.filter((id) => id !== pendingAction.toolCallId && !completed.has(id));
|
|
496
|
+
const names = new Map();
|
|
497
|
+
const deferredArgs = new Map();
|
|
498
|
+
if (deferredIds.length > 0) {
|
|
499
|
+
const { messages } = await prepared.session.buildContext();
|
|
500
|
+
for (const m of messages) {
|
|
501
|
+
if (m.role === "assistant") {
|
|
502
|
+
for (const c of m.content) {
|
|
503
|
+
if (c.type === "toolCall") {
|
|
504
|
+
names.set(c.id, c.name);
|
|
505
|
+
deferredArgs.set(c.id, c.arguments);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
for (const id of pendingAction.batchToolCallIds) {
|
|
512
|
+
if (id === pendingAction.toolCallId) {
|
|
513
|
+
await resolvePendingCall(runner, prepared, resume, emit, emitCommitted, onResolvedToolSuccess, onExecuteStart);
|
|
514
|
+
}
|
|
515
|
+
else if (!completed.has(id)) {
|
|
516
|
+
const name = names.get(id) ?? "unknown";
|
|
517
|
+
const displayLabel = (() => {
|
|
518
|
+
const l = prepared.tools.find((t) => t.name === name)?.label;
|
|
519
|
+
return l !== undefined && l !== name ? { label: l } : {};
|
|
520
|
+
})();
|
|
521
|
+
emit({ type: "tool_start", toolCallId: id, toolName: name, ...displayLabel, args: deferredArgs.get(id) ?? {} });
|
|
522
|
+
emit({ type: "tool_end", toolCallId: id, toolName: name, ...displayLabel, isError: true, ...toolEndBodyFrom({ content: formatHookFeedback(DEFERRED_REISSUE, prepared.reminderMark) }, true, prepared.structuredProjector) });
|
|
523
|
+
const eid = await prepared.session.appendMessage(toolResultMsg(id, name, formatHookFeedback(DEFERRED_REISSUE, prepared.reminderMark), true));
|
|
524
|
+
emitCommitted(eid, "toolResult", id);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted, onResolvedToolSuccess, onExecuteStart) {
|
|
529
|
+
const { pendingAction } = resume.cp;
|
|
530
|
+
const { outcome } = resume;
|
|
531
|
+
if (pendingAction.kind !== "tool_approval" || outcome.gate !== "policy_ask")
|
|
532
|
+
return;
|
|
533
|
+
const decidedGate = outcome.gateOutcome;
|
|
534
|
+
if (decidedGate === undefined) {
|
|
535
|
+
throw new CheckpointError("checkpoint.invalid_outcome", "pending action reached the resolver with no settlement record on its decision (gateOutcome) — refusing to execute or settle a decision that carries no record");
|
|
536
|
+
}
|
|
537
|
+
const resolvedArgs = pendingAction.toolName === ASK_USER_QUESTION_TOOL_NAME ? pendingAction.args : (outcome.updatedInput !== undefined ? outcome.updatedInput : pendingAction.args);
|
|
538
|
+
const pendingLabel = (() => { const l = prepared.tools.find((t) => t.name === pendingAction.toolName)?.label; return l !== undefined && l !== pendingAction.toolName ? { label: l } : {}; })();
|
|
539
|
+
emit({ type: "tool_start", toolCallId: pendingAction.toolCallId, toolName: pendingAction.toolName, ...pendingLabel, args: resolvedArgs });
|
|
540
|
+
const settleEnd = async (isError, result, gate = decidedGate) => {
|
|
541
|
+
emit({ type: "tool_end", toolCallId: pendingAction.toolCallId, toolName: pendingAction.toolName, ...pendingLabel, isError, ...toolEndBodyFrom(result, isError, prepared.structuredProjector, gate) });
|
|
542
|
+
const word = await resume.recordExecutionOutcome(gate);
|
|
543
|
+
settleExecutionRecord(runner.deps.onNotice, word, { toolName: pendingAction.toolName, gate, sessionId: prepared.sessionId, runId: prepared.runId, scope: resume.cp.scope, ...(resume.cp.checkpointId !== undefined ? { checkpointId: resume.cp.checkpointId } : {}) });
|
|
544
|
+
};
|
|
545
|
+
const vetoed = (layer) => mintGateOutcome({
|
|
546
|
+
deniedBy: layer,
|
|
547
|
+
...(outcome.gateOutcome?.settlement !== undefined && outcome.gateOutcome.origin !== undefined ? { settled: { settlement: outcome.gateOutcome.settlement, origin: outcome.gateOutcome.origin } } : {}),
|
|
548
|
+
});
|
|
549
|
+
if (outcome.decision === "deny") {
|
|
550
|
+
const defaultDenial = outcome.gateOutcome?.settlement?.kind === "park_sla_expired"
|
|
551
|
+
? `No one answered the approval request for the pending tool call "${pendingAction.toolName}" — the approval window elapsed with no answer, so it was not executed.`
|
|
552
|
+
: `The pending tool call "${pendingAction.toolName}" was denied by an approver.`;
|
|
553
|
+
const reason = outcome.reason ? delimitUntrusted("reviewer note", outcome.reason, REVIEWER_NOTE_MAX_BODY) : defaultDenial;
|
|
554
|
+
await settleEnd(true, { content: formatHookFeedback(reason, prepared.reminderMark) });
|
|
555
|
+
const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, formatHookFeedback(reason, prepared.reminderMark), true));
|
|
556
|
+
emitCommitted(eid, "toolResult", pendingAction.toolCallId);
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
if (outcome.decision !== "allow") {
|
|
560
|
+
throw new CheckpointError("checkpoint.invalid_outcome", `pending action reached the resolver with decision "${String(outcome.decision)}" — only "allow" executes and only "deny" injects a denial; refusing to execute`);
|
|
561
|
+
}
|
|
562
|
+
const beltBudget = {
|
|
563
|
+
resourceRemainingMicroUsd: remainingBudgetMicroUsd(prepared.resourceLedger),
|
|
564
|
+
resourceSpentMicroUsd: prepared.resourceLedger?.spentMicroUsd ?? 0,
|
|
565
|
+
suspendCount: resume.cp.suspendCount ?? 0,
|
|
566
|
+
};
|
|
567
|
+
if (outcome.decision === "allow" && outcome.updatedInput !== undefined && prepared.basePolicyForResumeEdit) {
|
|
568
|
+
const rechecked = refuseOutOfContractDecision(await prepared.basePolicyForResumeEdit.check({
|
|
569
|
+
toolName: pendingAction.toolName,
|
|
570
|
+
args: resolvedArgs,
|
|
571
|
+
toolCallId: pendingAction.toolCallId,
|
|
572
|
+
budget: beltBudget,
|
|
573
|
+
...(prepared.cwdRef !== undefined ? { cwd: prepared.cwdRef.current } : {}),
|
|
574
|
+
...callFaceSeat(toolCallFaceOf(prepared.toolRosterDeltas.current, pendingAction.toolName)),
|
|
575
|
+
}, prepared.abortController.signal));
|
|
576
|
+
const beltUnsafe = rechecked.action === "deny" ||
|
|
577
|
+
(rechecked.updatedInput !== undefined && !deepJsonEqual(rechecked.updatedInput, resolvedArgs));
|
|
578
|
+
if (beltUnsafe) {
|
|
579
|
+
const editedDenial = formatHookFeedback(`The approver EDITED this call's input; the edited call is refused by the deployment's tool policy and was not executed${rechecked.action === "deny" && rechecked.message ? `: ${rechecked.message}` : " (the policy rewrote the edit to a value that was not approved)"}.`, prepared.reminderMark);
|
|
580
|
+
await settleEnd(true, { content: editedDenial }, vetoed("policy"));
|
|
581
|
+
const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, editedDenial, true));
|
|
582
|
+
emitCommitted(eid, "toolResult", pendingAction.toolCallId);
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
const gateRealApproval = resume.cp.gate.kind === "irreversible_ask" ? resume.cp.gate.realApproval : undefined;
|
|
587
|
+
const gateOrgGoverned = realApprovalOrgFact(gateRealApproval) !== undefined;
|
|
588
|
+
if (gateOrgGoverned && prepared.permissionRuleOrg === undefined) {
|
|
589
|
+
const unwiredDenial = formatHookFeedback(`The approved tool call "${pendingAction.toolName}" was not executed: its approval was minted under organization governance (${gateRealApproval.origin}), and this worker has no org adjudication wiring — a governed approval may only be redeemed where governance can be enforced. This approval is spent; re-issue the call on an org-wired worker.`, prepared.reminderMark);
|
|
590
|
+
await settleEnd(true, { content: unwiredDenial }, vetoed("org"));
|
|
591
|
+
const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, unwiredDenial, true));
|
|
592
|
+
emitCommitted(eid, "toolResult", pendingAction.toolCallId);
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
if (prepared.permissionRuleOrg !== undefined) {
|
|
596
|
+
const orgVerdict = prepared.permissionRuleOrg
|
|
597
|
+
.adjudicate({ toolName: pendingAction.toolName, args: resolvedArgs, toolCallId: pendingAction.toolCallId })
|
|
598
|
+
.catch(() => ({ status: "unavailable", disclosures: ["the org adjudication face threw on resume"] }));
|
|
599
|
+
let orgWaitCancelled = false;
|
|
600
|
+
const org = await settleOrgVerdictWithin(orgVerdict, { status: "unavailable", disclosures: [`the org adjudication face did not answer within ${ORG_ADJUDICATION_TIMEOUT_MS}ms (or the task ended first)`] }, {
|
|
601
|
+
signal: prepared.abortController.signal,
|
|
602
|
+
timeoutMs: ORG_ADJUDICATION_TIMEOUT_MS,
|
|
603
|
+
onFallback: (cause) => {
|
|
604
|
+
orgWaitCancelled = cause === "aborted";
|
|
605
|
+
},
|
|
606
|
+
});
|
|
607
|
+
const blocked = org.status === "unavailable"
|
|
608
|
+
? realApprovalOrgFact(gateRealApproval) === "unavailable"
|
|
609
|
+
? undefined
|
|
610
|
+
: orgWaitCancelled
|
|
611
|
+
? "this deployment is org-governed and the task was cancelled before the organization policy snapshot could be adjudicated"
|
|
612
|
+
: "this deployment is org-governed and cannot currently adjudicate against an organization policy snapshot"
|
|
613
|
+
: org.verdict?.behavior === "deny"
|
|
614
|
+
? `an organization policy rule (${org.verdict.rule}) denies it`
|
|
615
|
+
: undefined;
|
|
616
|
+
if (blocked !== undefined) {
|
|
617
|
+
const orgDisclosures = org.status === "unavailable" && org.disclosures.length > 0
|
|
618
|
+
? ` Governance disclosures: ${inlineUntrusted(org.disclosures.join("; "), ORG_DISCLOSURE_MAX_CHARS)}.`
|
|
619
|
+
: "";
|
|
620
|
+
const orgDenial = formatHookFeedback(`The approved tool call "${pendingAction.toolName}" was not executed: ${blocked}.${orgDisclosures} This approval is spent — the call has to be re-issued and approved again once organization policy permits it.`, prepared.reminderMark);
|
|
621
|
+
await settleEnd(true, { content: orgDenial }, vetoed("org"));
|
|
622
|
+
const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, orgDenial, true));
|
|
623
|
+
emitCommitted(eid, "toolResult", pendingAction.toolCallId);
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
if (prepared.denyNarrowingPolicy) {
|
|
628
|
+
const narrowed = refuseOutOfContractDecision(await prepared.denyNarrowingPolicy.check({
|
|
629
|
+
toolName: pendingAction.toolName,
|
|
630
|
+
args: resolvedArgs,
|
|
631
|
+
toolCallId: pendingAction.toolCallId,
|
|
632
|
+
...callFaceSeat(toolCallFaceOf(prepared.toolRosterDeltas.current, pendingAction.toolName)),
|
|
633
|
+
budget: beltBudget,
|
|
634
|
+
...(prepared.cwdRef !== undefined ? { cwd: prepared.cwdRef.current } : {}),
|
|
635
|
+
}, prepared.abortController.signal));
|
|
636
|
+
if (narrowed.action === "deny") {
|
|
637
|
+
const narrowedDenial = formatHookFeedback(`The approved tool call "${pendingAction.toolName}" is now denied by a session rule and was not executed${narrowed.message ? `: ${narrowed.message}` : ""}.`, prepared.reminderMark);
|
|
638
|
+
await settleEnd(true, { content: narrowedDenial }, vetoed("policy"));
|
|
639
|
+
const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, narrowedDenial, true));
|
|
640
|
+
emitCommitted(eid, "toolResult", pendingAction.toolCallId);
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
if (prepared.persistedRuleLane !== undefined) {
|
|
645
|
+
const unreadable = { unreadable: true };
|
|
646
|
+
const read = await settleOrgVerdictWithin(Promise.resolve()
|
|
647
|
+
.then(() => prepared.persistedRuleLane.adjudicate({
|
|
648
|
+
toolName: pendingAction.toolName,
|
|
649
|
+
args: resolvedArgs,
|
|
650
|
+
toolCallId: pendingAction.toolCallId,
|
|
651
|
+
...callFaceSeat(toolCallFaceOf(prepared.toolRosterDeltas.current, pendingAction.toolName)),
|
|
652
|
+
budget: beltBudget,
|
|
653
|
+
...(prepared.cwdRef !== undefined ? { cwd: prepared.cwdRef.current } : {}),
|
|
654
|
+
}))
|
|
655
|
+
.then((answer) => normalizePersistedRuleHit(answer)), unreadable, { signal: prepared.abortController.signal, timeoutMs: ORG_ADJUDICATION_TIMEOUT_MS });
|
|
656
|
+
const tightened = applyPersistedTightening({ action: "allow" }, read);
|
|
657
|
+
if (tightened.tightened === "deny" || tightened.tightened === "unreadable") {
|
|
658
|
+
const why = tightened.tightened === "deny"
|
|
659
|
+
? `a standing deny rule of yours (${disclosedRuleSet(read.hit?.rules ?? [])}) now refuses it`
|
|
660
|
+
: "your persisted permission rules could not be read on this leg";
|
|
661
|
+
const ruleDenial = formatHookFeedback(`The approved tool call "${pendingAction.toolName}" was not executed: ${why}. This approval is spent — the call has to be re-issued and approved again.`, prepared.reminderMark);
|
|
662
|
+
await settleEnd(true, { content: ruleDenial }, vetoed("persisted_rule"));
|
|
663
|
+
const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, ruleDenial, true));
|
|
664
|
+
emitCommitted(eid, "toolResult", pendingAction.toolCallId);
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
const tool = prepared.tools.find((t) => t.name === pendingAction.toolName);
|
|
669
|
+
if (!tool) {
|
|
670
|
+
const e = new Error(`the approved tool "${pendingAction.toolName}" is no longer available on resume`);
|
|
671
|
+
e.code = "resume.tool_unavailable";
|
|
672
|
+
throw e;
|
|
673
|
+
}
|
|
674
|
+
const args = resolvedArgs;
|
|
675
|
+
onExecuteStart?.(pendingAction.toolCallId);
|
|
676
|
+
prepared.suspendProgressRef.executedApproved = true;
|
|
677
|
+
let res;
|
|
678
|
+
try {
|
|
679
|
+
res = await tool.execute(pendingAction.toolCallId, args, prepared.abortController.signal);
|
|
680
|
+
}
|
|
681
|
+
catch (err) {
|
|
682
|
+
const execError = `Error: ${err instanceof Error ? err.message : String(err)}`;
|
|
683
|
+
const marks = (() => {
|
|
684
|
+
if (err === null || typeof err !== "object")
|
|
685
|
+
return undefined;
|
|
686
|
+
const src = err;
|
|
687
|
+
let d;
|
|
688
|
+
if (src.details !== null && typeof src.details === "object" && !Array.isArray(src.details)) {
|
|
689
|
+
d = { ...src.details };
|
|
690
|
+
}
|
|
691
|
+
if (typeof src.errorKind === "string")
|
|
692
|
+
d = { ...(d ?? {}), errorKind: src.errorKind };
|
|
693
|
+
return d;
|
|
694
|
+
})();
|
|
695
|
+
await settleEnd(true, { content: execError, ...(marks !== undefined ? { details: marks } : {}) });
|
|
696
|
+
const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, execError, true));
|
|
697
|
+
emitCommitted(eid, "toolResult", pendingAction.toolCallId);
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
const executedIsError = res.isError === true;
|
|
701
|
+
await settleEnd(executedIsError, res);
|
|
702
|
+
onResolvedToolSuccess?.(pendingAction.toolName, executedIsError ? undefined : res.details);
|
|
703
|
+
const eid = await prepared.session.appendMessage({
|
|
704
|
+
role: "toolResult",
|
|
705
|
+
toolCallId: pendingAction.toolCallId,
|
|
706
|
+
toolName: pendingAction.toolName,
|
|
707
|
+
content: res.content,
|
|
708
|
+
details: res.details,
|
|
709
|
+
isError: executedIsError,
|
|
710
|
+
timestamp: Date.now(),
|
|
711
|
+
});
|
|
712
|
+
emitCommitted(eid, "toolResult", pendingAction.toolCallId);
|
|
713
|
+
}
|
|
@@ -4,7 +4,7 @@ import type { SessionStore } from "../session.js";
|
|
|
4
4
|
import { type PendingSessionNotifications, type SystemInjectionPriority, type TaskNotificationPayload } from "../task-notification.js";
|
|
5
5
|
import type { RunnerDeps, TaskEvent, TaskSpec } from "../types.js";
|
|
6
6
|
import type { SessionReadFileStates } from "./prepare-hands-readface.js";
|
|
7
|
-
import type { NotificationLaneBindings, Prepared,
|
|
7
|
+
import type { NotificationLaneBindings, Prepared, PrepareTaskFn, ResumeRun, RunInternals, RunnerDepsSeat, RunnerSelfSeat, TaskIdRef } from "./contracts.js";
|
|
8
8
|
export interface RunNotificationLaneInput<R> {
|
|
9
9
|
/** borrowed-readonly — the task spec: prepare's input, and the principal the peer scope is minted from. */
|
|
10
10
|
spec: TaskSpec;
|
|
@@ -28,8 +28,9 @@ export interface RunNotificationLaneInput<R> {
|
|
|
28
28
|
sessionReadStates: SessionReadFileStates;
|
|
29
29
|
/** borrowed-mutable — the Runner's per-session parked-notification store: the torn-down lane and the escalation pend here. */
|
|
30
30
|
pendingSessionNotifications: PendingSessionNotifications;
|
|
31
|
-
/** borrowed-readonly — the orchestrator's entry (a lane may not name the orchestrator; the driver hands it in)
|
|
32
|
-
|
|
31
|
+
/** borrowed-readonly — the orchestrator's entry (a lane may not name the orchestrator; the driver hands it in), as the ONE
|
|
32
|
+
* contract the orchestrator's own declaration is pinned to ({@link PrepareTaskFn}, contracts.ts — design/393 S7, #675). */
|
|
33
|
+
prepareTask: PrepareTaskFn;
|
|
33
34
|
/** borrowed-readonly — the lanes after this one, entered in this lane's last continuation with what it prepared and bound. */
|
|
34
35
|
next: (lane: RunNotificationLaneResult) => Promise<R>;
|
|
35
36
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { Model } from "../../internal/llm.js";
|
|
2
2
|
import { type MaybeCompactOptions } from "../auto-compaction.js";
|
|
3
|
-
import type { HookInvocationIdentity } from "../hooks.js";
|
|
4
3
|
import type { PushQueue } from "../push-queue.js";
|
|
5
4
|
import type { Brain, TaskEvent, TaskSpec } from "../types.js";
|
|
6
|
-
import type { Prepared, RunnerDepsSeat, RunState } from "./contracts.js";
|
|
5
|
+
import type { InstallingPhaseResult, Prepared, RunnerDepsSeat, RunState } from "./contracts.js";
|
|
7
6
|
export interface RunRecoveryLanesInput {
|
|
8
7
|
/** borrowed-readonly — the task spec: the compaction settings / instructions and the key-and-headers seat. */
|
|
9
8
|
spec: TaskSpec;
|
|
@@ -31,24 +30,12 @@ export interface RunRecoveryLanesInput {
|
|
|
31
30
|
};
|
|
32
31
|
/** borrowed-readonly — the window-safety option builder (the compaction-machinery lane's), per pass. */
|
|
33
32
|
windowSafetyOptions: (mainModel: Model) => Pick<MaybeCompactOptions, "fallbackBudget" | "onWindowSafety">;
|
|
34
|
-
/** borrowed-readonly — the Runner's deployment deps, read LIVE (`onError
|
|
33
|
+
/** borrowed-readonly — the Runner's deployment deps, read LIVE (`onError`; the compaction seams the pass reaches down
|
|
34
|
+
* for — compaction-seams.ts — read the summary provider and the hooks slot through it on every pass). */
|
|
35
35
|
runner: RunnerDepsSeat;
|
|
36
|
-
/** borrowed-readonly — the Runner's three compaction methods as delegates: the Seam C reuse options, the hook
|
|
37
|
-
* option wrapper and the reuse counter. The method bodies stay the Runner's; the pass calls them as the run body did. */
|
|
38
|
-
compactionSeats: {
|
|
39
|
-
seamCCompactionOptions: (prepared: Prepared) => Pick<MaybeCompactOptions, "summaryProvider" | "onCompaction" | "maxConsecutiveProviderReuse" | "consecutiveProviderReuse"> | undefined;
|
|
40
|
-
compactionHookOptions: (spec: TaskSpec, sessionId: string, trigger: "auto" | "manual" | "forced", identity?: HookInvocationIdentity, seatBound?: {
|
|
41
|
-
timeoutMs: number;
|
|
42
|
-
signal?: AbortSignal;
|
|
43
|
-
}) => Pick<MaybeCompactOptions, "trigger" | "preCompact" | "postCompact">;
|
|
44
|
-
recordCompactionReuse: (prepared: Prepared, comp: {
|
|
45
|
-
compacted: boolean;
|
|
46
|
-
reused?: boolean;
|
|
47
|
-
}) => void;
|
|
48
|
-
};
|
|
49
36
|
}
|
|
50
37
|
/** Nothing comes back: the lane's products are INSTALLED on the seats it borrowed — the harness's loop recovery
|
|
51
38
|
* chain and the microCompact arm-B seat — and the shared pass is read by those two installations alone. */
|
|
52
|
-
export interface RunRecoveryLanesResult {
|
|
39
|
+
export interface RunRecoveryLanesResult extends InstallingPhaseResult {
|
|
53
40
|
}
|
|
54
41
|
export declare function runRecoveryLanes(input: RunRecoveryLanesInput): RunRecoveryLanesResult;
|
|
@@ -7,8 +7,9 @@ import { rebaseCadenceWindows } from "./turn-attachments.js";
|
|
|
7
7
|
import { buildWorkingFileAttachments, centerAdoptionOption, contextInstructionFilesOption, emitInputTruncated, forkContextOption } from "./compaction-call-options.js";
|
|
8
8
|
import { gitRestateOption } from "./git-leg-delivery.js";
|
|
9
9
|
import { COMPACTION_FREED_EPSILON, COMPACTION_REGROWTH_FACTOR, MAX_CONSECUTIVE_COMPACTION_FAILURES } from "./compaction-knobs.js";
|
|
10
|
+
import { compactionHookOptions, recordCompactionReuse, seamCCompactionOptions } from "./compaction-seams.js";
|
|
10
11
|
export function runRecoveryLanes(input) {
|
|
11
|
-
const { spec, prepared, queue, rs, ident, compactionBrain, compactionBreaker, windowSafetyOptions, runner
|
|
12
|
+
const { spec, prepared, queue, rs, ident, compactionBrain, compactionBreaker, windowSafetyOptions, runner } = input;
|
|
12
13
|
const runForcedCompactionPass = async (lane, turnSignal) => {
|
|
13
14
|
if (!(spec.compaction?.enabled ?? true))
|
|
14
15
|
return false;
|
|
@@ -37,14 +38,14 @@ export function runRecoveryLanes(input) {
|
|
|
37
38
|
workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
|
|
38
39
|
...contextInstructionFilesOption(prepared),
|
|
39
40
|
...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
|
|
40
|
-
...
|
|
41
|
+
...seamCCompactionOptions(runner, prepared),
|
|
41
42
|
...gitRestateOption(prepared),
|
|
42
43
|
...windowSafetyOptions(prepared.harness.getModel()),
|
|
43
|
-
...
|
|
44
|
+
...compactionHookOptions(runner, spec, prepared.sessionId, "forced", prepared.hookIdentity, { timeoutMs: prepared.hookTimeoutMs, signal: passSignal }),
|
|
44
45
|
});
|
|
45
46
|
if (comp.compacted) {
|
|
46
47
|
compactionBreaker.failures = 0;
|
|
47
|
-
|
|
48
|
+
recordCompactionReuse(runner, prepared, comp);
|
|
48
49
|
if ((comp.freedTokens ?? 0) >= COMPACTION_FREED_EPSILON) {
|
|
49
50
|
const postSize = comp.postTriggerTokens ?? Math.max(0, (comp.triggerTokens ?? comp.tokensBefore ?? 0) - (comp.freedTokens ?? 0));
|
|
50
51
|
rs.counters.compactionFloor = Math.ceil(postSize * COMPACTION_REGROWTH_FACTOR);
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
* compaction, the forwarded-frame drain and the queue's `done` + close, the file-history boundary settle and the
|
|
10
10
|
* prompt-suggestion kickoff — then, in its finally, the four teardown legs in the order they were: the shell-lane
|
|
11
11
|
* children settle, the background-shell sweep, the registry clears / the background-agent abort / the retained
|
|
12
|
-
* child sessions, and the owned env's teardown.
|
|
12
|
+
* child sessions, and the owned env's teardown. The suggestion pass (`suggestNextPrompts`, with its four bounds) and the
|
|
13
|
+
* owned-env teardown (`teardownOwnedEnv`) are the lane's own module-private functions since design/393 S7, verbatim from
|
|
14
|
+
* the Runner's private methods: each has this one caller, and a sibling file would be a lane-to-lane reach (the S6 legs' reading).
|
|
13
15
|
*
|
|
14
16
|
* Async (eleven first-level awaits, all of them the same awaits at the same positions). The `queue.push("done")` and
|
|
15
17
|
* the teardown legs' order are contract (the forwarded-frame drain lands before `done`; the env is torn down after
|
|
@@ -21,9 +23,9 @@ import type { AssistantMessage } from "../../internal/llm.js";
|
|
|
21
23
|
import type { ResolvedReasoning } from "../../brain/reasoning.js";
|
|
22
24
|
import type { PushQueue } from "../push-queue.js";
|
|
23
25
|
import type { SessionStore } from "../session.js";
|
|
24
|
-
import type
|
|
26
|
+
import { type CompactOutcome, type DelegationLifecycleEvent, type TaskEvent, type TaskResult, type TaskSpec } from "../types.js";
|
|
25
27
|
import { type Stats } from "./assemble-result.js";
|
|
26
|
-
import type { EndOfTaskCompaction, ManualCompactRef, Prepared, ResumeRun, RunInternals, RunnerDepsSeat, RunState, SuspendReap, TaskIdRef } from "./contracts.js";
|
|
28
|
+
import type { EndOfTaskCompaction, InstallingPhaseResult, ManualCompactRef, Prepared, ResumeRun, RunInternals, RunnerDepsSeat, RunState, SuspendReap, TaskIdRef } from "./contracts.js";
|
|
27
29
|
export interface RunSettleAndTeardownInput {
|
|
28
30
|
/** borrowed-readonly — the task spec: the hooks slot, the suggestion opt-in, the retain / forward flags, the task id and principal. */
|
|
29
31
|
spec: TaskSpec;
|
|
@@ -76,6 +78,11 @@ export interface RunSettleAndTeardownInput {
|
|
|
76
78
|
threw: unknown;
|
|
77
79
|
/** borrowed-readonly — the live-abort flag captured before the leg's release-abort. */
|
|
78
80
|
abortedLive: boolean;
|
|
81
|
+
/** borrowed-readonly — the leg's snapshot of `loopLatch.userInterrupted`: names the origin of a stop that landed after the answer settled. */
|
|
82
|
+
userInterruptedLive: boolean;
|
|
83
|
+
/** borrowed-readonly — #677: the terminal-adoption lane's ONE evaluation of `answerSettled` (a clean `"stop"` final, no continuation
|
|
84
|
+
* lost). Read by the arbitration (`ResultFlags.answerSettled`), the teardown's stop-source attribution and the notice. */
|
|
85
|
+
answerSettled: boolean;
|
|
79
86
|
/** borrowed-readonly — design/174: the answered-but-never-collected deliveries the leg's finally settled. */
|
|
80
87
|
strandedHumanAnswers: ReadonlyArray<{
|
|
81
88
|
deliveryId: string;
|
|
@@ -93,17 +100,14 @@ export interface RunSettleAndTeardownInput {
|
|
|
93
100
|
onSuggestions: (p: Promise<string[]>) => void;
|
|
94
101
|
/** borrowed-readonly — the stream's reap-stash for a committed pause (what `destroy()` reaps when the run SUSPENDED). */
|
|
95
102
|
onSuspend: (reap: SuspendReap) => void;
|
|
96
|
-
/** borrowed-readonly — the Runner's deployment deps, read LIVE (`onError`, `hooks`, `checkpointStore`, `executionEnv`, `onNotice
|
|
97
|
-
*
|
|
103
|
+
/** borrowed-readonly — the Runner's deployment deps, read LIVE (`onError`, `hooks`, `checkpointStore`, `executionEnv`, `onNotice`; the
|
|
104
|
+
* suggestion pass reads `brain` / `pricing` / `roles` and the owned-env teardown `onError` through it too); the one home of why it
|
|
105
|
+
* is a seat and not a captured object is {@link RunnerDepsSeat}. */
|
|
98
106
|
runner: RunnerDepsSeat;
|
|
99
107
|
/** borrowed-readonly — the session store: the resumed-terminal leg unpins the checkpoint's session through it. */
|
|
100
108
|
sessions: SessionStore;
|
|
101
|
-
/** borrowed-readonly — the Runner's post-completion prompt-suggestion pass (its private method, as a delegate). */
|
|
102
|
-
suggestNextPrompts: (spec: TaskSpec, prepared: Prepared, result: TaskResult) => Promise<string[]>;
|
|
103
|
-
/** borrowed-readonly — the Runner's owned-env teardown (its private method, as a delegate; its gate mirrors the reap-stash's). */
|
|
104
|
-
teardownOwnedEnv: (prepared: Prepared) => Promise<void>;
|
|
105
109
|
}
|
|
106
110
|
/** Nothing comes back: the result is published through `setResult`, the queue is closed, the teardown legs ran. */
|
|
107
|
-
export interface RunSettleAndTeardownResult {
|
|
111
|
+
export interface RunSettleAndTeardownResult extends InstallingPhaseResult {
|
|
108
112
|
}
|
|
109
113
|
export declare function runSettleAndTeardown(input: RunSettleAndTeardownInput): Promise<RunSettleAndTeardownResult>;
|