@agentproto/workflow-runtime 0.13.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -74,12 +74,14 @@ type FanOutOutcome<T = unknown> = {
74
74
  /** `err.message` if the throw was an `Error`, else `String(err)`. */
75
75
  readonly error: string;
76
76
  } | {
77
- /** Never started: the fan-out's spawn circuit breaker opened first
78
- * (see {@link MapStep.maxConsecutiveSpawnFailures}). */
77
+ /** Never started: either the fan-out's spawn circuit breaker opened
78
+ * first (see {@link MapStep.maxConsecutiveSpawnFailures}), or the run
79
+ * was cancelled while earlier items were still in flight. */
79
80
  readonly status: "skipped";
80
81
  readonly index: number;
81
82
  readonly item: unknown;
82
- /** `circuit-open: <first error of the failure streak>`. */
83
+ /** `circuit-open: <first error of the failure streak>`, or
84
+ * `run-cancelled: run cancelled`. */
83
85
  readonly reason: string;
84
86
  };
85
87
  /**
@@ -525,6 +527,12 @@ type GateCommandRunner = (spec: {
525
527
  args: readonly string[];
526
528
  cwd: string;
527
529
  timeoutMs?: number;
530
+ /** The run's cancel signal — a cancelled run kills an in-flight gate
531
+ * command's child process the same way it kills an agent step's session.
532
+ * A host-injected runner should pass this through to its own subprocess
533
+ * spawn (e.g. `child_process.execFile`'s `signal` option) so the process
534
+ * is signalled, not merely orphaned. */
535
+ signal?: AbortSignal;
528
536
  }) => Promise<GateCommandResult>;
529
537
  /** One `kind: "gate"` command attempt's outcome, reported as it happens
530
538
  * (every attempt, not just the last) — the `gate-report` lifecycle event. */
@@ -733,13 +741,16 @@ interface StepSkippedInfo {
733
741
  /** `"branch-not-taken"`: the step sits in an untaken `branch` arm.
734
742
  * `"circuit-open"`: a `map`/`pipeline` item never started because the
735
743
  * fan-out's spawn circuit breaker opened
736
- * ({@link MapStep.maxConsecutiveSpawnFailures}). */
737
- reason: "branch-not-taken" | "circuit-open";
744
+ * ({@link MapStep.maxConsecutiveSpawnFailures}). `"run-cancelled"`: a
745
+ * `map`/`pipeline` item never started because the run was cancelled
746
+ * (`RunWorkflowArgs.signal` aborted) while earlier items were still in
747
+ * flight. */
748
+ reason: "branch-not-taken" | "circuit-open" | "run-cancelled";
738
749
  /** Id of the authored step whose decision skipped the step — the `branch`
739
- * step, or (circuit-open) the `map`/`pipeline` step. */
750
+ * step, or (circuit-open/run-cancelled) the `map`/`pipeline` step. */
740
751
  branchId: string;
741
- /** `"circuit-open"` only: the first error of the spawn-failure streak
742
- * that tripped the breaker. */
752
+ /** `"circuit-open"`: the first error of the spawn-failure streak that
753
+ * tripped the breaker. `"run-cancelled"`: a fixed "run cancelled" message. */
743
754
  message?: string;
744
755
  }
745
756
  /** What `onStepFailed` reports. */
@@ -898,6 +909,18 @@ declare class AgentSpawnError extends Error {
898
909
  readonly cause: unknown;
899
910
  constructor(stepId: string, cause: unknown);
900
911
  }
912
+ /**
913
+ * Thrown instead of dispatching a step whose run was cancelled
914
+ * (`ctx.signal.aborted`) — checked BEFORE any work for the step begins (see
915
+ * {@link execStepBody}'s entry guard), so a cancel stops the run from
916
+ * starting any further step, including a sibling within the SAME stage/
917
+ * fan-out, not just a later one. Never journaled: it's thrown before a
918
+ * cacheable step's `cache.set` call, so `workflow_retry` re-executes it.
919
+ */
920
+ declare class WorkflowCancelledError extends Error {
921
+ readonly stepId: string;
922
+ constructor(stepId: string);
923
+ }
901
924
  declare function runWorkflow(args: RunWorkflowArgs): Promise<WorkflowRunResult>;
902
925
 
903
926
  /**
@@ -1180,4 +1203,4 @@ declare class NodeFsPort implements FsPort {
1180
1203
  lock(): Promise<FsLockHandle>;
1181
1204
  }
1182
1205
 
1183
- export { type AgentHarness, AgentInputRequiredError, type AgentRefResolution, type AgentSandboxRef, type AgentSessionHost, AgentSpawnError, type AgentStep, type AgentStepFields, type ApprovalDecision, type ApprovalRequest, type ApprovalStep, type ArtifactEntry, type ArtifactStep, type Bindings, type BranchStep, type CompileWorkflowOptions, DEFAULT_MAX_CONSECUTIVE_SPAWN_FAILURES, type FanOutOutcome, type GateCommandResult, type GateCommandRunner, type GateReportEvent, type GateStep, type GroupStep, type HarnessKnowledgeSelector, type InputRequiredRequest, type KnowledgeAppliedRecord, type LoopStep, type MapStep, type MaterializedKnowledge, MissingArtifactError, NodeFsPort, type OutputSchemaLike, type OutputsFileContract, type ParallelStep, type PipelineStep, type ResumeRequest, type RunStep, type RunWorkflowArgs, type RuntimeWorkflow, type SchemaValidationIssue, type Selector, type StepCache, type StepCacheEntry, type StepFailedInfo, type StepHookInfo, StepOutcomeError, type StepSkippedInfo, type SubworkflowStep, type SuspendStep, type TolerantFanOutResult, type ToolStep, type TransformStep, WorkflowCompileError, type WorkflowInputValidation, type WorkflowRunResult, WorkflowSuspendedError, buildAgentStep, compileWorkflow, compileWorkflowManifest, evalPredicate, interpolateTemplate, isCompilableJsonSchema, materializeKnowledge, normalizeWorkflowInputsSchema, resolveKnowledgeSelectors, resolveRef, resolveRefPrefixed, resolveValue, runWorkflow, validateAgainstJsonSchema, validateWorkflowInput };
1206
+ export { type AgentHarness, AgentInputRequiredError, type AgentRefResolution, type AgentSandboxRef, type AgentSessionHost, AgentSpawnError, type AgentStep, type AgentStepFields, type ApprovalDecision, type ApprovalRequest, type ApprovalStep, type ArtifactEntry, type ArtifactStep, type Bindings, type BranchStep, type CompileWorkflowOptions, DEFAULT_MAX_CONSECUTIVE_SPAWN_FAILURES, type FanOutOutcome, type GateCommandResult, type GateCommandRunner, type GateReportEvent, type GateStep, type GroupStep, type HarnessKnowledgeSelector, type InputRequiredRequest, type KnowledgeAppliedRecord, type LoopStep, type MapStep, type MaterializedKnowledge, MissingArtifactError, NodeFsPort, type OutputSchemaLike, type OutputsFileContract, type ParallelStep, type PipelineStep, type ResumeRequest, type RunStep, type RunWorkflowArgs, type RuntimeWorkflow, type SchemaValidationIssue, type Selector, type StepCache, type StepCacheEntry, type StepFailedInfo, type StepHookInfo, StepOutcomeError, type StepSkippedInfo, type SubworkflowStep, type SuspendStep, type TolerantFanOutResult, type ToolStep, type TransformStep, WorkflowCancelledError, WorkflowCompileError, type WorkflowInputValidation, type WorkflowRunResult, WorkflowSuspendedError, buildAgentStep, compileWorkflow, compileWorkflowManifest, evalPredicate, interpolateTemplate, isCompilableJsonSchema, materializeKnowledge, normalizeWorkflowInputsSchema, resolveKnowledgeSelectors, resolveRef, resolveRefPrefixed, resolveValue, runWorkflow, validateAgainstJsonSchema, validateWorkflowInput };
package/dist/index.mjs CHANGED
@@ -1014,6 +1014,14 @@ var AgentSpawnError = class extends Error {
1014
1014
  stepId;
1015
1015
  cause;
1016
1016
  };
1017
+ var WorkflowCancelledError = class extends Error {
1018
+ constructor(stepId) {
1019
+ super(`step '${stepId}': run cancelled \u2014 not started`);
1020
+ this.stepId = stepId;
1021
+ this.name = "WorkflowCancelledError";
1022
+ }
1023
+ stepId;
1024
+ };
1017
1025
  function withReleaseScope(ctx) {
1018
1026
  return { ...ctx, spawned: [] };
1019
1027
  }
@@ -1079,9 +1087,9 @@ function spawnBreaker(threshold) {
1079
1087
  }
1080
1088
  };
1081
1089
  }
1082
- function skipUnstartedItems(ctx, fanOutId, from, items, bodiesOf, reason, results) {
1090
+ function skipUnstartedItems(ctx, fanOutId, from, items, bodiesOf, kind, reason, results) {
1083
1091
  for (let idx = from; idx < items.length; idx++) {
1084
- results[idx] = { status: "skipped", index: idx, item: items[idx], reason: `circuit-open: ${reason}` };
1092
+ results[idx] = { status: "skipped", index: idx, item: items[idx], reason: `${kind}: ${reason}` };
1085
1093
  const itemCtx = withIndexedHooks(ctx, idx);
1086
1094
  if (!itemCtx.onStepSkipped) continue;
1087
1095
  let bodies;
@@ -1091,7 +1099,7 @@ function skipUnstartedItems(ctx, fanOutId, from, items, bodiesOf, reason, result
1091
1099
  continue;
1092
1100
  }
1093
1101
  for (const id of new Set(skippableStepIds(bodies))) {
1094
- itemCtx.onStepSkipped(id, { reason: "circuit-open", branchId: fanOutId, message: reason });
1102
+ itemCtx.onStepSkipped(id, { reason: kind, branchId: fanOutId, message: reason });
1095
1103
  }
1096
1104
  }
1097
1105
  }
@@ -1333,7 +1341,7 @@ ${inner(b2)}` };
1333
1341
  } : void 0;
1334
1342
  let sessionId;
1335
1343
  if (step.adapter) {
1336
- if (ctx.signal?.aborted) throw new Error(`step '${step.id}': run cancelled \u2014 not spawning`);
1344
+ if (ctx.signal?.aborted) throw new WorkflowCancelledError(step.id);
1337
1345
  try {
1338
1346
  sessionId = await ctx.agents.spawn(resolveSel(step.adapter, b), {
1339
1347
  cwd,
@@ -1445,7 +1453,7 @@ function defaultRunGateCommand(spec) {
1445
1453
  execFile(
1446
1454
  spec.command,
1447
1455
  [...spec.args],
1448
- { cwd: spec.cwd, timeout: spec.timeoutMs, maxBuffer: 10 * 1024 * 1024 },
1456
+ { cwd: spec.cwd, timeout: spec.timeoutMs, maxBuffer: 10 * 1024 * 1024, signal: spec.signal },
1449
1457
  (err, stdout, stderr) => {
1450
1458
  if (!err) {
1451
1459
  resolve2({ exitCode: 0, stdout, stderr });
@@ -1485,6 +1493,7 @@ async function execGateStep(step, ctx, b) {
1485
1493
  const maxAttempts = Math.max(1, step.retry?.maxAttempts ?? 1);
1486
1494
  let last;
1487
1495
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1496
+ if (ctx.signal?.aborted) throw new WorkflowCancelledError(step.id);
1488
1497
  if (attempt > 1 && step.onFail?.reprompt) {
1489
1498
  if (!ctx.agents) {
1490
1499
  throw new Error(`step '${step.id}': on_fail.reprompt requires a host agents implementation`);
@@ -1516,8 +1525,10 @@ Please address the findings above, then reply when done.`
1516
1525
  command: step.command,
1517
1526
  args,
1518
1527
  cwd,
1519
- timeoutMs: step.timeoutMs
1528
+ timeoutMs: step.timeoutMs,
1529
+ signal: ctx.signal
1520
1530
  });
1531
+ if (ctx.signal?.aborted) throw new WorkflowCancelledError(step.id);
1521
1532
  const report = await resolveGateReport(cmdResult, cwd, step.reportPath);
1522
1533
  const ok = cmdResult.exitCode === 0;
1523
1534
  last = { ok, exitCode: cmdResult.exitCode, report };
@@ -1551,6 +1562,7 @@ async function execStep(step, ctx, item, index) {
1551
1562
  }
1552
1563
  async function execStepBody(step, ctx, item, index) {
1553
1564
  const { state, signal } = ctx;
1565
+ if (signal?.aborted) throw new WorkflowCancelledError(step.id);
1554
1566
  const b = view(ctx, item, index);
1555
1567
  if (step.kind !== "agent" && step.kind !== "tool" && step.kind !== "artifact") {
1556
1568
  ctx.onStepStart?.(step.id);
@@ -1610,15 +1622,20 @@ async function execStepBody(step, ctx, item, index) {
1610
1622
  }
1611
1623
  };
1612
1624
  const worker = async () => {
1613
- while (!failed && breaker.open === void 0 && next < arr.length) {
1625
+ while (!failed && breaker.open === void 0 && signal?.aborted !== true && next < arr.length) {
1614
1626
  const idx = next++;
1615
1627
  await runItem(idx);
1616
1628
  }
1617
1629
  };
1618
1630
  await Promise.all(Array.from({ length: Math.min(parallelism, arr.length) }, () => worker()));
1631
+ if (signal?.aborted === true && next < arr.length) {
1632
+ if (!tolerant) throw new WorkflowCancelledError(step.id);
1633
+ skipUnstartedItems(ctx, step.id, next, arr, (el, idx) => [step.body(el, idx, view(ctx, el, idx))], "run-cancelled", "run cancelled", results);
1634
+ return tolerantResult(results, breaker.open);
1635
+ }
1619
1636
  if (!tolerant) return results;
1620
1637
  if (breaker.open !== void 0) {
1621
- skipUnstartedItems(ctx, step.id, next, arr, (el, idx) => [step.body(el, idx, view(ctx, el, idx))], breaker.open, results);
1638
+ skipUnstartedItems(ctx, step.id, next, arr, (el, idx) => [step.body(el, idx, view(ctx, el, idx))], "circuit-open", breaker.open, results);
1622
1639
  }
1623
1640
  return tolerantResult(results, breaker.open);
1624
1641
  }
@@ -1653,12 +1670,26 @@ async function execStepBody(step, ctx, item, index) {
1653
1670
  }
1654
1671
  };
1655
1672
  const worker = async () => {
1656
- while ((!tolerant || breaker.open === void 0) && next < items.length) {
1673
+ while ((!tolerant || breaker.open === void 0) && signal?.aborted !== true && next < items.length) {
1657
1674
  const idx = next++;
1658
1675
  await runItem(idx);
1659
1676
  }
1660
1677
  };
1661
1678
  await Promise.all(Array.from({ length: Math.min(cap, items.length) }, () => worker()));
1679
+ if (signal?.aborted === true && next < items.length) {
1680
+ if (!tolerant) throw new WorkflowCancelledError(step.id);
1681
+ skipUnstartedItems(
1682
+ ctx,
1683
+ step.id,
1684
+ next,
1685
+ items,
1686
+ (el, idx) => step.stages.map((stage) => stage(el, idx, void 0, view(ctx, el, idx))),
1687
+ "run-cancelled",
1688
+ "run cancelled",
1689
+ results
1690
+ );
1691
+ return tolerantResult(results, breaker.open);
1692
+ }
1662
1693
  if (!tolerant) return results;
1663
1694
  if (breaker.open !== void 0) {
1664
1695
  skipUnstartedItems(
@@ -1667,6 +1698,7 @@ async function execStepBody(step, ctx, item, index) {
1667
1698
  next,
1668
1699
  items,
1669
1700
  (el, idx) => step.stages.map((stage) => stage(el, idx, void 0, view(ctx, el, idx))),
1701
+ "circuit-open",
1670
1702
  breaker.open,
1671
1703
  results
1672
1704
  );
@@ -1950,6 +1982,6 @@ function compileWorkflowManifest(source, opts) {
1950
1982
  return compileWorkflow(handle, opts);
1951
1983
  }
1952
1984
 
1953
- export { AgentInputRequiredError, AgentSpawnError, DEFAULT_MAX_CONSECUTIVE_SPAWN_FAILURES, MissingArtifactError, NodeFsPort, StepOutcomeError, WorkflowCompileError, WorkflowSuspendedError, buildAgentStep, compileWorkflow, compileWorkflowManifest, evalPredicate, interpolateTemplate, isCompilableJsonSchema, materializeKnowledge, normalizeWorkflowInputsSchema, resolveKnowledgeSelectors, resolveRef, resolveRefPrefixed, resolveValue, runWorkflow, validateAgainstJsonSchema, validateWorkflowInput };
1985
+ export { AgentInputRequiredError, AgentSpawnError, DEFAULT_MAX_CONSECUTIVE_SPAWN_FAILURES, MissingArtifactError, NodeFsPort, StepOutcomeError, WorkflowCancelledError, WorkflowCompileError, WorkflowSuspendedError, buildAgentStep, compileWorkflow, compileWorkflowManifest, evalPredicate, interpolateTemplate, isCompilableJsonSchema, materializeKnowledge, normalizeWorkflowInputsSchema, resolveKnowledgeSelectors, resolveRef, resolveRefPrefixed, resolveValue, runWorkflow, validateAgainstJsonSchema, validateWorkflowInput };
1954
1986
  //# sourceMappingURL=index.mjs.map
1955
1987
  //# sourceMappingURL=index.mjs.map