@theokit/sdk 2.26.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.
- package/CHANGELOG.md +28 -0
- package/dist/index.cjs +249 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +249 -45
- package/dist/index.js.map +1 -1
- package/dist/internal/workflow/ctx.d.ts +6 -1
- package/dist/internal/workflow/event-stream.d.ts +13 -0
- package/dist/internal/workflow/executor-helpers.d.ts +30 -0
- package/dist/types/workflow.d.ts +134 -1
- package/dist/workflow.cjs +289 -45
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +42 -2
- package/dist/workflow.d.ts +42 -2
- package/dist/workflow.js +288 -46
- package/dist/workflow.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.27.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- c2bdd87: **SE27 — workflow-level `inputSchema` / `outputSchema` (validate the whole-workflow I/O).**
|
|
8
|
+
|
|
9
|
+
`Workflow.create({ ..., inputSchema, outputSchema })` (from `@theokit/sdk/workflow`) now validates the workflow's overall input and final output, closing the SE19 debt (a Workflow carried no top-level schema — only per-step `FnStep` schemas). When `inputSchema` is set, `run(input)` validates `input` BEFORE step 1; a mismatch fails fast with `status: "failed"` and a typed `WorkflowInputError` in `run.error` (no step executes, no silent coerce). When `outputSchema` is set, the terminal `completed` output is validated before `WorkflowRun.output` is populated; a mismatch yields `status: "failed"` with a typed `WorkflowOutputError` (only the `completed` path is checked — suspended/failed runs skip output validation).
|
|
10
|
+
|
|
11
|
+
Both surface as `status: "failed"` (never a throw — consistent with the executor's non-throwing step-error contract). Back-compat: absent schemas ⇒ unchanged. New exports `WorkflowInputError` / `WorkflowOutputError`. `workflowAsTool` (SE19) keeps taking its own `inputSchema` to preserve its structural `{ run }` contract. Mirrors Mastra's `createWorkflow({ inputSchema, outputSchema })`. From the Mastra Workflows comparison (SDK Evolution roadmap SE27).
|
|
12
|
+
|
|
13
|
+
- 09b89ea: **SE28 — `Workflow.stream()` (step-event stream during execution).**
|
|
14
|
+
|
|
15
|
+
`workflow.stream(input, opts?)` (from `@theokit/sdk/workflow`) runs the workflow and emits step-level events as they happen, instead of only the terminal result. It returns a `WorkflowStream` — an async iterator of `WorkflowEvent`s (`step_started` / `step_completed` (with `output`) / `step_failed` (with `error`) / `workflow_suspended` / `workflow_completed`) plus a `result` promise resolving to the SAME terminal `WorkflowRun` `run()` returns (the authoritative outcome — the stream ends when the run terminates).
|
|
16
|
+
|
|
17
|
+
Events fire in execution order for top-level steps (nested `parallel`/`branch`/`foreach` emit as their single wrapping step — coarse-grained by design). This is a STEP-event stream, distinct from the token-delta agent stream deferred in SE24. `run()` is unchanged + authoritative. New public types `WorkflowEvent` + `WorkflowStream`. Mirrors Mastra's `run.stream()` / `stream.result`. From the Mastra Workflows comparison (SDK Evolution roadmap SE28).
|
|
18
|
+
|
|
19
|
+
- f13d499: **SE29 — workflow shared state (`stateSchema` + `state` / `setState`).**
|
|
20
|
+
|
|
21
|
+
Workflow steps can now share values without threading them through every step's input/output. `Workflow.create({ stateSchema, initialState })` (from `@theokit/sdk/workflow`) seeds a shared state; every step's `StepContext` gains `state` (read the current value) and `setState(next)` (update it for subsequent steps). `setState` validates against `stateSchema` when set — a mismatch throws a typed `WorkflowStateError` that fails the step/run (Rule 8); an invalid `initialState` fails the run fast before step 1.
|
|
22
|
+
|
|
23
|
+
State is captured in the `WorkflowSnapshot` (bumped to `_schemaVersion: 2`) and restored on `Workflow.resume` — it survives a suspend→resume round-trip. A pre-SE29 (`_schemaVersion: 1`) snapshot has no state and resumes with `initialState`. Back-compat: no `stateSchema`/`initialState` ⇒ `state` is `undefined` and `setState` is unvalidated. New export `WorkflowStateError`. Mirrors Mastra's workflow `state`/`setState`/`stateSchema`. From the Mastra Workflows comparison (SDK Evolution roadmap SE29).
|
|
24
|
+
|
|
25
|
+
- 8ce8441: **SE30 — workflows-as-steps (`workflowStep`) + `cloneWorkflow`.**
|
|
26
|
+
|
|
27
|
+
`workflowStep(child, { id? })` (from `@theokit/sdk/workflow`) uses a committed `Workflow` as a step inside another workflow: `.then(workflowStep(child))`. The child runs in its OWN executor (own runId, single-flight lock, and step-id space — so nested ids never collide with the parent's); its output becomes the step output. `cloneWorkflow(wf, { id })` returns a new independent `Workflow` with the same committed steps under a new name + a fresh workflowId (clones run independently, distinct observability identity).
|
|
28
|
+
|
|
29
|
+
A non-`completed` child fails the parent step with a typed `WorkflowNestedError`. **Nested suspend/resume is NOT supported in v1** (TheoKit's resume continues AFTER the suspended step, so a nested child would be skipped) — a nested `suspended` fails with a clear message pointing at a top-level suspend; re-running the child on resume (which would re-execute its side effects) is deliberately avoided. ADR 0010. New export `WorkflowNestedError`. Mirrors Mastra's workflows-as-steps + `cloneWorkflow`. From the Mastra Workflows comparison (SDK Evolution roadmap SE30).
|
|
30
|
+
|
|
3
31
|
## 2.26.0
|
|
4
32
|
|
|
5
33
|
### Minor Changes
|
package/dist/index.cjs
CHANGED
|
@@ -4336,7 +4336,7 @@ var init_batch = __esm({
|
|
|
4336
4336
|
});
|
|
4337
4337
|
|
|
4338
4338
|
// src/types/workflow.ts
|
|
4339
|
-
var WorkflowDuplicateStepIdError, WorkflowAlreadyRunningError, WorkflowSnapshotNotFoundError, WorkflowMaxIterationsExceededError, WorkflowNotSerializableError, WorkflowResumeStepNotFoundError, WorkflowParallelError, WorkflowCompensateNotImplementedError;
|
|
4339
|
+
var WorkflowDuplicateStepIdError, WorkflowInputError, WorkflowOutputError, WorkflowStateError, WorkflowAlreadyRunningError, WorkflowSnapshotNotFoundError, WorkflowMaxIterationsExceededError, WorkflowNotSerializableError, WorkflowResumeStepNotFoundError, WorkflowParallelError, WorkflowCompensateNotImplementedError;
|
|
4340
4340
|
var init_workflow = __esm({
|
|
4341
4341
|
"src/types/workflow.ts"() {
|
|
4342
4342
|
WorkflowDuplicateStepIdError = class extends Error {
|
|
@@ -4347,6 +4347,36 @@ var init_workflow = __esm({
|
|
|
4347
4347
|
stepId;
|
|
4348
4348
|
name = "WorkflowDuplicateStepIdError";
|
|
4349
4349
|
};
|
|
4350
|
+
WorkflowInputError = class extends Error {
|
|
4351
|
+
constructor(workflowName, detail) {
|
|
4352
|
+
super(`Workflow "${workflowName}" input failed schema validation: ${detail}`);
|
|
4353
|
+
this.workflowName = workflowName;
|
|
4354
|
+
this.detail = detail;
|
|
4355
|
+
}
|
|
4356
|
+
workflowName;
|
|
4357
|
+
detail;
|
|
4358
|
+
name = "WorkflowInputError";
|
|
4359
|
+
};
|
|
4360
|
+
WorkflowOutputError = class extends Error {
|
|
4361
|
+
constructor(workflowName, detail) {
|
|
4362
|
+
super(`Workflow "${workflowName}" output failed schema validation: ${detail}`);
|
|
4363
|
+
this.workflowName = workflowName;
|
|
4364
|
+
this.detail = detail;
|
|
4365
|
+
}
|
|
4366
|
+
workflowName;
|
|
4367
|
+
detail;
|
|
4368
|
+
name = "WorkflowOutputError";
|
|
4369
|
+
};
|
|
4370
|
+
WorkflowStateError = class extends Error {
|
|
4371
|
+
constructor(workflowName, detail) {
|
|
4372
|
+
super(`Workflow "${workflowName}" state failed schema validation: ${detail}`);
|
|
4373
|
+
this.workflowName = workflowName;
|
|
4374
|
+
this.detail = detail;
|
|
4375
|
+
}
|
|
4376
|
+
workflowName;
|
|
4377
|
+
detail;
|
|
4378
|
+
name = "WorkflowStateError";
|
|
4379
|
+
};
|
|
4350
4380
|
WorkflowAlreadyRunningError = class extends Error {
|
|
4351
4381
|
constructor(workflowName, runId) {
|
|
4352
4382
|
super(`Workflow "${workflowName}" run "${runId}" already in-flight.`);
|
|
@@ -4539,7 +4569,7 @@ var init_snapshot_store = __esm({
|
|
|
4539
4569
|
});
|
|
4540
4570
|
|
|
4541
4571
|
// src/internal/workflow/ctx.ts
|
|
4542
|
-
function makeStepContext(runId, signal) {
|
|
4572
|
+
function makeStepContext(runId, signal, state4) {
|
|
4543
4573
|
return {
|
|
4544
4574
|
runId,
|
|
4545
4575
|
signal,
|
|
@@ -4550,7 +4580,13 @@ function makeStepContext(runId, signal) {
|
|
|
4550
4580
|
},
|
|
4551
4581
|
suspend: async (payload) => {
|
|
4552
4582
|
throw new WorkflowSuspendedSentinel(payload);
|
|
4553
|
-
}
|
|
4583
|
+
},
|
|
4584
|
+
// SE29 — read reflects the current shared state; write goes through the
|
|
4585
|
+
// controller (which validates against `stateSchema`).
|
|
4586
|
+
get state() {
|
|
4587
|
+
return state4.getState();
|
|
4588
|
+
},
|
|
4589
|
+
setState: (next) => state4.setState(next)
|
|
4554
4590
|
};
|
|
4555
4591
|
}
|
|
4556
4592
|
function emit(level, runId, msg, attrs) {
|
|
@@ -4603,6 +4639,57 @@ var init_error_shape = __esm({
|
|
|
4603
4639
|
}
|
|
4604
4640
|
});
|
|
4605
4641
|
|
|
4642
|
+
// src/internal/workflow/executor-helpers.ts
|
|
4643
|
+
function assembleRun(params) {
|
|
4644
|
+
return {
|
|
4645
|
+
id: params.runId,
|
|
4646
|
+
name: params.name,
|
|
4647
|
+
status: params.status,
|
|
4648
|
+
startedAt: params.startedAt,
|
|
4649
|
+
endedAt: Date.now(),
|
|
4650
|
+
stepResults: params.stepResults,
|
|
4651
|
+
...params.output !== void 0 ? { output: params.output } : {},
|
|
4652
|
+
...params.error !== void 0 ? { error: params.error } : {}
|
|
4653
|
+
};
|
|
4654
|
+
}
|
|
4655
|
+
function abortRun(name, runId, startedAt, stepResults, signal) {
|
|
4656
|
+
return assembleRun({
|
|
4657
|
+
runId,
|
|
4658
|
+
name,
|
|
4659
|
+
status: "cancelled",
|
|
4660
|
+
stepResults,
|
|
4661
|
+
startedAt,
|
|
4662
|
+
error: { name: "AbortError", message: String(signal.reason ?? "Aborted") }
|
|
4663
|
+
});
|
|
4664
|
+
}
|
|
4665
|
+
function validateWorkflowSchema(schema, value) {
|
|
4666
|
+
if (schema === void 0) return void 0;
|
|
4667
|
+
let parsed;
|
|
4668
|
+
try {
|
|
4669
|
+
parsed = schema.safeParse(value);
|
|
4670
|
+
} catch {
|
|
4671
|
+
return "schema uses async refinements, which whole-workflow validation does not support (use a synchronous Zod schema)";
|
|
4672
|
+
}
|
|
4673
|
+
if (parsed.success) return void 0;
|
|
4674
|
+
return parsed.error.issues.map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; ");
|
|
4675
|
+
}
|
|
4676
|
+
function makeStateController(options, initial) {
|
|
4677
|
+
let current = initial;
|
|
4678
|
+
return {
|
|
4679
|
+
getState: () => current,
|
|
4680
|
+
setState: (next) => {
|
|
4681
|
+
const issues = validateWorkflowSchema(options.stateSchema, next);
|
|
4682
|
+
if (issues !== void 0) throw new WorkflowStateError(options.name, issues);
|
|
4683
|
+
current = next;
|
|
4684
|
+
}
|
|
4685
|
+
};
|
|
4686
|
+
}
|
|
4687
|
+
var init_executor_helpers = __esm({
|
|
4688
|
+
"src/internal/workflow/executor-helpers.ts"() {
|
|
4689
|
+
init_workflow();
|
|
4690
|
+
}
|
|
4691
|
+
});
|
|
4692
|
+
|
|
4606
4693
|
// src/internal/workflow/run-id.ts
|
|
4607
4694
|
function mintRunId() {
|
|
4608
4695
|
return `wfr-${globalThis.crypto.randomUUID().replace(/-/g, "").slice(0, 8)}`;
|
|
@@ -5269,6 +5356,8 @@ async function handleSuspend(err, ctx) {
|
|
|
5269
5356
|
suspendedPayload: err.payload,
|
|
5270
5357
|
stepResults: ctx.stepResults,
|
|
5271
5358
|
accumulatedInput: ctx.acc,
|
|
5359
|
+
state: ctx.stepCtx.state,
|
|
5360
|
+
// SE29 — capture the shared state at suspend
|
|
5272
5361
|
options: ctx.options
|
|
5273
5362
|
});
|
|
5274
5363
|
} catch (snapErr) {
|
|
@@ -5320,7 +5409,7 @@ async function runOneStep(args) {
|
|
|
5320
5409
|
result = await dispatchStep(args.step, args.acc, args.ctx, args.options, args.stepResults);
|
|
5321
5410
|
} catch (err) {
|
|
5322
5411
|
if (err instanceof WorkflowSuspendedSentinel) {
|
|
5323
|
-
const outcome = await handleSuspend(err, { ...args, stepSpan });
|
|
5412
|
+
const outcome = await handleSuspend(err, { ...args, stepSpan, stepCtx: args.ctx });
|
|
5324
5413
|
return { kind: "terminal", run: outcome.run };
|
|
5325
5414
|
}
|
|
5326
5415
|
result = {
|
|
@@ -5337,22 +5426,42 @@ async function runOneStep(args) {
|
|
|
5337
5426
|
stepSpan.end();
|
|
5338
5427
|
return { kind: "ok", result };
|
|
5339
5428
|
}
|
|
5340
|
-
function
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5429
|
+
function handleStepOutcome(outcome, step, loop, onStepEvent) {
|
|
5430
|
+
if (outcome.kind === "terminal") {
|
|
5431
|
+
if (outcome.run.status === "suspended") {
|
|
5432
|
+
onStepEvent?.({ type: "workflow_suspended", stepId: step.id });
|
|
5433
|
+
}
|
|
5434
|
+
return { terminal: outcome.run };
|
|
5435
|
+
}
|
|
5436
|
+
loop.stepResults.push(outcome.result);
|
|
5437
|
+
if (outcome.result.status === "failed") {
|
|
5438
|
+
onStepEvent?.({
|
|
5439
|
+
type: "step_failed",
|
|
5440
|
+
stepId: step.id,
|
|
5441
|
+
error: outcome.result.error ?? { name: "WorkflowStepError", message: "step failed" }
|
|
5442
|
+
});
|
|
5443
|
+
return {
|
|
5444
|
+
terminal: assembleRun({
|
|
5445
|
+
runId: loop.runId,
|
|
5446
|
+
name: loop.name,
|
|
5447
|
+
status: "failed",
|
|
5448
|
+
stepResults: loop.stepResults,
|
|
5449
|
+
startedAt: loop.startedAt,
|
|
5450
|
+
error: outcome.result.error
|
|
5451
|
+
})
|
|
5452
|
+
};
|
|
5453
|
+
}
|
|
5454
|
+
onStepEvent?.({ type: "step_completed", stepId: step.id, output: outcome.result.output });
|
|
5455
|
+
return { acc: outcome.result.output };
|
|
5349
5456
|
}
|
|
5350
5457
|
async function runStepsLoop(params) {
|
|
5351
|
-
const { options, steps, ctx, runId, startedAt, signal } = params;
|
|
5458
|
+
const { options, steps, ctx, runId, startedAt, signal, onStepEvent } = params;
|
|
5352
5459
|
const stepResults = [...params.initialStepResults ?? []];
|
|
5460
|
+
const loop = { stepResults, runId, name: options.name, startedAt };
|
|
5353
5461
|
let acc = params.input;
|
|
5354
5462
|
for (const step of steps) {
|
|
5355
5463
|
if (signal.aborted) return abortRun(options.name, runId, startedAt, stepResults, signal);
|
|
5464
|
+
onStepEvent?.({ type: "step_started", stepId: step.id });
|
|
5356
5465
|
const outcome = await runOneStep({
|
|
5357
5466
|
step,
|
|
5358
5467
|
acc,
|
|
@@ -5363,20 +5472,22 @@ async function runStepsLoop(params) {
|
|
|
5363
5472
|
name: options.name,
|
|
5364
5473
|
startedAt
|
|
5365
5474
|
});
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5475
|
+
const handled = handleStepOutcome(outcome, step, loop, onStepEvent);
|
|
5476
|
+
if ("terminal" in handled) return handled.terminal;
|
|
5477
|
+
acc = handled.acc;
|
|
5478
|
+
}
|
|
5479
|
+
const outputIssues = validateWorkflowSchema(options.outputSchema, acc);
|
|
5480
|
+
if (outputIssues !== void 0) {
|
|
5481
|
+
return assembleRun({
|
|
5482
|
+
runId,
|
|
5483
|
+
name: options.name,
|
|
5484
|
+
status: "failed",
|
|
5485
|
+
stepResults,
|
|
5486
|
+
startedAt,
|
|
5487
|
+
error: errToShape(new WorkflowOutputError(options.name, outputIssues))
|
|
5488
|
+
});
|
|
5379
5489
|
}
|
|
5490
|
+
onStepEvent?.({ type: "workflow_completed" });
|
|
5380
5491
|
return assembleRun({
|
|
5381
5492
|
runId,
|
|
5382
5493
|
name: options.name,
|
|
@@ -5399,8 +5510,33 @@ async function executeWorkflow(options, steps, input, runOpts) {
|
|
|
5399
5510
|
runSpan.end();
|
|
5400
5511
|
return abortRun(options.name, runId, startedAt, [], signal);
|
|
5401
5512
|
}
|
|
5402
|
-
const
|
|
5513
|
+
const internal = runOpts;
|
|
5514
|
+
const seededState = internal?.restoredState !== void 0 ? internal.restoredState : options.initialState;
|
|
5515
|
+
const stateController = makeStateController(options, seededState);
|
|
5516
|
+
const ctx = makeStepContext(runId, signal, stateController);
|
|
5403
5517
|
try {
|
|
5518
|
+
const inputIssues = validateWorkflowSchema(options.inputSchema, input);
|
|
5519
|
+
if (inputIssues !== void 0) {
|
|
5520
|
+
return assembleRun({
|
|
5521
|
+
runId,
|
|
5522
|
+
name: options.name,
|
|
5523
|
+
status: "failed",
|
|
5524
|
+
stepResults: [],
|
|
5525
|
+
startedAt,
|
|
5526
|
+
error: errToShape(new WorkflowInputError(options.name, inputIssues))
|
|
5527
|
+
});
|
|
5528
|
+
}
|
|
5529
|
+
const stateIssues = seededState !== void 0 ? validateWorkflowSchema(options.stateSchema, seededState) : void 0;
|
|
5530
|
+
if (stateIssues !== void 0) {
|
|
5531
|
+
return assembleRun({
|
|
5532
|
+
runId,
|
|
5533
|
+
name: options.name,
|
|
5534
|
+
status: "failed",
|
|
5535
|
+
stepResults: [],
|
|
5536
|
+
startedAt,
|
|
5537
|
+
error: errToShape(new WorkflowStateError(options.name, stateIssues))
|
|
5538
|
+
});
|
|
5539
|
+
}
|
|
5404
5540
|
return await runStepsLoop({
|
|
5405
5541
|
options,
|
|
5406
5542
|
steps,
|
|
@@ -5409,7 +5545,8 @@ async function executeWorkflow(options, steps, input, runOpts) {
|
|
|
5409
5545
|
runId,
|
|
5410
5546
|
startedAt,
|
|
5411
5547
|
signal,
|
|
5412
|
-
...
|
|
5548
|
+
...internal?.initialStepResults !== void 0 ? { initialStepResults: internal.initialStepResults } : {},
|
|
5549
|
+
...internal?.onStepEvent !== void 0 ? { onStepEvent: internal.onStepEvent } : {}
|
|
5413
5550
|
});
|
|
5414
5551
|
} finally {
|
|
5415
5552
|
runSpan.end();
|
|
@@ -5440,28 +5577,17 @@ async function dispatchStep(step, input, ctx, options, prevStepResults) {
|
|
|
5440
5577
|
}
|
|
5441
5578
|
}
|
|
5442
5579
|
}
|
|
5443
|
-
function assembleRun(params) {
|
|
5444
|
-
const endedAt = Date.now();
|
|
5445
|
-
return {
|
|
5446
|
-
id: params.runId,
|
|
5447
|
-
name: params.name,
|
|
5448
|
-
status: params.status,
|
|
5449
|
-
startedAt: params.startedAt,
|
|
5450
|
-
endedAt,
|
|
5451
|
-
stepResults: params.stepResults,
|
|
5452
|
-
...params.output !== void 0 ? { output: params.output } : {},
|
|
5453
|
-
...params.error !== void 0 ? { error: params.error } : {}
|
|
5454
|
-
};
|
|
5455
|
-
}
|
|
5456
5580
|
async function saveSnapshot(p) {
|
|
5457
5581
|
const snapshot = {
|
|
5458
|
-
_schemaVersion:
|
|
5582
|
+
_schemaVersion: 2,
|
|
5583
|
+
// SE29 — carries `state`
|
|
5459
5584
|
runId: p.runId,
|
|
5460
5585
|
workflowName: p.workflowName,
|
|
5461
5586
|
currentStepId: p.currentStepId,
|
|
5462
5587
|
suspendedPayload: p.suspendedPayload,
|
|
5463
5588
|
stepResults: p.stepResults,
|
|
5464
5589
|
accumulatedInput: p.accumulatedInput,
|
|
5590
|
+
...p.state !== void 0 ? { state: p.state } : {},
|
|
5465
5591
|
suspendedAt: Date.now()
|
|
5466
5592
|
};
|
|
5467
5593
|
const store = getSnapshotStoreFor(p.options);
|
|
@@ -5494,7 +5620,10 @@ async function resumeWorkflow(opts) {
|
|
|
5494
5620
|
signal: opts.signal,
|
|
5495
5621
|
runId: opts.runId,
|
|
5496
5622
|
// M3 #62 — restore prior step outputs so the resumed run is not lossy (internal seam).
|
|
5497
|
-
initialStepResults: snapshot.stepResults
|
|
5623
|
+
initialStepResults: snapshot.stepResults,
|
|
5624
|
+
// SE29 — restore shared state (v2 snapshot). A v1 snapshot has no `state` →
|
|
5625
|
+
// executeWorkflow falls back to `options.initialState`.
|
|
5626
|
+
...snapshot.state !== void 0 ? { restoredState: snapshot.state } : {}
|
|
5498
5627
|
});
|
|
5499
5628
|
}
|
|
5500
5629
|
var init_executor = __esm({
|
|
@@ -5502,6 +5631,7 @@ var init_executor = __esm({
|
|
|
5502
5631
|
init_workflow();
|
|
5503
5632
|
init_ctx();
|
|
5504
5633
|
init_error_shape();
|
|
5634
|
+
init_executor_helpers();
|
|
5505
5635
|
init_run_id();
|
|
5506
5636
|
init_single_flight();
|
|
5507
5637
|
init_snapshot_store();
|
|
@@ -21031,6 +21161,45 @@ var PersistenceSchema = zod.z.object({
|
|
|
21031
21161
|
|
|
21032
21162
|
// src/workflow.ts
|
|
21033
21163
|
init_path_guard();
|
|
21164
|
+
|
|
21165
|
+
// src/internal/workflow/event-stream.ts
|
|
21166
|
+
function createEventStream() {
|
|
21167
|
+
const buffer = [];
|
|
21168
|
+
const waiters = [];
|
|
21169
|
+
let ended = false;
|
|
21170
|
+
const stream = {
|
|
21171
|
+
push(event) {
|
|
21172
|
+
if (ended) return;
|
|
21173
|
+
const waiter = waiters.shift();
|
|
21174
|
+
if (waiter !== void 0) waiter({ value: event, done: false });
|
|
21175
|
+
else buffer.push(event);
|
|
21176
|
+
},
|
|
21177
|
+
end() {
|
|
21178
|
+
if (ended) return;
|
|
21179
|
+
ended = true;
|
|
21180
|
+
for (const waiter of waiters.splice(0)) waiter({ value: void 0, done: true });
|
|
21181
|
+
},
|
|
21182
|
+
next() {
|
|
21183
|
+
const buffered = buffer.shift();
|
|
21184
|
+
if (buffered !== void 0) return Promise.resolve({ value: buffered, done: false });
|
|
21185
|
+
if (ended) return Promise.resolve({ value: void 0, done: true });
|
|
21186
|
+
return new Promise((resolve3) => waiters.push(resolve3));
|
|
21187
|
+
},
|
|
21188
|
+
// `for await` calls return() on break/throw — close early so events stop
|
|
21189
|
+
// buffering in memory for a consumer that stopped iterating.
|
|
21190
|
+
return() {
|
|
21191
|
+
stream.end();
|
|
21192
|
+
buffer.length = 0;
|
|
21193
|
+
return Promise.resolve({ value: void 0, done: true });
|
|
21194
|
+
},
|
|
21195
|
+
[Symbol.asyncIterator]() {
|
|
21196
|
+
return stream;
|
|
21197
|
+
}
|
|
21198
|
+
};
|
|
21199
|
+
return stream;
|
|
21200
|
+
}
|
|
21201
|
+
|
|
21202
|
+
// src/workflow.ts
|
|
21034
21203
|
init_workflow();
|
|
21035
21204
|
var RetryPolicySchema = zod.z.object({
|
|
21036
21205
|
// EC-3 absorbed: maxAttempts MUST be a finite int in [1, 20].
|
|
@@ -21042,7 +21211,12 @@ var RetryPolicySchema = zod.z.object({
|
|
|
21042
21211
|
});
|
|
21043
21212
|
var WorkflowOptionsSchema = zod.z.object({
|
|
21044
21213
|
name: zod.z.string().min(1).max(128),
|
|
21045
|
-
persistence: PersistenceSchema
|
|
21214
|
+
persistence: PersistenceSchema,
|
|
21215
|
+
// SE27 — declared so a future `new WorkflowBuilder(parsed)` refactor cannot
|
|
21216
|
+
// silently drop them (create() passes the ORIGINAL options today, but the
|
|
21217
|
+
// schema is also the documentation of the shape).
|
|
21218
|
+
inputSchema: zod.z.custom().optional(),
|
|
21219
|
+
outputSchema: zod.z.custom().optional()
|
|
21046
21220
|
});
|
|
21047
21221
|
var WorkflowBuilder = class {
|
|
21048
21222
|
/** @internal */
|
|
@@ -21219,6 +21393,36 @@ var Workflow = class {
|
|
|
21219
21393
|
}
|
|
21220
21394
|
return result;
|
|
21221
21395
|
}
|
|
21396
|
+
/**
|
|
21397
|
+
* SE28 — run the workflow and STREAM step-level events as they happen. Returns
|
|
21398
|
+
* an async iterator of {@link WorkflowEvent}s (`step_started` / `step_completed`
|
|
21399
|
+
* / `step_failed` / `workflow_suspended` / `workflow_completed`, top-level
|
|
21400
|
+
* steps) plus a `result` promise resolving to the same terminal
|
|
21401
|
+
* {@link WorkflowRun} `run()` returns. Iterate for progress; await `result` for
|
|
21402
|
+
* the outcome. The stream ends when the run terminates.
|
|
21403
|
+
*
|
|
21404
|
+
* `result` is the AUTHORITATIVE terminal status. Not every terminal state has a
|
|
21405
|
+
* closing event: a step failure emits `step_failed`, but an `outputSchema`
|
|
21406
|
+
* rejection (SE27) or an abort ends the stream WITHOUT `workflow_completed` —
|
|
21407
|
+
* always `await result` to read the final `status`. Consuming order is free:
|
|
21408
|
+
* awaiting `result` without draining, or draining without awaiting `result`,
|
|
21409
|
+
* both work (breaking out of `for await` stops the buffering early).
|
|
21410
|
+
*/
|
|
21411
|
+
stream(input, opts) {
|
|
21412
|
+
const queue = createEventStream();
|
|
21413
|
+
const result = (async () => {
|
|
21414
|
+
const { executeWorkflow: executeWorkflow2 } = await Promise.resolve().then(() => (init_executor(), executor_exports));
|
|
21415
|
+
try {
|
|
21416
|
+
return await executeWorkflow2(this._options, this._steps, input, {
|
|
21417
|
+
...opts,
|
|
21418
|
+
onStepEvent: (event) => queue.push(event)
|
|
21419
|
+
});
|
|
21420
|
+
} finally {
|
|
21421
|
+
queue.end();
|
|
21422
|
+
}
|
|
21423
|
+
})();
|
|
21424
|
+
return Object.assign(queue, { result });
|
|
21425
|
+
}
|
|
21222
21426
|
/**
|
|
21223
21427
|
* Resume a suspended workflow from its snapshot. Throws
|
|
21224
21428
|
* `WorkflowSnapshotNotFoundError` if `runId` is unknown.
|