@sema-agent/core 7.9.2 → 7.11.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 +102 -0
  2. package/dist/agents/child-model-seat.d.ts +71 -14
  3. package/dist/agents/child-model-seat.js +23 -7
  4. package/dist/agents/subagent.d.ts +2 -2
  5. package/dist/agents/subagent.js +8 -5
  6. package/dist/agents/teacher.js +2 -2
  7. package/dist/core/ask-unresolvable-notice.d.ts +52 -0
  8. package/dist/core/ask-unresolvable-notice.js +25 -0
  9. package/dist/core/auto-mode-defaults.d.ts +15 -3
  10. package/dist/core/auto-mode-defaults.js +1 -0
  11. package/dist/core/auto-mode.d.ts +86 -23
  12. package/dist/core/auto-mode.js +43 -12
  13. package/dist/core/checkpoint-store.d.ts +14 -0
  14. package/dist/core/checkpoint-store.js +2 -1
  15. package/dist/core/engine-notice.d.ts +28 -7
  16. package/dist/core/gate-fold.js +1 -0
  17. package/dist/core/gate-lanes.d.ts +6 -1
  18. package/dist/core/gate-lanes.js +60 -18
  19. package/dist/core/governance-codes.d.ts +1 -1
  20. package/dist/core/governance-codes.js +4 -0
  21. package/dist/core/hooks.d.ts +37 -1
  22. package/dist/core/hooks.js +2 -0
  23. package/dist/core/permission-rule-model.d.ts +53 -16
  24. package/dist/core/permission-rule-model.js +59 -21
  25. package/dist/core/permission-rules.d.ts +6 -4
  26. package/dist/core/permission-rules.js +14 -14
  27. package/dist/core/persisted-rule-arms.js +4 -3
  28. package/dist/core/read-only-shell-table.d.ts +87 -0
  29. package/dist/core/read-only-shell-table.js +485 -0
  30. package/dist/core/read-only-shell.d.ts +42 -0
  31. package/dist/core/read-only-shell.js +316 -0
  32. package/dist/core/roles.d.ts +3 -2
  33. package/dist/core/runner/contracts.d.ts +26 -2
  34. package/dist/core/runner/denial-limit-arms.d.ts +14 -3
  35. package/dist/core/runner/denial-limit-arms.js +15 -5
  36. package/dist/core/runner/gate-exit.d.ts +5 -0
  37. package/dist/core/runner/permission-rule-lanes.d.ts +7 -1
  38. package/dist/core/runner/permission-rule-lanes.js +9 -3
  39. package/dist/core/runner/prepare-caps-and-workflow.d.ts +1 -1
  40. package/dist/core/runner/prepare-caps-and-workflow.js +35 -14
  41. package/dist/core/runner/prepare-gate-stations.d.ts +3 -2
  42. package/dist/core/runner/prepare-gate-stations.js +12 -0
  43. package/dist/core/runner/prepare-policy-chain.js +7 -6
  44. package/dist/core/runner/prepare-task.js +1 -1
  45. package/dist/core/runner/prepare-turn-wiring.js +1 -1
  46. package/dist/core/runner/prepare-wiring-manifest.d.ts +1 -1
  47. package/dist/core/runner/prepare-wiring-manifest.js +8 -1
  48. package/dist/core/runner/runtask.d.ts +33 -32
  49. package/dist/core/runner/runtask.js +63 -33
  50. package/dist/core/runner-deps.d.ts +9 -2
  51. package/dist/core/shell-lexer.d.ts +18 -0
  52. package/dist/core/shell-lexer.js +17 -10
  53. package/dist/core/shell-wrapper-table.js +8 -5
  54. package/dist/core/swappable-deps.d.ts +90 -0
  55. package/dist/core/swappable-deps.js +55 -0
  56. package/dist/core/tool-policy.d.ts +30 -1
  57. package/dist/core/tool-policy.js +6 -2
  58. package/dist/core/tools.d.ts +28 -7
  59. package/dist/core/tools.js +44 -4
  60. package/dist/core/trace.d.ts +15 -0
  61. package/dist/core/wiring-manifest.d.ts +15 -1
  62. package/dist/core/wiring-manifest.js +10 -2
  63. package/dist/core/workflow-journal-store.d.ts +21 -2
  64. package/dist/core/workflow-journal-store.js +1 -1
  65. package/dist/engine/execution-env/node-execution-env.d.ts +2 -0
  66. package/dist/engine/execution-env/node-execution-env.js +2 -1
  67. package/dist/engine/harness/agent-harness.d.ts +3 -1
  68. package/dist/engine/harness/agent-harness.js +1 -1
  69. package/dist/engine/harness/types.d.ts +15 -2
  70. package/dist/index.d.ts +8 -4
  71. package/dist/index.js +7 -3
  72. package/dist/orchestration/run-workflow-tool.d.ts +22 -2
  73. package/dist/orchestration/run-workflow-tool.js +14 -1
  74. package/dist/orchestration/workflow-governance.d.ts +3 -2
  75. package/dist/orchestration/workflow-observe.d.ts +1 -1
  76. package/dist/orchestration/workflow-observe.js +2 -0
  77. package/dist/orchestration/workflow-primitives.d.ts +4 -1
  78. package/dist/orchestration/workflow-primitives.js +1 -6
  79. package/dist/orchestration/workflow-types.d.ts +37 -2
  80. package/dist/orchestration/workflow-types.js +16 -0
  81. package/dist/orchestration/workflow.d.ts +53 -6
  82. package/dist/orchestration/workflow.js +319 -51
  83. package/dist/prompt-assembly/turn-snapshot.d.ts +4 -2
  84. package/dist/stores/file/workflow-journal-store.js +10 -3
  85. package/package.json +1 -1
  86. package/test/export-surface.snapshot.json +85 -5
@@ -2,7 +2,7 @@ import { spawn } from "node:child_process";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { closeSync, constants, createReadStream, mkdtempSync, openSync, readSync, statSync, truncateSync, unlinkSync } from "node:fs";
4
4
  import { access, appendFile, lstat, mkdir, mkdtemp, open, readdir, readFile, readlink, realpath, rename, rm, unlink, writeFile, } from "node:fs/promises";
5
- import { tmpdir } from "node:os";
5
+ import { homedir, tmpdir } from "node:os";
6
6
  import { isAbsolute, join, resolve } from "node:path";
7
7
  import { createInterface } from "node:readline";
8
8
  import { ExecutionError, err, FileError, ok, toError, } from "../harness/types.js";
@@ -284,6 +284,7 @@ export function openSpoolPair(base) {
284
284
  }
285
285
  export class NodeExecutionEnv {
286
286
  cwd;
287
+ homeDir = homedir();
287
288
  shellPath;
288
289
  shellEnv;
289
290
  inheritEnv;
@@ -131,6 +131,7 @@ export declare class AgentHarness<TSkill extends Skill = Skill, TPromptTemplate
131
131
  private runPromise?;
132
132
  private pendingSessionWrites;
133
133
  private model;
134
+ /** The run's thinking level; `undefined` = undeclared (provider default, no wire key) — distinct from "off". */
134
135
  private thinkingLevel;
135
136
  /** RB-30 terminal fix — runner-set sink for engine-note payloads left undrained at agent_end. */
136
137
  onUndrainedEngineNotes?: (payloads: unknown[]) => void;
@@ -410,7 +411,8 @@ export declare class AgentHarness<TSkill extends Skill = Skill, TPromptTemplate
410
411
  } & UserMessageProvenance): Promise<void>;
411
412
  appendMessage(message: AgentMessage): Promise<void>;
412
413
  getModel(): Model;
413
- getThinkingLevel(): ThinkingLevel;
414
+ /** The current level, or `undefined` when none was declared (provider default — no wire key). */
415
+ getThinkingLevel(): ThinkingLevel | undefined;
414
416
  setModel(model: Model): Promise<void>;
415
417
  setThinkingLevel(level: ThinkingLevel): Promise<void>;
416
418
  setActiveTools(toolNames: string[]): Promise<void>;
@@ -277,7 +277,7 @@ export class AgentHarness {
277
277
  this.tools.set(tool.name, tool);
278
278
  }
279
279
  this.model = options.model;
280
- this.thinkingLevel = options.thinkingLevel ?? "off";
280
+ this.thinkingLevel = options.thinkingLevel;
281
281
  this.activeToolNames =
282
282
  options.activeToolNames ?? (options.tools ?? []).map((tool) => tool.name);
283
283
  this.steeringQueueMode = options.steeringMode ?? "one-at-a-time";
@@ -498,6 +498,17 @@ export interface ExecutionEnv extends FileSystem, Shell {
498
498
  * SSH env to an organization-managed build host can be non-isolated yet omit this flag.
499
499
  */
500
500
  readonly externalContentTarget?: boolean;
501
+ /**
502
+ * #644 — declared by the ADAPTER: the HOME DIRECTORY of the user this environment runs as, as an absolute
503
+ * path in the environment's own namespace. The base a `~/`-relative permission rule (`Edit(~/.ssh/**)`)
504
+ * resolves against for calls executing in this env. Omitted ⇒ the environment declares no home, and every
505
+ * `~/` deny/ask rule reads UNREADABLE for its calls (a fail-closed ask a person clears), because the only
506
+ * other candidate — the ENGINE PROCESS's home — is the wrong directory on any leg whose environment is not
507
+ * the engine host (a remote executor, a sandbox), and guarding the wrong directory silently was the
508
+ * defect. A local Node environment declares `os.homedir()` (it IS the host). A declared value that is not
509
+ * an absolute path is refused at prepare (`config.execution_env_home_dir_invalid`), never read as absent.
510
+ */
511
+ readonly homeDir?: string;
501
512
  }
502
513
  /** Base fields shared by append-only session tree entries. */
503
514
  export interface SessionTreeEntryBase {
@@ -1167,7 +1178,8 @@ export interface ModelSelectEvent {
1167
1178
  export interface ThinkingLevelSelectEvent {
1168
1179
  type: "thinking_level_select";
1169
1180
  level: ThinkingLevel;
1170
- previousLevel: ThinkingLevel;
1181
+ /** `undefined` when the run had no declared level before this selection (provider default). */
1182
+ previousLevel: ThinkingLevel | undefined;
1171
1183
  }
1172
1184
  export interface ResourcesUpdateEvent<TSkill extends Skill = Skill, TPromptTemplate extends PromptTemplate = PromptTemplate> {
1173
1185
  type: "resources_update";
@@ -1335,7 +1347,8 @@ export interface AgentHarnessOptions<TSkill extends Skill = Skill, TPromptTempla
1335
1347
  env: ExecutionEnv;
1336
1348
  session: Session;
1337
1349
  model: Model;
1338
- thinkingLevel: ThinkingLevel;
1350
+ /** `undefined` = no level declared (provider default). */
1351
+ thinkingLevel: ThinkingLevel | undefined;
1339
1352
  activeTools: TTool[];
1340
1353
  resources: AgentHarnessResources<TSkill, TPromptTemplate>;
1341
1354
  }) => string | Promise<string>);
package/dist/index.d.ts CHANGED
@@ -54,6 +54,7 @@ export { pgQuery, mysqlQuery, sqliteQuery } from "./tools/sql-adapters.js";
54
54
  export { materializeMcpTools, MCP_PREFIX, type MaterializedMcp, type McpServerStatus, type McpRefreshResult } from "./core/mcp.js";
55
55
  export { MCP_FAILURE_KINDS, MCP_DELIVERY_VERDICTS, classifyMcpFailure, type McpFailure, type McpFailureKind, type McpDelivered } from "./core/mcp-failure.js";
56
56
  export { MCP_INJECTION_DROP_REASONS, MCP_INJECTION_DROP_TEXT, mcpInjectionDroppedNotice, type McpInjectionDropReason, type McpInjectionDropFacts } from "./core/mcp-injection-drop.js";
57
+ export { askUnresolvableNotice, type AskUnresolvableFacts } from "./core/ask-unresolvable-notice.js";
57
58
  export { materializeA2aTools, A2aRpcError, type MaterializedA2a, type A2aPeerStatus, type A2aRefreshResult, type A2aToolAxis } from "./core/a2a.js";
58
59
  export { PROTOCOL_TABLE, MCP_NAMESPACE, A2A_NAMESPACE, protocolOf, type ProtocolNamespace, type ProtocolId } from "./core/protocol-table.js";
59
60
  export { InMemorySessionPolicyStore, SessionPolicyError, loosenReasons, normalizeRules, stripRev, type SessionPolicyStore, type SessionPermissionRules, type StoredSessionRules, type SessionRulesRecord, type PutRulesOptions, } from "./core/session-policy-store.js";
@@ -166,7 +167,8 @@ export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, create
166
167
  export { type AskOrigin, ASK_ORIGINS, isAskOrigin, classifierMayAnswer, ORIGIN_IMPLIES_REAL_APPROVAL } from "./core/ask-origin.js";
167
168
  export { SETTLEMENT_KINDS, type SettlementKind, isSettlementKind, type Settlement, SETTLEMENT_IS_REFUSAL, DENIED_BY_VALUES, type DeniedBy, isDeniedBy, DENIED_BY_MAY_VETO, type GateDisposition, type GateOutcome, screenGateOutcome } from "./core/gate-outcome.js";
168
169
  export { type AskCarry } from "./core/hooks.js";
169
- export { parseAutoModeResponse, createAutoModeDecider, type AutoModeVerdict, type AutoModeDecider, type AutoModeDeciderOptions, type AutoModeClassified, type AutoModeClassifyFn, type AutoModeClassifyInput, createAutoModeDenialTracker, denialLimitFallbackMessage, denialLimitSentence, unarmedWindow, type AutoModeDenialTracker, type AutoModeDenialLimitOptions, type DenialLimitCounts, type DenialLimitFallbackFace, type UnarmedDenialLimitFallback, type DenialLimitFallback, type DenialLimitVerdict, } from "./core/auto-mode.js";
170
+ export { SWAPPABLE_DEP_SEATS, SWAP_SEAT_NOTICE, isSwappableDepSeat, screenSwappableDeps, type SwappableDepSeat, type SwappableDeps } from "./core/swappable-deps.js";
171
+ export { parseAutoModeResponse, createAutoModeDecider, AUTO_MODE_UNAVAILABLE_CAUSES, isAutoModeUnavailableCause, AUTO_MODE_BREAKER_CAUSES, isAutoModeBreakerCause, AutoModeBreakerLedger, type AutoModeUnavailableCause, type AutoModeBreakerCause, type AutoModeBreakerTrip, type AutoModeVerdict, type AutoModeDecider, type AutoModeDeciderOptions, type AutoModeClassified, type AutoModeClassifyFn, type AutoModeClassifyInput, createAutoModeDenialTracker, denialLimitFallbackMessage, denialLimitSentence, unarmedWindow, type AutoModeDenialTracker, type AutoModeDenialLimitOptions, type DenialLimitCounts, type DenialLimitFallbackFace, type UnarmedDenialLimitFallback, type DenialLimitFallback, type DenialLimitVerdict, } from "./core/auto-mode.js";
170
172
  export { AUTO_MODE_DENIAL_LIMIT_DEFAULTS, AUTO_MODE_DENIAL_AUTO_DENY_DEFAULT_MS, AUTO_MODE_CLASSIFIER_MAX_TOKENS } from "./core/auto-mode-defaults.js";
171
173
  export { buildAutoModePrompt, renderAutoModeWindow, renderAutoModeAction, AUTO_MODE_DEFAULTS_SENTINEL, type AutoModeRules, type BuildAutoModePromptOptions, type AutoModeWindowOptions, } from "./core/auto-mode-prompt.js";
172
174
  export { AUTO_MODE_BASE_PROMPT, AUTO_MODE_PERMISSIONS_EXTERNAL } from "./core/auto-mode-prompt-assets.js";
@@ -188,12 +190,14 @@ export { createPermissionRulePolicy, validatePermissionRules, parsePermissionRul
188
190
  * and nothing more. Removal is exported without ceremony, because narrowing on a user's behalf is
189
191
  * allowed and widening is not.
190
192
  */
191
- export { RULE_BEHAVIORS, RULE_BEHAVIOR_PRECEDENCE, RULE_BEHAVIORS_BY_PRECEDENCE, isRuleBehavior, readRowBehavior, adjudicatePersistedRules, adjudicatePersistedPathRules, ruleReachesProgramRun, programRunReachOf, PROGRAM_RUN_REACHES, type ProgramRunReach, type ProgramRunReachOutcome, pathRuleReaches, ruleToolGrammarOf, COMMAND_RULE_TOOL, READ_RULE_TOOL, type PathRuleBases, type RuleBehavior, type PersistedRuleVerdict, parseRuleText, formatRuleText, ruleAdmitsCommand, findAdmittingRule, suggestRulesForCommand, scopeCoversCwd, pathWithinRoot, isRuleLive, renderUntrustedCommandText, stripFormatCharacters, UNCOVERED_SEGMENT_REASON_BASELINE, RULE_OFFERS_ABSENCE_BASELINE, type UncoveredSegmentDetail, type EditedRuleBreadthWarning, directoryRuleAdmits, BARE_INTERPRETER_NAMES, MAX_RULE_TEXT_CHARS, type PersistedRule, type RuleTombstone, type RuleScope, type RuleDot, type RuleAdd, type RuleAddOrigin, type RuleOffer, type RuleOfferBatchMember, type SegmentRuleSuggestion, type SegmentCoverage, type RuleReject, type RuleRejectCode, type ParsedRule, type PersistedRuleTool, type PersistedRuleMatch, } from "./core/permission-rule-model.js";
193
+ export { RULE_BEHAVIORS, RULE_BEHAVIOR_PRECEDENCE, RULE_BEHAVIORS_BY_PRECEDENCE, isRuleBehavior, readRowBehavior, adjudicatePersistedRules, adjudicatePersistedPathRules, ruleReachesProgramRun, programRunReachOf, PROGRAM_RUN_REACHES, type ProgramRunReach, type ProgramRunReachOutcome, pathRuleReachOf, ruleBasesNeeded, PATH_RULE_BASES, PATH_RULE_BASE_LABEL, ruleToolGrammarOf, COMMAND_RULE_TOOL, READ_RULE_TOOL, type PathRuleBase, type PathRuleBases, type RuleBehavior, type PersistedRuleVerdict, parseRuleText, formatRuleText, ruleAdmitsCommand, findAdmittingRule, suggestRulesForCommand, scopeCoversCwd, pathWithinRoot, isRuleLive, renderUntrustedCommandText, stripFormatCharacters, UNCOVERED_SEGMENT_REASON_BASELINE, RULE_OFFERS_ABSENCE_BASELINE, type UncoveredSegmentDetail, type EditedRuleBreadthWarning, directoryRuleAdmits, BARE_INTERPRETER_NAMES, MAX_RULE_TEXT_CHARS, type PersistedRule, type RuleTombstone, type RuleScope, type RuleDot, type RuleAdd, type RuleAddOrigin, type RuleOffer, type RuleOfferBatchMember, type SegmentRuleSuggestion, type SegmentCoverage, type RuleReject, type RuleRejectCode, type ParsedRule, type PersistedRuleTool, type PersistedRuleMatch, } from "./core/permission-rule-model.js";
192
194
  export { removePersistedRule, applyTombstones, sameScope, sameRuleIdentity, isValidConsentScope, isValidDurableScope, InMemoryDurableRulePartition, EMPTY_DURABLE_RULE_PARTITION, type DurableRulePartition, type DurableRulePartitionProvider, type RuleWriteOutcome, type StoredRules, type RemoveResult, type PutResult, joinRuleStates, screenRuleSyncState, collectBelowFrontier, ruleSyncVector, joinFrontiers, dotAtOrBelowFrontier, sameRuleOwner, type RuleSyncState, type RuleSyncFrontier, type RuleSyncDrop, type RuleSyncLandingReport, type RuleOwner, type QuarantinedRuleAdd, PERMISSION_RULE_WRITER, writerOf, foldDelta, addDotsOf, assertDeleteDeltaCarriesNoAdd, assertRedemptionNotQuarantined, assertWriteDeltaScopeDurable, type PermissionRuleWriter, type WritableDurableRulePartition, type RuleWriteDelta, type RuleAddDelta, type RuleDeleteDelta, type RuleSyncJoinDelta, type RawRuleSyncState, type RedemptionAuthorization, } from "./core/permission-rule-store.js";
193
195
  export { syncPermissionRules, parseRuleSyncResponse, PERMISSION_RULE_SYNC_PATH, LOCAL_OWNER_UNSYNCABLE_CODE, type PermissionRuleSyncTransport, type PermissionRuleSyncResult, type RuleSyncRequestBody, type RuleSyncResponseBody, } from "./core/permission-rule-sync.js";
194
196
  export { createPermissionRuleStoreProvider, effectivePermissionRules, effectiveOrThrow, ruleSourceOf, type PermissionRuleStore, type PermissionRuleStoreProvider, type PermissionRuleStoreConfig, type EffectivePermissionRules, type EffectivePermissionRule, type RemovedPermissionRule, type RuleSource, } from "./core/permission-rule-provider.js";
195
197
  export { InMemorySessionRulePartition, type SessionRulePartition, type SessionRuleAdd, type SessionRuleApplyResult, } from "./core/permission-rule-session.js";
196
- export { readShellCommand, isFullyReadable, MAX_SHELL_READ_CHARS, SHELL_WRAPPER_TABLE, type ShellCommandShape, type ShellSegment, type ShellWord, type ShellWrapperName, } from "./core/shell-lexer.js";
198
+ export { readShellCommand, isFullyReadable, MAX_SHELL_READ_CHARS, SHELL_WRAPPER_TABLE, type ShellCommandShape, type ShellSegment, type ShellWord, type ShellRedirection, type ShellWrapperName, } from "./core/shell-lexer.js";
199
+ export { readOnlyShellVerdict, type ReadOnlyShellVerdict } from "./core/read-only-shell.js";
200
+ export { READ_ONLY_FLAG_ARITIES, FLAG_VALUE_ACCEPTS, READ_ONLY_COMMAND_TABLE, READ_ONLY_BARE_PROGRAMS, READ_ONLY_GLOB_PROGRAMS, READ_ONLY_EXACT_FORMS, READ_ONLY_BARE_ONLY, FIND_ACTION_PRIMARIES, FIND_VALUE_PRIMARIES, FIND_NEWER_PRIMARY, READ_ONLY_ENV_NAMES, XARGS_READ_ONLY_TARGETS, type ReadOnlyFlagArity, type ReadOnlyCommandRow, } from "./core/read-only-shell-table.js";
197
201
  export { orgRuleVerdictFor, type OrgRuleVerdict, orgRuleShadows, unenforceableOrgRules, ORG_UNAVAILABLE_DECISION_REASON, ORG_RULE_DECISION_REASON, ORG_ADJUDICATION_TIMEOUT_MS, type OrgPermissionRule, type OrgRuleSnapshot, type OrgRuleSnapshotProvider, type OrgRuleStatePersistence, type PersistedOrgRuleState, type OrgRulePartitionConfig, type OrgRuleResolution, type OrgRuleStatus, } from "./core/permission-rule-org.js";
198
202
  export { RULE_SYNC_DROP_CODES, type RuleSyncDropReason, type RuleQuarantineReason } from "./core/governance-codes.js";
199
203
  export { prepareCardApproval, confirmRuleApproval, type ConfirmResult, type ConfirmRefusalReason, precheckEditedRuleText, type EditedRuleTextPrecheck, redeemRuleTicket, redeemRuleBatch, prepareCcImport, prepareStarterBatch, mintRuleTicket, STARTER_RULES, InMemoryRuleApprovalRecordStore, ruleOffersOfRecord, type RuleTicket, type RuleCandidate, type RuleApprovalKind, type RuleApprovalRecord, type RuleApprovalRecordStore, type RuleOffer2, type StaleRuleApprovalRecord, type RuleConsentDeps, type RedeemResult, type RedeemedBatchMember, type CcImportLayer, type ImportedSettingsLayer, type ImportPreview, } from "./core/permission-rule-consent.js";
@@ -228,7 +232,7 @@ export { type ReasoningIntensity, type ReasoningResolution, type ResolvedReasoni
228
232
  export { DESIGN_REVIEW_PROMPTS, CODE_REVIEW_PROMPT, SCENARIO_REGISTRY, runScenario, type ScenarioId, type CodeReviewMode, type ScenarioProfile, type RunScenarioOptions, type RunScenarioResult, } from "./scenarios/scenario-registry.js";
229
233
  export { teacherMode, TEACHER_PROFILE, type TeacherModePair, type TeacherProfile, } from "./scenarios/teacher-quickstart.js";
230
234
  export { loadOrchestrationEnv, DEFAULT_REASONING_INTENSITY, type OrchestrationMode, type OrchestrationEnv, } from "./scenarios/env.js";
231
- export { runWorkflow, startWorkflow, workflowAgentCallKey, WorkflowBudgetExceededError, WorkflowNestingError, WorkflowAgentSchemaError, WorkflowAgentStalledError, WorkflowAgentBlockedError, WORKFLOW_SPAWN_BLOCKED_ERROR_CODE, type WorkflowFanOutSlotError, type WorkflowFanOutOptions, WORKFLOW_SUBAGENT_PROMPT, WORKFLOW_SUBAGENT_PROMPT_SCHEMA, WORKFLOW_SUBAGENT_APPEND, WORKFLOW_SUBAGENT_APPEND_SCHEMA, type WorkflowHandle, MAX_WORKFLOW_ITEMS, type WorkflowRun, type WorkflowRunStatus, type WorkflowItemStatus, type WorkflowPhase, type WorkflowGroup, type WorkflowAgentRun, type WorkflowAgentHandle, type WorkflowRunStats, type WorkflowEvent, type WorkflowBudget, type WorkflowAgentOptions, type WorkflowRunContext, type WorkflowInternals, type RunWorkflowOptions, type RunWorkflowResult, type WorkflowTimers, } from "./orchestration/workflow.js";
235
+ export { runWorkflow, startWorkflow, workflowAgentCallKey, WorkflowBudgetExceededError, WorkflowNestingError, WorkflowAgentSchemaError, WorkflowAgentStalledError, WorkflowAgentBlockedError, WORKFLOW_SPAWN_BLOCKED_ERROR_CODE, WorkflowAgentParkedError, WORKFLOW_AGENT_PARKED_ERROR_CODE, type WorkflowParkedResume, type WorkflowFanOutSlotError, type WorkflowFanOutOptions, WORKFLOW_SUBAGENT_PROMPT, WORKFLOW_SUBAGENT_PROMPT_SCHEMA, WORKFLOW_SUBAGENT_APPEND, WORKFLOW_SUBAGENT_APPEND_SCHEMA, type WorkflowHandle, MAX_WORKFLOW_ITEMS, type WorkflowRun, type WorkflowRunStatus, type WorkflowItemStatus, type WorkflowPhase, type WorkflowGroup, type WorkflowAgentRun, type WorkflowAgentHandle, type WorkflowRunStats, type WorkflowEvent, type WorkflowBudget, type WorkflowAgentOptions, type WorkflowRunContext, type WorkflowInternals, type RunWorkflowOptions, type RunWorkflowResult, type WorkflowTimers, } from "./orchestration/workflow.js";
232
236
  export { listWorkflowRuns, getWorkflowRun, subscribeWorkflow, deriveAgentDisplayStatus, type AgentDisplayStatus } from "./orchestration/workflow-observe.js";
233
237
  export { runGoal, DECLARE_DONE_TOOL_NAME, type GoalSpec, type GoalResult, type GoalStatus, type GoalBudgetCause, type GoalVerdict, type GoalTurnState, type GoalVerificationKind, } from "./orchestration/goal.js";
234
238
  export { emitTaskOutcome, type TaskOutcome } from "./core/task-outcome.js";
package/dist/index.js CHANGED
@@ -41,6 +41,7 @@ export { pgQuery, mysqlQuery, sqliteQuery } from "./tools/sql-adapters.js";
41
41
  export { materializeMcpTools, MCP_PREFIX } from "./core/mcp.js";
42
42
  export { MCP_FAILURE_KINDS, MCP_DELIVERY_VERDICTS, classifyMcpFailure } from "./core/mcp-failure.js";
43
43
  export { MCP_INJECTION_DROP_REASONS, MCP_INJECTION_DROP_TEXT, mcpInjectionDroppedNotice } from "./core/mcp-injection-drop.js";
44
+ export { askUnresolvableNotice } from "./core/ask-unresolvable-notice.js";
44
45
  export { materializeA2aTools, A2aRpcError } from "./core/a2a.js";
45
46
  export { PROTOCOL_TABLE, MCP_NAMESPACE, A2A_NAMESPACE, protocolOf } from "./core/protocol-table.js";
46
47
  export { InMemorySessionPolicyStore, SessionPolicyError, loosenReasons, normalizeRules, stripRev, } from "./core/session-policy-store.js";
@@ -140,19 +141,22 @@ export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, create
140
141
  export { ASK_ORIGINS, isAskOrigin, classifierMayAnswer, ORIGIN_IMPLIES_REAL_APPROVAL } from "./core/ask-origin.js";
141
142
  export { SETTLEMENT_KINDS, isSettlementKind, SETTLEMENT_IS_REFUSAL, DENIED_BY_VALUES, isDeniedBy, DENIED_BY_MAY_VETO, screenGateOutcome } from "./core/gate-outcome.js";
142
143
  export {} from "./core/hooks.js";
143
- export { parseAutoModeResponse, createAutoModeDecider, createAutoModeDenialTracker, denialLimitFallbackMessage, denialLimitSentence, unarmedWindow, } from "./core/auto-mode.js";
144
+ export { SWAPPABLE_DEP_SEATS, SWAP_SEAT_NOTICE, isSwappableDepSeat, screenSwappableDeps } from "./core/swappable-deps.js";
145
+ export { parseAutoModeResponse, createAutoModeDecider, AUTO_MODE_UNAVAILABLE_CAUSES, isAutoModeUnavailableCause, AUTO_MODE_BREAKER_CAUSES, isAutoModeBreakerCause, AutoModeBreakerLedger, createAutoModeDenialTracker, denialLimitFallbackMessage, denialLimitSentence, unarmedWindow, } from "./core/auto-mode.js";
144
146
  export { AUTO_MODE_DENIAL_LIMIT_DEFAULTS, AUTO_MODE_DENIAL_AUTO_DENY_DEFAULT_MS, AUTO_MODE_CLASSIFIER_MAX_TOKENS } from "./core/auto-mode-defaults.js";
145
147
  export { buildAutoModePrompt, renderAutoModeWindow, renderAutoModeAction, AUTO_MODE_DEFAULTS_SENTINEL, } from "./core/auto-mode-prompt.js";
146
148
  export { AUTO_MODE_BASE_PROMPT, AUTO_MODE_PERMISSIONS_EXTERNAL } from "./core/auto-mode-prompt-assets.js";
147
149
  export { AUTO_MODE_ARMING_RECIPE_VERSION, autoModeArmingRecipeOf, sanitizeAutoModeArmingRecipe, foldAutoModeArming, } from "./core/auto-mode-arming.js";
148
150
  export { rebuildAutoModeDecider, } from "./core/auto-mode-rebuild.js";
149
151
  export { createPermissionRulePolicy, validatePermissionRules, parsePermissionRule, wildcardMatch, isNamespacedCoveringRuleName, namespacedRuleNameCovers, } from "./core/permission-rules.js";
150
- export { RULE_BEHAVIORS, RULE_BEHAVIOR_PRECEDENCE, RULE_BEHAVIORS_BY_PRECEDENCE, isRuleBehavior, readRowBehavior, adjudicatePersistedRules, adjudicatePersistedPathRules, ruleReachesProgramRun, programRunReachOf, PROGRAM_RUN_REACHES, pathRuleReaches, ruleToolGrammarOf, COMMAND_RULE_TOOL, READ_RULE_TOOL, parseRuleText, formatRuleText, ruleAdmitsCommand, findAdmittingRule, suggestRulesForCommand, scopeCoversCwd, pathWithinRoot, isRuleLive, renderUntrustedCommandText, stripFormatCharacters, UNCOVERED_SEGMENT_REASON_BASELINE, RULE_OFFERS_ABSENCE_BASELINE, directoryRuleAdmits, BARE_INTERPRETER_NAMES, MAX_RULE_TEXT_CHARS, } from "./core/permission-rule-model.js";
152
+ export { RULE_BEHAVIORS, RULE_BEHAVIOR_PRECEDENCE, RULE_BEHAVIORS_BY_PRECEDENCE, isRuleBehavior, readRowBehavior, adjudicatePersistedRules, adjudicatePersistedPathRules, ruleReachesProgramRun, programRunReachOf, PROGRAM_RUN_REACHES, pathRuleReachOf, ruleBasesNeeded, PATH_RULE_BASES, PATH_RULE_BASE_LABEL, ruleToolGrammarOf, COMMAND_RULE_TOOL, READ_RULE_TOOL, parseRuleText, formatRuleText, ruleAdmitsCommand, findAdmittingRule, suggestRulesForCommand, scopeCoversCwd, pathWithinRoot, isRuleLive, renderUntrustedCommandText, stripFormatCharacters, UNCOVERED_SEGMENT_REASON_BASELINE, RULE_OFFERS_ABSENCE_BASELINE, directoryRuleAdmits, BARE_INTERPRETER_NAMES, MAX_RULE_TEXT_CHARS, } from "./core/permission-rule-model.js";
151
153
  export { removePersistedRule, applyTombstones, sameScope, sameRuleIdentity, isValidConsentScope, isValidDurableScope, InMemoryDurableRulePartition, EMPTY_DURABLE_RULE_PARTITION, joinRuleStates, screenRuleSyncState, collectBelowFrontier, ruleSyncVector, joinFrontiers, dotAtOrBelowFrontier, sameRuleOwner, PERMISSION_RULE_WRITER, writerOf, foldDelta, addDotsOf, assertDeleteDeltaCarriesNoAdd, assertRedemptionNotQuarantined, assertWriteDeltaScopeDurable, } from "./core/permission-rule-store.js";
152
154
  export { syncPermissionRules, parseRuleSyncResponse, PERMISSION_RULE_SYNC_PATH, LOCAL_OWNER_UNSYNCABLE_CODE, } from "./core/permission-rule-sync.js";
153
155
  export { createPermissionRuleStoreProvider, effectivePermissionRules, effectiveOrThrow, ruleSourceOf, } from "./core/permission-rule-provider.js";
154
156
  export { InMemorySessionRulePartition, } from "./core/permission-rule-session.js";
155
157
  export { readShellCommand, isFullyReadable, MAX_SHELL_READ_CHARS, SHELL_WRAPPER_TABLE, } from "./core/shell-lexer.js";
158
+ export { readOnlyShellVerdict } from "./core/read-only-shell.js";
159
+ export { READ_ONLY_FLAG_ARITIES, FLAG_VALUE_ACCEPTS, READ_ONLY_COMMAND_TABLE, READ_ONLY_BARE_PROGRAMS, READ_ONLY_GLOB_PROGRAMS, READ_ONLY_EXACT_FORMS, READ_ONLY_BARE_ONLY, FIND_ACTION_PRIMARIES, FIND_VALUE_PRIMARIES, FIND_NEWER_PRIMARY, READ_ONLY_ENV_NAMES, XARGS_READ_ONLY_TARGETS, } from "./core/read-only-shell-table.js";
156
160
  export { orgRuleVerdictFor, orgRuleShadows, unenforceableOrgRules, ORG_UNAVAILABLE_DECISION_REASON, ORG_RULE_DECISION_REASON, ORG_ADJUDICATION_TIMEOUT_MS, } from "./core/permission-rule-org.js";
157
161
  export { RULE_SYNC_DROP_CODES } from "./core/governance-codes.js";
158
162
  export { prepareCardApproval, confirmRuleApproval, precheckEditedRuleText, redeemRuleTicket, redeemRuleBatch, prepareCcImport, prepareStarterBatch, mintRuleTicket, STARTER_RULES, InMemoryRuleApprovalRecordStore, ruleOffersOfRecord, } from "./core/permission-rule-consent.js";
@@ -186,7 +190,7 @@ export { DEFAULT_EFFORT_LEVELS, REASONING_BUDGET_SHARE, isThinkingLevel, rankOf,
186
190
  export { DESIGN_REVIEW_PROMPTS, CODE_REVIEW_PROMPT, SCENARIO_REGISTRY, runScenario, } from "./scenarios/scenario-registry.js";
187
191
  export { teacherMode, TEACHER_PROFILE, } from "./scenarios/teacher-quickstart.js";
188
192
  export { loadOrchestrationEnv, DEFAULT_REASONING_INTENSITY, } from "./scenarios/env.js";
189
- export { runWorkflow, startWorkflow, workflowAgentCallKey, WorkflowBudgetExceededError, WorkflowNestingError, WorkflowAgentSchemaError, WorkflowAgentStalledError, WorkflowAgentBlockedError, WORKFLOW_SPAWN_BLOCKED_ERROR_CODE, WORKFLOW_SUBAGENT_PROMPT, WORKFLOW_SUBAGENT_PROMPT_SCHEMA, WORKFLOW_SUBAGENT_APPEND, WORKFLOW_SUBAGENT_APPEND_SCHEMA, MAX_WORKFLOW_ITEMS, } from "./orchestration/workflow.js";
193
+ export { runWorkflow, startWorkflow, workflowAgentCallKey, WorkflowBudgetExceededError, WorkflowNestingError, WorkflowAgentSchemaError, WorkflowAgentStalledError, WorkflowAgentBlockedError, WORKFLOW_SPAWN_BLOCKED_ERROR_CODE, WorkflowAgentParkedError, WORKFLOW_AGENT_PARKED_ERROR_CODE, WORKFLOW_SUBAGENT_PROMPT, WORKFLOW_SUBAGENT_PROMPT_SCHEMA, WORKFLOW_SUBAGENT_APPEND, WORKFLOW_SUBAGENT_APPEND_SCHEMA, MAX_WORKFLOW_ITEMS, } from "./orchestration/workflow.js";
190
194
  export { listWorkflowRuns, getWorkflowRun, subscribeWorkflow, deriveAgentDisplayStatus } from "./orchestration/workflow-observe.js";
191
195
  export { runGoal, DECLARE_DONE_TOOL_NAME, } from "./orchestration/goal.js";
192
196
  export { emitTaskOutcome } from "./core/task-outcome.js";
@@ -260,8 +260,11 @@ export interface RunWorkflowToolDeps {
260
260
  /** The HOST task's effective working root — threaded into every spawned agent's trusted internals so a
261
261
  * TOC env factory can root the child at the parent's cwd (CC parity, 2026-07-03). */
262
262
  parentCwd?: string;
263
- /** Call-time getter for the HOST task's current thinking level a spawned agent with no explicit
264
- * script/baseline `thinking` inherits it (the parentCwd/model-snapshot companion). */
263
+ /** Call-time getter for the level a spawned agent runs at when neither the script, the agentType
264
+ * definition nor the governance baseline set `thinking` (the mount folds the deployment's STATED
265
+ * `roles.subagent.thinking` over the HOST task's current level — the child thinking seat's lower rungs).
266
+ * Threaded to the workflow as `defaultThinking` and applied at the launch site AFTER the agentType fold,
267
+ * the `parentModel` → `defaultModel` companion. */
265
268
  parentThinking?: () => import("../core/types.js").TaskSpec["thinking"];
266
269
  /** 5.30 merge-rescan (design/199 parity gap) — call-time getter for the HOST task's RESOLVED
267
270
  * read-face containment; folds stricter-wins into every spawned workflow child (see
@@ -307,6 +310,23 @@ export interface RunWorkflowToolDeps {
307
310
  * Absent on both seats ⇒ byte-identical baseline: a child's asks keep the pre-#342 resolution
308
311
  * (`RunnerDeps.onAsk`, else the fail-closed headless auto-deny). */
309
312
  parentOnAsk?: import("../core/tool-policy.js").OnAsk;
313
+ /** #642 — the HOST run's `durableApproval` opt-in (value copy; the Runner mints it from `spec.durableApproval`
314
+ * beside `parentOnAsk`, the same seat the delegation tool reads as `ctx.durableApprovalForChildren`). Folded
315
+ * into `RunWorkflowOptions.defaultDurableApproval` at execute — ONLY when a `store` is wired (the wa* row's
316
+ * durable home; without it the child keeps the pre-#642 lifecycle: its unavailable ask denies fail-closed
317
+ * and the `delegation.ask_unresolvable` notice says so). `ctx.durableApprovalForChildren` wins when a
318
+ * wrapping path provides it; this dep covers the auto-mounted tool's minimal execute ctx, like `parentOnAsk`.
319
+ * Absent on both seats ⇒ byte-identical: a workflow child's ask keeps the host-seat resolution alone. */
320
+ parentDurableApproval?: {
321
+ scope: string;
322
+ ttlMs?: number;
323
+ };
324
+ /** #642 — the decisions a host holds for PARKED wa* rows of a prior run, read at execute when the model
325
+ * re-invokes with `resumeFromRunId` (a call-time getter over the run id: the decisions arrive on the host's
326
+ * trusted run channel, `RunInternals.workflowParkedResume`, and only the ones naming THIS resume's source run
327
+ * apply). Threaded into `RunWorkflowOptions.parkedResume`: the resume drives the parked child on with the
328
+ * decision instead of re-parking. Never a tool argument — a model cannot decide an approval. */
329
+ parkedResume?: (resumeFromRunId: string) => ReadonlyArray<import("./workflow.js").WorkflowParkedResume> | undefined;
310
330
  /** The HOST run's display sink (its `RunInternals.onForwardEvent` behind the runner's ctx wrapper:
311
331
  * `task_progress` always, plus the children's content events — `text_delta`/`text_end`/
312
332
  * `reasoning_delta`/`tool_start`/`tool_end`, UNTRUSTED-RAW: the consumer must redact — when the HOST spec set
@@ -5,6 +5,7 @@ import { redactSecrets, redactHostLeaks, boundedRedactedSummary } from "../core/
5
5
  import { withDelegationProvenance } from "../core/tool-policy.js";
6
6
  import { LAUNCH_RECEIPT_OWN_WORDS_CLAUSE, launchReceiptNoQuoteClause } from "../agents/launch-receipt-contract.js";
7
7
  import { startWorkflow } from "./workflow.js";
8
+ import { WORKFLOW_AGENT_PARKED_ERROR_CODE } from "./workflow-types.js";
8
9
  import { buildWorkflowPrimitives } from "./workflow-primitives.js";
9
10
  import { parseWorkflowMeta, splitWorkflowMeta, workflowScriptReadsClockOrRandom } from "./workflow-meta.js";
10
11
  import { mergeWorkflowArgs, normalizeStringArg } from "./workflow-script-store.js";
@@ -51,6 +52,7 @@ function workflowUsageBlock(run) {
51
52
  agent_count: agents.length,
52
53
  agents_done: agents.filter((a) => a.status === "completed").length,
53
54
  agents_error: agents.filter((a) => a.status === "failed").length,
55
+ ...(agents.some((a) => a.status === "parked") ? { agents_parked: agents.filter((a) => a.status === "parked").length } : {}),
54
56
  agents_empty_result: agents.filter((a) => a.status === "completed" && (a.output === undefined || a.output === "")).length,
55
57
  agents_replayed: agents.filter((a) => a.replayed === true).length,
56
58
  ...(run.journalSkips !== undefined && run.journalSkips > 0 ? { journal_skipped: run.journalSkips } : {}),
@@ -76,6 +78,7 @@ function workflowDiagnostics(runId, journalRef, resumeMiss) {
76
78
  }
77
79
  const SCRIPT_ERROR_CODES = new Set([
78
80
  "workflow.script_error",
81
+ "workflow.parked_call_changed",
79
82
  "workflow.nesting",
80
83
  "workflow.model_not_allowed",
81
84
  "workflow.agent_schema",
@@ -86,6 +89,12 @@ const SCRIPT_ERROR_CODES = new Set([
86
89
  function failureSummary(err, runId) {
87
90
  const e = err;
88
91
  const code = typeof e?.code === "string" ? e.code : undefined;
92
+ if (code === WORKFLOW_AGENT_PARKED_ERROR_CODE) {
93
+ const msg = typeof e?.message === "string" ? redactSecrets(e.message) : "";
94
+ return (`workflow parked (${code}): ${msg.length > 200 ? `${msg.slice(0, 200)}…` : msg} — it did not fail and is not finished` +
95
+ (runId ? `; per-agent rows via TaskOutput("${runId}") (the parked row reads status "parked")` : "") +
96
+ `; do not re-issue the same call — once the approval is decided, the deployment resumes this run${runId ? ` (resumeFromRunId: "${runId}")` : ""} and the script continues from the parked call`);
97
+ }
89
98
  const guide = runId
90
99
  ? `; per-agent rows via TaskOutput("${runId}"); after fixing, re-invoke with resumeFromRunId: "${runId}" (completed agents replay from the journal)`
91
100
  : "";
@@ -465,6 +474,7 @@ export async function createRunWorkflowTool(d) {
465
474
  return structuredError(`workflow script failed to compile: ${err instanceof Error ? err.message : String(err)}`);
466
475
  }
467
476
  const hostOnAsk = ctx.onAsk ?? d.parentOnAsk;
477
+ const hostDurableApproval = ctx.durableApprovalForChildren ?? d.parentDurableApproval;
468
478
  const runGovernance = hostOnAsk !== undefined && governance.baseline.base.onAsk === undefined
469
479
  ? {
470
480
  ...governance,
@@ -478,7 +488,7 @@ export async function createRunWorkflowTool(d) {
478
488
  }
479
489
  : governance;
480
490
  const scriptFn = (wfCtx) => {
481
- const primitives = buildWorkflowPrimitives(wfCtx, runGovernance, d.onAgentSpawn, d.parentThinking, principal, ctx.checkpointStoreDisabledForChildren === true || d.parentCheckpointStoreDisabled === true, d.parentReadFace, d.parentReadDenyPatterns, ctx.handsReadOnly === true || d.parentHandsReadOnly === true, ctx.interactiveTools === false || d.parentInteractiveTools === false);
491
+ const primitives = buildWorkflowPrimitives(wfCtx, runGovernance, d.onAgentSpawn, principal, ctx.checkpointStoreDisabledForChildren === true || d.parentCheckpointStoreDisabled === true, d.parentReadFace, d.parentReadDenyPatterns, ctx.handsReadOnly === true || d.parentHandsReadOnly === true, ctx.interactiveTools === false || d.parentInteractiveTools === false);
482
492
  return d.scriptRunner.run({ scriptSource: script, primitives, scriptArgs: effectiveArgs, signal: wfCtx.signal }).then((r) => r.result);
483
493
  };
484
494
  if (ctx.signal?.aborted) {
@@ -536,7 +546,10 @@ export async function createRunWorkflowTool(d) {
536
546
  return d.parentMemoryCaptureState !== undefined ? { parentMemoryCaptureState: d.parentMemoryCaptureState } : {};
537
547
  })(),
538
548
  ...(d.parentModel !== undefined ? { defaultModel: d.parentModel } : {}),
549
+ ...(d.parentThinking !== undefined ? { defaultThinking: d.parentThinking } : {}),
539
550
  ...(d.parentGetApiKeyAndHeaders !== undefined ? { defaultGetApiKeyAndHeaders: d.parentGetApiKeyAndHeaders } : {}),
551
+ ...(hostDurableApproval !== undefined && d.store !== undefined ? { defaultDurableApproval: { ...hostDurableApproval } } : {}),
552
+ ...(resumeFromRunId !== undefined && d.parkedResume !== undefined && d.parkedResume(resumeFromRunId) !== undefined ? { parkedResume: d.parkedResume(resumeFromRunId) } : {}),
540
553
  ...(parentCenterArtifactDigest !== undefined ? { parentCenterArtifactDigest } : {}),
541
554
  ...(parentCenterSourceRevision !== undefined ? { parentCenterSourceRevision } : {}),
542
555
  ...((ctx.forwardEvent ?? d.forwardEvent) !== undefined ? { onForwardEvent: (ctx.forwardEvent ?? d.forwardEvent) } : {}),
@@ -8,8 +8,9 @@
8
8
  * (toolPolicy / onAsk / hooks / principal / tools / mcp / skills / lspManager / checkpointStore /
9
9
  * getApiKeyAndHeaders / promptProvider / sessionId / signal / …) is structurally never copied. "Never
10
10
  * copied" is a statement about the SCRIPT's spec — the child's control plane still arrives from the
11
- * TRUSTED side, and some of it inherits from the HOST run on trusted lanes of its own: `principal` /
12
- * `thinking` / the durable off-switch via `buildWorkflowPrimitives`' engine injections, and the host's
11
+ * TRUSTED side, and some of it inherits from the HOST run on trusted lanes of its own: `principal` / the
12
+ * durable off-switch via `buildWorkflowPrimitives`' engine injections, `model` / `thinking` / the stated
13
+ * subagent persona via the launch site's child seats (`withWorkflowChildSeats`), and the host's
13
14
  * effective approver via the run-workflow mount's base-slot fold (`RunWorkflowToolDeps.parentOnAsk` →
14
15
  * `baseline.base.onAsk`, backlog #342 — filled only when the deployment did not pin the seat). Those are
15
16
  * host-ctx bindings the engine writes onto the baseline/child, never a read of anything the script wrote:
@@ -56,7 +56,7 @@ export declare function listWorkflowRuns(store: WorkflowRunStore, scope: string,
56
56
  */
57
57
  export declare function getWorkflowRun(store: WorkflowRunStore, id: string, scope: string): Promise<WorkflowRun | null>;
58
58
  /** design/99 MF-W display status. */
59
- export type AgentDisplayStatus = "queued" | "running" | "done" | "failed" | "interrupted";
59
+ export type AgentDisplayStatus = "queued" | "running" | "done" | "failed" | "interrupted" | "parked";
60
60
  /**
61
61
  * design/99 MF-W (design-review DoR ⑤+⑥): the SHARED, anti-drift projection of a workflow agent's record-level
62
62
  * status → a CC-style display status, derived PURELY from the persisted record (the agent's `status` + `startedAt`
@@ -66,6 +66,8 @@ export function deriveAgentDisplayStatus(agent, runStatus) {
66
66
  return "done";
67
67
  if (agent.status === "failed")
68
68
  return "failed";
69
+ if (agent.status === "parked")
70
+ return "parked";
69
71
  if (runStatus !== "running")
70
72
  return "interrupted";
71
73
  return agent.startedAt === undefined ? "queued" : "running";
@@ -31,8 +31,11 @@ export interface WorkflowGovernance {
31
31
  /**
32
32
  * Build the flat {@link WorkflowPrimitives} a {@link WorkflowScriptRunner} runs the script against. The
33
33
  * `agent` primitive is GOVERNED when `governance` is set (LLM-authored), else a trusted pass-through.
34
+ * The host's model and thinking are NOT injected here: both are seats the launch site (`workflow.ts`,
35
+ * `withWorkflowChildSeats`) fills AFTER the agentType fold, so a definition's own value is the explicit rung
36
+ * — filling them here ran ahead of the fold and made the fold's "when unset" guard permanently false.
34
37
  */
35
- export declare function buildWorkflowPrimitives(ctx: WorkflowRunContext, governance?: WorkflowGovernance, onAgentSpawn?: (handle: WorkflowAgentHandle) => void, parentThinking?: () => TaskSpec["thinking"], parentPrincipal?: string,
38
+ export declare function buildWorkflowPrimitives(ctx: WorkflowRunContext, governance?: WorkflowGovernance, onAgentSpawn?: (handle: WorkflowAgentHandle) => void, parentPrincipal?: string,
36
39
  /** ruled 2026-08-04 — the host run set `TaskSpec.checkpointStore: "disabled"` (the per-run durable off
37
40
  * switch). Every agent this workflow spawns inherits it; see the injection below. */
38
41
  parentCheckpointStoreDisabled?: boolean,
@@ -65,7 +65,7 @@ function formatResourceClampNote(notes) {
65
65
  const parts = notes.map((n) => `${n.field}: requested ${n.requested === undefined ? "unset" : n.requested} → applied ${n.applied}`);
66
66
  return `workflow governance tightened this agent's resource limits (${parts.join("; ")})`;
67
67
  }
68
- export function buildWorkflowPrimitives(ctx, governance, onAgentSpawn, parentThinking, parentPrincipal, parentCheckpointStoreDisabled, parentReadFace, parentReadDenyPatterns, parentHandsReadOnly, parentInteractiveToolsOff) {
68
+ export function buildWorkflowPrimitives(ctx, governance, onAgentSpawn, parentPrincipal, parentCheckpointStoreDisabled, parentReadFace, parentReadDenyPatterns, parentHandsReadOnly, parentInteractiveToolsOff) {
69
69
  const agent = (spec, opts) => {
70
70
  if (typeof spec === "string")
71
71
  spec = { objective: spec };
@@ -74,11 +74,6 @@ export function buildWorkflowPrimitives(ctx, governance, onAgentSpawn, parentThi
74
74
  const childSpec = governance
75
75
  ? buildGovernedChildSpec(spec, effectiveBaseline(governance.baseline), governance.models, governance.caps, (notes) => ctx.log(formatResourceClampNote(notes)), governance.onNotice)
76
76
  : { ...spec };
77
- if (childSpec.thinking === undefined && parentThinking) {
78
- const inherited = parentThinking();
79
- if (inherited !== undefined)
80
- childSpec.thinking = inherited;
81
- }
82
77
  if (childSpec.principal === undefined && parentPrincipal !== undefined) {
83
78
  childSpec.principal = parentPrincipal;
84
79
  }
@@ -1,7 +1,9 @@
1
1
  import type { TaskResult, TaskStatus, ToolActivity } from "../core/types.js";
2
2
  export type WorkflowRunStatus = "running" | "completed" | "failed";
3
- /** Status of one phase / agent-run within a workflow. */
4
- export type WorkflowItemStatus = "running" | "completed" | "failed";
3
+ /** Status of one phase / agent-run within a workflow. `"parked"` (#642) is an AGENT row's word only — the
4
+ * agent durably paused at an approval gate and the run suspended on it (the row carries the token, see
5
+ * {@link WorkflowAgentRun.parkedCheckpointToken}); a phase or group never parks (a parked agent ends the run). */
6
+ export type WorkflowItemStatus = "running" | "completed" | "failed" | "parked";
5
7
  export interface WorkflowPhase {
6
8
  title: string;
7
9
  /** F7/B7 (CC pretty.js:446478): a phase PRE-REGISTERED from `meta.phases` starts as `"pending"` — the plan
@@ -119,6 +121,16 @@ export interface WorkflowAgentRun {
119
121
  * (`fork(sessionId)→runTask`, or `runTask({sessionId})`) instead of a fresh re-run. An opaque id (not
120
122
  * content) → scope-gated via `getWorkflowRun`, no redaction needed. Absent for a stub run that minted none. */
121
123
  sessionId?: string;
124
+ /**
125
+ * #642 — the durable-approval checkpoint token this agent is PARKED on (`status: "parked"` only): the child
126
+ * durably paused at an approval gate under the host's forwarded `durableApproval`, the run recorded the
127
+ * park here and suspended. The mirror of the background agent row's `parkedCheckpointToken`, and the
128
+ * workflow-origin JOIN a host routes a parked approval by: a checkpoint whose `sourceTaskId` equals this
129
+ * row's {@link sessionId} is a workflow child's park, and this token is the same row's redemption key —
130
+ * the checkpoint row itself carries no workflow key. It is the resume CAPABILITY (never log it or put it
131
+ * in a URL); a durable row is its home exactly as on the background lane. Absent on every other status.
132
+ */
133
+ parkedCheckpointToken?: string;
122
134
  /**
123
135
  * #499 — the ENGINE-minted identity of the task run behind this record (= its `TaskResult.runId`).
124
136
  *
@@ -515,6 +527,29 @@ export declare class WorkflowAgentBlockedError extends Error {
515
527
  /** Human-readable cause, already bounded + redacted by the engine (classifier text is model output). */
516
528
  reason: string);
517
529
  }
530
+ /** #642 — the machine code of a run that SUSPENDED on a parked agent (the thrown error's `code`, the run's
531
+ * failed terminal). Not a script fault and not a host fault: an approval a person still has to decide. */
532
+ export declare const WORKFLOW_AGENT_PARKED_ERROR_CODE = "workflow.agent_parked";
533
+ /**
534
+ * #642 — thrown by `ctx.agent` / `ctx.agentStream().result()` when the child durably PAUSED at an approval gate
535
+ * under the host's forwarded `durableApproval` (the workflow lane's park family, the background delegation's
536
+ * twin): the wa* row records `status:"parked"` + `parkedCheckpointToken`, the journal records the parked leg at
537
+ * its ordinal, and the RUN SUSPENDS — every later spawn is refused with this same error and the run's terminal
538
+ * is this park whatever the script body returns (the team-discussion `teamPause` shape). Nothing after the
539
+ * parked call runs; the script must not retry it (an identical call parks again). A resume of the run
540
+ * (`resumeFromRunId`) with the host's decision for the token drives the parked child on and the script
541
+ * continues from here; without a decision the ordinal re-parks.
542
+ *
543
+ * Carries the non-secret `checkpointId` (display/correlation) and the gate kind — never the token (the resume
544
+ * capability lives on the wa* row, a durable row, exactly as on the background lane).
545
+ */
546
+ export declare class WorkflowAgentParkedError extends Error {
547
+ readonly label: string;
548
+ readonly gateKind: string;
549
+ readonly checkpointId?: string | undefined;
550
+ readonly code = "workflow.agent_parked";
551
+ constructor(label: string, gateKind: string, checkpointId?: string | undefined);
552
+ }
518
553
  /** design/98 §D.6 hard cap: thrown by `ctx.agent` once the workflow has spawned `max` agents (a runaway
519
554
  * LLM-authored script is bounded, not trusted — this counts cumulative spawns, so it binds even when the
520
555
  * token budget has room left, or when no budget was set at all). */
@@ -55,6 +55,22 @@ export class WorkflowAgentBlockedError extends Error {
55
55
  this.name = "WorkflowAgentBlockedError";
56
56
  }
57
57
  }
58
+ export const WORKFLOW_AGENT_PARKED_ERROR_CODE = "workflow.agent_parked";
59
+ export class WorkflowAgentParkedError extends Error {
60
+ label;
61
+ gateKind;
62
+ checkpointId;
63
+ code = WORKFLOW_AGENT_PARKED_ERROR_CODE;
64
+ constructor(label, gateKind, checkpointId) {
65
+ super(`workflow agent "${label}" is parked at an approval gate (${gateKind}${checkpointId !== undefined ? `, checkpoint ${checkpointId}` : ""}) — ` +
66
+ "the workflow is suspended until the approval is decided; nothing after this call runs. Do not re-issue the call: " +
67
+ "a resume of this run carrying the decision continues from here.");
68
+ this.label = label;
69
+ this.gateKind = gateKind;
70
+ this.checkpointId = checkpointId;
71
+ this.name = "WorkflowAgentParkedError";
72
+ }
73
+ }
58
74
  export class WorkflowMaxAgentsError extends Error {
59
75
  max;
60
76
  budgetTotal;
@@ -1,6 +1,7 @@
1
1
  import type { TSchema } from "typebox";
2
- import type { RunnerSelfSeat } from "../core/runner/contracts.js";
3
- import type { AgentDefinition, TaskEvent, TaskResult, TaskSpec } from "../core/types.js";
2
+ import type { InheritedGate, RunnerSelfSeat } from "../core/runner/contracts.js";
3
+ import type { CheckpointToken, ResumeOutcome } from "../core/checkpoint-store.js";
4
+ import type { AgentDefinition, TaskEvent, TaskResult, TaskSpec, ThinkingLevel } from "../core/types.js";
4
5
  import type { WorkflowRunStore } from "../core/workflow-run-store.js";
5
6
  import type { WorkflowJournalStore, ResumeClaimArgs } from "../core/workflow-journal-store.js";
6
7
  import type { WorkflowRun, WorkflowEvent } from "./workflow-types.js";
@@ -21,9 +22,11 @@ export declare const WORKFLOW_SUBAGENT_APPEND_SCHEMA = "---\n\nNOTE: You are run
21
22
  * Apply the G5 default persona to a `ctx.agent`/`ctx.agentStream` child spec. Two-state on the EFFECTIVE
22
23
  * schema (`agentOpts.schema` wins over a spec-carried `outputSchema`, same as the runSpec injection):
23
24
  * • no `spec.systemPrompt` → the dedicated workflow-subagent persona REPLACES the role base (198
24
- * default `workflow-subagent` agent-type semantics);
25
- * a script-supplied `spec.systemPrompt` (custom persona) the matching NOTE is APPENDED via
26
- * `appendSystemPrompt` (198 composite semantics — append, never replace), after any existing append.
25
+ * default `workflow-subagent` agent-type semantics) — reached only when neither the script, the
26
+ * agentType definition nor the deployment's stated subagent preset supplied one ({@link withWorkflowChildSeats}
27
+ * writes the preset first);
28
+ * • a `spec.systemPrompt` (custom persona: script, definition or stated preset) → the matching NOTE is
29
+ * APPENDED via `appendSystemPrompt` (198 composite semantics — append, never replace), after any existing append.
27
30
  * Called AFTER the call-key is computed (the journal identity keys the AUTHORED spec, so a resume across
28
31
  * core versions replays cleanly; the persona is an execution detail, not call identity).
29
32
  */
@@ -120,7 +123,9 @@ export declare class WorkflowJournalIncompatibleError extends Error {
120
123
  readonly fromRunId: string;
121
124
  readonly ordinal: number;
122
125
  readonly code = "workflow.journal_incompatible";
123
- constructor(fromRunId: string, ordinal: number);
126
+ constructor(fromRunId: string, ordinal: number,
127
+ /** #642: an alternative reason clause (the parked-row cross-check); absent ⇒ the no-terminal-cause wording. */
128
+ reason?: string);
124
129
  }
125
130
  /**
126
131
  * A TRUSTED, run-scoped internal channel carrying the workflow **nesting depth** across a process boundary
@@ -282,6 +287,18 @@ export interface WorkflowRunContext {
282
287
  /** Emit a narrator log line (observability only — not stored on the run). */
283
288
  log(message: string): void;
284
289
  }
290
+ /**
291
+ * #642 — one decision a resume carries for a PARKED ordinal of the prior run ({@link RunWorkflowOptions.parkedResume}):
292
+ * the checkpoint token the wa* row is parked on (the row's `parkedCheckpointToken`, the redemption key), the
293
+ * caller's decision for it (the same {@link ResumeOutcome} a top-level `runner.resume` takes), and the optional
294
+ * cross-process re-supply of the checkpoint's opaque parent constraints. The token is matched by string equality
295
+ * against the journaled parked entry — an entry whose token no decision names re-parks.
296
+ */
297
+ export interface WorkflowParkedResume {
298
+ token: CheckpointToken;
299
+ outcome: ResumeOutcome;
300
+ inheritedGate?: InheritedGate;
301
+ }
285
302
  export interface RunWorkflowOptions {
286
303
  /** Trusted caller-supplied run id. Used by the unified task registry so tool-launched workflows expose
287
304
  * `task_id === runId` (`w*`) without making the model choose an id. Omit for the legacy UUID mint path. */
@@ -431,10 +448,40 @@ export interface RunWorkflowOptions {
431
448
  * re-resolution that loses per-model routing (the 4/4-agents-404 incident: session model id
432
449
  * re-resolved against the base gateway). Mirrors the subagent lane's `ctx.model` semantics. */
433
450
  defaultModel?: () => import("../internal/llm.js").Model | undefined;
451
+ /** Call-time getter for the thinking level a spawned agent runs at when neither the script, the
452
+ * agentType definition nor the governance baseline set `thinking` — the child thinking seat's lower rungs
453
+ * (the deployment's STATED `roles.subagent.thinking`, else the host's current level), as the run-workflow
454
+ * mount folds them. Snapshotted ONCE at call entry and folded into the call identity like `defaultModel`;
455
+ * applied at the launch site AFTER the agentType fold ({@link withWorkflowChildSeats}). */
456
+ defaultThinking?: () => ThinkingLevel | undefined;
434
457
  /** The HOST's per-model auth hook, inherited into every spawned agent's spec (the
435
458
  * credential half of model inheritance; scripts can never set it — governance strips it — so
436
459
  * this is always the host's). NOT call identity (auth, not behavior; a function, not data). */
437
460
  defaultGetApiKeyAndHeaders?: TaskSpec["getApiKeyAndHeaders"];
461
+ /**
462
+ * #642 — the HOST run's `durableApproval` opt-in (value copy), inherited into every spawned agent whose
463
+ * fold left the seat unpinned (a deployment baseline that pins `durableApproval` wins; scripts can never set
464
+ * it — governance strips it). With it a workflow child's plain policy `ask` — an ask the host's approver
465
+ * answers `unavailable` for, or a durable mandate — PARKS durably instead of denying fail-closed, exactly as
466
+ * a background delegation child's does under the §7.3 park family: the wa* row records `status:"parked"` +
467
+ * the token, the run SUSPENDS (the script cannot continue past a parked call), and a resume drives the
468
+ * parked child on with the caller's decision ({@link parkedResume}). Tighten-only: a park capability,
469
+ * never a widening — the decision stays with a person. REQUIRES {@link store} (the wa* row's durable home;
470
+ * refused loudly at entry without it). Threaded by the Workflow tool from the host's trusted seat; a
471
+ * directly-started workflow passes its own. NOT call identity.
472
+ */
473
+ defaultDurableApproval?: TaskSpec["durableApproval"];
474
+ /**
475
+ * #642 — the decisions a resume ({@link resumeFromRunId}) carries for PARKED ordinals of the prior run: at
476
+ * an ordinal whose journal entry is `parked` (a matching call key), the run drives the parked child's own
477
+ * resume — `runner.resumeStream(token, outcome, …)` on the pinned session, the child's spec rebuilt from
478
+ * the script call exactly as at spawn — and settles its result at that ordinal, so the script continues past
479
+ * the call it parked on. A parked ordinal with NO decision here re-parks (the row and the journal say the
480
+ * same thing again, the run suspends again); it is never run live. `inheritedGate` is the cross-process
481
+ * re-supply of the checkpoint's opaque parent constraints (the same seat the background lane's drive
482
+ * takes). TRUSTED: a host-supplied decision, never a script/model argument; requires `resumeFromRunId`.
483
+ */
484
+ parkedResume?: ReadonlyArray<WorkflowParkedResume>;
438
485
  /** design/148 S1 — the HOST run's adopted center artifact (trusted, threaded by the Workflow tool
439
486
  * from ctx): every spawned agent composes the same closure. */
440
487
  parentCenterArtifactDigest?: string;