@sema-agent/core 5.13.0 → 5.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.
Files changed (86) hide show
  1. package/CHANGELOG.md +296 -0
  2. package/dist/agents/send-message-tool.js +1 -0
  3. package/dist/agents/subagent.d.ts +4 -0
  4. package/dist/agents/subagent.js +133 -41
  5. package/dist/brain/anthropic.js +33 -10
  6. package/dist/brain/context-overflow.d.ts +20 -0
  7. package/dist/brain/context-overflow.js +58 -0
  8. package/dist/brain/open-responses.js +24 -10
  9. package/dist/brain/openai.js +29 -11
  10. package/dist/brain/request-params.d.ts +2 -0
  11. package/dist/brain/request-params.js +16 -0
  12. package/dist/brain/stream-engine.d.ts +9 -1
  13. package/dist/brain/stream-engine.js +256 -27
  14. package/dist/brain/timeout.d.ts +1 -0
  15. package/dist/brain/timeout.js +1 -0
  16. package/dist/core/a2a.d.ts +2 -2
  17. package/dist/core/a2a.js +3 -3
  18. package/dist/core/ask-question.d.ts +47 -2
  19. package/dist/core/ask-question.js +209 -28
  20. package/dist/core/background-agent-store.d.ts +2 -0
  21. package/dist/core/checkpoint-store.d.ts +41 -17
  22. package/dist/core/checkpoint-store.js +114 -3
  23. package/dist/core/hooks.d.ts +24 -2
  24. package/dist/core/hooks.js +97 -10
  25. package/dist/core/human-input-projection.d.ts +12 -0
  26. package/dist/core/human-input-projection.js +27 -0
  27. package/dist/core/mcp.d.ts +7 -2
  28. package/dist/core/mcp.js +7 -7
  29. package/dist/core/memory-admission.d.ts +4 -0
  30. package/dist/core/memory-admission.js +3 -0
  31. package/dist/core/runner/assemble-result.d.ts +1 -0
  32. package/dist/core/runner/assemble-result.js +1 -1
  33. package/dist/core/runner/prepare-task.d.ts +16 -6
  34. package/dist/core/runner/prepare-task.js +301 -24
  35. package/dist/core/runner/runtask.d.ts +3 -6
  36. package/dist/core/runner/runtask.js +186 -36
  37. package/dist/core/runner/tool-output-projection.js +1 -0
  38. package/dist/core/session-store.d.ts +3 -0
  39. package/dist/core/session-store.js +4 -0
  40. package/dist/core/session.d.ts +1 -0
  41. package/dist/core/store-contracts/background-agent-store-contract.js +19 -0
  42. package/dist/core/store-contracts/checkpoint-store-contract.js +62 -3
  43. package/dist/core/task-notification.d.ts +2 -0
  44. package/dist/core/task-notification.js +5 -3
  45. package/dist/core/task-registry-agent.d.ts +1 -0
  46. package/dist/core/task-registry-agent.js +6 -0
  47. package/dist/core/task-registry.d.ts +1 -0
  48. package/dist/core/task-registry.js +4 -1
  49. package/dist/core/tool-policy.d.ts +5 -0
  50. package/dist/core/tool-policy.js +2 -1
  51. package/dist/core/types.d.ts +32 -1
  52. package/dist/core/wiring-manifest.d.ts +97 -0
  53. package/dist/core/wiring-manifest.js +186 -0
  54. package/dist/engine/compaction/compaction.js +2 -2
  55. package/dist/engine/harness/agent-harness.d.ts +2 -1
  56. package/dist/engine/harness/agent-harness.js +8 -1
  57. package/dist/engine/harness/types.d.ts +3 -1
  58. package/dist/engine/llm/types.d.ts +7 -0
  59. package/dist/engine/llm/types.js +8 -1
  60. package/dist/engine/session/import-validate.d.ts +6 -1
  61. package/dist/engine/session/import-validate.js +29 -6
  62. package/dist/engine/session/memory-repo.d.ts +3 -1
  63. package/dist/engine/session/memory-repo.js +2 -2
  64. package/dist/index.d.ts +7 -4
  65. package/dist/index.js +7 -4
  66. package/dist/internal/harness-types.d.ts +1 -1
  67. package/dist/internal/llm.d.ts +2 -2
  68. package/dist/internal/llm.js +1 -1
  69. package/dist/orchestration/run-workflow-tool.d.ts +4 -0
  70. package/dist/orchestration/run-workflow-tool.js +3 -0
  71. package/dist/orchestration/workflow-types.d.ts +8 -0
  72. package/dist/orchestration/workflow-types.js +14 -0
  73. package/dist/orchestration/workflow.d.ts +4 -0
  74. package/dist/orchestration/workflow.js +134 -5
  75. package/dist/prompts/default.js +1 -1
  76. package/dist/stores/file/checkpoint-store.d.ts +3 -5
  77. package/dist/stores/file/checkpoint-store.js +31 -2
  78. package/dist/stores/file/index.js +1 -1
  79. package/dist/stores/file/session-store.d.ts +3 -1
  80. package/dist/stores/file/session-store.js +2 -2
  81. package/dist/stores/file/shared-ledger.js +8 -1
  82. package/dist/tools/fs/bash-readonly-classifier.d.ts +3 -0
  83. package/dist/tools/fs/bash-readonly-classifier.js +94 -0
  84. package/dist/tools/fs/fs-bash.js +31 -12
  85. package/dist/tools/fs/safety.js +34 -10
  86. package/package.json +1 -1
@@ -12,6 +12,8 @@ import { primaryActivityArg } from "../arg-summary.js";
12
12
  import { materializeMcpTools } from "../mcp.js";
13
13
  import { materializeA2aTools } from "../a2a.js";
14
14
  import { Type } from "typebox";
15
+ import { Value } from "typebox/value";
16
+ import { uuidv7 } from "../../engine/session/uuid.js";
15
17
  import { brainToRuntime } from "../runtime.js";
16
18
  import { StoredSession, isSessionConflict, hasSessionFork } from "../session.js";
17
19
  import { createSubagentWorktreeHelper, forkGovernanceDenial } from "../../agents/subagent.js";
@@ -24,7 +26,7 @@ import { CHANGED_FILES_MTIME_EPS_MS, fenceMcpServerInstructions, renderAgentList
24
26
  import { inlineUntrusted } from "../untrusted-text.js";
25
27
  import { emitTrace } from "../trace.js";
26
28
  import { createSessionRulePolicy } from "./session-rule-policy.js";
27
- import { cloneObserverInput, formatHookFeedback, runToolGate } from "../hooks.js";
29
+ import { cloneObserverInput, createHookEnvCapabilities, formatHookFeedback, runToolGate } from "../hooks.js";
28
30
  import { reconcileInterruptedSession } from "../session-reconcile.js";
29
31
  import { CacheBreakDetector, toolsToFingerprintInputs } from "../cache-break-detector.js";
30
32
  import { reservedCollisions, reservedFor } from "../../brain/request-params.js";
@@ -64,7 +66,7 @@ import { createMonitorTool } from "../../tools/monitor.js";
64
66
  import { createWorktreeTools } from "../../tools/worktree.js";
65
67
  import { applyCompactionToReadFileState, bashReversibilityProbe, createHandsToolkit, isReadDedupStubResult, seedReadFileStateFromContext, seedReadFileStateFromTranscript, HAND_TOOL_EFFECTS, pdfModelCapabilitiesOf } from "../../tools/fs/index.js";
66
68
  import { decodeTextBytes } from "../../tools/fs/encoding.js";
67
- import { ASK_USER_QUESTION_TOOL_NAME, createAskUserQuestionTool } from "../ask-question.js";
69
+ import { ASK_USER_QUESTION_TOOL_NAME, createAskUserQuestionTool, classifyQuestionOutcome, isLiveQuestionFace, validateAskQuestions, } from "../ask-question.js";
68
70
  import { createSchedulerTools } from "../../tools/scheduler-tools.js";
69
71
  import { createPresentPlanTool, createEnterPlanModeTool, PRESENT_PLAN_TOOL_NAME, ENTER_PLAN_MODE_TOOL_NAME } from "../present-plan-tool.js";
70
72
  import { isSelfOrchestrationActive, selfOrchestrationFailClosedReason } from "../../orchestration/workflow-script-runner.js";
@@ -73,8 +75,9 @@ import { resolveWorkflowSizeGuideline } from "../../orchestration/workflow-size-
73
75
  import { createLspTool, gitCheckIgnoreFilter, resolveLspPath } from "../lsp.js";
74
76
  import { resolveKey } from "../../tools/fs/safety.js";
75
77
  import { wholeFileRecordsFromTranscript } from "./session-file-state-replay.js";
76
- import { BINDING_CHECKPOINT_VERSION, mintCheckpointToken, ORG_ADMISSION_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, buildRiskDescriptor, debitLedger, remainingBudgetMicroUsd, } from "../checkpoint-store.js";
78
+ import { BINDING_CHECKPOINT_VERSION, mintCheckpointToken, ORG_ADMISSION_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, buildRiskDescriptor, debitLedger, remainingBudgetMicroUsd, resolveCheckpointStore, } from "../checkpoint-store.js";
77
79
  import { boundInputHashOf } from "../canonical-json.js";
80
+ import { countElicitOptIns, deriveAskEffective, deriveWiringManifest, resolveAskSeamForm, resolveDeclaredDurability, resolveElicitSeam, resolveQuestionSeam } from "../wiring-manifest.js";
78
81
  import { GLOBAL_USAGE_KEY, resolveUsageWindows, usageRetryAfterMs } from "../usage-window-store.js";
79
82
  const RECONCILE_MAX_RETRIES = 3;
80
83
  const DEFAULT_MAX_SUSPENDS = 5;
@@ -177,11 +180,7 @@ export const DEFAULT_IRREVERSIBLE_SCOPE = "irreversible";
177
180
  export function checkpointScopeOf(spec) {
178
181
  return spec.durableApproval?.scope || spec.principal || DEFAULT_IRREVERSIBLE_SCOPE;
179
182
  }
180
- export function resolveCheckpointStore(spec, deps) {
181
- if (spec.checkpointStore === null)
182
- return undefined;
183
- return spec.checkpointStore ?? deps.checkpointStore;
184
- }
183
+ export { resolveCheckpointStore } from "../checkpoint-store.js";
185
184
  export function isFableFamilyModelId(id) {
186
185
  const tail = id.toLowerCase().split("/").pop() ?? "";
187
186
  return /^claude-fable-\d/.test(tail) || /^claude-mythos-5(?!\d)/.test(tail);
@@ -351,6 +350,54 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
351
350
  { name: "toolResultStore", store: deps.toolResultStore },
352
351
  ],
353
352
  });
353
+ const resolvedInteractionPosture = spec.interactionPosture ?? internals?.parentInteractionPosture ?? deps.interactionPosture;
354
+ {
355
+ const interactionPosture = resolvedInteractionPosture;
356
+ const discloseInteractionPostureRefusal = (err) => {
357
+ try {
358
+ deps.onError?.(err, { phase: "config", sessionId: spec.sessionId ?? "(pre-session)", classification: "interaction-posture-refused" });
359
+ }
360
+ catch {
361
+ }
362
+ };
363
+ if (interactionPosture !== undefined && interactionPosture !== "interactive" && interactionPosture !== "headless") {
364
+ const e = new Error(`interactionPosture ${JSON.stringify(interactionPosture)} is not a recognized posture ("interactive" | "headless") — ` +
365
+ `an unevaluable declaration is refused loudly, never folded to either posture.`);
366
+ e.code = "config.interaction_posture";
367
+ discloseInteractionPostureRefusal(e);
368
+ throw e;
369
+ }
370
+ if (interactionPosture === "interactive") {
371
+ const askDoor = resolveAskSeamForm(spec, deps);
372
+ const humanReachable = deriveAskEffective(askDoor.form, "unresolved") === "human_reachable";
373
+ const questionDoor = resolveQuestionSeam(spec, deps);
374
+ const strippedByEngine = internals?.questionFaceStripped === true;
375
+ if (spec.interactiveTools === false) {
376
+ const e = new Error(`interaction posture "interactive" declared together with interactiveTools: false — the hard-headless ` +
377
+ `clamp removes the AskUserQuestion mount, so no content question can ever reach the human this posture ` +
378
+ `promises. Drop one of the two declarations.`);
379
+ e.code = "config.interaction_posture";
380
+ discloseInteractionPostureRefusal(e);
381
+ throw e;
382
+ }
383
+ if (!humanReachable || !(questionDoor.wired || strippedByEngine)) {
384
+ const missing = [];
385
+ if (!humanReachable) {
386
+ missing.push(askDoor.form === "absent"
387
+ ? "no onAsk approver is wired (spec.onAsk ?? deps.onAsk is absent — asks would auto-deny or park)"
388
+ : `the resolved onAsk seat is the blanket policy "${askDoor.form}" (${askDoor.provenance ?? "?"}) — a policy setting is not a reachable human`);
389
+ }
390
+ if (!questionDoor.wired && !strippedByEngine) {
391
+ missing.push("no content-question channel (spec.onQuestion ?? deps.onQuestion is absent, and this leg is not an engine-stripped background lane)");
392
+ }
393
+ const e = new Error(`interaction posture "interactive" declared, but this assembly cannot reach a human: ${missing.join("; ")}. ` +
394
+ `Wire the missing seam(s), or drop the posture declaration (absent = no check).`);
395
+ e.code = "config.interaction_posture";
396
+ discloseInteractionPostureRefusal(e);
397
+ throw e;
398
+ }
399
+ }
400
+ }
354
401
  resolveTaskLimits(spec.limits);
355
402
  if (spec.resourceSuspend !== undefined) {
356
403
  const rsus = spec.resourceSuspend;
@@ -392,6 +439,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
392
439
  const egressTools = new Set();
393
440
  const irreversibleTools = new Set();
394
441
  const irreversibilityTier = new Map();
442
+ const axisExplicitNegatives = new Map();
395
443
  const reversibilityProbes = new Map();
396
444
  let shellGatedBash = false;
397
445
  let shellGatedMonitor = false;
@@ -958,9 +1006,20 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
958
1006
  const seedAdmittedOrg = seedInheritedGate?.admittedOrgScopes;
959
1007
  const inheritedAdmittedOrgScopes = liveAdmittedOrg === undefined ? seedAdmittedOrg : seedAdmittedOrg === undefined ? liveAdmittedOrg : liveAdmittedOrg.filter((s) => seedAdmittedOrg.includes(s));
960
1008
  const inheritedOrgGoverned = liveInheritedGate?.orgAdmissionGoverned === true || seedInheritedGate?.orgAdmissionGoverned === true;
961
- const priorOwnOrgVerdict = resume?.seed.inheritedGate?.ownAdmittedOrgScopes !== undefined
1009
+ const checkpointOwnOrgVerdict = resume?.seed.inheritedGate?.ownAdmittedOrgScopes !== undefined
962
1010
  ? { scopes: resume.seed.inheritedGate.ownAdmittedOrgScopes, writeScope: resume.seed.inheritedGate.ownAdmittedOrgWriteScope ?? null }
963
1011
  : undefined;
1012
+ const refOwnOrgVerdict = internals?.ownOrgAdmissionRef?.current;
1013
+ const priorOwnOrgVerdict = checkpointOwnOrgVerdict === undefined
1014
+ ? refOwnOrgVerdict
1015
+ : refOwnOrgVerdict === undefined
1016
+ ? checkpointOwnOrgVerdict
1017
+ : {
1018
+ scopes: checkpointOwnOrgVerdict.scopes.filter((sc) => refOwnOrgVerdict.scopes.includes(sc)),
1019
+ writeScope: checkpointOwnOrgVerdict.writeScope !== null && checkpointOwnOrgVerdict.writeScope === refOwnOrgVerdict.writeScope
1020
+ ? checkpointOwnOrgVerdict.writeScope
1021
+ : null,
1022
+ };
964
1023
  const orgGovernedProvenance = deps.memoryScopeAdmission !== undefined ||
965
1024
  (deps.deploymentMemoryScopes !== undefined && deps.deploymentMemoryScopes.length > 0) ||
966
1025
  deps.compliancePostureResolver !== undefined ||
@@ -1055,6 +1114,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
1055
1114
  : {}),
1056
1115
  sessionId,
1057
1116
  ...(spec.backgroundScope !== undefined ? { backgroundScope: spec.backgroundScope } : {}),
1117
+ ...(resolvedInteractionPosture !== undefined ? { interactionPosture: resolvedInteractionPosture } : {}),
1058
1118
  ...(deps.onBackgroundChildEvent ? { onBackgroundChildEvent: deps.onBackgroundChildEvent } : {}),
1059
1119
  ...(internals?.onTaskNotification ? { onTaskNotification: internals.onTaskNotification } : {}),
1060
1120
  ...(forwardEvent ? { forwardEvent } : {}),
@@ -1208,6 +1268,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
1208
1268
  ...(spec.getApiKeyAndHeaders !== undefined ? { parentGetApiKeyAndHeaders: spec.getApiKeyAndHeaders } : {}),
1209
1269
  principal: spec.principal,
1210
1270
  oneShot: spec.oneShot,
1271
+ ...(resolvedInteractionPosture !== undefined ? { parentInteractionPosture: resolvedInteractionPosture } : {}),
1272
+ autoModeReview: () => (autoModeDecider !== undefined ? { decider: autoModeDecider } : undefined),
1211
1273
  workflowDepth: internals?.workflowDepth,
1212
1274
  parentCwd: taskRootPath,
1213
1275
  parentThinking: () => harnessRef.current?.getThinkingLevel() ?? thinking,
@@ -1380,6 +1442,12 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
1380
1442
  irreversibilityTier.set(axis.name, "always");
1381
1443
  irreversibleTools.add(axis.name);
1382
1444
  }
1445
+ if (axis.irreversibility === "never") {
1446
+ axisExplicitNegatives.set(axis.name, { ...axisExplicitNegatives.get(axis.name), irreversible: false });
1447
+ }
1448
+ if (axis.egress === false) {
1449
+ axisExplicitNegatives.set(axis.name, { ...axisExplicitNegatives.get(axis.name), egress: false });
1450
+ }
1383
1451
  if (axis.egress) {
1384
1452
  if (axis.effect !== undefined && axis.effect !== "write") {
1385
1453
  const e = new Error(`${protocolLabel} tool "${axis.name}" resolves to egress:true with effect:"${axis.effect}" — an egress tool (external write) must have effect:"write". Clear egress (toolAxes egress:false) if it is a pure read, or set effect:"write".`);
@@ -1535,6 +1603,11 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
1535
1603
  }
1536
1604
  tools.push(...band.map((t) => firstPartyOffload(t)));
1537
1605
  const shellGate = effectiveShellGate;
1606
+ if (shellGate === "off" && !(executionEnv instanceof StubExecutionEnv) && spec.handsReadOnly !== true) {
1607
+ deps.onError?.(new Error(`shell gate doctrine is "off" while a real writable shell (Bash) is mounted — no shell safety-axis ` +
1608
+ `fold applies to this run (commands are adjudicated by the ordinary policy/hook chain only). ` +
1609
+ `Set spec.shellGate to "classify" or "always" if this deployment expects doctrine-gated shell behavior.`), { phase: "config", sessionId, classification: "shell-gate-off" });
1610
+ }
1538
1611
  if (shellGate !== "off" && !(executionEnv instanceof StubExecutionEnv) && spec.handsReadOnly !== true) {
1539
1612
  shellGatedBash = !egressTools.has("Bash") && !irreversibilityTier.has("Bash");
1540
1613
  irreversibilityTier.set("Bash", shellGate === "always" ? "always" : "maybe");
@@ -1655,10 +1728,79 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
1655
1728
  if (offloadStore)
1656
1729
  tools.push(createReadToolResultTool(offloadStore));
1657
1730
  const onQuestion = frozenOnQuestion;
1731
+ const liveQuestionFace = isLiveQuestionFace(onQuestion) ? onQuestion : undefined;
1732
+ const contentAskBindings = new Map();
1733
+ const CONTENT_ASK_BINDING_CAP = 32;
1734
+ const contentAskRoutable = (toolCallId) => liveQuestionFace !== undefined &&
1735
+ mountedQuestionTool !== undefined &&
1736
+ tools.includes(mountedQuestionTool) &&
1737
+ runtimeCaps?.forceDurableGate !== true &&
1738
+ !inheritedUnavailableAsks.has(toolCallId);
1739
+ const lateStrandedAnswers = [];
1740
+ const discloseStrandedAnswers = (records, why) => {
1741
+ if (records.length === 0)
1742
+ return;
1743
+ try {
1744
+ deps.onError?.(new Error(`AskUserQuestion: ${records.length} question(s) were answered by a person but the call never ` +
1745
+ `executed to collect the answer (${records.map((r) => `${r.toolCallId} [delivery ${r.deliveryId}]`).join(", ")}) — ${why}. The answer(s) were NOT ` +
1746
+ `delivered to the model and are gone with this leg; re-ask if the decision is still needed.`), { phase: "degraded", sessionId, classification: "unconsumed-human-answer" });
1747
+ }
1748
+ catch {
1749
+ }
1750
+ };
1751
+ const settleContentAskBindings = () => {
1752
+ const stranded = [];
1753
+ for (const [callId, bound] of contentAskBindings) {
1754
+ if (bound.kind === "answered")
1755
+ stranded.push({ deliveryId: bound.deliveryId, toolCallId: callId });
1756
+ }
1757
+ contentAskBindings.clear();
1758
+ discloseStrandedAnswers(stranded, "the leg ended first (abort, batch teardown, or a loop failure)");
1759
+ const byDelivery = new Map();
1760
+ for (const r of [...stranded, ...lateStrandedAnswers])
1761
+ byDelivery.set(r.deliveryId, r);
1762
+ return [...byDelivery.values()];
1763
+ };
1658
1764
  const durableQuestionFace = resolveCheckpointStore(spec, deps) !== undefined &&
1659
1765
  (spec.durableApproval !== undefined || runtimeCaps?.forceDurableGate === true);
1660
- if (spec.interactiveTools === true || (spec.interactiveTools !== false && (onQuestion !== undefined || durableQuestionFace)))
1661
- tools.push(createAskUserQuestionTool(onQuestion, { principal: spec.principal, sourceTaskId: sessionId }));
1766
+ const mountedQuestionFace = liveQuestionFace !== undefined
1767
+ ? async (req, signal) => {
1768
+ const bound = contentAskBindings.get(req.toolCallId);
1769
+ if (bound !== undefined) {
1770
+ if (bound.questionsHash === boundInputHashOf(req.questions)) {
1771
+ contentAskBindings.delete(req.toolCallId);
1772
+ if (bound.kind === "answered")
1773
+ return bound.answer;
1774
+ throw bound.error;
1775
+ }
1776
+ contentAskBindings.delete(req.toolCallId);
1777
+ }
1778
+ return liveQuestionFace(req, signal);
1779
+ }
1780
+ : onQuestion;
1781
+ const questionToolMounted = spec.interactiveTools === true || (spec.interactiveTools !== false && (onQuestion !== undefined || durableQuestionFace));
1782
+ let mountedQuestionTool;
1783
+ if (questionToolMounted)
1784
+ tools.push((mountedQuestionTool =
1785
+ createAskUserQuestionTool(mountedQuestionFace, { principal: spec.principal, sourceTaskId: sessionId }, {
1786
+ ...(resume?.redeemedContentAskCallId !== undefined
1787
+ ? {
1788
+ redeemedApprovalCallId: resume.redeemedContentAskCallId,
1789
+ ...(resume.redeemedContentAskQuestionsHash !== undefined ? { redeemedApprovalQuestionsHash: resume.redeemedContentAskQuestionsHash } : {}),
1790
+ }
1791
+ : {}),
1792
+ ...(resolvedInteractionPosture !== undefined ? { posture: resolvedInteractionPosture } : {}),
1793
+ ...(spec.interactiveQuestionFallback === true ? { interactiveFallback: true } : {}),
1794
+ onSyntheticContinuation: ({ questionId, reason }) => {
1795
+ deps.onError?.(new Error(`AskUserQuestion ${questionId}: no human answer was obtainable (` +
1796
+ (reason === "seam_absent"
1797
+ ? "no onQuestion seam is wired"
1798
+ : reason === "declined_unavailable"
1799
+ ? "the wired question channel reported nobody was reachable"
1800
+ : "the wired question channel failed") +
1801
+ `) — the model was instructed to self-answer and the run CONTINUES (warning, not a failure).`), { phase: "degraded", sessionId, classification: "no-human-autoanswered" });
1802
+ },
1803
+ })));
1662
1804
  if (spec.handsReadOnly !== true) {
1663
1805
  const sessionScope = sessionId ?? spec.principal ?? spec.taskId ?? "default";
1664
1806
  tools.push(...createSchedulerTools(executionEnv, {
@@ -1721,6 +1863,9 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
1721
1863
  });
1722
1864
  memoryAdmittedOrgScopesRef.current = memoryAdmittedOrgScopes;
1723
1865
  ownOrgVerdictRef.current = memoryOwnOrgVerdict ?? priorOwnOrgVerdict;
1866
+ if (internals?.ownOrgAdmissionRef !== undefined && ownOrgVerdictRef.current !== undefined) {
1867
+ internals.ownOrgAdmissionRef.current = ownOrgVerdictRef.current;
1868
+ }
1724
1869
  let memoryBlock = memoryBlockFromEngine;
1725
1870
  if (memorySeedFiles?.length && seedContextFiles) {
1726
1871
  try {
@@ -2117,6 +2262,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
2117
2262
  model,
2118
2263
  deferNames: (toolFaceSnapshot.defer ?? []).filter((n) => tools.some((t) => t.name === n)),
2119
2264
  alwaysLoadNames: [
2265
+ ASK_USER_QUESTION_TOOL_NAME,
2120
2266
  ...(toolFaceSnapshot.alwaysLoad ?? []),
2121
2267
  ...mcp.tools
2122
2268
  .filter((t) => t.mcpAlwaysLoad === true && !(toolFaceSnapshot.defer ?? []).includes(t.name))
@@ -2598,6 +2744,15 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
2598
2744
  ? { sourceAgentName: internals?.explicitAgentName ?? internals?.agentName }
2599
2745
  : {}),
2600
2746
  });
2747
+ const riskAxesOf = (toolName) => {
2748
+ const tier = irreversibilityTier.get(toolName);
2749
+ const negatives = axisExplicitNegatives.get(toolName);
2750
+ const irreversible = tier === "always" || tier === "maybe" ? true : tier === "never" ? false : negatives?.irreversible;
2751
+ const egress = egressTools.has(toolName) ? true : negatives?.egress;
2752
+ if (irreversible === undefined && egress === undefined)
2753
+ return {};
2754
+ return { riskAxes: { ...(irreversible !== undefined ? { irreversible } : {}), ...(egress !== undefined ? { egress } : {}) } };
2755
+ };
2601
2756
  const recheckApprovedEdit = async (pol, onAskOf, creq, edit, csignal) => {
2602
2757
  let editArgs = edit;
2603
2758
  for (let round = 0;; round++) {
@@ -2630,6 +2785,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
2630
2785
  args: editArgs,
2631
2786
  message: re.message ?? `approval required for "${creq.toolName}" (inherited parent policy)`,
2632
2787
  ...askSourceIdentity(),
2788
+ ...riskAxesOf(creq.toolName),
2633
2789
  ...(re.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
2634
2790
  }, onAskOf, csignal ?? abortController.signal);
2635
2791
  if (rr.action !== "allow")
@@ -2654,8 +2810,9 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
2654
2810
  return first;
2655
2811
  if (first.action === "allow")
2656
2812
  return { action: "allow" };
2657
- if (creq.toolName === ASK_USER_QUESTION_TOOL_NAME)
2813
+ if (creq.toolName === ASK_USER_QUESTION_TOOL_NAME && (pc.durableMandate !== true || markInheritedUnavailable(creq.toolCallId))) {
2658
2814
  return first;
2815
+ }
2659
2816
  if (pc.durableMandate === true) {
2660
2817
  if (resolveCheckpointStore(spec, deps) !== undefined &&
2661
2818
  (spec.durableApproval !== undefined || runtimeCaps?.forceDurableGate === true) &&
@@ -2676,6 +2833,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
2676
2833
  args: presentedArgs,
2677
2834
  message: first.message ?? `approval required for "${creq.toolName}" (inherited parent policy)`,
2678
2835
  ...askSourceIdentity(),
2836
+ ...riskAxesOf(creq.toolName),
2679
2837
  ...(first.action === "ask" && first.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
2680
2838
  }, pc.onAsk, csignal ?? abortController.signal);
2681
2839
  const askWaitMs = Math.max(0, now() - askT0);
@@ -2710,8 +2868,9 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
2710
2868
  }
2711
2869
  if (decision.action !== "ask")
2712
2870
  return decision;
2713
- if (creq.toolName === ASK_USER_QUESTION_TOOL_NAME)
2871
+ if (creq.toolName === ASK_USER_QUESTION_TOOL_NAME && (pc.durableMandate !== true || markInheritedUnavailable(creq.toolCallId))) {
2714
2872
  return decision;
2873
+ }
2715
2874
  if (pc.durableMandate === true) {
2716
2875
  if (resolveCheckpointStore(spec, deps) !== undefined &&
2717
2876
  (spec.durableApproval !== undefined || runtimeCaps?.forceDurableGate === true) &&
@@ -2732,6 +2891,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
2732
2891
  args: presentedArgs,
2733
2892
  message: decision.message ?? `approval required for "${creq.toolName}" (inherited parent policy)`,
2734
2893
  ...askSourceIdentity(),
2894
+ ...riskAxesOf(creq.toolName),
2735
2895
  ...(decision.action === "ask" && decision.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
2736
2896
  }, pc.onAsk, csignal ?? abortController.signal);
2737
2897
  const askWaitMs = Math.max(0, now() - askT0);
@@ -2917,6 +3077,42 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
2917
3077
  };
2918
3078
  })();
2919
3079
  const platformSuspendArmed = durableSuspendInfraReady && (envLifetimeSuspendAt !== undefined || usageGovernance !== undefined);
3080
+ const checkpointStore = resolveCheckpointStore(spec, deps);
3081
+ const durableApproval = spec.durableApproval ??
3082
+ (runtimeCaps?.forceDurableGate ? { scope: spec.principal || DEFAULT_IRREVERSIBLE_SCOPE } : undefined);
3083
+ const wiringQuestionSeam = resolveQuestionSeam(spec, deps);
3084
+ const wiringQuestionStripped = internals?.questionFaceStripped === true;
3085
+ const wiringAskSeam = resolveAskSeamForm(spec, deps);
3086
+ const wiringManifest = deriveWiringManifest({
3087
+ half: "effective",
3088
+ leg: resume !== undefined ? "resume" : internals?.isDelegatedChild === true ? "child" : "root",
3089
+ askForm: wiringAskSeam.form,
3090
+ ...(wiringAskSeam.provenance !== undefined ? { askProvenance: wiringAskSeam.provenance } : {}),
3091
+ questionWired: wiringQuestionSeam.wired,
3092
+ ...(wiringQuestionSeam.provenance !== undefined ? { questionProvenance: wiringQuestionSeam.provenance } : {}),
3093
+ ...(wiringQuestionStripped ? { questionStrippedByEngine: true } : {}),
3094
+ ...(resolvedInteractionPosture !== undefined ? { interactionPosture: resolvedInteractionPosture } : {}),
3095
+ ...(spec.interactiveTools === true && !wiringQuestionSeam.wired && !durableQuestionFace && !wiringQuestionStripped
3096
+ ? { interactiveToolsWithoutDeliveryFace: true }
3097
+ : {}),
3098
+ elicitSeamWired: resolveElicitSeam(deps),
3099
+ elicitServersOptedIn: countElicitOptIns(spec),
3100
+ parkCapable: checkpointStore !== undefined,
3101
+ parkDurableApprovalOptIn: spec.durableApproval !== undefined,
3102
+ parkForceDurableGate: runtimeCaps?.forceDurableGate === true,
3103
+ parkSafetyVocabularyArmed: irreversibleTools.size > 0 || egressTools.size > 0,
3104
+ ...(checkpointStore !== undefined ? { checkpointDurability: resolveDeclaredDurability(checkpointStore, "checkpointStore") } : {}),
3105
+ sessionDurability: resolveDeclaredDurability(sessions, "sessionStore"),
3106
+ backgroundAgentStoreWired: deps.backgroundAgentStore !== undefined,
3107
+ hostChildEventSinkWired: deps.onBackgroundChildEvent !== undefined,
3108
+ lockedConfigWired: deps.lockedConfig !== undefined,
3109
+ complianceWired: deps.compliancePostureResolver !== undefined,
3110
+ memoryAdmissionWired: deps.memoryScopeAdmission !== undefined,
3111
+ retentionPolicyWired: deps.retentionPolicy !== undefined,
3112
+ });
3113
+ const parkLaneArmed = wiringManifest.parkLane.effective === true;
3114
+ const hookContextConsumerWired = hooks?.preToolUse !== undefined || hooks?.postToolUse !== undefined || hooks?.postToolUseFailure !== undefined;
3115
+ const hookEnvFace = hookContextConsumerWired && (ownedEnv ?? deps.executionEnv) != null ? createHookEnvCapabilities(executionEnv) : undefined;
2920
3116
  if (effectivePolicy || hooks?.preToolUse || egressTools.size > 0 || irreversibleTools.size > 0 || resourceSuspendEligible || platformSuspendArmed || spec.enablePlanMode === true) {
2921
3117
  const adjudicate = effectivePolicy
2922
3118
  ? (req) => raceAbort(Promise.resolve(effectivePolicy.check({ ...req, budget: budgetSnapshot }, abortController.signal)), abortController.signal, () => ({
@@ -2998,6 +3194,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
2998
3194
  })(),
2999
3195
  message: decision.message ?? `approval required for "${req.toolName}"`,
3000
3196
  ...askSourceIdentity(),
3197
+ ...riskAxesOf(req.toolName),
3001
3198
  ...(decision.action === "ask" && decision.requiresRealApproval === true ? { requiresRealApproval: true } : {}),
3002
3199
  }, onAsk, abortController.signal);
3003
3200
  const waitMs = Math.max(0, now() - t0);
@@ -3037,9 +3234,6 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
3037
3234
  catch {
3038
3235
  }
3039
3236
  };
3040
- const checkpointStore = resolveCheckpointStore(spec, deps);
3041
- const durableApproval = spec.durableApproval ??
3042
- (runtimeCaps?.forceDurableGate ? { scope: spec.principal || DEFAULT_IRREVERSIBLE_SCOPE } : undefined);
3043
3237
  const inFlightSpendMicroUsd = () => {
3044
3238
  const own = liveSpendRef.get?.().costMicroUsd ?? 0;
3045
3239
  const seededNested = resume?.seed.nestedStats.costMicroUsd;
@@ -3078,6 +3272,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
3078
3272
  return live.length > 0 ? live : undefined;
3079
3273
  })(),
3080
3274
  pendingSteer: undefined,
3275
+ pendingSteerQueue: undefined,
3081
3276
  inheritedGate: (() => {
3082
3277
  const requiresParentConstraint = (inheritedParentConstraints?.length ?? 0) > 0 || seedInheritedGate?.requiresParentConstraint === true;
3083
3278
  const parentConstraintCount = (inheritedParentConstraints?.length ?? 0) > 0 ? inheritedParentConstraints.length : seedInheritedGate?.parentConstraintCount;
@@ -3325,12 +3520,92 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
3325
3520
  return true;
3326
3521
  }
3327
3522
  : undefined;
3328
- const suspendAsk = checkpointStore && (durableApproval || irreversibleTools.size > 0 || egressTools.size > 0)
3329
- ? async (req, postHookArgs, safety, approverUnavailable) => {
3330
- if (onAsk !== undefined &&
3523
+ const resolveContentAsk = async (req) => {
3524
+ if (!contentAskRoutable(req.toolCallId) || liveQuestionFace === undefined || mountedQuestionTool === undefined) {
3525
+ return { kind: "unavailable", parkDeclined: false };
3526
+ }
3527
+ const deliveryId = uuidv7();
3528
+ const bindOutcome = (entry, questionsHash) => {
3529
+ if (contentAskBindings.size >= CONTENT_ASK_BINDING_CAP && !contentAskBindings.has(req.toolCallId))
3530
+ return;
3531
+ contentAskBindings.set(req.toolCallId, { ...entry, questionsHash, deliveryId });
3532
+ };
3533
+ const refuseBeforeDelivery = (code, presentedInput) => ({
3534
+ kind: "delivery_failure",
3535
+ code,
3536
+ ...(presentedInput !== undefined ? { presentedInput } : {}),
3537
+ });
3538
+ let retained;
3539
+ let presented;
3540
+ try {
3541
+ retained = structuredClone(req.args);
3542
+ presented = structuredClone(retained.questions);
3543
+ }
3544
+ catch {
3545
+ return refuseBeforeDelivery("question.malformed_request");
3546
+ }
3547
+ const retainedQuestionsHash = boundInputHashOf(retained.questions);
3548
+ if (!Value.Check(mountedQuestionTool.parameters, retained) || validateAskQuestions(presented) !== undefined) {
3549
+ return refuseBeforeDelivery("question.malformed_request", retained);
3550
+ }
3551
+ if (contentAskBindings.size >= CONTENT_ASK_BINDING_CAP && !contentAskBindings.has(req.toolCallId)) {
3552
+ return { kind: "unavailable", parkDeclined: true };
3553
+ }
3554
+ if (abortController.signal.aborted) {
3555
+ return { kind: "delivery_failure", code: "question.aborted", presentedInput: retained };
3556
+ }
3557
+ try {
3558
+ const facePromise = (async () => liveQuestionFace({
3559
+ toolCallId: req.toolCallId,
3560
+ questions: presented,
3561
+ ...(spec.principal !== undefined ? { principal: spec.principal } : {}),
3562
+ sourceTaskId: sessionId,
3563
+ boundInputHash: boundInputHashOf(retained),
3564
+ deliveryId,
3565
+ }, abortController.signal))();
3566
+ const settlement = await raceAbort(facePromise.then((outcome) => ({ tag: "outcome", outcome }), (error) => ({ tag: "threw", error })), abortController.signal, () => ({ tag: "aborted" }));
3567
+ if (settlement.tag === "aborted") {
3568
+ void facePromise.then((late) => {
3569
+ if (classifyQuestionOutcome(late).shape !== "answered")
3570
+ return;
3571
+ lateStrandedAnswers.push({ deliveryId, toolCallId: req.toolCallId });
3572
+ discloseStrandedAnswers([{ deliveryId, toolCallId: req.toolCallId }], "the task had already ended when the answer arrived");
3573
+ }, () => undefined).catch(() => undefined);
3574
+ }
3575
+ if (settlement.tag === "outcome") {
3576
+ const outcome = settlement.outcome;
3577
+ const reading = classifyQuestionOutcome(outcome);
3578
+ if (reading.shape === "contradictory") {
3579
+ bindOutcome({ kind: "failed", error: new Error("the question channel returned a contradictory outcome (an unavailable answer)") }, retainedQuestionsHash);
3580
+ return { kind: "delivery_failure", code: "question.human_channel_failed", presentedInput: retained };
3581
+ }
3582
+ if (reading.shape === "unavailable")
3583
+ return { kind: "unavailable", parkDeclined: true, presentedInput: retained };
3584
+ const answerSnapshot = reading.answer;
3585
+ bindOutcome({ kind: "answered", answer: answerSnapshot }, retainedQuestionsHash);
3586
+ return { kind: "answered", presentedInput: retained };
3587
+ }
3588
+ const error = settlement.tag === "threw"
3589
+ ? settlement.error
3590
+ : Object.assign(new Error("the task ended while this question was still out"), { name: "AbortError" });
3591
+ bindOutcome({ kind: "failed", error }, retainedQuestionsHash);
3592
+ return {
3593
+ kind: "delivery_failure",
3594
+ code: settlement.tag === "aborted" || abortController.signal.aborted ? "question.aborted" : "question.human_channel_failed",
3595
+ presentedInput: retained,
3596
+ };
3597
+ }
3598
+ catch (err) {
3599
+ bindOutcome({ kind: "failed", error: err }, retainedQuestionsHash);
3600
+ return { kind: "delivery_failure", code: "question.human_channel_failed", presentedInput: retained };
3601
+ }
3602
+ };
3603
+ const suspendAsk = parkLaneArmed && checkpointStore !== undefined
3604
+ ? async (req, postHookArgs, safety, liveFaceUnavailable) => {
3605
+ const syncFirstEligible = req.toolName === ASK_USER_QUESTION_TOOL_NAME ? contentAskRoutable(req.toolCallId) : onAsk !== undefined;
3606
+ if (syncFirstEligible &&
3331
3607
  runtimeCaps?.forceDurableGate !== true &&
3332
- approverUnavailable !== true &&
3333
- req.toolName !== ASK_USER_QUESTION_TOOL_NAME &&
3608
+ liveFaceUnavailable !== true &&
3334
3609
  !inheritedUnavailableAsks.has(req.toolCallId)) {
3335
3610
  return undefined;
3336
3611
  }
@@ -3519,9 +3794,11 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
3519
3794
  onNotifyError: (f) => emitTrace(deps.tracer, () => ({ kind: "observer.notify_failed", version: 1, taskId: spec.taskId ?? sessionId, site: f.site, message: f.error.message, ts: Date.now() })),
3520
3795
  event: e,
3521
3796
  preToolUse: hooks?.preToolUse,
3797
+ ...(hookEnvFace !== undefined ? { hookEnv: hookEnvFace } : {}),
3522
3798
  adjudicate,
3523
3799
  resolveAsk: resolveAskBound,
3524
3800
  suspendAsk,
3801
+ resolveContentAsk,
3525
3802
  egress: egressTools.has(e.toolName),
3526
3803
  irreversibility: irreversibilityTier.get(e.toolName),
3527
3804
  reversibilityProbe: reversibilityProbes.get(e.toolName),
@@ -3574,7 +3851,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
3574
3851
  isInterrupt: abortController.signal.aborted || spec.signal?.aborted === true,
3575
3852
  content: e.content.map((c) => ({ ...c })),
3576
3853
  details: clonedDetails,
3577
- }, { toolCallId: e.toolCallId, toolName: e.toolName });
3854
+ }, { toolCallId: e.toolCallId, toolName: e.toolName, ...(hookEnvFace !== undefined ? { env: hookEnvFace } : {}) });
3578
3855
  if (patch?.additionalContext) {
3579
3856
  content = [...content, { type: "text", text: formatHookFeedback(patch.additionalContext) }];
3580
3857
  changed = true;
@@ -3582,7 +3859,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
3582
3859
  }
3583
3860
  }
3584
3861
  else if (hooks?.postToolUse) {
3585
- const patch = await hooks.postToolUse(e.toolName, e.input, { content: e.content, details: e.details, isError: e.isError }, { toolCallId: e.toolCallId, toolName: e.toolName });
3862
+ const patch = await hooks.postToolUse(e.toolName, e.input, { content: e.content, details: e.details, isError: e.isError }, { toolCallId: e.toolCallId, toolName: e.toolName, ...(hookEnvFace !== undefined ? { env: hookEnvFace } : {}) });
3586
3863
  if (patch?.updatedOutput) {
3587
3864
  content = patch.updatedOutput;
3588
3865
  changed = true;
@@ -3831,7 +4108,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
3831
4108
  : undefined;
3832
4109
  overheadState.promptChars = systemPrompt.length;
3833
4110
  const preparedHolder = {};
3834
- const buildPrepared = () => ({ harness, session, sessionId, taskRootPath, model, thinking, compModel, mcp: mcp, ...(a2a !== undefined && a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), cwdRef: handsCwdRef, ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), denyNarrowingPolicy, ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), releaseSignal, cacheBreakDetector, cacheFingerprint, promptManifest, epochDeclaredSections, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), toolMaterializeStatic, ownedEnv, suspendRef, suspendProgressRef, reviewRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(suspendForPlatformLimit !== undefined ? { suspendForPlatformLimit } : {}), ...(envLifetimeSuspendAt !== undefined ? { envLifetimeSuspendAt } : {}), ...(usageGovernance !== undefined ? { usageGovernance } : {}), callIssuedAtRef, brainCallGuardrailRef, suspendForReview, resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolEffects, wakeRecovered, promptOverheadTokens, lastBrainContext, readTaskFile, recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit, runIdent: lspRunIdent } } : {}), planModeRef, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, listBackgroundTasks, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}) });
4111
+ const buildPrepared = () => ({ harness, session, sessionId, taskRootPath, model, thinking, compModel, mcp: mcp, ...(a2a !== undefined && a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), cwdRef: handsCwdRef, ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), denyNarrowingPolicy, ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), releaseSignal, settleContentAskBindings, cacheBreakDetector, cacheFingerprint, wiringManifest, promptManifest, epochDeclaredSections, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), toolMaterializeStatic, ownedEnv, suspendRef, suspendProgressRef, reviewRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(suspendForPlatformLimit !== undefined ? { suspendForPlatformLimit } : {}), ...(envLifetimeSuspendAt !== undefined ? { envLifetimeSuspendAt } : {}), ...(usageGovernance !== undefined ? { usageGovernance } : {}), callIssuedAtRef, brainCallGuardrailRef, suspendForReview, resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolEffects, wakeRecovered, promptOverheadTokens, lastBrainContext, readTaskFile, recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit, runIdent: lspRunIdent } } : {}), planModeRef, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, listBackgroundTasks, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}) });
3835
4112
  const prepared = buildPrepared();
3836
4113
  preparedHolder.current = prepared;
3837
4114
  return prepared;
@@ -1,5 +1,5 @@
1
- import type { Model } from "../../internal/llm.js";
2
- import { type Checkpoint, type CheckpointToken, type ReopenReason, type ResumeOutcome } from "../checkpoint-store.js";
1
+ import { type Model } from "../../internal/llm.js";
2
+ import { type Checkpoint, type CheckpointToken, type PendingSteerEntry, type ReopenReason, type ResumeOutcome } from "../checkpoint-store.js";
3
3
  import type { RunInternals } from "./prepare-task.js";
4
4
  import { type TaskOutcome } from "../task-outcome.js";
5
5
  import { type SideQuerySpec, type SideQueryResult } from "../side-query.js";
@@ -13,10 +13,7 @@ interface ResumeRun {
13
13
  outcome: Extract<ResumeOutcome, {
14
14
  gate: "policy_ask" | "resource_limit" | "dry_run_review" | "plan_review" | "wake";
15
15
  }>;
16
- wakeMessage?: {
17
- text: string;
18
- trusted: boolean;
19
- };
16
+ wakeMessage?: Omit<PendingSteerEntry, "seq">;
20
17
  onEnvRestoreFailed?: (reason: ReopenReason) => Promise<void>;
21
18
  decisionDelivered?: boolean;
22
19
  }