@sema-agent/core 7.9.2 → 7.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/dist/agents/child-model-seat.d.ts +31 -1
- package/dist/agents/child-model-seat.js +12 -0
- package/dist/agents/subagent.d.ts +2 -2
- package/dist/agents/subagent.js +6 -4
- package/dist/core/ask-unresolvable-notice.d.ts +52 -0
- package/dist/core/ask-unresolvable-notice.js +25 -0
- package/dist/core/auto-mode.d.ts +62 -3
- package/dist/core/auto-mode.js +31 -0
- package/dist/core/checkpoint-store.d.ts +14 -0
- package/dist/core/checkpoint-store.js +2 -1
- package/dist/core/engine-notice.d.ts +28 -7
- package/dist/core/gate-lanes.js +15 -0
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +4 -0
- package/dist/core/hooks.d.ts +24 -1
- package/dist/core/hooks.js +2 -0
- package/dist/core/permission-rule-model.d.ts +51 -16
- package/dist/core/permission-rule-model.js +55 -21
- package/dist/core/permission-rules.d.ts +6 -4
- package/dist/core/permission-rules.js +14 -14
- package/dist/core/runner/contracts.d.ts +26 -2
- package/dist/core/runner/denial-limit-arms.d.ts +14 -3
- package/dist/core/runner/denial-limit-arms.js +15 -5
- package/dist/core/runner/permission-rule-lanes.d.ts +7 -1
- package/dist/core/runner/permission-rule-lanes.js +9 -3
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +1 -1
- package/dist/core/runner/prepare-caps-and-workflow.js +13 -3
- package/dist/core/runner/prepare-gate-stations.d.ts +3 -2
- package/dist/core/runner/prepare-gate-stations.js +3 -0
- package/dist/core/runner/prepare-policy-chain.js +7 -6
- package/dist/core/runner/prepare-wiring-manifest.d.ts +1 -1
- package/dist/core/runner/prepare-wiring-manifest.js +8 -1
- package/dist/core/runner/runtask.d.ts +33 -32
- package/dist/core/runner/runtask.js +63 -33
- package/dist/core/runner-deps.d.ts +9 -2
- package/dist/core/swappable-deps.d.ts +90 -0
- package/dist/core/swappable-deps.js +55 -0
- package/dist/core/tool-policy.d.ts +26 -0
- package/dist/core/tool-policy.js +5 -1
- package/dist/core/wiring-manifest.d.ts +15 -1
- package/dist/core/wiring-manifest.js +10 -2
- package/dist/core/workflow-journal-store.d.ts +21 -2
- package/dist/core/workflow-journal-store.js +1 -1
- package/dist/engine/execution-env/node-execution-env.d.ts +2 -0
- package/dist/engine/execution-env/node-execution-env.js +2 -1
- package/dist/engine/harness/types.d.ts +11 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.js +5 -3
- package/dist/orchestration/run-workflow-tool.d.ts +17 -0
- package/dist/orchestration/run-workflow-tool.js +12 -0
- package/dist/orchestration/workflow-observe.d.ts +1 -1
- package/dist/orchestration/workflow-observe.js +2 -0
- package/dist/orchestration/workflow-types.d.ts +37 -2
- package/dist/orchestration/workflow-types.js +16 -0
- package/dist/orchestration/workflow.d.ts +41 -2
- package/dist/orchestration/workflow.js +295 -44
- package/dist/stores/file/workflow-journal-store.js +10 -3
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +51 -5
|
@@ -244,10 +244,21 @@ export interface WiringManifest {
|
|
|
244
244
|
* classifier decider was minted for this leg), and `reason` names the first arm that failed
|
|
245
245
|
* otherwise — see {@link AUTO_MODE_ARM_REASONS}. A serving layer that used to infer the mode from
|
|
246
246
|
* spec shape reads it here instead.
|
|
247
|
+
*
|
|
248
|
+
* `breaker` (#616) — the SESSION-level breaker read face: the most recent one-way breaker trip recorded
|
|
249
|
+
* for this session on this Runner (an EARLIER leg's decider — the latch is a per-run fact and a leg-start
|
|
250
|
+
* manifest's own decider is closed by construction, which is why there is no `open` boolean here: it
|
|
251
|
+
* would read `false` on every mint; the reason vocabulary reserves `latch_open` for a mid-leg re-read
|
|
252
|
+
* face nothing mints today). Present ⇔ a trip was recorded (never tripped, evicted or a standalone
|
|
253
|
+
* prepare ⇒ absent). `{ openedAtMs, lastCause, failures, runId }` — see
|
|
254
|
+
* {@link import("./auto-mode.js").AutoModeBreakerTrip}. A per-leg observation like `mcp`, so it is NOT
|
|
255
|
+
* part of {@link configFingerprint}: legs of one assembly must fingerprint alike whether or not a
|
|
256
|
+
* classifier was down.
|
|
247
257
|
*/
|
|
248
258
|
autoMode?: {
|
|
249
259
|
armed: boolean;
|
|
250
260
|
reason: AutoModeArmReason;
|
|
261
|
+
breaker?: import("./auto-mode.js").AutoModeBreakerTrip;
|
|
251
262
|
};
|
|
252
263
|
/**
|
|
253
264
|
* EFFECTIVE half only, and ALWAYS present on an engine-minted effective manifest (the `autoMode`
|
|
@@ -336,10 +347,13 @@ export interface WiringFacts {
|
|
|
336
347
|
restore: string;
|
|
337
348
|
};
|
|
338
349
|
/** Effective half only — see {@link WiringManifest.autoMode}; the static half has no leg to arm.
|
|
339
|
-
* `armed` must agree with `reason` (`armed ⇔ reason === "armed"`); a contradicting pair is refused.
|
|
350
|
+
* `armed` must agree with `reason` (`armed ⇔ reason === "armed"`); a contradicting pair is refused.
|
|
351
|
+
* `breaker` (#616) is the session's most recent recorded trip, or absent; a trip whose cause is outside
|
|
352
|
+
* the closed set or whose numbers are not finite is refused. */
|
|
340
353
|
autoMode?: {
|
|
341
354
|
armed: boolean;
|
|
342
355
|
reason: AutoModeArmReason;
|
|
356
|
+
breaker?: import("./auto-mode.js").AutoModeBreakerTrip;
|
|
343
357
|
};
|
|
344
358
|
/** Effective half only — see {@link WiringManifest.mcp}; the static half materializes nothing.
|
|
345
359
|
* Copied entry-wise onto the manifest (the caller's array is never aliased). */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { AUTO_MODE_BREAKER_CAUSES, isAutoModeBreakerCause } from "./auto-mode.js";
|
|
2
3
|
import { canonicalize } from "./canonical-json.js";
|
|
3
4
|
import { resolveCheckpointStore } from "./checkpoint-store.js";
|
|
4
5
|
import { isLiveQuestionFace } from "./ask-question.js";
|
|
@@ -71,7 +72,13 @@ function readAutoModeFact(fact) {
|
|
|
71
72
|
if (!AUTO_MODE_ARM_REASONS.includes(fact.reason) || fact.armed !== (fact.reason === "armed")) {
|
|
72
73
|
throw new Error(`the auto-mode wiring fact is inconsistent (armed=${String(fact.armed)}, reason=${JSON.stringify(fact.reason)}) — armed must hold exactly when reason is "armed", and reason must be one of ${AUTO_MODE_ARM_REASONS.join("|")}`);
|
|
73
74
|
}
|
|
74
|
-
|
|
75
|
+
const b = fact.breaker;
|
|
76
|
+
if (b === undefined)
|
|
77
|
+
return { armed: fact.armed, reason: fact.reason };
|
|
78
|
+
if (!isAutoModeBreakerCause(b.lastCause) || !Number.isFinite(b.openedAtMs) || !Number.isInteger(b.failures) || b.failures < 1 || typeof b.runId !== "string" || b.runId === "") {
|
|
79
|
+
throw new Error(`the auto-mode breaker fact is malformed (${JSON.stringify(b)}) — lastCause must be one of ${AUTO_MODE_BREAKER_CAUSES.join("|")}, openedAtMs finite, failures a positive integer, runId a non-empty string`);
|
|
80
|
+
}
|
|
81
|
+
return { armed: fact.armed, reason: fact.reason, breaker: { openedAtMs: b.openedAtMs, lastCause: b.lastCause, failures: b.failures, runId: b.runId } };
|
|
75
82
|
}
|
|
76
83
|
export function deriveWiringManifest(facts) {
|
|
77
84
|
if (facts.half === "static" && facts.leg !== undefined) {
|
|
@@ -133,8 +140,9 @@ export function deriveWiringManifest(facts) {
|
|
|
133
140
|
const { leg: _leg, mcp: _mcp, tools: _tools, ...assembly } = manifest;
|
|
134
141
|
const { provenance: _askSeat, ...askForHash } = assembly.ask;
|
|
135
142
|
const { provenance: _questionSeat, ...questionForHash } = assembly.question;
|
|
143
|
+
const { breaker: _breaker, ...autoModeForHash } = assembly.autoMode ?? {};
|
|
136
144
|
manifest.configFingerprint = createHash("sha256")
|
|
137
|
-
.update(canonicalize({ ...assembly, ask: askForHash, question: questionForHash }))
|
|
145
|
+
.update(canonicalize({ ...assembly, ask: askForHash, question: questionForHash, ...(assembly.autoMode !== undefined ? { autoMode: autoModeForHash } : {}) }))
|
|
138
146
|
.digest("hex")
|
|
139
147
|
.slice(0, 16);
|
|
140
148
|
}
|
|
@@ -5,12 +5,31 @@ import type { TaskResult } from "./types.js";
|
|
|
5
5
|
* longest unchanged PREFIX of these (keyed by the deterministic {@link workflowAgentCallKey}) and runs only the
|
|
6
6
|
* first changed/new call + everything after it live. Same script + same args → 100% cache hit.
|
|
7
7
|
*/
|
|
8
|
-
export
|
|
8
|
+
export type WorkflowJournalEntry = {
|
|
9
9
|
/** The agent's deterministic call key (`ordinal:specIdentityHash`) — the replay match key. */
|
|
10
10
|
callKey: string;
|
|
11
11
|
/** The agent's TaskResult, replayed verbatim when a resume's call key matches at the same ordinal. */
|
|
12
12
|
result: TaskResult;
|
|
13
|
-
|
|
13
|
+
parked?: never;
|
|
14
|
+
} | {
|
|
15
|
+
callKey: string;
|
|
16
|
+
result?: never;
|
|
17
|
+
/**
|
|
18
|
+
* #642 — the ordinal's leg is PARKED at a durable approval gate: the child's own paused `TaskResult`
|
|
19
|
+
* (its `terminal` carries the checkpoint token + gate, its `sessionId` the pinned session). A resume
|
|
20
|
+
* reaching this ordinal with a matching call key does NOT run the call live (the parked child's
|
|
21
|
+
* session is pinned under a pending checkpoint; a fresh spawn would duplicate it) — it drives the
|
|
22
|
+
* parked child's resume when the caller hands it a decision for the token, else re-parks. Deliberately
|
|
23
|
+
* a DIFFERENT key from `result`: a journal reader from before this entry kind existed finds no
|
|
24
|
+
* `result.terminal` and refuses the whole resume (`WorkflowJournalIncompatibleError`) instead of
|
|
25
|
+
* admitting a paused cause it would re-run live — one-way, loud, like every journal schema step.
|
|
26
|
+
*/
|
|
27
|
+
parked: TaskResult & {
|
|
28
|
+
terminal: Extract<TaskResult["terminal"], {
|
|
29
|
+
kind: "paused";
|
|
30
|
+
}>;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
14
33
|
/** REF-D5: the resume-claim key triple — ONE shape for the interface pair and every implementation
|
|
15
34
|
* (it was re-inlined seven times; a key-field rename must red every leg at once). */
|
|
16
35
|
export interface ResumeClaimArgs {
|
|
@@ -65,7 +65,7 @@ export class InMemoryWorkflowJournalStore {
|
|
|
65
65
|
return [...rec.byOrdinal.entries()].sort((a, b) => a[0] - b[0]).map(([, e]) => snapshot(e));
|
|
66
66
|
}
|
|
67
67
|
async append(runId, scope, entry) {
|
|
68
|
-
if (oversizeJournalResult(JSON.stringify(entry.result)))
|
|
68
|
+
if (oversizeJournalResult(JSON.stringify(entry.parked !== undefined ? entry.parked : entry.result)))
|
|
69
69
|
return;
|
|
70
70
|
let rec = this.runs.get(runId);
|
|
71
71
|
if (!rec) {
|
|
@@ -79,6 +79,8 @@ export declare function openSpoolPair(base: string): {
|
|
|
79
79
|
};
|
|
80
80
|
export declare class NodeExecutionEnv implements ExecutionEnv, BackgroundShellCapability, SchedulerCapability {
|
|
81
81
|
cwd: string;
|
|
82
|
+
/** #644 — this adapter runs on the engine host, so the host's home IS the environment's (`ExecutionEnv.homeDir`). */
|
|
83
|
+
readonly homeDir: string;
|
|
82
84
|
private shellPath?;
|
|
83
85
|
private shellEnv?;
|
|
84
86
|
private inheritEnv;
|
|
@@ -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;
|
|
@@ -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 {
|
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 {
|
|
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,7 +190,7 @@ 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,
|
|
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";
|
|
@@ -228,7 +230,7 @@ export { type ReasoningIntensity, type ReasoningResolution, type ResolvedReasoni
|
|
|
228
230
|
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
231
|
export { teacherMode, TEACHER_PROFILE, type TeacherModePair, type TeacherProfile, } from "./scenarios/teacher-quickstart.js";
|
|
230
232
|
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";
|
|
233
|
+
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
234
|
export { listWorkflowRuns, getWorkflowRun, subscribeWorkflow, deriveAgentDisplayStatus, type AgentDisplayStatus } from "./orchestration/workflow-observe.js";
|
|
233
235
|
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
236
|
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,14 +141,15 @@ 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 {
|
|
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,
|
|
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";
|
|
@@ -186,7 +188,7 @@ export { DEFAULT_EFFORT_LEVELS, REASONING_BUDGET_SHARE, isThinkingLevel, rankOf,
|
|
|
186
188
|
export { DESIGN_REVIEW_PROMPTS, CODE_REVIEW_PROMPT, SCENARIO_REGISTRY, runScenario, } from "./scenarios/scenario-registry.js";
|
|
187
189
|
export { teacherMode, TEACHER_PROFILE, } from "./scenarios/teacher-quickstart.js";
|
|
188
190
|
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";
|
|
191
|
+
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
192
|
export { listWorkflowRuns, getWorkflowRun, subscribeWorkflow, deriveAgentDisplayStatus } from "./orchestration/workflow-observe.js";
|
|
191
193
|
export { runGoal, DECLARE_DONE_TOOL_NAME, } from "./orchestration/goal.js";
|
|
192
194
|
export { emitTaskOutcome } from "./core/task-outcome.js";
|
|
@@ -307,6 +307,23 @@ export interface RunWorkflowToolDeps {
|
|
|
307
307
|
* Absent on both seats ⇒ byte-identical baseline: a child's asks keep the pre-#342 resolution
|
|
308
308
|
* (`RunnerDeps.onAsk`, else the fail-closed headless auto-deny). */
|
|
309
309
|
parentOnAsk?: import("../core/tool-policy.js").OnAsk;
|
|
310
|
+
/** #642 — the HOST run's `durableApproval` opt-in (value copy; the Runner mints it from `spec.durableApproval`
|
|
311
|
+
* beside `parentOnAsk`, the same seat the delegation tool reads as `ctx.durableApprovalForChildren`). Folded
|
|
312
|
+
* into `RunWorkflowOptions.defaultDurableApproval` at execute — ONLY when a `store` is wired (the wa* row's
|
|
313
|
+
* durable home; without it the child keeps the pre-#642 lifecycle: its unavailable ask denies fail-closed
|
|
314
|
+
* and the `delegation.ask_unresolvable` notice says so). `ctx.durableApprovalForChildren` wins when a
|
|
315
|
+
* wrapping path provides it; this dep covers the auto-mounted tool's minimal execute ctx, like `parentOnAsk`.
|
|
316
|
+
* Absent on both seats ⇒ byte-identical: a workflow child's ask keeps the host-seat resolution alone. */
|
|
317
|
+
parentDurableApproval?: {
|
|
318
|
+
scope: string;
|
|
319
|
+
ttlMs?: number;
|
|
320
|
+
};
|
|
321
|
+
/** #642 — the decisions a host holds for PARKED wa* rows of a prior run, read at execute when the model
|
|
322
|
+
* re-invokes with `resumeFromRunId` (a call-time getter over the run id: the decisions arrive on the host's
|
|
323
|
+
* trusted run channel, `RunInternals.workflowParkedResume`, and only the ones naming THIS resume's source run
|
|
324
|
+
* apply). Threaded into `RunWorkflowOptions.parkedResume`: the resume drives the parked child on with the
|
|
325
|
+
* decision instead of re-parking. Never a tool argument — a model cannot decide an approval. */
|
|
326
|
+
parkedResume?: (resumeFromRunId: string) => ReadonlyArray<import("./workflow.js").WorkflowParkedResume> | undefined;
|
|
310
327
|
/** The HOST run's display sink (its `RunInternals.onForwardEvent` behind the runner's ctx wrapper:
|
|
311
328
|
* `task_progress` always, plus the children's content events — `text_delta`/`text_end`/
|
|
312
329
|
* `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,
|
|
@@ -537,6 +547,8 @@ export async function createRunWorkflowTool(d) {
|
|
|
537
547
|
})(),
|
|
538
548
|
...(d.parentModel !== undefined ? { defaultModel: d.parentModel } : {}),
|
|
539
549
|
...(d.parentGetApiKeyAndHeaders !== undefined ? { defaultGetApiKeyAndHeaders: d.parentGetApiKeyAndHeaders } : {}),
|
|
550
|
+
...(hostDurableApproval !== undefined && d.store !== undefined ? { defaultDurableApproval: { ...hostDurableApproval } } : {}),
|
|
551
|
+
...(resumeFromRunId !== undefined && d.parkedResume !== undefined && d.parkedResume(resumeFromRunId) !== undefined ? { parkedResume: d.parkedResume(resumeFromRunId) } : {}),
|
|
540
552
|
...(parentCenterArtifactDigest !== undefined ? { parentCenterArtifactDigest } : {}),
|
|
541
553
|
...(parentCenterSourceRevision !== undefined ? { parentCenterSourceRevision } : {}),
|
|
542
554
|
...((ctx.forwardEvent ?? d.forwardEvent) !== undefined ? { onForwardEvent: (ctx.forwardEvent ?? d.forwardEvent) } : {}),
|
|
@@ -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";
|
|
@@ -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
|
-
|
|
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,5 +1,6 @@
|
|
|
1
1
|
import type { TSchema } from "typebox";
|
|
2
|
-
import type { RunnerSelfSeat } from "../core/runner/contracts.js";
|
|
2
|
+
import type { InheritedGate, RunnerSelfSeat } from "../core/runner/contracts.js";
|
|
3
|
+
import type { CheckpointToken, ResumeOutcome } from "../core/checkpoint-store.js";
|
|
3
4
|
import type { AgentDefinition, TaskEvent, TaskResult, TaskSpec } 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";
|
|
@@ -120,7 +121,9 @@ export declare class WorkflowJournalIncompatibleError extends Error {
|
|
|
120
121
|
readonly fromRunId: string;
|
|
121
122
|
readonly ordinal: number;
|
|
122
123
|
readonly code = "workflow.journal_incompatible";
|
|
123
|
-
constructor(fromRunId: string, ordinal: number
|
|
124
|
+
constructor(fromRunId: string, ordinal: number,
|
|
125
|
+
/** #642: an alternative reason clause (the parked-row cross-check); absent ⇒ the no-terminal-cause wording. */
|
|
126
|
+
reason?: string);
|
|
124
127
|
}
|
|
125
128
|
/**
|
|
126
129
|
* A TRUSTED, run-scoped internal channel carrying the workflow **nesting depth** across a process boundary
|
|
@@ -282,6 +285,18 @@ export interface WorkflowRunContext {
|
|
|
282
285
|
/** Emit a narrator log line (observability only — not stored on the run). */
|
|
283
286
|
log(message: string): void;
|
|
284
287
|
}
|
|
288
|
+
/**
|
|
289
|
+
* #642 — one decision a resume carries for a PARKED ordinal of the prior run ({@link RunWorkflowOptions.parkedResume}):
|
|
290
|
+
* the checkpoint token the wa* row is parked on (the row's `parkedCheckpointToken`, the redemption key), the
|
|
291
|
+
* caller's decision for it (the same {@link ResumeOutcome} a top-level `runner.resume` takes), and the optional
|
|
292
|
+
* cross-process re-supply of the checkpoint's opaque parent constraints. The token is matched by string equality
|
|
293
|
+
* against the journaled parked entry — an entry whose token no decision names re-parks.
|
|
294
|
+
*/
|
|
295
|
+
export interface WorkflowParkedResume {
|
|
296
|
+
token: CheckpointToken;
|
|
297
|
+
outcome: ResumeOutcome;
|
|
298
|
+
inheritedGate?: InheritedGate;
|
|
299
|
+
}
|
|
285
300
|
export interface RunWorkflowOptions {
|
|
286
301
|
/** Trusted caller-supplied run id. Used by the unified task registry so tool-launched workflows expose
|
|
287
302
|
* `task_id === runId` (`w*`) without making the model choose an id. Omit for the legacy UUID mint path. */
|
|
@@ -435,6 +450,30 @@ export interface RunWorkflowOptions {
|
|
|
435
450
|
* credential half of model inheritance; scripts can never set it — governance strips it — so
|
|
436
451
|
* this is always the host's). NOT call identity (auth, not behavior; a function, not data). */
|
|
437
452
|
defaultGetApiKeyAndHeaders?: TaskSpec["getApiKeyAndHeaders"];
|
|
453
|
+
/**
|
|
454
|
+
* #642 — the HOST run's `durableApproval` opt-in (value copy), inherited into every spawned agent whose
|
|
455
|
+
* fold left the seat unpinned (a deployment baseline that pins `durableApproval` wins; scripts can never set
|
|
456
|
+
* it — governance strips it). With it a workflow child's plain policy `ask` — an ask the host's approver
|
|
457
|
+
* answers `unavailable` for, or a durable mandate — PARKS durably instead of denying fail-closed, exactly as
|
|
458
|
+
* a background delegation child's does under the §7.3 park family: the wa* row records `status:"parked"` +
|
|
459
|
+
* the token, the run SUSPENDS (the script cannot continue past a parked call), and a resume drives the
|
|
460
|
+
* parked child on with the caller's decision ({@link parkedResume}). Tighten-only: a park capability,
|
|
461
|
+
* never a widening — the decision stays with a person. REQUIRES {@link store} (the wa* row's durable home;
|
|
462
|
+
* refused loudly at entry without it). Threaded by the Workflow tool from the host's trusted seat; a
|
|
463
|
+
* directly-started workflow passes its own. NOT call identity.
|
|
464
|
+
*/
|
|
465
|
+
defaultDurableApproval?: TaskSpec["durableApproval"];
|
|
466
|
+
/**
|
|
467
|
+
* #642 — the decisions a resume ({@link resumeFromRunId}) carries for PARKED ordinals of the prior run: at
|
|
468
|
+
* an ordinal whose journal entry is `parked` (a matching call key), the run drives the parked child's own
|
|
469
|
+
* resume — `runner.resumeStream(token, outcome, …)` on the pinned session, the child's spec rebuilt from
|
|
470
|
+
* the script call exactly as at spawn — and settles its result at that ordinal, so the script continues past
|
|
471
|
+
* the call it parked on. A parked ordinal with NO decision here re-parks (the row and the journal say the
|
|
472
|
+
* same thing again, the run suspends again); it is never run live. `inheritedGate` is the cross-process
|
|
473
|
+
* re-supply of the checkpoint's opaque parent constraints (the same seat the background lane's drive
|
|
474
|
+
* takes). TRUSTED: a host-supplied decision, never a script/model argument; requires `resumeFromRunId`.
|
|
475
|
+
*/
|
|
476
|
+
parkedResume?: ReadonlyArray<WorkflowParkedResume>;
|
|
438
477
|
/** design/148 S1 — the HOST run's adopted center artifact (trusted, threaded by the Workflow tool
|
|
439
478
|
* from ctx): every spawned agent composes the same closure. */
|
|
440
479
|
parentCenterArtifactDigest?: string;
|