@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.
- package/CHANGELOG.md +57 -0
- package/dist/a2a/index.cjs +208 -4
- package/dist/a2a/index.cjs.map +1 -1
- package/dist/a2a/index.js +208 -4
- package/dist/a2a/index.js.map +1 -1
- package/dist/{cron-B44D-678.d.ts → cron-BR1NCSk1.d.cts} +11 -1
- package/dist/{cron-qI-dbG7c.d.cts → cron-DgEQCJ2i.d.ts} +11 -1
- package/dist/cron.cjs +187 -4
- package/dist/cron.cjs.map +1 -1
- package/dist/cron.d.cts +2 -2
- package/dist/cron.d.ts +2 -2
- package/dist/cron.js +187 -4
- package/dist/cron.js.map +1 -1
- package/dist/{errors-DRS-kqOK.d.ts → errors-CbY3pxY7.d.ts} +1 -1
- package/dist/{errors-DIKBXffg.d.cts → errors-DLMNb4Ka.d.cts} +1 -1
- package/dist/errors.d.cts +2 -2
- package/dist/eval.cjs +187 -4
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +187 -4
- package/dist/eval.js.map +1 -1
- package/dist/index.cjs +483 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -7
- package/dist/index.d.ts +69 -7
- package/dist/index.js +481 -52
- package/dist/index.js.map +1 -1
- package/dist/internal/runtime/processors/run-processors.d.ts +10 -0
- package/dist/internal/runtime/processors/tripwire-run.d.ts +16 -0
- package/dist/internal/runtime/processors/wrap-output-run.d.ts +18 -0
- 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/{run-Cr0C6cOM.d.cts → run-CdWiihyU.d.cts} +109 -2
- package/dist/{run-Cr0C6cOM.d.ts → run-CdWiihyU.d.ts} +109 -2
- package/dist/types/agent.d.ts +10 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/processors.d.ts +84 -0
- package/dist/types/run-events.d.ts +11 -1
- package/dist/types/run.d.ts +12 -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/dist/types/workflow.d.ts
CHANGED
|
@@ -101,6 +101,19 @@ export interface StepContext {
|
|
|
101
101
|
};
|
|
102
102
|
/** Pause the workflow; resume via `Workflow.resume({...})`. */
|
|
103
103
|
readonly suspend: (payload?: unknown) => Promise<never>;
|
|
104
|
+
/**
|
|
105
|
+
* SE29 — the workflow's shared state (from `WorkflowOptions.initialState`,
|
|
106
|
+
* mutated by {@link setState}), visible to every subsequent step in the run.
|
|
107
|
+
* `undefined` when no `initialState`/`setState` has run. Persisted across
|
|
108
|
+
* suspend/resume.
|
|
109
|
+
*/
|
|
110
|
+
readonly state: unknown;
|
|
111
|
+
/**
|
|
112
|
+
* SE29 — update the shared state for subsequent steps. Validated against
|
|
113
|
+
* `WorkflowOptions.stateSchema` when set (a mismatch throws
|
|
114
|
+
* {@link WorkflowStateError}, which fails the step/run — Rule 8).
|
|
115
|
+
*/
|
|
116
|
+
readonly setState: (next: unknown) => void;
|
|
104
117
|
}
|
|
105
118
|
export interface StepResult {
|
|
106
119
|
readonly stepId: string;
|
|
@@ -128,15 +141,57 @@ export interface WorkflowRun<TOutput = unknown> {
|
|
|
128
141
|
readonly stepResults: ReadonlyArray<StepResult>;
|
|
129
142
|
}
|
|
130
143
|
export interface WorkflowSnapshot {
|
|
131
|
-
|
|
144
|
+
/** v1 = pre-SE29 (no `state`); v2 = SE29 (carries `state`). Resume reads both. */
|
|
145
|
+
readonly _schemaVersion: 1 | 2;
|
|
132
146
|
readonly runId: string;
|
|
133
147
|
readonly workflowName: string;
|
|
134
148
|
readonly currentStepId: string;
|
|
135
149
|
readonly suspendedPayload?: unknown;
|
|
136
150
|
readonly stepResults: ReadonlyArray<StepResult>;
|
|
137
151
|
readonly accumulatedInput: unknown;
|
|
152
|
+
/** SE29 — shared state captured at suspend (v2). Absent on a v1 snapshot. */
|
|
153
|
+
readonly state?: unknown;
|
|
138
154
|
readonly suspendedAt: number;
|
|
139
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* SE28 — a step-level workflow event emitted by `Workflow.stream()` as top-level
|
|
158
|
+
* steps run. Coarse-grained (one event per top-level step; nested
|
|
159
|
+
* parallel/branch/foreach emit as their single wrapping step), distinct from the
|
|
160
|
+
* token-delta agent stream. Discriminate on `type`.
|
|
161
|
+
*
|
|
162
|
+
* @public
|
|
163
|
+
*/
|
|
164
|
+
export type WorkflowEvent = {
|
|
165
|
+
readonly type: "step_started";
|
|
166
|
+
readonly stepId: string;
|
|
167
|
+
} | {
|
|
168
|
+
readonly type: "step_completed";
|
|
169
|
+
readonly stepId: string;
|
|
170
|
+
readonly output: unknown;
|
|
171
|
+
} | {
|
|
172
|
+
readonly type: "step_failed";
|
|
173
|
+
readonly stepId: string;
|
|
174
|
+
readonly error: {
|
|
175
|
+
readonly name: string;
|
|
176
|
+
readonly message: string;
|
|
177
|
+
};
|
|
178
|
+
} | {
|
|
179
|
+
readonly type: "workflow_suspended";
|
|
180
|
+
readonly stepId: string;
|
|
181
|
+
} | {
|
|
182
|
+
readonly type: "workflow_completed";
|
|
183
|
+
};
|
|
184
|
+
/**
|
|
185
|
+
* SE28 — the async iterator returned by `Workflow.stream()`. Yields
|
|
186
|
+
* {@link WorkflowEvent}s in execution order; `result` resolves to the same
|
|
187
|
+
* terminal {@link WorkflowRun} the `run()` path returns (the authoritative
|
|
188
|
+
* outcome — the stream ends when the run terminates).
|
|
189
|
+
*
|
|
190
|
+
* @public
|
|
191
|
+
*/
|
|
192
|
+
export type WorkflowStream<TOutput = unknown> = AsyncIterableIterator<WorkflowEvent> & {
|
|
193
|
+
readonly result: Promise<WorkflowRun<TOutput>>;
|
|
194
|
+
};
|
|
140
195
|
export interface WorkflowPersistenceOptions {
|
|
141
196
|
readonly backend: "memory" | "json";
|
|
142
197
|
/** Required for `backend: "json"`. */
|
|
@@ -145,6 +200,34 @@ export interface WorkflowPersistenceOptions {
|
|
|
145
200
|
export interface WorkflowOptions {
|
|
146
201
|
readonly name: string;
|
|
147
202
|
readonly persistence?: WorkflowPersistenceOptions;
|
|
203
|
+
/**
|
|
204
|
+
* SE27 — Zod schema for the WHOLE workflow's input. When set, `run(input)`
|
|
205
|
+
* validates `input` BEFORE step 1; a mismatch yields `status: "failed"` with a
|
|
206
|
+
* typed {@link WorkflowInputError} in `error` (fail-fast, no step runs, no
|
|
207
|
+
* silent coerce). Absent ⇒ no whole-workflow input validation (unchanged).
|
|
208
|
+
*/
|
|
209
|
+
readonly inputSchema?: ZodType;
|
|
210
|
+
/**
|
|
211
|
+
* SE27 — Zod schema for the workflow's final output. When set, the terminal
|
|
212
|
+
* `completed` output is validated before `WorkflowRun.output` is populated; a
|
|
213
|
+
* mismatch yields `status: "failed"` with a typed {@link WorkflowOutputError}.
|
|
214
|
+
* Only validated on the `completed` path (suspended/failed runs skip it).
|
|
215
|
+
*/
|
|
216
|
+
readonly outputSchema?: ZodType;
|
|
217
|
+
/**
|
|
218
|
+
* SE29 — Zod schema for the workflow's shared state (see `StepContext.state` /
|
|
219
|
+
* `setState`). When set, `initialState` and every `setState(next)` are
|
|
220
|
+
* validated against it (a mismatch throws {@link WorkflowStateError}). When
|
|
221
|
+
* `initialState` is absent, `state` starts as `undefined` and validation fires
|
|
222
|
+
* on the first `setState` call.
|
|
223
|
+
*/
|
|
224
|
+
readonly stateSchema?: ZodType;
|
|
225
|
+
/**
|
|
226
|
+
* SE29 — the initial shared state, seeded onto `StepContext.state` before
|
|
227
|
+
* step 1. Validated against `stateSchema` when both are set. Persisted across
|
|
228
|
+
* suspend/resume.
|
|
229
|
+
*/
|
|
230
|
+
readonly initialState?: unknown;
|
|
148
231
|
/** Internal — minted at `.commit()`. Not user-facing. */
|
|
149
232
|
readonly workflowId?: string;
|
|
150
233
|
}
|
|
@@ -179,6 +262,56 @@ export declare class WorkflowDuplicateStepIdError extends Error {
|
|
|
179
262
|
readonly name = "WorkflowDuplicateStepIdError";
|
|
180
263
|
constructor(stepId: string);
|
|
181
264
|
}
|
|
265
|
+
/**
|
|
266
|
+
* SE27 — the whole-workflow `inputSchema` rejected `run(input)` (before step 1).
|
|
267
|
+
* `detail` is a pre-formatted issues summary (a string, NOT Zod's `ZodIssue[]`).
|
|
268
|
+
*/
|
|
269
|
+
export declare class WorkflowInputError extends Error {
|
|
270
|
+
readonly workflowName: string;
|
|
271
|
+
readonly detail: string;
|
|
272
|
+
readonly name = "WorkflowInputError";
|
|
273
|
+
constructor(workflowName: string, detail: string);
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* SE27 — the whole-workflow `outputSchema` rejected the final output (on `completed`).
|
|
277
|
+
* `detail` is a pre-formatted issues summary (a string, NOT Zod's `ZodIssue[]`).
|
|
278
|
+
*/
|
|
279
|
+
export declare class WorkflowOutputError extends Error {
|
|
280
|
+
readonly workflowName: string;
|
|
281
|
+
readonly detail: string;
|
|
282
|
+
readonly name = "WorkflowOutputError";
|
|
283
|
+
constructor(workflowName: string, detail: string);
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* SE29 — `WorkflowOptions.stateSchema` rejected an `initialState` or a
|
|
287
|
+
* `setState(next)` call. `detail` is a pre-formatted issues summary.
|
|
288
|
+
*/
|
|
289
|
+
export declare class WorkflowStateError extends Error {
|
|
290
|
+
readonly workflowName: string;
|
|
291
|
+
readonly detail: string;
|
|
292
|
+
readonly name = "WorkflowStateError";
|
|
293
|
+
constructor(workflowName: string, detail: string);
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* SE30 — a nested workflow (via `workflowStep`) did not `complete`. A nested
|
|
297
|
+
* `suspended` is NOT resumable in v1 (resume continues AFTER the step, so the
|
|
298
|
+
* child would be skipped) — restructure with a top-level suspend. A nested
|
|
299
|
+
* `failed`/`cancelled` fails the parent step with the child's error attached.
|
|
300
|
+
*/
|
|
301
|
+
export declare class WorkflowNestedError extends Error {
|
|
302
|
+
readonly stepId: string;
|
|
303
|
+
readonly childName: string;
|
|
304
|
+
readonly childStatus: Exclude<WorkflowRun["status"], "completed">;
|
|
305
|
+
readonly childError?: {
|
|
306
|
+
name: string;
|
|
307
|
+
message: string;
|
|
308
|
+
} | undefined;
|
|
309
|
+
readonly name = "WorkflowNestedError";
|
|
310
|
+
constructor(stepId: string, childName: string, childStatus: Exclude<WorkflowRun["status"], "completed">, childError?: {
|
|
311
|
+
name: string;
|
|
312
|
+
message: string;
|
|
313
|
+
} | undefined);
|
|
314
|
+
}
|
|
182
315
|
export declare class WorkflowAlreadyRunningError extends Error {
|
|
183
316
|
readonly workflowName: string;
|
|
184
317
|
readonly runId: string;
|
package/dist/workflow.cjs
CHANGED
|
@@ -213,7 +213,7 @@ var init_errors = __esm({
|
|
|
213
213
|
});
|
|
214
214
|
|
|
215
215
|
// src/types/workflow.ts
|
|
216
|
-
exports.WorkflowDuplicateStepIdError = void 0; exports.WorkflowAlreadyRunningError = void 0; exports.WorkflowSnapshotNotFoundError = void 0; exports.WorkflowMaxIterationsExceededError = void 0; exports.WorkflowNotSerializableError = void 0; exports.WorkflowResumeStepNotFoundError = void 0; exports.WorkflowParallelError = void 0; exports.WorkflowCompensateNotImplementedError = void 0;
|
|
216
|
+
exports.WorkflowDuplicateStepIdError = void 0; exports.WorkflowInputError = void 0; exports.WorkflowOutputError = void 0; exports.WorkflowStateError = void 0; exports.WorkflowNestedError = void 0; exports.WorkflowAlreadyRunningError = void 0; exports.WorkflowSnapshotNotFoundError = void 0; exports.WorkflowMaxIterationsExceededError = void 0; exports.WorkflowNotSerializableError = void 0; exports.WorkflowResumeStepNotFoundError = void 0; exports.WorkflowParallelError = void 0; exports.WorkflowCompensateNotImplementedError = void 0;
|
|
217
217
|
var init_workflow = __esm({
|
|
218
218
|
"src/types/workflow.ts"() {
|
|
219
219
|
exports.WorkflowDuplicateStepIdError = class extends Error {
|
|
@@ -224,6 +224,57 @@ var init_workflow = __esm({
|
|
|
224
224
|
stepId;
|
|
225
225
|
name = "WorkflowDuplicateStepIdError";
|
|
226
226
|
};
|
|
227
|
+
exports.WorkflowInputError = class extends Error {
|
|
228
|
+
constructor(workflowName, detail) {
|
|
229
|
+
super(`Workflow "${workflowName}" input failed schema validation: ${detail}`);
|
|
230
|
+
this.workflowName = workflowName;
|
|
231
|
+
this.detail = detail;
|
|
232
|
+
}
|
|
233
|
+
workflowName;
|
|
234
|
+
detail;
|
|
235
|
+
name = "WorkflowInputError";
|
|
236
|
+
};
|
|
237
|
+
exports.WorkflowOutputError = class extends Error {
|
|
238
|
+
constructor(workflowName, detail) {
|
|
239
|
+
super(`Workflow "${workflowName}" output failed schema validation: ${detail}`);
|
|
240
|
+
this.workflowName = workflowName;
|
|
241
|
+
this.detail = detail;
|
|
242
|
+
}
|
|
243
|
+
workflowName;
|
|
244
|
+
detail;
|
|
245
|
+
name = "WorkflowOutputError";
|
|
246
|
+
};
|
|
247
|
+
exports.WorkflowStateError = class extends Error {
|
|
248
|
+
constructor(workflowName, detail) {
|
|
249
|
+
super(`Workflow "${workflowName}" state failed schema validation: ${detail}`);
|
|
250
|
+
this.workflowName = workflowName;
|
|
251
|
+
this.detail = detail;
|
|
252
|
+
}
|
|
253
|
+
workflowName;
|
|
254
|
+
detail;
|
|
255
|
+
name = "WorkflowStateError";
|
|
256
|
+
};
|
|
257
|
+
exports.WorkflowNestedError = class extends Error {
|
|
258
|
+
constructor(stepId, childName, childStatus, childError) {
|
|
259
|
+
super(
|
|
260
|
+
`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}` : ""}`,
|
|
261
|
+
// Reconstruct a synthetic Error from the serialized child-error shape so
|
|
262
|
+
// debuggers surface the nested cause chain — the original Error instance is
|
|
263
|
+
// lost at the WorkflowRun serialization boundary, so this is the best
|
|
264
|
+
// achievable without changing the run protocol.
|
|
265
|
+
childError ? { cause: Object.assign(new Error(childError.message), { name: childError.name }) } : void 0
|
|
266
|
+
);
|
|
267
|
+
this.stepId = stepId;
|
|
268
|
+
this.childName = childName;
|
|
269
|
+
this.childStatus = childStatus;
|
|
270
|
+
this.childError = childError;
|
|
271
|
+
}
|
|
272
|
+
stepId;
|
|
273
|
+
childName;
|
|
274
|
+
childStatus;
|
|
275
|
+
childError;
|
|
276
|
+
name = "WorkflowNestedError";
|
|
277
|
+
};
|
|
227
278
|
exports.WorkflowAlreadyRunningError = class extends Error {
|
|
228
279
|
constructor(workflowName, runId) {
|
|
229
280
|
super(`Workflow "${workflowName}" run "${runId}" already in-flight.`);
|
|
@@ -472,7 +523,7 @@ var init_snapshot_store = __esm({
|
|
|
472
523
|
});
|
|
473
524
|
|
|
474
525
|
// src/internal/workflow/ctx.ts
|
|
475
|
-
function makeStepContext(runId, signal) {
|
|
526
|
+
function makeStepContext(runId, signal, state2) {
|
|
476
527
|
return {
|
|
477
528
|
runId,
|
|
478
529
|
signal,
|
|
@@ -483,7 +534,13 @@ function makeStepContext(runId, signal) {
|
|
|
483
534
|
},
|
|
484
535
|
suspend: async (payload) => {
|
|
485
536
|
throw new WorkflowSuspendedSentinel(payload);
|
|
486
|
-
}
|
|
537
|
+
},
|
|
538
|
+
// SE29 — read reflects the current shared state; write goes through the
|
|
539
|
+
// controller (which validates against `stateSchema`).
|
|
540
|
+
get state() {
|
|
541
|
+
return state2.getState();
|
|
542
|
+
},
|
|
543
|
+
setState: (next) => state2.setState(next)
|
|
487
544
|
};
|
|
488
545
|
}
|
|
489
546
|
function emit(level, runId, msg, attrs) {
|
|
@@ -536,6 +593,57 @@ var init_error_shape = __esm({
|
|
|
536
593
|
}
|
|
537
594
|
});
|
|
538
595
|
|
|
596
|
+
// src/internal/workflow/executor-helpers.ts
|
|
597
|
+
function assembleRun(params) {
|
|
598
|
+
return {
|
|
599
|
+
id: params.runId,
|
|
600
|
+
name: params.name,
|
|
601
|
+
status: params.status,
|
|
602
|
+
startedAt: params.startedAt,
|
|
603
|
+
endedAt: Date.now(),
|
|
604
|
+
stepResults: params.stepResults,
|
|
605
|
+
...params.output !== void 0 ? { output: params.output } : {},
|
|
606
|
+
...params.error !== void 0 ? { error: params.error } : {}
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
function abortRun(name, runId, startedAt, stepResults, signal) {
|
|
610
|
+
return assembleRun({
|
|
611
|
+
runId,
|
|
612
|
+
name,
|
|
613
|
+
status: "cancelled",
|
|
614
|
+
stepResults,
|
|
615
|
+
startedAt,
|
|
616
|
+
error: { name: "AbortError", message: String(signal.reason ?? "Aborted") }
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
function validateWorkflowSchema(schema, value) {
|
|
620
|
+
if (schema === void 0) return void 0;
|
|
621
|
+
let parsed;
|
|
622
|
+
try {
|
|
623
|
+
parsed = schema.safeParse(value);
|
|
624
|
+
} catch {
|
|
625
|
+
return "schema uses async refinements, which whole-workflow validation does not support (use a synchronous Zod schema)";
|
|
626
|
+
}
|
|
627
|
+
if (parsed.success) return void 0;
|
|
628
|
+
return parsed.error.issues.map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; ");
|
|
629
|
+
}
|
|
630
|
+
function makeStateController(options, initial) {
|
|
631
|
+
let current = initial;
|
|
632
|
+
return {
|
|
633
|
+
getState: () => current,
|
|
634
|
+
setState: (next) => {
|
|
635
|
+
const issues = validateWorkflowSchema(options.stateSchema, next);
|
|
636
|
+
if (issues !== void 0) throw new exports.WorkflowStateError(options.name, issues);
|
|
637
|
+
current = next;
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
var init_executor_helpers = __esm({
|
|
642
|
+
"src/internal/workflow/executor-helpers.ts"() {
|
|
643
|
+
init_workflow();
|
|
644
|
+
}
|
|
645
|
+
});
|
|
646
|
+
|
|
539
647
|
// src/internal/workflow/run-id.ts
|
|
540
648
|
function mintRunId() {
|
|
541
649
|
return `wfr-${globalThis.crypto.randomUUID().replace(/-/g, "").slice(0, 8)}`;
|
|
@@ -1273,6 +1381,8 @@ async function handleSuspend(err, ctx) {
|
|
|
1273
1381
|
suspendedPayload: err.payload,
|
|
1274
1382
|
stepResults: ctx.stepResults,
|
|
1275
1383
|
accumulatedInput: ctx.acc,
|
|
1384
|
+
state: ctx.stepCtx.state,
|
|
1385
|
+
// SE29 — capture the shared state at suspend
|
|
1276
1386
|
options: ctx.options
|
|
1277
1387
|
});
|
|
1278
1388
|
} catch (snapErr) {
|
|
@@ -1324,7 +1434,7 @@ async function runOneStep(args) {
|
|
|
1324
1434
|
result = await dispatchStep(args.step, args.acc, args.ctx, args.options, args.stepResults);
|
|
1325
1435
|
} catch (err) {
|
|
1326
1436
|
if (err instanceof WorkflowSuspendedSentinel) {
|
|
1327
|
-
const outcome = await handleSuspend(err, { ...args, stepSpan });
|
|
1437
|
+
const outcome = await handleSuspend(err, { ...args, stepSpan, stepCtx: args.ctx });
|
|
1328
1438
|
return { kind: "terminal", run: outcome.run };
|
|
1329
1439
|
}
|
|
1330
1440
|
result = {
|
|
@@ -1341,22 +1451,42 @@ async function runOneStep(args) {
|
|
|
1341
1451
|
stepSpan.end();
|
|
1342
1452
|
return { kind: "ok", result };
|
|
1343
1453
|
}
|
|
1344
|
-
function
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1454
|
+
function handleStepOutcome(outcome, step, loop, onStepEvent) {
|
|
1455
|
+
if (outcome.kind === "terminal") {
|
|
1456
|
+
if (outcome.run.status === "suspended") {
|
|
1457
|
+
onStepEvent?.({ type: "workflow_suspended", stepId: step.id });
|
|
1458
|
+
}
|
|
1459
|
+
return { terminal: outcome.run };
|
|
1460
|
+
}
|
|
1461
|
+
loop.stepResults.push(outcome.result);
|
|
1462
|
+
if (outcome.result.status === "failed") {
|
|
1463
|
+
onStepEvent?.({
|
|
1464
|
+
type: "step_failed",
|
|
1465
|
+
stepId: step.id,
|
|
1466
|
+
error: outcome.result.error ?? { name: "WorkflowStepError", message: "step failed" }
|
|
1467
|
+
});
|
|
1468
|
+
return {
|
|
1469
|
+
terminal: assembleRun({
|
|
1470
|
+
runId: loop.runId,
|
|
1471
|
+
name: loop.name,
|
|
1472
|
+
status: "failed",
|
|
1473
|
+
stepResults: loop.stepResults,
|
|
1474
|
+
startedAt: loop.startedAt,
|
|
1475
|
+
error: outcome.result.error
|
|
1476
|
+
})
|
|
1477
|
+
};
|
|
1478
|
+
}
|
|
1479
|
+
onStepEvent?.({ type: "step_completed", stepId: step.id, output: outcome.result.output });
|
|
1480
|
+
return { acc: outcome.result.output };
|
|
1353
1481
|
}
|
|
1354
1482
|
async function runStepsLoop(params) {
|
|
1355
|
-
const { options, steps, ctx, runId, startedAt, signal } = params;
|
|
1483
|
+
const { options, steps, ctx, runId, startedAt, signal, onStepEvent } = params;
|
|
1356
1484
|
const stepResults = [...params.initialStepResults ?? []];
|
|
1485
|
+
const loop = { stepResults, runId, name: options.name, startedAt };
|
|
1357
1486
|
let acc = params.input;
|
|
1358
1487
|
for (const step of steps) {
|
|
1359
1488
|
if (signal.aborted) return abortRun(options.name, runId, startedAt, stepResults, signal);
|
|
1489
|
+
onStepEvent?.({ type: "step_started", stepId: step.id });
|
|
1360
1490
|
const outcome = await runOneStep({
|
|
1361
1491
|
step,
|
|
1362
1492
|
acc,
|
|
@@ -1367,20 +1497,22 @@ async function runStepsLoop(params) {
|
|
|
1367
1497
|
name: options.name,
|
|
1368
1498
|
startedAt
|
|
1369
1499
|
});
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
return assembleRun({
|
|
1374
|
-
runId,
|
|
1375
|
-
name: options.name,
|
|
1376
|
-
status: "failed",
|
|
1377
|
-
stepResults,
|
|
1378
|
-
startedAt,
|
|
1379
|
-
error: outcome.result.error
|
|
1380
|
-
});
|
|
1381
|
-
}
|
|
1382
|
-
acc = outcome.result.output;
|
|
1500
|
+
const handled = handleStepOutcome(outcome, step, loop, onStepEvent);
|
|
1501
|
+
if ("terminal" in handled) return handled.terminal;
|
|
1502
|
+
acc = handled.acc;
|
|
1383
1503
|
}
|
|
1504
|
+
const outputIssues = validateWorkflowSchema(options.outputSchema, acc);
|
|
1505
|
+
if (outputIssues !== void 0) {
|
|
1506
|
+
return assembleRun({
|
|
1507
|
+
runId,
|
|
1508
|
+
name: options.name,
|
|
1509
|
+
status: "failed",
|
|
1510
|
+
stepResults,
|
|
1511
|
+
startedAt,
|
|
1512
|
+
error: errToShape(new exports.WorkflowOutputError(options.name, outputIssues))
|
|
1513
|
+
});
|
|
1514
|
+
}
|
|
1515
|
+
onStepEvent?.({ type: "workflow_completed" });
|
|
1384
1516
|
return assembleRun({
|
|
1385
1517
|
runId,
|
|
1386
1518
|
name: options.name,
|
|
@@ -1403,8 +1535,33 @@ async function executeWorkflow(options, steps, input, runOpts) {
|
|
|
1403
1535
|
runSpan.end();
|
|
1404
1536
|
return abortRun(options.name, runId, startedAt, [], signal);
|
|
1405
1537
|
}
|
|
1406
|
-
const
|
|
1538
|
+
const internal = runOpts;
|
|
1539
|
+
const seededState = internal?.restoredState !== void 0 ? internal.restoredState : options.initialState;
|
|
1540
|
+
const stateController = makeStateController(options, seededState);
|
|
1541
|
+
const ctx = makeStepContext(runId, signal, stateController);
|
|
1407
1542
|
try {
|
|
1543
|
+
const inputIssues = validateWorkflowSchema(options.inputSchema, input);
|
|
1544
|
+
if (inputIssues !== void 0) {
|
|
1545
|
+
return assembleRun({
|
|
1546
|
+
runId,
|
|
1547
|
+
name: options.name,
|
|
1548
|
+
status: "failed",
|
|
1549
|
+
stepResults: [],
|
|
1550
|
+
startedAt,
|
|
1551
|
+
error: errToShape(new exports.WorkflowInputError(options.name, inputIssues))
|
|
1552
|
+
});
|
|
1553
|
+
}
|
|
1554
|
+
const stateIssues = seededState !== void 0 ? validateWorkflowSchema(options.stateSchema, seededState) : void 0;
|
|
1555
|
+
if (stateIssues !== void 0) {
|
|
1556
|
+
return assembleRun({
|
|
1557
|
+
runId,
|
|
1558
|
+
name: options.name,
|
|
1559
|
+
status: "failed",
|
|
1560
|
+
stepResults: [],
|
|
1561
|
+
startedAt,
|
|
1562
|
+
error: errToShape(new exports.WorkflowStateError(options.name, stateIssues))
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1408
1565
|
return await runStepsLoop({
|
|
1409
1566
|
options,
|
|
1410
1567
|
steps,
|
|
@@ -1413,7 +1570,8 @@ async function executeWorkflow(options, steps, input, runOpts) {
|
|
|
1413
1570
|
runId,
|
|
1414
1571
|
startedAt,
|
|
1415
1572
|
signal,
|
|
1416
|
-
...
|
|
1573
|
+
...internal?.initialStepResults !== void 0 ? { initialStepResults: internal.initialStepResults } : {},
|
|
1574
|
+
...internal?.onStepEvent !== void 0 ? { onStepEvent: internal.onStepEvent } : {}
|
|
1417
1575
|
});
|
|
1418
1576
|
} finally {
|
|
1419
1577
|
runSpan.end();
|
|
@@ -1444,28 +1602,17 @@ async function dispatchStep(step, input, ctx, options, prevStepResults) {
|
|
|
1444
1602
|
}
|
|
1445
1603
|
}
|
|
1446
1604
|
}
|
|
1447
|
-
function assembleRun(params) {
|
|
1448
|
-
const endedAt = Date.now();
|
|
1449
|
-
return {
|
|
1450
|
-
id: params.runId,
|
|
1451
|
-
name: params.name,
|
|
1452
|
-
status: params.status,
|
|
1453
|
-
startedAt: params.startedAt,
|
|
1454
|
-
endedAt,
|
|
1455
|
-
stepResults: params.stepResults,
|
|
1456
|
-
...params.output !== void 0 ? { output: params.output } : {},
|
|
1457
|
-
...params.error !== void 0 ? { error: params.error } : {}
|
|
1458
|
-
};
|
|
1459
|
-
}
|
|
1460
1605
|
async function saveSnapshot(p) {
|
|
1461
1606
|
const snapshot = {
|
|
1462
|
-
_schemaVersion:
|
|
1607
|
+
_schemaVersion: 2,
|
|
1608
|
+
// SE29 — carries `state`
|
|
1463
1609
|
runId: p.runId,
|
|
1464
1610
|
workflowName: p.workflowName,
|
|
1465
1611
|
currentStepId: p.currentStepId,
|
|
1466
1612
|
suspendedPayload: p.suspendedPayload,
|
|
1467
1613
|
stepResults: p.stepResults,
|
|
1468
1614
|
accumulatedInput: p.accumulatedInput,
|
|
1615
|
+
...p.state !== void 0 ? { state: p.state } : {},
|
|
1469
1616
|
suspendedAt: Date.now()
|
|
1470
1617
|
};
|
|
1471
1618
|
const store = getSnapshotStoreFor(p.options);
|
|
@@ -1498,7 +1645,10 @@ async function resumeWorkflow(opts) {
|
|
|
1498
1645
|
signal: opts.signal,
|
|
1499
1646
|
runId: opts.runId,
|
|
1500
1647
|
// M3 #62 — restore prior step outputs so the resumed run is not lossy (internal seam).
|
|
1501
|
-
initialStepResults: snapshot.stepResults
|
|
1648
|
+
initialStepResults: snapshot.stepResults,
|
|
1649
|
+
// SE29 — restore shared state (v2 snapshot). A v1 snapshot has no `state` →
|
|
1650
|
+
// executeWorkflow falls back to `options.initialState`.
|
|
1651
|
+
...snapshot.state !== void 0 ? { restoredState: snapshot.state } : {}
|
|
1502
1652
|
});
|
|
1503
1653
|
}
|
|
1504
1654
|
var init_executor = __esm({
|
|
@@ -1506,6 +1656,7 @@ var init_executor = __esm({
|
|
|
1506
1656
|
init_workflow();
|
|
1507
1657
|
init_ctx();
|
|
1508
1658
|
init_error_shape();
|
|
1659
|
+
init_executor_helpers();
|
|
1509
1660
|
init_run_id();
|
|
1510
1661
|
init_single_flight();
|
|
1511
1662
|
init_snapshot_store();
|
|
@@ -2244,6 +2395,43 @@ function sanitizeIdentifier(input, options) {
|
|
|
2244
2395
|
}
|
|
2245
2396
|
return input.toLowerCase();
|
|
2246
2397
|
}
|
|
2398
|
+
|
|
2399
|
+
// src/internal/workflow/event-stream.ts
|
|
2400
|
+
function createEventStream() {
|
|
2401
|
+
const buffer = [];
|
|
2402
|
+
const waiters = [];
|
|
2403
|
+
let ended = false;
|
|
2404
|
+
const stream = {
|
|
2405
|
+
push(event) {
|
|
2406
|
+
if (ended) return;
|
|
2407
|
+
const waiter = waiters.shift();
|
|
2408
|
+
if (waiter !== void 0) waiter({ value: event, done: false });
|
|
2409
|
+
else buffer.push(event);
|
|
2410
|
+
},
|
|
2411
|
+
end() {
|
|
2412
|
+
if (ended) return;
|
|
2413
|
+
ended = true;
|
|
2414
|
+
for (const waiter of waiters.splice(0)) waiter({ value: void 0, done: true });
|
|
2415
|
+
},
|
|
2416
|
+
next() {
|
|
2417
|
+
const buffered = buffer.shift();
|
|
2418
|
+
if (buffered !== void 0) return Promise.resolve({ value: buffered, done: false });
|
|
2419
|
+
if (ended) return Promise.resolve({ value: void 0, done: true });
|
|
2420
|
+
return new Promise((resolve2) => waiters.push(resolve2));
|
|
2421
|
+
},
|
|
2422
|
+
// `for await` calls return() on break/throw — close early so events stop
|
|
2423
|
+
// buffering in memory for a consumer that stopped iterating.
|
|
2424
|
+
return() {
|
|
2425
|
+
stream.end();
|
|
2426
|
+
buffer.length = 0;
|
|
2427
|
+
return Promise.resolve({ value: void 0, done: true });
|
|
2428
|
+
},
|
|
2429
|
+
[Symbol.asyncIterator]() {
|
|
2430
|
+
return stream;
|
|
2431
|
+
}
|
|
2432
|
+
};
|
|
2433
|
+
return stream;
|
|
2434
|
+
}
|
|
2247
2435
|
function toJsonSchema(schema, options = { unrepresentable: "any" }) {
|
|
2248
2436
|
return zod.toJSONSchema(schema, options);
|
|
2249
2437
|
}
|
|
@@ -2262,7 +2450,12 @@ var RetryPolicySchema = zod.z.object({
|
|
|
2262
2450
|
});
|
|
2263
2451
|
var WorkflowOptionsSchema = zod.z.object({
|
|
2264
2452
|
name: zod.z.string().min(1).max(128),
|
|
2265
|
-
persistence: PersistenceSchema
|
|
2453
|
+
persistence: PersistenceSchema,
|
|
2454
|
+
// SE27 — declared so a future `new WorkflowBuilder(parsed)` refactor cannot
|
|
2455
|
+
// silently drop them (create() passes the ORIGINAL options today, but the
|
|
2456
|
+
// schema is also the documentation of the shape).
|
|
2457
|
+
inputSchema: zod.z.custom().optional(),
|
|
2458
|
+
outputSchema: zod.z.custom().optional()
|
|
2266
2459
|
});
|
|
2267
2460
|
var WorkflowBuilder = class {
|
|
2268
2461
|
/** @internal */
|
|
@@ -2439,6 +2632,36 @@ var Workflow = class {
|
|
|
2439
2632
|
}
|
|
2440
2633
|
return result;
|
|
2441
2634
|
}
|
|
2635
|
+
/**
|
|
2636
|
+
* SE28 — run the workflow and STREAM step-level events as they happen. Returns
|
|
2637
|
+
* an async iterator of {@link WorkflowEvent}s (`step_started` / `step_completed`
|
|
2638
|
+
* / `step_failed` / `workflow_suspended` / `workflow_completed`, top-level
|
|
2639
|
+
* steps) plus a `result` promise resolving to the same terminal
|
|
2640
|
+
* {@link WorkflowRun} `run()` returns. Iterate for progress; await `result` for
|
|
2641
|
+
* the outcome. The stream ends when the run terminates.
|
|
2642
|
+
*
|
|
2643
|
+
* `result` is the AUTHORITATIVE terminal status. Not every terminal state has a
|
|
2644
|
+
* closing event: a step failure emits `step_failed`, but an `outputSchema`
|
|
2645
|
+
* rejection (SE27) or an abort ends the stream WITHOUT `workflow_completed` —
|
|
2646
|
+
* always `await result` to read the final `status`. Consuming order is free:
|
|
2647
|
+
* awaiting `result` without draining, or draining without awaiting `result`,
|
|
2648
|
+
* both work (breaking out of `for await` stops the buffering early).
|
|
2649
|
+
*/
|
|
2650
|
+
stream(input, opts) {
|
|
2651
|
+
const queue = createEventStream();
|
|
2652
|
+
const result = (async () => {
|
|
2653
|
+
const { executeWorkflow: executeWorkflow2 } = await Promise.resolve().then(() => (init_executor(), executor_exports));
|
|
2654
|
+
try {
|
|
2655
|
+
return await executeWorkflow2(this._options, this._steps, input, {
|
|
2656
|
+
...opts,
|
|
2657
|
+
onStepEvent: (event) => queue.push(event)
|
|
2658
|
+
});
|
|
2659
|
+
} finally {
|
|
2660
|
+
queue.end();
|
|
2661
|
+
}
|
|
2662
|
+
})();
|
|
2663
|
+
return Object.assign(queue, { result });
|
|
2664
|
+
}
|
|
2442
2665
|
/**
|
|
2443
2666
|
* Resume a suspended workflow from its snapshot. Throws
|
|
2444
2667
|
* `WorkflowSnapshotNotFoundError` if `runId` is unknown.
|
|
@@ -2473,6 +2696,25 @@ function agentStep(id, agent, promptTemplate, opts) {
|
|
|
2473
2696
|
...opts?.origin !== void 0 ? { origin: opts.origin } : {}
|
|
2474
2697
|
};
|
|
2475
2698
|
}
|
|
2699
|
+
function workflowStep(child, opts) {
|
|
2700
|
+
const id = opts?.id ?? `workflow_${child.__options.name}`;
|
|
2701
|
+
validateStepId(id);
|
|
2702
|
+
return {
|
|
2703
|
+
kind: "fn",
|
|
2704
|
+
id,
|
|
2705
|
+
fn: async (input, ctx) => {
|
|
2706
|
+
const run = await child.run(input, { signal: ctx.signal });
|
|
2707
|
+
if (run.status === "completed") return run.output;
|
|
2708
|
+
throw new exports.WorkflowNestedError(id, child.__options.name, run.status, run.error);
|
|
2709
|
+
}
|
|
2710
|
+
};
|
|
2711
|
+
}
|
|
2712
|
+
function cloneWorkflow(wf, opts) {
|
|
2713
|
+
return new Workflow(
|
|
2714
|
+
{ ...wf.__options, name: opts.id, workflowId: `wf-${mintShortId()}` },
|
|
2715
|
+
[...wf.__steps]
|
|
2716
|
+
);
|
|
2717
|
+
}
|
|
2476
2718
|
var WorkflowToolError = class extends Error {
|
|
2477
2719
|
constructor(toolName, workflowStatus, workflowError) {
|
|
2478
2720
|
super(
|
|
@@ -2535,7 +2777,9 @@ exports.WorkflowBuilder = WorkflowBuilder;
|
|
|
2535
2777
|
exports.WorkflowToolError = WorkflowToolError;
|
|
2536
2778
|
exports.__resetSnapshotStoresForTests = __resetSnapshotStoresForTests;
|
|
2537
2779
|
exports.agentStep = agentStep;
|
|
2780
|
+
exports.cloneWorkflow = cloneWorkflow;
|
|
2538
2781
|
exports.fn = fn;
|
|
2539
2782
|
exports.workflowAsTool = workflowAsTool;
|
|
2783
|
+
exports.workflowStep = workflowStep;
|
|
2540
2784
|
//# sourceMappingURL=workflow.cjs.map
|
|
2541
2785
|
//# sourceMappingURL=workflow.cjs.map
|