@orkestrel/workflow 0.0.2 → 0.0.4

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.
@@ -1,5 +1,4 @@
1
- import { createTool } from "@orkestrel/agent";
2
- import { arrayShape, compileGuard, createContract, integerShape, isArray, isBoolean, isNumber, isRecord, isString, literalShape, objectShape, optionalShape, rawShape, schemaToParameters, stringShape } from "@orkestrel/contract";
1
+ import { arrayShape, compileGuard, createContract, integerShape, isArray, isBoolean, isNumber, isRecord, isString, literalShape, objectShape, optionalShape, rawShape, stringShape } from "@orkestrel/contract";
3
2
  import { createDatabase, createMemoryDriver } from "@orkestrel/database";
4
3
  import { createAbort } from "@orkestrel/abort";
5
4
  import { Emitter } from "@orkestrel/emitter";
@@ -178,102 +177,6 @@ var TASK_TRANSITIONS = Object.freeze({
178
177
  * phase may still DECLARE a larger explicit `concurrency` and pays that allocation knowingly.
179
178
  */
180
179
  var DEFAULT_PHASE_CONCURRENCY = 1024;
181
- /**
182
- * The maximum nesting depth a workflow → agent → workflow chain may reach — the bound
183
- * the {@link import('./factories.js').createAgentFunction} and
184
- * {@link import('./factories.js').createWorkflowTool} adapters' depth/cycle guards enforce.
185
- *
186
- * @remarks
187
- * The limit lives in ONE place. An {@link import('./factories.js').createAgentFunction}-wrapped
188
- * agent running at this depth can no longer author + run a NESTED workflow through its bound
189
- * workflow tool (that would be depth `MAX_WORKFLOW_DEPTH + 1`), so the over-deep invocation is
190
- * REJECTED (a typed `DEPTH` {@link import('./errors.js').WorkflowError} throw). The chain
191
- * therefore nests workflows down to this depth, and the nested run at
192
- * depth `MAX_WORKFLOW_DEPTH` fails.
193
- */
194
- var MAX_WORKFLOW_DEPTH = 8;
195
- /**
196
- * The name under which {@link import('./factories.js').createAgentFunction} BINDS the
197
- * depth/cycle-aware workflow tool onto a wrapped agent's `context.tools` (`AgentContextInterface`,
198
- * `@orkestrel/agent`).
199
- *
200
- * @remarks
201
- * The propagation seam's well-known key: when its `runner` option is supplied, the adapter adds a
202
- * {@link import('./factories.js').createWorkflowTool}-built tool under this name to the
203
- * agent's `context.tools`, so it can author + run a NESTED workflow (bounded by
204
- * {@link MAX_WORKFLOW_DEPTH}). An agent that wants to fan out into a workflow calls this tool by
205
- * this name; the bound handler runs the nested workflow at depth + 1.
206
- */
207
- var WORKFLOW_TOOL_NAME = "workflow";
208
- /**
209
- * A complete FLAT authoring example — the PRIMARY way a small model authors a workflow
210
- * through {@link import('./factories.js').createWorkflowTool}: `{ name, steps: [{ name }] }`.
211
- *
212
- * @remarks
213
- * Each step becomes a one-task phase, in order; a step's `name` is a REGISTERED behavior name
214
- * (not a label) — the registry key its task's `run` resolves against. The tool expands this
215
- * ({@link import('./helpers.js').expandSteps}) into a valid {@link WorkflowDefinition}. It
216
- * is embedded VERBATIM in {@link WORKFLOW_TOOL_DESCRIPTION} and guarded by a parity test
217
- * (it must expand to a tree the STRICT contract accepts), so the doc example can never drift.
218
- */
219
- var WORKFLOW_TOOL_FLAT_EXAMPLE = Object.freeze({
220
- name: "release",
221
- steps: Object.freeze([Object.freeze({ name: "compile" }), Object.freeze({ name: "publish" })])
222
- });
223
- /**
224
- * A minimal NESTED authoring example — the ADVANCED escape-hatch form a model may use
225
- * instead of the flat shape: a full {@link WorkflowDefinition}.
226
- *
227
- * @remarks
228
- * The full four-level form, documented in {@link WORKFLOW_TOOL_DESCRIPTION} as the advanced
229
- * alternative. It is embedded VERBATIM and guarded by a parity test (`createWorkflowContract().is`
230
- * must accept it), so the doc example can never drift from a valid definition.
231
- */
232
- var WORKFLOW_TOOL_NESTED_EXAMPLE = Object.freeze({
233
- id: "release",
234
- name: "Release",
235
- phases: Object.freeze([Object.freeze({
236
- id: "build",
237
- name: "Build",
238
- tasks: Object.freeze([Object.freeze({
239
- id: "compile",
240
- name: "Compile",
241
- run: "compile"
242
- })])
243
- })])
244
- });
245
- /**
246
- * The DESCRIPTION {@link import('./factories.js').createWorkflowTool} advertises — a
247
- * multi-line guide that teaches a small model how to author a complete workflow tree.
248
- *
249
- * @remarks
250
- * Presents the SIMPLE flat shape (`{ name, steps: [{ name }] }`) as the PRIMARY way with
251
- * one complete worked example ({@link WORKFLOW_TOOL_FLAT_EXAMPLE}), names that a step's
252
- * `name` is a REGISTERED name (not a human label), and documents the full nested
253
- * {@link WorkflowDefinition} as the ADVANCED form with a minimal example
254
- * ({@link WORKFLOW_TOOL_NESTED_EXAMPLE}). Both examples are interpolated VERBATIM from the
255
- * validated constants, so a parity test pins them — the description can never drift from a
256
- * real, contract-valid example. The `parameters` the tool advertises are the FLAT shape's
257
- * schema; the nested form is the documented escape-hatch (the tool accepts both). NOTE: a step's
258
- * "registered behavior name" is authored STRUCTURE only —
259
- * {@link import('./factories.js').createWorkflowTool} runs the authored tree with no
260
- * {@link WorkflowFunctions} registry of its own, so every one of its tasks auto-completes under
261
- * the no-handler rule; the tool validates/synthesizes shape, it does not dispatch behavior.
262
- */
263
- var WORKFLOW_TOOL_DESCRIPTION = [
264
- "Author and run a workflow (phases run sequentially, the tasks within a phase run concurrently) in one call.",
265
- "",
266
- "SIMPLEST way — a flat list of steps. Each step runs one registered behavior; steps run one after another:",
267
- " { \"name\": \"<workflow name>\", \"steps\": [ { \"name\": \"<registered name>\" }, ... ] }",
268
- "- a step's \"name\" is a REGISTERED behavior name (a registry key), NOT a human label.",
269
- "- the top-level \"name\" (the workflow name) is optional. Ids are filled in for you.",
270
- "Example:",
271
- JSON.stringify(WORKFLOW_TOOL_FLAT_EXAMPLE),
272
- "",
273
- "ADVANCED — the full nested form, for multi-task phases or explicit ids. A workflow has phases; a phase has tasks; a task has a \"run\" (a registered behavior name):",
274
- JSON.stringify(WORKFLOW_TOOL_NESTED_EXAMPLE),
275
- "In the nested form you may omit any \"id\"/\"name\" and they are filled in positionally; a provided one is kept."
276
- ].join("\n");
277
180
  //#endregion
278
181
  //#region src/core/errors.ts
279
182
  /**
@@ -284,11 +187,11 @@ var WORKFLOW_TOOL_DESCRIPTION = [
284
187
  * offending node id / status. Thrown for an illegal lifecycle transition
285
188
  * (`TRANSITION`), a structurally invalid {@link import('./types.js').WorkflowSnapshot}
286
189
  * passed to {@link import('./factories.js').restoreWorkflow} (`RESTORE`), an over-deep /
287
- * cyclic nested-workflow dispatch (`DEPTH`), and a malformed
288
- * {@link import('./factories.js').createWorkflowTool} args blob (`TOOL`). On the
289
- * workflow-tool seam the `DEPTH` / `TOOL` throw is ISOLATED by the
290
- * `@orkestrel/agent` package's `ToolManager` into the tool result's
291
- * top-level `error` (AGENTS §14 — the universal tool-handler contract).
190
+ * cyclic nested-workflow dispatch (`DEPTH`), and a malformed workflow-authoring-tool args
191
+ * blob (`TOOL`). `DEPTH` and `TOOL` are public type surface constructed by the
192
+ * `@orkestrel/tool` package's workflow-tool / agent-function adapters; on that seam the
193
+ * throw is ISOLATED by its `ToolManager` into the tool result's top-level `error`
194
+ * (AGENTS §14 — the universal tool-handler contract).
292
195
  */
293
196
  var WorkflowError = class extends Error {
294
197
  code;
@@ -321,37 +224,6 @@ function isWorkflowError(value) {
321
224
  //#endregion
322
225
  //#region src/core/helpers.ts
323
226
  /**
324
- * The ancestry identifier of a workflow run — `workflow:<id>`.
325
- *
326
- * @remarks
327
- * The {@link import('./WorkflowRunner.js').WorkflowRunner}'s cycle guard records one of
328
- * these per workflow in the current nested run chain (carried on
329
- * {@link import('./types.js').WorkflowRunOptions.ancestry}). Tagging the bare id keeps a
330
- * workflow id and an {@link agentTag} agent name in ONE namespaced set without collision,
331
- * so re-entering a workflow OR an agent already in the chain is a single `includes` check.
332
- *
333
- * @param id - The workflow definition's `id`
334
- * @returns The namespaced ancestry tag (`workflow:<id>`)
335
- */
336
- function workflowTag(id) {
337
- return `workflow:${id}`;
338
- }
339
- /**
340
- * The ancestry identifier of an agent in a run chain — `agent:<name>`.
341
- *
342
- * @remarks
343
- * The agent counterpart of {@link workflowTag}: the runner adds one when it dispatches an
344
- * `agent` task, and rejects the task (a typed `DEPTH` `task.fail`) when the same tag is
345
- * already in the ancestry (a re-entry cycle). The `agent:` namespace keeps it distinct
346
- * from a same-string workflow id.
347
- *
348
- * @param name - The agent's registry name (the `agent`-form's `name`)
349
- * @returns The namespaced ancestry tag (`agent:<name>`)
350
- */
351
- function agentTag(name) {
352
- return `agent:${name}`;
353
- }
354
- /**
355
227
  * Test whether a {@link LifecycleStatus} is TERMINAL — a node in this state will not
356
228
  * transition further.
357
229
  *
@@ -721,120 +593,6 @@ function collectResults(phases) {
721
593
  return phases.flat();
722
594
  }
723
595
  /**
724
- * Summarize a terminal {@link WorkflowResult} into the PLAIN value a
725
- * {@link import('./factories.js').createWorkflowTool} handler returns on success.
726
- *
727
- * @remarks
728
- * This is the run summary the handler returns DIRECTLY — NOT a `ToolResult` (the future `@orkestrel/agent` package).
729
- * The handler conforms to the universal tool-handler contract (AGENTS §14): it returns the plain value
730
- * (and throws on failure), so the `@orkestrel/agent` package's `ToolManager` performs
731
- * the ONE canonical wrap (`{ id, name, value }`) and the model reads exactly this summary — once,
732
- * identically — over BOTH the agent loop and MCP. The summary is LEAN: the workflow's terminal `status`
733
- * and the COUNT of settled task results — enough for a caller / model to react without serializing the
734
- * whole live tree. (It carries no synthetic `id` / `name`: a tool handler has no call id; the manager
735
- * supplies the canonical envelope's identity.)
736
- *
737
- * @param result - The terminal {@link WorkflowResult} the run produced
738
- * @returns The plain success summary — `{ status, count }`
739
- */
740
- function workflowToolSummary(result) {
741
- return {
742
- status: result.status,
743
- count: result.results.length
744
- };
745
- }
746
- /**
747
- * Complete a {@link WorkflowDraft} into a strict {@link WorkflowDefinition} — synthesize
748
- * any MISSING `id` deterministically + positionally, and default any MISSING `name` to
749
- * its (now-resolved) `id`.
750
- *
751
- * @remarks
752
- * The positional id scheme is stable and human-legible: the workflow is `wf`, phase `i`
753
- * is `phase-<i>`, and task `j` of that phase is `<phaseId>-task-<j>` (so a provided phase
754
- * id flows into its tasks' synthesized ids). A PROVIDED `id` / `name` at any level is kept
755
- * VERBATIM — synthesis touches only the omitted ones. A missing `name` defaults to the
756
- * resolved `id` (never the other way round), so the result always has both. `run`,
757
- * `description`, the per-phase `concurrency` / `bail`, the per-task `retries` / `timeout`, and
758
- * the workflow `bail` carry over unchanged. The result is a complete
759
- * {@link WorkflowDefinition}; the caller still validates it against the STRICT contract.
760
- *
761
- * @param draft - The draft workflow (id/name optional at all three levels)
762
- * @returns A complete {@link WorkflowDefinition} with every id/name filled
763
- */
764
- function completeDraft(draft) {
765
- const id = draft.id ?? "wf";
766
- return {
767
- id,
768
- name: draft.name ?? id,
769
- ...draft.description === void 0 ? {} : { description: draft.description },
770
- phases: draft.phases.map((phase, index) => completePhaseDraft(phase, index)),
771
- ...draft.bail === void 0 ? {} : { bail: draft.bail }
772
- };
773
- }
774
- /**
775
- * Complete one {@link PhaseDraft} into a strict {@link PhaseDefinition} — the per-phase
776
- * step of {@link completeDraft} (phase `index` → `phase-<index>` when its id is omitted).
777
- *
778
- * @param phase - The draft phase
779
- * @param index - The phase's positional index in the workflow
780
- * @returns A complete {@link PhaseDefinition}
781
- */
782
- function completePhaseDraft(phase, index) {
783
- const id = phase.id ?? `phase-${index}`;
784
- return {
785
- id,
786
- name: phase.name ?? id,
787
- ...phase.description === void 0 ? {} : { description: phase.description },
788
- tasks: phase.tasks.map((task, taskIndex) => completeTaskDraft(task, id, taskIndex)),
789
- ...phase.concurrency === void 0 ? {} : { concurrency: phase.concurrency },
790
- ...phase.bail === void 0 ? {} : { bail: phase.bail }
791
- };
792
- }
793
- /**
794
- * Complete one {@link TaskDraft} into a strict {@link TaskDefinition} — the per-task leaf
795
- * step of {@link completeDraft} (task `index` of phase `<phaseId>` → `<phaseId>-task-<index>`
796
- * when its id is omitted).
797
- *
798
- * @param task - The draft task
799
- * @param phaseId - The (resolved) parent phase id, so the synthesized task id nests under it
800
- * @param index - The task's positional index within its phase
801
- * @returns A complete {@link TaskDefinition}
802
- */
803
- function completeTaskDraft(task, phaseId, index) {
804
- const id = task.id ?? `${phaseId}-task-${index}`;
805
- return {
806
- id,
807
- name: task.name ?? id,
808
- ...task.description === void 0 ? {} : { description: task.description },
809
- ...task.run === void 0 ? {} : { run: task.run },
810
- ...task.retries === void 0 ? {} : { retries: task.retries },
811
- ...task.timeout === void 0 ? {} : { timeout: task.timeout }
812
- };
813
- }
814
- /**
815
- * Expand a flat {@link WorkflowSteps} blob into a strict {@link WorkflowDefinition} — each
816
- * step becomes a one-task phase, IN ORDER.
817
- *
818
- * @remarks
819
- * The expansion of the tool's ADVERTISED surface (AGENTS §21 — the simplest form a small
820
- * model can author). Each {@link WorkflowStep} maps to a phase holding exactly one task:
821
- * the step's `name` becomes the task's `run` (the behavior-registry key). Ids/names are
822
- * auto-filled positionally — it builds an ids-omitted {@link WorkflowDraft} and delegates
823
- * to {@link completeDraft}, so the two lenient surfaces share ONE synthesis path (step `i`
824
- * → phase `phase-<i>`, its task `phase-<i>-task-0`). The optional `name` becomes the
825
- * workflow's `name`. The result is a complete definition the caller validates against the
826
- * STRICT contract before running.
827
- *
828
- * @param flat - The flat steps blob (`{ name?, steps: [{ name }] }`)
829
- * @returns A complete {@link WorkflowDefinition} (one one-task phase per step)
830
- */
831
- function expandSteps(flat) {
832
- return completeDraft({
833
- ...flat.name === void 0 ? {} : { name: flat.name },
834
- phases: flat.steps.map((step) => ({ tasks: [{ run: step.name }] }))
835
- });
836
- }
837
- /**
838
596
  * Insert one `[key, value]` entry at a positional index into a readonly entries array —
839
597
  * the pure splice-in step behind an insertion-ordered registry's `add`.
840
598
  *
@@ -1012,118 +770,6 @@ var workflowShape = objectShape({
1012
770
  bail: optionalShape(literalShape([true, false], { description: "Failure policy: false (default) continues gracefully, true halts on the first failure." }))
1013
771
  });
1014
772
  /**
1015
- * The shape of a TASK in a draft workflow — identical to {@link taskShape} EXCEPT `id`
1016
- * and `name` are OPTIONAL (the tool synthesizes any missing one positionally).
1017
- *
1018
- * @remarks
1019
- * A PROVIDED `id` / `name` still carries `minLength: 1`, so an explicitly-empty `id: ''`
1020
- * is INVALID (rejected by the draft contract), never auto-filled — keeping "garbage"
1021
- * distinct from "omitted". `run` stays optional, mirroring {@link taskShape}.
1022
- */
1023
- var taskDraftShape = objectShape({
1024
- id: optionalShape(stringShape({
1025
- min: 1,
1026
- description: "Task id; auto-filled when omitted."
1027
- })),
1028
- name: optionalShape(stringShape({
1029
- min: 1,
1030
- description: "Task name; defaults to the id when omitted."
1031
- })),
1032
- description: optionalShape(stringShape({ description: "Optional task description." })),
1033
- run: optionalShape(stringShape({
1034
- min: 1,
1035
- description: "The registered behavior name to invoke (a registry key, not a label); omitted has no handler."
1036
- })),
1037
- retries: optionalShape(integerShape({
1038
- min: 0,
1039
- description: "Extra attempts after the first on failure; overrides the phase default. Omitted means none."
1040
- })),
1041
- timeout: optionalShape(integerShape({
1042
- min: 0,
1043
- description: "Per-attempt deadline in milliseconds; overrides the phase default. Omitted means no deadline."
1044
- }))
1045
- });
1046
- /**
1047
- * The shape of a PHASE in a draft workflow — identical to {@link phaseShape} EXCEPT
1048
- * `id` and `name` are OPTIONAL, and its tasks are {@link taskDraftShape}s.
1049
- */
1050
- var phaseDraftShape = objectShape({
1051
- id: optionalShape(stringShape({
1052
- min: 1,
1053
- description: "Phase id; auto-filled when omitted."
1054
- })),
1055
- name: optionalShape(stringShape({
1056
- min: 1,
1057
- description: "Phase name; defaults to the id when omitted."
1058
- })),
1059
- description: optionalShape(stringShape({ description: "Optional phase description." })),
1060
- tasks: arrayShape(taskDraftShape, { description: "The phase tasks; they run CONCURRENTLY." }),
1061
- concurrency: optionalShape(integerShape({
1062
- min: 1,
1063
- description: "Max tasks in flight at once (a resource throttle); omitted means unbounded."
1064
- })),
1065
- bail: optionalShape(literalShape([true, false], { description: "Per-phase failure-policy override; omitted inherits the workflow bail." }))
1066
- });
1067
- /**
1068
- * The shape of a DRAFT workflow — identical to {@link workflowShape} EXCEPT `id` and
1069
- * `name` are OPTIONAL at all three levels (workflow / phase / task), so a small model
1070
- * can omit the six identity strings and let the tool synthesize them positionally.
1071
- *
1072
- * @remarks
1073
- * The lenient counterpart {@link import('./factories.js').createWorkflowDraftContract}
1074
- * compiles. `run` stays required; a provided `id` / `name` still has `minLength: 1` (so an
1075
- * explicitly-empty `id: ''` is REJECTED, not auto-filled). After
1076
- * {@link import('./helpers.js').completeDraft} fills the missing ids/names, the result is
1077
- * validated against the STRICT {@link import('./factories.js').createWorkflowContract} gate
1078
- * before running.
1079
- */
1080
- var workflowDraftShape = objectShape({
1081
- id: optionalShape(stringShape({
1082
- min: 1,
1083
- description: "Workflow id; auto-filled when omitted."
1084
- })),
1085
- name: optionalShape(stringShape({
1086
- min: 1,
1087
- description: "Workflow name; defaults to the id when omitted."
1088
- })),
1089
- description: optionalShape(stringShape({ description: "Optional workflow description." })),
1090
- phases: arrayShape(phaseDraftShape, { description: "The workflow phases; they run SEQUENTIALLY, in order." }),
1091
- bail: optionalShape(literalShape([true, false], { description: "Failure policy: false (default) continues gracefully, true halts on the first failure." }))
1092
- });
1093
- /**
1094
- * The shape of ONE flat step — `{ name }` — the building block of
1095
- * {@link workflowStepsShape}.
1096
- *
1097
- * @remarks
1098
- * `name` is the REGISTERED behavior name the step runs (it becomes the task's `run`). The
1099
- * tool expands each step into a one-task phase, in order
1100
- * ({@link import('./helpers.js').expandSteps}).
1101
- */
1102
- var stepShape = objectShape({ name: stringShape({
1103
- min: 1,
1104
- description: "The registered behavior name this step runs (becomes the task run)."
1105
- }) });
1106
- /**
1107
- * The FLAT authoring shape `createWorkflowTool` advertises as its `parameters` — the
1108
- * simplest surface a small model can fill: `{ name?, steps: [{ name }] }`.
1109
- *
1110
- * @remarks
1111
- * The deliberately-reduced surface (AGENTS §21): a flat ordered list of steps, each a
1112
- * `{ name }`. The tool EXPANDS it ({@link import('./helpers.js').expandSteps}) into a
1113
- * full {@link import('./types.js').WorkflowDefinition} — one one-task phase per step, in
1114
- * order — then validates against the STRICT
1115
- * {@link import('./factories.js').createWorkflowContract} gate. The full nested form is
1116
- * STILL accepted by the tool (it branches on the args' shape) and is documented as the
1117
- * advanced escape-hatch in the tool's description — but THIS is what `parameters` advertises.
1118
- */
1119
- var workflowStepsShape = objectShape({
1120
- name: optionalShape(stringShape({
1121
- min: 1,
1122
- description: "Optional workflow name."
1123
- })),
1124
- steps: arrayShape(stepShape, { description: "The ordered steps to run, one after another (each becomes a one-task phase)." })
1125
- });
1126
- /**
1127
773
  * The shape of a {@link import('./types.js').TaskUpdate} — a partial edit to a
1128
774
  * `pending` task's `name` / `description`, both optional.
1129
775
  *
@@ -2197,6 +1843,91 @@ var Workflow = class {
2197
1843
  }
2198
1844
  };
2199
1845
  //#endregion
1846
+ //#region src/core/WorkflowManager.ts
1847
+ /**
1848
+ * The store-backed registry of {@link WorkflowInterface}s keyed by `id`, in insertion order —
1849
+ * the additive manager tier mirroring the `@orkestrel/agent` line's `ConversationManager` /
1850
+ * `WorkspaceManager`. Event-free (a registry, like its twins); the observability lives on each
1851
+ * {@link WorkflowInterface}.
1852
+ *
1853
+ * @remarks
1854
+ * - **Registry.** Workflows live in an insertion-ordered `Map` keyed by `id`. `add(definition)`
1855
+ * mints a live {@link WorkflowInterface} through {@link createWorkflow} (flowing the manager's
1856
+ * `functions` registry in) and stores it under `definition.id` — an already-present id
1857
+ * OVERWRITES (last write wins). `count` is the map size, `workflow(id)` looks one up,
1858
+ * `workflows()` lists them in insertion order.
1859
+ * - **Durable open / save.** `open(id)` returns an already-registered workflow directly; on a
1860
+ * registry MISS with a `store` set it rehydrates through {@link restoreWorkflow} (flowing the
1861
+ * manager's `functions` registry in so the rehydrated tree is RUNNABLE), registers it, and
1862
+ * returns it — lenient (`undefined`) with no store or a store miss. `save(id)` persists a
1863
+ * registered workflow's `snapshot()` to the `store` — lenient (`false`) with no store or an
1864
+ * unknown id.
1865
+ * - **Removal.** `remove` drops one by id, or a batch (§9.2, array overload FIRST) — `true` when
1866
+ * any was removed. `clear` empties the registry.
1867
+ * - **No active pointer.** Unlike its `ConversationManager` / `WorkspaceManager` twins, there is
1868
+ * no `active` / `switch` — nothing in the workflow domain renders "the current workflow".
1869
+ *
1870
+ * @example
1871
+ * ```ts
1872
+ * const manager = new WorkflowManager({
1873
+ * functions: { compile: async (controller) => `built ${controller.task.id}` },
1874
+ * })
1875
+ * const workflow = manager.add(definition) // minted, registered, RUNNABLE
1876
+ * manager.workflow(workflow.id) // the same workflow
1877
+ * manager.count // 1
1878
+ * ```
1879
+ */
1880
+ var WorkflowManager = class {
1881
+ #workflows = /* @__PURE__ */ new Map();
1882
+ #functions;
1883
+ #store;
1884
+ constructor(options) {
1885
+ this.#functions = options?.functions;
1886
+ this.#store = options?.store;
1887
+ }
1888
+ get count() {
1889
+ return this.#workflows.size;
1890
+ }
1891
+ workflow(id) {
1892
+ return this.#workflows.get(id);
1893
+ }
1894
+ workflows() {
1895
+ return [...this.#workflows.values()];
1896
+ }
1897
+ add(definition) {
1898
+ const workflow = createWorkflow(definition, { functions: this.#functions });
1899
+ this.#workflows.set(workflow.id, workflow);
1900
+ return workflow;
1901
+ }
1902
+ async open(id) {
1903
+ const existing = this.#workflows.get(id);
1904
+ if (existing !== void 0) return existing;
1905
+ if (this.#store === void 0) return void 0;
1906
+ const snapshot = await this.#store.get(id);
1907
+ if (snapshot === void 0) return void 0;
1908
+ const workflow = restoreWorkflow(snapshot, { functions: this.#functions });
1909
+ this.#workflows.set(workflow.id, workflow);
1910
+ return workflow;
1911
+ }
1912
+ async save(id) {
1913
+ const workflow = this.#workflows.get(id);
1914
+ if (this.#store === void 0 || workflow === void 0) return false;
1915
+ await this.#store.set(workflow.snapshot());
1916
+ return true;
1917
+ }
1918
+ remove(ids) {
1919
+ if (isArray(ids)) {
1920
+ let removed = false;
1921
+ for (const id of ids) if (this.#workflows.delete(id)) removed = true;
1922
+ return removed;
1923
+ }
1924
+ return this.#workflows.delete(ids);
1925
+ }
1926
+ clear() {
1927
+ this.#workflows.clear();
1928
+ }
1929
+ };
1930
+ //#endregion
2200
1931
  //#region src/core/Controller.ts
2201
1932
  /**
2202
1933
  * The per-unit handle a runner handler receives — wraps the unit's identity,
@@ -2580,10 +2311,10 @@ var TaskController = class {
2580
2311
  * {@link import('./types.js').TaskInterface.handler} ONCE at construction (build, restore,
2581
2312
  * or a live mint all resolve it identically, from {@link WorkflowOptions.functions}), so
2582
2313
  * dispatch is simply "invoke the task's own handler". Static tool / agent calling is an
2583
- * OPT-IN concern of `factories.ts`'s adapter factories ({@link import('./factories.js').createToolFunction},
2584
- * {@link import('./factories.js').createAgentFunction}) — plain {@link import('./types.js').WorkflowFunction}s a
2585
- * caller wires into {@link WorkflowOptions.functions} like any other behavior. This module
2586
- * never imports `@orkestrel/agent`.
2314
+ * OPT-IN concern of the `@orkestrel/tool` package's adapter factories plain
2315
+ * {@link import('./types.js').WorkflowFunction}s a caller wires into
2316
+ * {@link WorkflowOptions.functions} like any other behavior. This module never imports
2317
+ * any tool/agent package.
2587
2318
  * - **Two `execute` forms, one engine.** `execute(definition, options)` BUILDS the live tree
2588
2319
  * from a {@link WorkflowDefinition} (single source of truth for the `run` / `concurrency`
2589
2320
  * metadata); `execute(workflow, options)` DRIVES a caller-owned, ALREADY-BUILT
@@ -2896,41 +2627,6 @@ function createWorkflowContract() {
2896
2627
  };
2897
2628
  }
2898
2629
  /**
2899
- * Compile the LENIENT workflow DRAFT contract — identical to
2900
- * {@link createWorkflowContract} EXCEPT `id` and `name` are OPTIONAL at all three levels
2901
- * (workflow / phase / task), so a small model can omit the six identity strings.
2902
- *
2903
- * @remarks
2904
- * The widened authoring surface {@link createWorkflowTool} parses an authored blob through
2905
- * before {@link import('./helpers.js').completeDraft} fills the missing ids/names. It does
2906
- * NOT relax the canonical contract — {@link createWorkflowContract} stays byte-for-byte
2907
- * unchanged and STRICT, and the completed draft is re-validated against THAT strict gate
2908
- * before running (soundness preserved). A PROVIDED `id` / `name` still carries `minLength: 1`,
2909
- * so an explicitly-empty `id: ''` is REJECTED (parses to `undefined`), never auto-filled —
2910
- * keeping "garbage" distinct from "omitted". `run` stays required.
2911
- *
2912
- * @returns The compiled {@link WorkflowDraft} contract
2913
- *
2914
- * @example
2915
- * ```ts
2916
- * import { createWorkflowDraftContract, completeDraft } from '@src/core'
2917
- *
2918
- * const draft = createWorkflowDraftContract()
2919
- * const parsed = draft.parse({ phases: [{ tasks: [{ run: { via: 'function', name: 'f' } }] }] })
2920
- * const definition = parsed && completeDraft(parsed) // ids/names filled positionally
2921
- * draft.parse({ id: '', phases: [] }) // undefined — an explicit empty id is rejected
2922
- * ```
2923
- */
2924
- function createWorkflowDraftContract() {
2925
- const contract = createContract(workflowDraftShape);
2926
- return {
2927
- schema: contract.schema,
2928
- is: contract.is,
2929
- generate: (random) => contract.generate(random),
2930
- parse: (value) => contract.parse(value)
2931
- };
2932
- }
2933
- /**
2934
2630
  * Build the live W-b entity tree from a {@link WorkflowDefinition} — the whole
2935
2631
  * {@link WorkflowInterface} → {@link import('./types.js').PhaseInterface} →
2936
2632
  * {@link import('./types.js').TaskInterface} tree, each level wired with its lineage
@@ -3164,11 +2860,11 @@ function createDatabaseWorkflowStore(driver = createMemoryDriver()) {
3164
2860
  * the live entity (`start` → `complete` / `fail`), and resolves a
3165
2861
  * {@link import('./types.js').WorkflowResult}.
3166
2862
  *
3167
- * Static tool / agent calling is OPT-IN, wired through the adapter factories
3168
- * {@link createToolFunction} / {@link createAgentFunction} — plain
3169
- * {@link import('./types.js').WorkflowFunction}s a caller composes into its OWN
3170
- * {@link WorkflowOptions.functions} registry, same as any other behavior. A task with no
3171
- * resolved handler AUTO-COMPLETES (the ROADMAP no-handler rule).
2863
+ * Static tool / agent calling is OPT-IN: a caller wires a plain
2864
+ * {@link import('./types.js').WorkflowFunction} into its OWN {@link WorkflowOptions.functions}
2865
+ * registry, same as any other behavior the `@orkestrel/tool` package ships the
2866
+ * tool/agent adapter factories for that. A task with no resolved handler AUTO-COMPLETES
2867
+ * (the ROADMAP no-handler rule).
3172
2868
  *
3173
2869
  * @param options - An optional pacing `scheduler` (default the shipped cross-environment one).
3174
2870
  * See {@link WorkflowRunnerOptions}.
@@ -3193,229 +2889,38 @@ function createWorkflowRunner(options) {
3193
2889
  return new WorkflowRunner(options?.scheduler ?? createScheduler());
3194
2890
  }
3195
2891
  /**
3196
- * Wrap a registered tool as a {@link WorkflowFunction} — the OPT-IN adapter that lets a
3197
- * `function`-form task run a `@orkestrel/agent` tool BY NAME.
3198
- *
3199
- * @remarks
3200
- * Composes into a caller's {@link WorkflowOptions.functions} registry like any other behavior
3201
- * (`{ publish: createToolFunction(tools, 'publish') }`); the PURE
3202
- * {@link import('./WorkflowRunner.js').WorkflowRunner} has no knowledge of tools itself. The
3203
- * returned function executes `name` against `tools` with the task's `controller.input` as the
3204
- * call arguments, id-correlated to the task's own id. A `ToolManagerInterface.execute` NEVER
3205
- * throws (a handler throw is isolated into `result.error`), so a failing tool is surfaced here
3206
- * as a THROWN `Error` carrying the original message as `cause` — the leaf `fail`s, honouring
3207
- * `bail`. An UNREGISTERED tool name is a programmer error (an explicit binding to a name that
3208
- * doesn't exist) — unlike the engine's own silent auto-complete of an unresolved task handler,
3209
- * this THROWS a typed `TOOL` {@link WorkflowError}.
3210
- *
3211
- * @param tools - The {@link ToolManagerInterface} the named tool is registered on
3212
- * @param name - The registered tool's name
3213
- * @returns A {@link WorkflowFunction} that runs the named tool
3214
- *
3215
- * @example
3216
- * ```ts
3217
- * import { createToolFunction, createToolManager, createWorkflowRunner } from '@src/core'
3218
- *
3219
- * const tools = createToolManager()
3220
- * tools.add(myPublishTool)
3221
- * const runner = createWorkflowRunner()
3222
- * await runner.execute(definition, { functions: { publish: createToolFunction(tools, 'publish') } })
3223
- * ```
3224
- */
3225
- function createToolFunction(tools, name) {
3226
- return async (controller) => {
3227
- if (tools.tool(name) === void 0) throw new WorkflowError("TOOL", `tool '${name}' is not registered`, { tool: name });
3228
- const result = await tools.execute({
3229
- id: controller.task.id,
3230
- name,
3231
- arguments: controller.input
3232
- });
3233
- if (result.error !== void 0) throw new Error(result.error, { cause: result.error });
3234
- return result.value;
3235
- };
3236
- }
3237
- /**
3238
- * Wrap a live `AgentInterface` (`@orkestrel/agent`) as a {@link WorkflowFunction} — the OPT-IN
3239
- * adapter that runs the agent to a settled result, folding a nested workflow-authoring
3240
- * depth / cycle guard into its own closure.
3241
- *
3242
- * @remarks
3243
- * Composes into a caller's {@link WorkflowOptions.functions} registry like any other behavior;
3244
- * the PURE {@link import('./WorkflowRunner.js').WorkflowRunner} has no knowledge of agents
3245
- * itself. Before running the agent, the depth/cycle guard REJECTS the call (a THROWN typed
3246
- * `DEPTH` {@link WorkflowError}, which the leaf `fail`s) when running it would push a nested
3247
- * chain past {@link MAX_WORKFLOW_DEPTH}, OR when this agent is already an ancestor (a cycle) —
3248
- * ported from the former engine-side guard. When {@link AgentFunctionOptions.runner} is
3249
- * supplied, the adapter BINDS a depth/cycle-aware {@link createWorkflowTool} onto the agent's
3250
- * `context.tools` (the propagation seam) — closed over `depth` and the extended ancestry (the
3251
- * tool itself computes `depth + 1` internally) — so the agent can author + run a NESTED
3252
- * workflow through it; the wrapped default is the CURRENT task's own workflow id (used only on
3253
- * a no-args tool call). The task's cancellation folds into the agent run: an already-aborted
3254
- * `controller.signal` cancels the agent up front; otherwise a one-shot listener fires
3255
- * `agent.abort(reason)` when the task cancels, removed in `finally`. `agent.generate()` resolves
3256
- * a partial `AgentResult` on a cancel (never rejects), returned as the task's completed value.
3257
- *
3258
- * A bound agent is effectively SINGLE-RUN: `context.tools.add` binds one {@link ToolInterface}
3259
- * under the fixed {@link import('./constants.js').WORKFLOW_TOOL_NAME}, and `agent.generate()` /
3260
- * `agent.abort()` are per-agent state. Two CONCURRENT tasks sharing the SAME `agent` instance
3261
- * race on that one tool binding (last-write-wins) and on generate/abort — give each concurrent
3262
- * task its OWN agent instance.
3263
- *
3264
- * @param agent - The live `AgentInterface` to run
3265
- * @param options - The nested-workflow binding + depth/cycle bookkeeping (see {@link AgentFunctionOptions})
3266
- * @returns A {@link WorkflowFunction} that runs `agent` to its settled result
3267
- *
3268
- * @example
3269
- * ```ts
3270
- * import { createAgentFunction, createWorkflowRunner } from '@src/core'
3271
- *
3272
- * const runner = createWorkflowRunner()
3273
- * const review = createAgentFunction(myAgent, { runner })
3274
- * await runner.execute(definition, { functions: { review } })
3275
- * ```
3276
- */
3277
- function createAgentFunction(agent, options) {
3278
- return async (controller) => {
3279
- const depth = options?.depth ?? 0;
3280
- const ancestry = options?.ancestry ?? [];
3281
- if (depth + 1 > 8) throw new WorkflowError("DEPTH", `agent '${agent.id}' exceeds max workflow depth`, {
3282
- agent: agent.id,
3283
- depth,
3284
- max: 8
3285
- });
3286
- const tag = agentTag(agent.id);
3287
- if (ancestry.includes(tag)) throw new WorkflowError("DEPTH", `agent '${agent.id}' is already an ancestor (cycle)`, {
3288
- agent: agent.id,
3289
- ancestry: [...ancestry]
3290
- });
3291
- const runner = options?.runner;
3292
- if (runner !== void 0) {
3293
- const workflowId = controller.task.phase.workflow.id;
3294
- const wrapped = {
3295
- id: workflowId,
3296
- name: workflowId,
3297
- phases: []
3298
- };
3299
- agent.context.tools.add(createWorkflowTool(wrapped, runner, {
3300
- depth,
3301
- ancestry: [...ancestry, tag]
3302
- }));
3303
- }
3304
- const signal = controller.signal;
3305
- const onAbort = () => agent.abort(signal.reason);
3306
- if (signal.aborted) agent.abort(signal.reason);
3307
- else signal.addEventListener("abort", onAbort, { once: true });
3308
- try {
3309
- return await agent.generate();
3310
- } finally {
3311
- signal.removeEventListener("abort", onAbort);
3312
- }
3313
- };
3314
- }
3315
- /**
3316
- * Wrap a {@link WorkflowDefinition} as an LLM-callable {@link ToolInterface} — it ADVERTISES
3317
- * the SIMPLE flat authoring shape (`{ name?, steps: [{ name }] }`) as its `parameters` so
3318
- * even a small model can author a complete tree, and its handler EXPANDS / COMPLETES the
3319
- * authored blob, validates it against the STRICT contract, runs it through `runner`, and
3320
- * returns the run SUMMARY (throwing a typed {@link WorkflowError} on failure).
2892
+ * Create a {@link WorkflowManagerInterface} — the store-backed registry of
2893
+ * {@link WorkflowInterface}s, the additive manager tier mirroring the `@orkestrel/agent`
2894
+ * line's `createConversationManager` / `createWorkspaceManager`.
3321
2895
  *
3322
2896
  * @remarks
3323
- * A plain {@link ToolManagerInterface}-compatible tool (so `createMCPServer` / `createMCPRoutes`
3324
- * expose it for free — nothing MCP is wired here). It is ALSO the propagation carrier
3325
- * {@link createAgentFunction} binds onto a wrapped agent's `context.tools`: because a tool
3326
- * handler receives ONLY the model-supplied `args` (no ambient context, no signal), the run's
3327
- * depth + ancestry are CLOSED OVER at bind time via {@link WorkflowToolOptions}, and the
3328
- * handler enforces the SAME depth / cycle guard itself (this function owns it now — the engine
3329
- * carries none) before running the nested workflow at `depth + 1` with the extended ancestry.
3330
- *
3331
- * **Widened authoring surface (additive — the canonical contract + runner stay STRICT and
3332
- * unchanged).** A 2B model reliably CALLS the tool but cannot reliably emit the full four-level
3333
- * nested {@link WorkflowDefinition} (six required `id`/`name` strings, an all-or-nothing tree).
3334
- * So the tool ACCEPTS three authoring forms and converges them on the SAME strict
3335
- * {@link createWorkflowContract} gate before running (soundness preserved):
3336
- * - the FLAT shape `{ name?, steps: [{ name }] }` — the ADVERTISED `parameters` (the simplest
3337
- * form, {@link import('./helpers.js').expandSteps}'d into one one-task phase per step);
3338
- * - a nested DRAFT with any `id`/`name` OMITTED — {@link createWorkflowDraftContract}-parsed then
3339
- * {@link import('./helpers.js').completeDraft}'d (missing ids synthesized positionally);
3340
- * - the full nested {@link WorkflowDefinition} — the advanced escape-hatch (documented in the
3341
- * description), accepted as the draft super-set.
3342
- *
3343
- * The handler conforms to the universal tool-handler contract (AGENTS §14): it returns the PLAIN
3344
- * run-summary VALUE on success and THROWS a typed {@link WorkflowError} on every failure path. It
3345
- * does NOT build a {@link ToolResult} itself — the `@orkestrel/agent` package's `ToolManager`
3346
- * performs the ONE canonical wrap (`{ id, name, value }` on a return; `{ id, name, error }` on a
3347
- * throw, ISOLATED so nothing escapes the run), so the outcome appears EXACTLY ONCE, identically,
3348
- * over BOTH the agent loop and MCP (a throw → MCP `isError: true`):
3349
- * - **No authored args** (an empty `arguments`) ⇒ runs the WRAPPED `definition`.
3350
- * - **A `steps` array** ⇒ the FLAT form: parse it, {@link import('./helpers.js').expandSteps} it.
3351
- * - **Otherwise** ⇒ the nested form: {@link createWorkflowDraftContract}-parse it,
3352
- * {@link import('./helpers.js').completeDraft} it.
3353
- * - **Strict gate** ⇒ the expanded / completed result is validated against
3354
- * {@link createWorkflowContract}.`is`; a blob that can't expand, or whose result fails the strict
3355
- * gate (e.g. an explicit empty `id`, `concurrency: 0`) ⇒ THROW a `TOOL` {@link WorkflowError} (no run).
3356
- * - **Over-deep / cyclic** ⇒ THROW a `DEPTH` {@link WorkflowError} when the nested run would exceed
3357
- * {@link MAX_WORKFLOW_DEPTH}, or the target workflow id is already an ancestor (a cycle) — the
3358
- * SAME `code` {@link createAgentFunction}'s own guard raises. Enforced HERE, INSIDE this
3359
- * handler, before ever calling `runner.execute` — the engine itself performs no such check.
3360
- * - **Otherwise** ⇒ `runner.execute(target)`, RETURNING the plain summary of the terminal run
3361
- * (`{ status, count }`, via {@link workflowToolSummary}).
3362
- *
3363
- * The tool executes AUTHORED STRUCTURE, not consumer behavior: a nested tree authored through
3364
- * it (flat, draft, or full form) carries no {@link WorkflowFunctions} registry, so EVERY one of
3365
- * its tasks auto-completes under the no-handler rule. This handler validates and synthesizes
3366
- * shape — it never runs a caller's handlers.
3367
- *
3368
- * @param definition - The workflow the tool runs when called with no authored args
3369
- * @param runner - The {@link WorkflowRunnerInterface} that executes the (nested) workflow
3370
- * @param options - The depth + ancestry to run the nested workflow under (see
3371
- * {@link WorkflowToolOptions}); omitted ⇒ depth `0` / empty ancestry (a top-level wrap)
3372
- * @returns A {@link ToolInterface} (named {@link import('./constants.js').WORKFLOW_TOOL_NAME})
3373
- * whose `parameters` advertise the FLAT authoring schema (the nested form stays accepted)
2897
+ * `options.functions` flows into every workflow the manager mints (`add`, via
2898
+ * {@link createWorkflow}) or hydrates (`open`'s registry-miss path, via
2899
+ * {@link restoreWorkflow}), so a hydrated workflow is RUNNABLE rather than a dead snapshot
2900
+ * mirror. `options.store` is the EXACT analogue of the twins' `store` seam omitted the
2901
+ * manager is registry-only (`open` resolves only what is registered, `save` is a no-op). This
2902
+ * is PURELY ADDITIVE: direct {@link WorkflowStoreInterface} use and
2903
+ * {@link restoreWorkflow} remain valid the manager is one more caller-driven persistence
2904
+ * seam, not a replacement.
2905
+ *
2906
+ * @param options - The optional `store` seam and the `functions` registry threaded into every mint/hydrate
2907
+ * @returns A working {@link WorkflowManagerInterface}
3374
2908
  *
3375
2909
  * @example
3376
2910
  * ```ts
3377
- * import { createWorkflowRunner, createWorkflowTool, createToolManager } from '@src/core'
2911
+ * import { createMemoryWorkflowStore, createWorkflowManager } from '@src/core'
3378
2912
  *
3379
- * const runner = createWorkflowRunner()
3380
- * const tool = createWorkflowTool(definition, runner)
3381
- * const tools = createToolManager()
3382
- * tools.add(tool) // a model can now author + run a workflow in one call
2913
+ * const manager = createWorkflowManager({
2914
+ * store: createMemoryWorkflowStore(),
2915
+ * functions: { compile: async (controller) => `built ${controller.task.id}` },
2916
+ * })
2917
+ * const workflow = manager.add(definition) // minted, registered, RUNNABLE
2918
+ * await manager.save(workflow.id) // persisted to the store
2919
+ * const reopened = await manager.open(workflow.id) // already registered — no store hit
3383
2920
  * ```
3384
2921
  */
3385
- function createWorkflowTool(definition, runner, options) {
3386
- const strict = createWorkflowContract();
3387
- const draft = createWorkflowDraftContract();
3388
- const steps = createContract(workflowStepsShape);
3389
- const depth = options?.depth ?? 0;
3390
- const ancestry = options?.ancestry ?? [];
3391
- return createTool({
3392
- name: WORKFLOW_TOOL_NAME,
3393
- description: WORKFLOW_TOOL_DESCRIPTION,
3394
- parameters: schemaToParameters(steps.schema),
3395
- execute: async (args) => {
3396
- let target;
3397
- if (Object.keys(args).length === 0) target = definition;
3398
- else if (Array.isArray(args.steps)) {
3399
- const flat = steps.parse(args);
3400
- target = flat === void 0 ? void 0 : expandSteps(flat);
3401
- } else {
3402
- const parsed = draft.parse(args);
3403
- target = parsed === void 0 ? void 0 : completeDraft(parsed);
3404
- }
3405
- if (target === void 0 || !strict.is(target)) throw new WorkflowError("TOOL", "malformed workflow definition", { workflow: definition.id });
3406
- if (depth + 1 > 8) throw new WorkflowError("DEPTH", `nested workflow exceeds max depth 8`, {
3407
- workflow: target.id,
3408
- depth,
3409
- max: 8
3410
- });
3411
- const tag = workflowTag(target.id);
3412
- if (ancestry.includes(tag)) throw new WorkflowError("DEPTH", `workflow '${target.id}' is already an ancestor (cycle)`, {
3413
- workflow: target.id,
3414
- ancestry: [...ancestry]
3415
- });
3416
- return workflowToolSummary(await runner.execute(target));
3417
- }
3418
- });
2922
+ function createWorkflowManager(options) {
2923
+ return new WorkflowManager(options);
3419
2924
  }
3420
2925
  /**
3421
2926
  * Create the safe cross-environment cooperative-yield default — a
@@ -3509,6 +3014,6 @@ function createRunner(options) {
3509
3014
  return new Runner(options);
3510
3015
  }
3511
3016
  //#endregion
3512
- export { Controller, DEFAULT_BAIL, DEFAULT_PHASE_CONCURRENCY, DatabaseWorkflowStore, MAX_WORKFLOW_DEPTH, MemoryWorkflowStore, PHASE_STATUSES, Phase, PhaseManager, Runner, Scheduler, TASK_STATUSES, TASK_TRANSITIONS, TERMINAL_TASK_STATUSES, Task, TaskController, TaskManager, WORKFLOW_STATUSES, WORKFLOW_TOOL_DESCRIPTION, WORKFLOW_TOOL_FLAT_EXAMPLE, WORKFLOW_TOOL_NAME, WORKFLOW_TOOL_NESTED_EXAMPLE, Workflow, WorkflowError, WorkflowRunner, agentTag, assertSnapshot, buildPhaseContext, buildTaskContext, buildWorkflowContext, canTransitionTask, collectResults, completeDraft, completePhaseDraft, completeTaskDraft, createAgentFunction, createDatabaseWorkflowStore, createDeferred, createMemoryWorkflowStore, createRunner, createScheduler, createToolFunction, createWorkflow, createWorkflowContract, createWorkflowDraftContract, createWorkflowRunner, createWorkflowTool, definitionToSnapshot, deriveBoundary, derivePhaseStatus, deriveWorkflowStatus, expandSteps, failure, findFailure, insertEntry, isTerminalStatus, isWorkflowError, isWorkflowSnapshot, moveEntry, parkSignal, phaseDefinitionToSnapshot, phaseDraftShape, phaseShape, phaseUpdateShape, restoreWorkflow, stepShape, success, taskDefinitionToSnapshot, taskDraftShape, taskShape, taskUpdateShape, workflowDraftShape, workflowShape, workflowStepsShape, workflowTag, workflowToolSummary };
3017
+ export { Controller, DEFAULT_BAIL, DEFAULT_PHASE_CONCURRENCY, DatabaseWorkflowStore, MemoryWorkflowStore, PHASE_STATUSES, Phase, PhaseManager, Runner, Scheduler, TASK_STATUSES, TASK_TRANSITIONS, TERMINAL_TASK_STATUSES, Task, TaskController, TaskManager, WORKFLOW_STATUSES, Workflow, WorkflowError, WorkflowManager, WorkflowRunner, assertSnapshot, buildPhaseContext, buildTaskContext, buildWorkflowContext, canTransitionTask, collectResults, createDatabaseWorkflowStore, createDeferred, createMemoryWorkflowStore, createRunner, createScheduler, createWorkflow, createWorkflowContract, createWorkflowManager, createWorkflowRunner, definitionToSnapshot, deriveBoundary, derivePhaseStatus, deriveWorkflowStatus, failure, findFailure, insertEntry, isTerminalStatus, isWorkflowError, isWorkflowSnapshot, moveEntry, parkSignal, phaseDefinitionToSnapshot, phaseShape, phaseUpdateShape, restoreWorkflow, success, taskDefinitionToSnapshot, taskShape, taskUpdateShape, workflowShape };
3513
3018
 
3514
3019
  //# sourceMappingURL=index.js.map