@theokit/sdk 2.25.0 → 2.27.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 (47) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/dist/a2a/index.cjs +208 -4
  3. package/dist/a2a/index.cjs.map +1 -1
  4. package/dist/a2a/index.js +208 -4
  5. package/dist/a2a/index.js.map +1 -1
  6. package/dist/{cron-B44D-678.d.ts → cron-BR1NCSk1.d.cts} +11 -1
  7. package/dist/{cron-qI-dbG7c.d.cts → cron-DgEQCJ2i.d.ts} +11 -1
  8. package/dist/cron.cjs +187 -4
  9. package/dist/cron.cjs.map +1 -1
  10. package/dist/cron.d.cts +2 -2
  11. package/dist/cron.d.ts +2 -2
  12. package/dist/cron.js +187 -4
  13. package/dist/cron.js.map +1 -1
  14. package/dist/{errors-DRS-kqOK.d.ts → errors-CbY3pxY7.d.ts} +1 -1
  15. package/dist/{errors-DIKBXffg.d.cts → errors-DLMNb4Ka.d.cts} +1 -1
  16. package/dist/errors.d.cts +2 -2
  17. package/dist/eval.cjs +187 -4
  18. package/dist/eval.cjs.map +1 -1
  19. package/dist/eval.js +187 -4
  20. package/dist/eval.js.map +1 -1
  21. package/dist/index.cjs +483 -51
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +69 -7
  24. package/dist/index.d.ts +69 -7
  25. package/dist/index.js +481 -52
  26. package/dist/index.js.map +1 -1
  27. package/dist/internal/runtime/processors/run-processors.d.ts +10 -0
  28. package/dist/internal/runtime/processors/tripwire-run.d.ts +16 -0
  29. package/dist/internal/runtime/processors/wrap-output-run.d.ts +18 -0
  30. package/dist/internal/workflow/ctx.d.ts +6 -1
  31. package/dist/internal/workflow/event-stream.d.ts +13 -0
  32. package/dist/internal/workflow/executor-helpers.d.ts +30 -0
  33. package/dist/{run-Cr0C6cOM.d.cts → run-CdWiihyU.d.cts} +109 -2
  34. package/dist/{run-Cr0C6cOM.d.ts → run-CdWiihyU.d.ts} +109 -2
  35. package/dist/types/agent.d.ts +10 -0
  36. package/dist/types/index.d.ts +1 -0
  37. package/dist/types/processors.d.ts +84 -0
  38. package/dist/types/run-events.d.ts +11 -1
  39. package/dist/types/run.d.ts +12 -0
  40. package/dist/types/workflow.d.ts +134 -1
  41. package/dist/workflow.cjs +289 -45
  42. package/dist/workflow.cjs.map +1 -1
  43. package/dist/workflow.d.cts +42 -2
  44. package/dist/workflow.d.ts +42 -2
  45. package/dist/workflow.js +288 -46
  46. package/dist/workflow.js.map +1 -1
  47. package/package.json +1 -1
@@ -26,7 +26,7 @@ import type { ZodType } from "zod";
26
26
  import { z } from "zod";
27
27
  import type { CustomTool, SDKAgent } from "./types/agent.js";
28
28
  import type { MessageOrigin } from "./types/run.js";
29
- import type { AgentStep, BranchStep, DowhileStep, FnStep, RetryPolicy, Step, StepContext, WorkflowOptions, WorkflowResumeOptions, WorkflowRun, WorkflowRunOptions } from "./types/workflow.js";
29
+ import type { AgentStep, BranchStep, DowhileStep, FnStep, RetryPolicy, Step, StepContext, WorkflowOptions, WorkflowResumeOptions, WorkflowRun, WorkflowRunOptions, WorkflowStream } from "./types/workflow.js";
30
30
  export declare class WorkflowBuilder<TInput = unknown, TOutput = unknown> {
31
31
  private readonly options;
32
32
  private readonly _steps;
@@ -73,6 +73,22 @@ export declare class Workflow<TInput = unknown, TOutput = unknown> {
73
73
  * `run.status === "failed"`.
74
74
  */
75
75
  run(input: TInput, opts?: WorkflowRunOptions): Promise<WorkflowRun<TOutput>>;
76
+ /**
77
+ * SE28 — run the workflow and STREAM step-level events as they happen. Returns
78
+ * an async iterator of {@link WorkflowEvent}s (`step_started` / `step_completed`
79
+ * / `step_failed` / `workflow_suspended` / `workflow_completed`, top-level
80
+ * steps) plus a `result` promise resolving to the same terminal
81
+ * {@link WorkflowRun} `run()` returns. Iterate for progress; await `result` for
82
+ * the outcome. The stream ends when the run terminates.
83
+ *
84
+ * `result` is the AUTHORITATIVE terminal status. Not every terminal state has a
85
+ * closing event: a step failure emits `step_failed`, but an `outputSchema`
86
+ * rejection (SE27) or an abort ends the stream WITHOUT `workflow_completed` —
87
+ * always `await result` to read the final `status`. Consuming order is free:
88
+ * awaiting `result` without draining, or draining without awaiting `result`,
89
+ * both work (breaking out of `for await` stops the buffering early).
90
+ */
91
+ stream(input: TInput, opts?: WorkflowRunOptions): WorkflowStream<TOutput>;
76
92
  /**
77
93
  * Resume a suspended workflow from its snapshot. Throws
78
94
  * `WorkflowSnapshotNotFoundError` if `runId` is unknown.
@@ -95,9 +111,33 @@ export declare function agentStep(id: string, agent: SDKAgent, promptTemplate: s
95
111
  retry?: RetryPolicy;
96
112
  origin?: MessageOrigin;
97
113
  }): AgentStep;
114
+ /**
115
+ * SE30 — use a committed {@link Workflow} as a step inside another workflow.
116
+ * Wraps the child as an `FnStep` (opaque — the child runs in its OWN executor
117
+ * with its own id-space, so nested step-ids never collide with the parent's).
118
+ * The child's output becomes the step output. A non-`completed` child fails the
119
+ * parent step with a typed {@link WorkflowNestedError}: nested `suspended` is NOT
120
+ * resumable in v1 (resume continues AFTER the step — the child would be skipped;
121
+ * use a top-level suspend). See ADR 0010.
122
+ *
123
+ * @public
124
+ */
125
+ export declare function workflowStep<TI = unknown, TO = unknown>(child: Workflow<TI, TO>, opts?: {
126
+ id?: string;
127
+ }): FnStep;
128
+ /**
129
+ * SE30 — clone a committed workflow under a new id/name. The clone runs
130
+ * independently (its own single-flight lock + observability identity) with the
131
+ * same committed steps. Mirrors Mastra's `cloneWorkflow`.
132
+ *
133
+ * @public
134
+ */
135
+ export declare function cloneWorkflow<TI = unknown, TO = unknown>(wf: Workflow<TI, TO>, opts: {
136
+ id: string;
137
+ }): Workflow<TI, TO>;
98
138
  export { __resetSnapshotStoresForTests } from "./internal/workflow/snapshot-store.js";
99
139
  export type * from "./types/workflow.js";
100
- export { WorkflowAlreadyRunningError, WorkflowCompensateNotImplementedError, WorkflowDuplicateStepIdError, WorkflowMaxIterationsExceededError, WorkflowNotSerializableError, WorkflowParallelError, WorkflowResumeStepNotFoundError, WorkflowSnapshotNotFoundError, } from "./types/workflow.js";
140
+ export { WorkflowAlreadyRunningError, WorkflowCompensateNotImplementedError, WorkflowDuplicateStepIdError, WorkflowInputError, WorkflowMaxIterationsExceededError, WorkflowNestedError, WorkflowNotSerializableError, WorkflowOutputError, WorkflowParallelError, WorkflowResumeStepNotFoundError, WorkflowSnapshotNotFoundError, WorkflowStateError, } from "./types/workflow.js";
101
141
  /**
102
142
  * Raised by a {@link workflowAsTool} tool when the wrapped workflow run does not
103
143
  * reach `status: "completed"` (a step failed, the run was cancelled/suspended).
@@ -26,7 +26,7 @@ import type { ZodType } from "zod";
26
26
  import { z } from "zod";
27
27
  import type { CustomTool, SDKAgent } from "./types/agent.js";
28
28
  import type { MessageOrigin } from "./types/run.js";
29
- import type { AgentStep, BranchStep, DowhileStep, FnStep, RetryPolicy, Step, StepContext, WorkflowOptions, WorkflowResumeOptions, WorkflowRun, WorkflowRunOptions } from "./types/workflow.js";
29
+ import type { AgentStep, BranchStep, DowhileStep, FnStep, RetryPolicy, Step, StepContext, WorkflowOptions, WorkflowResumeOptions, WorkflowRun, WorkflowRunOptions, WorkflowStream } from "./types/workflow.js";
30
30
  export declare class WorkflowBuilder<TInput = unknown, TOutput = unknown> {
31
31
  private readonly options;
32
32
  private readonly _steps;
@@ -73,6 +73,22 @@ export declare class Workflow<TInput = unknown, TOutput = unknown> {
73
73
  * `run.status === "failed"`.
74
74
  */
75
75
  run(input: TInput, opts?: WorkflowRunOptions): Promise<WorkflowRun<TOutput>>;
76
+ /**
77
+ * SE28 — run the workflow and STREAM step-level events as they happen. Returns
78
+ * an async iterator of {@link WorkflowEvent}s (`step_started` / `step_completed`
79
+ * / `step_failed` / `workflow_suspended` / `workflow_completed`, top-level
80
+ * steps) plus a `result` promise resolving to the same terminal
81
+ * {@link WorkflowRun} `run()` returns. Iterate for progress; await `result` for
82
+ * the outcome. The stream ends when the run terminates.
83
+ *
84
+ * `result` is the AUTHORITATIVE terminal status. Not every terminal state has a
85
+ * closing event: a step failure emits `step_failed`, but an `outputSchema`
86
+ * rejection (SE27) or an abort ends the stream WITHOUT `workflow_completed` —
87
+ * always `await result` to read the final `status`. Consuming order is free:
88
+ * awaiting `result` without draining, or draining without awaiting `result`,
89
+ * both work (breaking out of `for await` stops the buffering early).
90
+ */
91
+ stream(input: TInput, opts?: WorkflowRunOptions): WorkflowStream<TOutput>;
76
92
  /**
77
93
  * Resume a suspended workflow from its snapshot. Throws
78
94
  * `WorkflowSnapshotNotFoundError` if `runId` is unknown.
@@ -95,9 +111,33 @@ export declare function agentStep(id: string, agent: SDKAgent, promptTemplate: s
95
111
  retry?: RetryPolicy;
96
112
  origin?: MessageOrigin;
97
113
  }): AgentStep;
114
+ /**
115
+ * SE30 — use a committed {@link Workflow} as a step inside another workflow.
116
+ * Wraps the child as an `FnStep` (opaque — the child runs in its OWN executor
117
+ * with its own id-space, so nested step-ids never collide with the parent's).
118
+ * The child's output becomes the step output. A non-`completed` child fails the
119
+ * parent step with a typed {@link WorkflowNestedError}: nested `suspended` is NOT
120
+ * resumable in v1 (resume continues AFTER the step — the child would be skipped;
121
+ * use a top-level suspend). See ADR 0010.
122
+ *
123
+ * @public
124
+ */
125
+ export declare function workflowStep<TI = unknown, TO = unknown>(child: Workflow<TI, TO>, opts?: {
126
+ id?: string;
127
+ }): FnStep;
128
+ /**
129
+ * SE30 — clone a committed workflow under a new id/name. The clone runs
130
+ * independently (its own single-flight lock + observability identity) with the
131
+ * same committed steps. Mirrors Mastra's `cloneWorkflow`.
132
+ *
133
+ * @public
134
+ */
135
+ export declare function cloneWorkflow<TI = unknown, TO = unknown>(wf: Workflow<TI, TO>, opts: {
136
+ id: string;
137
+ }): Workflow<TI, TO>;
98
138
  export { __resetSnapshotStoresForTests } from "./internal/workflow/snapshot-store.js";
99
139
  export type * from "./types/workflow.js";
100
- export { WorkflowAlreadyRunningError, WorkflowCompensateNotImplementedError, WorkflowDuplicateStepIdError, WorkflowMaxIterationsExceededError, WorkflowNotSerializableError, WorkflowParallelError, WorkflowResumeStepNotFoundError, WorkflowSnapshotNotFoundError, } from "./types/workflow.js";
140
+ export { WorkflowAlreadyRunningError, WorkflowCompensateNotImplementedError, WorkflowDuplicateStepIdError, WorkflowInputError, WorkflowMaxIterationsExceededError, WorkflowNestedError, WorkflowNotSerializableError, WorkflowOutputError, WorkflowParallelError, WorkflowResumeStepNotFoundError, WorkflowSnapshotNotFoundError, WorkflowStateError, } from "./types/workflow.js";
101
141
  /**
102
142
  * Raised by a {@link workflowAsTool} tool when the wrapped workflow run does not
103
143
  * reach `status: "completed"` (a step failed, the run was cancelled/suspended).
package/dist/workflow.js CHANGED
@@ -210,7 +210,7 @@ var init_errors = __esm({
210
210
  });
211
211
 
212
212
  // src/types/workflow.ts
213
- var WorkflowDuplicateStepIdError, WorkflowAlreadyRunningError, WorkflowSnapshotNotFoundError, WorkflowMaxIterationsExceededError, WorkflowNotSerializableError, WorkflowResumeStepNotFoundError, WorkflowParallelError, WorkflowCompensateNotImplementedError;
213
+ var WorkflowDuplicateStepIdError, WorkflowInputError, WorkflowOutputError, WorkflowStateError, WorkflowNestedError, WorkflowAlreadyRunningError, WorkflowSnapshotNotFoundError, WorkflowMaxIterationsExceededError, WorkflowNotSerializableError, WorkflowResumeStepNotFoundError, WorkflowParallelError, WorkflowCompensateNotImplementedError;
214
214
  var init_workflow = __esm({
215
215
  "src/types/workflow.ts"() {
216
216
  WorkflowDuplicateStepIdError = class extends Error {
@@ -221,6 +221,57 @@ var init_workflow = __esm({
221
221
  stepId;
222
222
  name = "WorkflowDuplicateStepIdError";
223
223
  };
224
+ WorkflowInputError = class extends Error {
225
+ constructor(workflowName, detail) {
226
+ super(`Workflow "${workflowName}" input failed schema validation: ${detail}`);
227
+ this.workflowName = workflowName;
228
+ this.detail = detail;
229
+ }
230
+ workflowName;
231
+ detail;
232
+ name = "WorkflowInputError";
233
+ };
234
+ WorkflowOutputError = class extends Error {
235
+ constructor(workflowName, detail) {
236
+ super(`Workflow "${workflowName}" output failed schema validation: ${detail}`);
237
+ this.workflowName = workflowName;
238
+ this.detail = detail;
239
+ }
240
+ workflowName;
241
+ detail;
242
+ name = "WorkflowOutputError";
243
+ };
244
+ WorkflowStateError = class extends Error {
245
+ constructor(workflowName, detail) {
246
+ super(`Workflow "${workflowName}" state failed schema validation: ${detail}`);
247
+ this.workflowName = workflowName;
248
+ this.detail = detail;
249
+ }
250
+ workflowName;
251
+ detail;
252
+ name = "WorkflowStateError";
253
+ };
254
+ WorkflowNestedError = class extends Error {
255
+ constructor(stepId, childName, childStatus, childError) {
256
+ super(
257
+ `Nested workflow "${childName}" (step "${stepId}") ended with status "${childStatus}"${childStatus === "suspended" ? " \u2014 nested suspend/resume is not supported in v1 (use a top-level suspend)" : ""}${childError ? `: ${childError.name}: ${childError.message}` : ""}`,
258
+ // Reconstruct a synthetic Error from the serialized child-error shape so
259
+ // debuggers surface the nested cause chain — the original Error instance is
260
+ // lost at the WorkflowRun serialization boundary, so this is the best
261
+ // achievable without changing the run protocol.
262
+ childError ? { cause: Object.assign(new Error(childError.message), { name: childError.name }) } : void 0
263
+ );
264
+ this.stepId = stepId;
265
+ this.childName = childName;
266
+ this.childStatus = childStatus;
267
+ this.childError = childError;
268
+ }
269
+ stepId;
270
+ childName;
271
+ childStatus;
272
+ childError;
273
+ name = "WorkflowNestedError";
274
+ };
224
275
  WorkflowAlreadyRunningError = class extends Error {
225
276
  constructor(workflowName, runId) {
226
277
  super(`Workflow "${workflowName}" run "${runId}" already in-flight.`);
@@ -469,7 +520,7 @@ var init_snapshot_store = __esm({
469
520
  });
470
521
 
471
522
  // src/internal/workflow/ctx.ts
472
- function makeStepContext(runId, signal) {
523
+ function makeStepContext(runId, signal, state2) {
473
524
  return {
474
525
  runId,
475
526
  signal,
@@ -480,7 +531,13 @@ function makeStepContext(runId, signal) {
480
531
  },
481
532
  suspend: async (payload) => {
482
533
  throw new WorkflowSuspendedSentinel(payload);
483
- }
534
+ },
535
+ // SE29 — read reflects the current shared state; write goes through the
536
+ // controller (which validates against `stateSchema`).
537
+ get state() {
538
+ return state2.getState();
539
+ },
540
+ setState: (next) => state2.setState(next)
484
541
  };
485
542
  }
486
543
  function emit(level, runId, msg, attrs) {
@@ -533,6 +590,57 @@ var init_error_shape = __esm({
533
590
  }
534
591
  });
535
592
 
593
+ // src/internal/workflow/executor-helpers.ts
594
+ function assembleRun(params) {
595
+ return {
596
+ id: params.runId,
597
+ name: params.name,
598
+ status: params.status,
599
+ startedAt: params.startedAt,
600
+ endedAt: Date.now(),
601
+ stepResults: params.stepResults,
602
+ ...params.output !== void 0 ? { output: params.output } : {},
603
+ ...params.error !== void 0 ? { error: params.error } : {}
604
+ };
605
+ }
606
+ function abortRun(name, runId, startedAt, stepResults, signal) {
607
+ return assembleRun({
608
+ runId,
609
+ name,
610
+ status: "cancelled",
611
+ stepResults,
612
+ startedAt,
613
+ error: { name: "AbortError", message: String(signal.reason ?? "Aborted") }
614
+ });
615
+ }
616
+ function validateWorkflowSchema(schema, value) {
617
+ if (schema === void 0) return void 0;
618
+ let parsed;
619
+ try {
620
+ parsed = schema.safeParse(value);
621
+ } catch {
622
+ return "schema uses async refinements, which whole-workflow validation does not support (use a synchronous Zod schema)";
623
+ }
624
+ if (parsed.success) return void 0;
625
+ return parsed.error.issues.map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; ");
626
+ }
627
+ function makeStateController(options, initial) {
628
+ let current = initial;
629
+ return {
630
+ getState: () => current,
631
+ setState: (next) => {
632
+ const issues = validateWorkflowSchema(options.stateSchema, next);
633
+ if (issues !== void 0) throw new WorkflowStateError(options.name, issues);
634
+ current = next;
635
+ }
636
+ };
637
+ }
638
+ var init_executor_helpers = __esm({
639
+ "src/internal/workflow/executor-helpers.ts"() {
640
+ init_workflow();
641
+ }
642
+ });
643
+
536
644
  // src/internal/workflow/run-id.ts
537
645
  function mintRunId() {
538
646
  return `wfr-${globalThis.crypto.randomUUID().replace(/-/g, "").slice(0, 8)}`;
@@ -1270,6 +1378,8 @@ async function handleSuspend(err, ctx) {
1270
1378
  suspendedPayload: err.payload,
1271
1379
  stepResults: ctx.stepResults,
1272
1380
  accumulatedInput: ctx.acc,
1381
+ state: ctx.stepCtx.state,
1382
+ // SE29 — capture the shared state at suspend
1273
1383
  options: ctx.options
1274
1384
  });
1275
1385
  } catch (snapErr) {
@@ -1321,7 +1431,7 @@ async function runOneStep(args) {
1321
1431
  result = await dispatchStep(args.step, args.acc, args.ctx, args.options, args.stepResults);
1322
1432
  } catch (err) {
1323
1433
  if (err instanceof WorkflowSuspendedSentinel) {
1324
- const outcome = await handleSuspend(err, { ...args, stepSpan });
1434
+ const outcome = await handleSuspend(err, { ...args, stepSpan, stepCtx: args.ctx });
1325
1435
  return { kind: "terminal", run: outcome.run };
1326
1436
  }
1327
1437
  result = {
@@ -1338,22 +1448,42 @@ async function runOneStep(args) {
1338
1448
  stepSpan.end();
1339
1449
  return { kind: "ok", result };
1340
1450
  }
1341
- function abortRun(name, runId, startedAt, stepResults, signal) {
1342
- return assembleRun({
1343
- runId,
1344
- name,
1345
- status: "cancelled",
1346
- stepResults,
1347
- startedAt,
1348
- error: { name: "AbortError", message: String(signal.reason ?? "Aborted") }
1349
- });
1451
+ function handleStepOutcome(outcome, step, loop, onStepEvent) {
1452
+ if (outcome.kind === "terminal") {
1453
+ if (outcome.run.status === "suspended") {
1454
+ onStepEvent?.({ type: "workflow_suspended", stepId: step.id });
1455
+ }
1456
+ return { terminal: outcome.run };
1457
+ }
1458
+ loop.stepResults.push(outcome.result);
1459
+ if (outcome.result.status === "failed") {
1460
+ onStepEvent?.({
1461
+ type: "step_failed",
1462
+ stepId: step.id,
1463
+ error: outcome.result.error ?? { name: "WorkflowStepError", message: "step failed" }
1464
+ });
1465
+ return {
1466
+ terminal: assembleRun({
1467
+ runId: loop.runId,
1468
+ name: loop.name,
1469
+ status: "failed",
1470
+ stepResults: loop.stepResults,
1471
+ startedAt: loop.startedAt,
1472
+ error: outcome.result.error
1473
+ })
1474
+ };
1475
+ }
1476
+ onStepEvent?.({ type: "step_completed", stepId: step.id, output: outcome.result.output });
1477
+ return { acc: outcome.result.output };
1350
1478
  }
1351
1479
  async function runStepsLoop(params) {
1352
- const { options, steps, ctx, runId, startedAt, signal } = params;
1480
+ const { options, steps, ctx, runId, startedAt, signal, onStepEvent } = params;
1353
1481
  const stepResults = [...params.initialStepResults ?? []];
1482
+ const loop = { stepResults, runId, name: options.name, startedAt };
1354
1483
  let acc = params.input;
1355
1484
  for (const step of steps) {
1356
1485
  if (signal.aborted) return abortRun(options.name, runId, startedAt, stepResults, signal);
1486
+ onStepEvent?.({ type: "step_started", stepId: step.id });
1357
1487
  const outcome = await runOneStep({
1358
1488
  step,
1359
1489
  acc,
@@ -1364,20 +1494,22 @@ async function runStepsLoop(params) {
1364
1494
  name: options.name,
1365
1495
  startedAt
1366
1496
  });
1367
- if (outcome.kind === "terminal") return outcome.run;
1368
- stepResults.push(outcome.result);
1369
- if (outcome.result.status === "failed") {
1370
- return assembleRun({
1371
- runId,
1372
- name: options.name,
1373
- status: "failed",
1374
- stepResults,
1375
- startedAt,
1376
- error: outcome.result.error
1377
- });
1378
- }
1379
- acc = outcome.result.output;
1497
+ const handled = handleStepOutcome(outcome, step, loop, onStepEvent);
1498
+ if ("terminal" in handled) return handled.terminal;
1499
+ acc = handled.acc;
1380
1500
  }
1501
+ const outputIssues = validateWorkflowSchema(options.outputSchema, acc);
1502
+ if (outputIssues !== void 0) {
1503
+ return assembleRun({
1504
+ runId,
1505
+ name: options.name,
1506
+ status: "failed",
1507
+ stepResults,
1508
+ startedAt,
1509
+ error: errToShape(new WorkflowOutputError(options.name, outputIssues))
1510
+ });
1511
+ }
1512
+ onStepEvent?.({ type: "workflow_completed" });
1381
1513
  return assembleRun({
1382
1514
  runId,
1383
1515
  name: options.name,
@@ -1400,8 +1532,33 @@ async function executeWorkflow(options, steps, input, runOpts) {
1400
1532
  runSpan.end();
1401
1533
  return abortRun(options.name, runId, startedAt, [], signal);
1402
1534
  }
1403
- const ctx = makeStepContext(runId, signal);
1535
+ const internal = runOpts;
1536
+ const seededState = internal?.restoredState !== void 0 ? internal.restoredState : options.initialState;
1537
+ const stateController = makeStateController(options, seededState);
1538
+ const ctx = makeStepContext(runId, signal, stateController);
1404
1539
  try {
1540
+ const inputIssues = validateWorkflowSchema(options.inputSchema, input);
1541
+ if (inputIssues !== void 0) {
1542
+ return assembleRun({
1543
+ runId,
1544
+ name: options.name,
1545
+ status: "failed",
1546
+ stepResults: [],
1547
+ startedAt,
1548
+ error: errToShape(new WorkflowInputError(options.name, inputIssues))
1549
+ });
1550
+ }
1551
+ const stateIssues = seededState !== void 0 ? validateWorkflowSchema(options.stateSchema, seededState) : void 0;
1552
+ if (stateIssues !== void 0) {
1553
+ return assembleRun({
1554
+ runId,
1555
+ name: options.name,
1556
+ status: "failed",
1557
+ stepResults: [],
1558
+ startedAt,
1559
+ error: errToShape(new WorkflowStateError(options.name, stateIssues))
1560
+ });
1561
+ }
1405
1562
  return await runStepsLoop({
1406
1563
  options,
1407
1564
  steps,
@@ -1410,7 +1567,8 @@ async function executeWorkflow(options, steps, input, runOpts) {
1410
1567
  runId,
1411
1568
  startedAt,
1412
1569
  signal,
1413
- ...runOpts?.initialStepResults !== void 0 ? { initialStepResults: runOpts.initialStepResults } : {}
1570
+ ...internal?.initialStepResults !== void 0 ? { initialStepResults: internal.initialStepResults } : {},
1571
+ ...internal?.onStepEvent !== void 0 ? { onStepEvent: internal.onStepEvent } : {}
1414
1572
  });
1415
1573
  } finally {
1416
1574
  runSpan.end();
@@ -1441,28 +1599,17 @@ async function dispatchStep(step, input, ctx, options, prevStepResults) {
1441
1599
  }
1442
1600
  }
1443
1601
  }
1444
- function assembleRun(params) {
1445
- const endedAt = Date.now();
1446
- return {
1447
- id: params.runId,
1448
- name: params.name,
1449
- status: params.status,
1450
- startedAt: params.startedAt,
1451
- endedAt,
1452
- stepResults: params.stepResults,
1453
- ...params.output !== void 0 ? { output: params.output } : {},
1454
- ...params.error !== void 0 ? { error: params.error } : {}
1455
- };
1456
- }
1457
1602
  async function saveSnapshot(p) {
1458
1603
  const snapshot = {
1459
- _schemaVersion: 1,
1604
+ _schemaVersion: 2,
1605
+ // SE29 — carries `state`
1460
1606
  runId: p.runId,
1461
1607
  workflowName: p.workflowName,
1462
1608
  currentStepId: p.currentStepId,
1463
1609
  suspendedPayload: p.suspendedPayload,
1464
1610
  stepResults: p.stepResults,
1465
1611
  accumulatedInput: p.accumulatedInput,
1612
+ ...p.state !== void 0 ? { state: p.state } : {},
1466
1613
  suspendedAt: Date.now()
1467
1614
  };
1468
1615
  const store = getSnapshotStoreFor(p.options);
@@ -1495,7 +1642,10 @@ async function resumeWorkflow(opts) {
1495
1642
  signal: opts.signal,
1496
1643
  runId: opts.runId,
1497
1644
  // M3 #62 — restore prior step outputs so the resumed run is not lossy (internal seam).
1498
- initialStepResults: snapshot.stepResults
1645
+ initialStepResults: snapshot.stepResults,
1646
+ // SE29 — restore shared state (v2 snapshot). A v1 snapshot has no `state` →
1647
+ // executeWorkflow falls back to `options.initialState`.
1648
+ ...snapshot.state !== void 0 ? { restoredState: snapshot.state } : {}
1499
1649
  });
1500
1650
  }
1501
1651
  var init_executor = __esm({
@@ -1503,6 +1653,7 @@ var init_executor = __esm({
1503
1653
  init_workflow();
1504
1654
  init_ctx();
1505
1655
  init_error_shape();
1656
+ init_executor_helpers();
1506
1657
  init_run_id();
1507
1658
  init_single_flight();
1508
1659
  init_snapshot_store();
@@ -2241,6 +2392,43 @@ function sanitizeIdentifier(input, options) {
2241
2392
  }
2242
2393
  return input.toLowerCase();
2243
2394
  }
2395
+
2396
+ // src/internal/workflow/event-stream.ts
2397
+ function createEventStream() {
2398
+ const buffer = [];
2399
+ const waiters = [];
2400
+ let ended = false;
2401
+ const stream = {
2402
+ push(event) {
2403
+ if (ended) return;
2404
+ const waiter = waiters.shift();
2405
+ if (waiter !== void 0) waiter({ value: event, done: false });
2406
+ else buffer.push(event);
2407
+ },
2408
+ end() {
2409
+ if (ended) return;
2410
+ ended = true;
2411
+ for (const waiter of waiters.splice(0)) waiter({ value: void 0, done: true });
2412
+ },
2413
+ next() {
2414
+ const buffered = buffer.shift();
2415
+ if (buffered !== void 0) return Promise.resolve({ value: buffered, done: false });
2416
+ if (ended) return Promise.resolve({ value: void 0, done: true });
2417
+ return new Promise((resolve2) => waiters.push(resolve2));
2418
+ },
2419
+ // `for await` calls return() on break/throw — close early so events stop
2420
+ // buffering in memory for a consumer that stopped iterating.
2421
+ return() {
2422
+ stream.end();
2423
+ buffer.length = 0;
2424
+ return Promise.resolve({ value: void 0, done: true });
2425
+ },
2426
+ [Symbol.asyncIterator]() {
2427
+ return stream;
2428
+ }
2429
+ };
2430
+ return stream;
2431
+ }
2244
2432
  function toJsonSchema(schema, options = { unrepresentable: "any" }) {
2245
2433
  return toJSONSchema(schema, options);
2246
2434
  }
@@ -2259,7 +2447,12 @@ var RetryPolicySchema = z.object({
2259
2447
  });
2260
2448
  var WorkflowOptionsSchema = z.object({
2261
2449
  name: z.string().min(1).max(128),
2262
- persistence: PersistenceSchema
2450
+ persistence: PersistenceSchema,
2451
+ // SE27 — declared so a future `new WorkflowBuilder(parsed)` refactor cannot
2452
+ // silently drop them (create() passes the ORIGINAL options today, but the
2453
+ // schema is also the documentation of the shape).
2454
+ inputSchema: z.custom().optional(),
2455
+ outputSchema: z.custom().optional()
2263
2456
  });
2264
2457
  var WorkflowBuilder = class {
2265
2458
  /** @internal */
@@ -2436,6 +2629,36 @@ var Workflow = class {
2436
2629
  }
2437
2630
  return result;
2438
2631
  }
2632
+ /**
2633
+ * SE28 — run the workflow and STREAM step-level events as they happen. Returns
2634
+ * an async iterator of {@link WorkflowEvent}s (`step_started` / `step_completed`
2635
+ * / `step_failed` / `workflow_suspended` / `workflow_completed`, top-level
2636
+ * steps) plus a `result` promise resolving to the same terminal
2637
+ * {@link WorkflowRun} `run()` returns. Iterate for progress; await `result` for
2638
+ * the outcome. The stream ends when the run terminates.
2639
+ *
2640
+ * `result` is the AUTHORITATIVE terminal status. Not every terminal state has a
2641
+ * closing event: a step failure emits `step_failed`, but an `outputSchema`
2642
+ * rejection (SE27) or an abort ends the stream WITHOUT `workflow_completed` —
2643
+ * always `await result` to read the final `status`. Consuming order is free:
2644
+ * awaiting `result` without draining, or draining without awaiting `result`,
2645
+ * both work (breaking out of `for await` stops the buffering early).
2646
+ */
2647
+ stream(input, opts) {
2648
+ const queue = createEventStream();
2649
+ const result = (async () => {
2650
+ const { executeWorkflow: executeWorkflow2 } = await Promise.resolve().then(() => (init_executor(), executor_exports));
2651
+ try {
2652
+ return await executeWorkflow2(this._options, this._steps, input, {
2653
+ ...opts,
2654
+ onStepEvent: (event) => queue.push(event)
2655
+ });
2656
+ } finally {
2657
+ queue.end();
2658
+ }
2659
+ })();
2660
+ return Object.assign(queue, { result });
2661
+ }
2439
2662
  /**
2440
2663
  * Resume a suspended workflow from its snapshot. Throws
2441
2664
  * `WorkflowSnapshotNotFoundError` if `runId` is unknown.
@@ -2470,6 +2693,25 @@ function agentStep(id, agent, promptTemplate, opts) {
2470
2693
  ...opts?.origin !== void 0 ? { origin: opts.origin } : {}
2471
2694
  };
2472
2695
  }
2696
+ function workflowStep(child, opts) {
2697
+ const id = opts?.id ?? `workflow_${child.__options.name}`;
2698
+ validateStepId(id);
2699
+ return {
2700
+ kind: "fn",
2701
+ id,
2702
+ fn: async (input, ctx) => {
2703
+ const run = await child.run(input, { signal: ctx.signal });
2704
+ if (run.status === "completed") return run.output;
2705
+ throw new WorkflowNestedError(id, child.__options.name, run.status, run.error);
2706
+ }
2707
+ };
2708
+ }
2709
+ function cloneWorkflow(wf, opts) {
2710
+ return new Workflow(
2711
+ { ...wf.__options, name: opts.id, workflowId: `wf-${mintShortId()}` },
2712
+ [...wf.__steps]
2713
+ );
2714
+ }
2473
2715
  var WorkflowToolError = class extends Error {
2474
2716
  constructor(toolName, workflowStatus, workflowError) {
2475
2717
  super(
@@ -2527,6 +2769,6 @@ function walkStepsValidating(steps, seen) {
2527
2769
  }
2528
2770
  }
2529
2771
 
2530
- export { Workflow, WorkflowAlreadyRunningError, WorkflowBuilder, WorkflowCompensateNotImplementedError, WorkflowDuplicateStepIdError, WorkflowMaxIterationsExceededError, WorkflowNotSerializableError, WorkflowParallelError, WorkflowResumeStepNotFoundError, WorkflowSnapshotNotFoundError, WorkflowToolError, __resetSnapshotStoresForTests, agentStep, fn, workflowAsTool };
2772
+ export { Workflow, WorkflowAlreadyRunningError, WorkflowBuilder, WorkflowCompensateNotImplementedError, WorkflowDuplicateStepIdError, WorkflowInputError, WorkflowMaxIterationsExceededError, WorkflowNestedError, WorkflowNotSerializableError, WorkflowOutputError, WorkflowParallelError, WorkflowResumeStepNotFoundError, WorkflowSnapshotNotFoundError, WorkflowStateError, WorkflowToolError, __resetSnapshotStoresForTests, agentStep, cloneWorkflow, fn, workflowAsTool, workflowStep };
2531
2773
  //# sourceMappingURL=workflow.js.map
2532
2774
  //# sourceMappingURL=workflow.js.map