@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
1
  import { AbortInterface } from '@orkestrel/abort';
2
- import { AgentInterface } from '@orkestrel/agent';
3
2
  import { ArrayShape } from '@orkestrel/contract';
4
3
  import { BudgetInterface } from '@orkestrel/budget';
5
4
  import { ContractInterface } from '@orkestrel/contract';
@@ -17,46 +16,6 @@ import { StringShape } from '@orkestrel/contract';
17
16
  import { Success } from '@orkestrel/contract';
18
17
  import { TableInterface } from '@orkestrel/database';
19
18
  import { TokenUsage } from '@orkestrel/budget';
20
- import { ToolInterface } from '@orkestrel/agent';
21
- import { ToolManagerInterface } from '@orkestrel/agent';
22
-
23
- /**
24
- * Options for {@link import('./factories.js').createAgentFunction} — the OPT-IN adapter that
25
- * wraps a live `AgentInterface` (`@orkestrel/agent`) as a {@link WorkflowFunction}, folding a
26
- * nested workflow-authoring depth / cycle guard into its closure.
27
- *
28
- * @remarks
29
- * All fields are optional: omitted entirely, the adapter runs the agent with no nested
30
- * workflow tool bound and no depth/cycle bound (depth `0`, empty ancestry).
31
- * - `runner` — when supplied, the adapter BINDS a depth/cycle-aware
32
- * {@link import('./factories.js').createWorkflowTool} onto the agent's `context.tools` (the
33
- * propagation seam), so the agent can author + run a NESTED workflow through it. Omitted ⇒
34
- * the agent runs with no workflow tool bound.
35
- * - `depth` — this invocation's nesting depth (default `0`); the bound workflow tool runs its
36
- * nested workflow at `depth + 1`, bounded by {@link import('./constants.js').MAX_WORKFLOW_DEPTH}.
37
- * - `ancestry` — the workflow / agent identifiers already in this run chain (default empty); a
38
- * cycle (this agent already present) is rejected with a typed `DEPTH`
39
- * {@link import('./errors.js').WorkflowError}.
40
- */
41
- export declare interface AgentFunctionOptions {
42
- readonly runner?: WorkflowRunnerInterface;
43
- readonly depth?: number;
44
- readonly ancestry?: readonly string[];
45
- }
46
-
47
- /**
48
- * The ancestry identifier of an agent in a run chain — `agent:<name>`.
49
- *
50
- * @remarks
51
- * The agent counterpart of {@link workflowTag}: the runner adds one when it dispatches an
52
- * `agent` task, and rejects the task (a typed `DEPTH` `task.fail`) when the same tag is
53
- * already in the ancestry (a re-entry cycle). The `agent:` namespace keeps it distinct
54
- * from a same-string workflow id.
55
- *
56
- * @param name - The agent's registry name (the `agent`-form's `name`)
57
- * @returns The namespaced ancestry tag (`agent:<name>`)
58
- */
59
- export declare function agentTag(name: string): string;
60
19
 
61
20
  /**
62
21
  * Assert that a {@link WorkflowSnapshot} carries a `boolean` `bail` — at the workflow tier AND
@@ -145,48 +104,6 @@ export declare function canTransitionTask(from: TaskStatus, to: TaskStatus): boo
145
104
  */
146
105
  export declare function collectResults(phases: readonly (readonly TaskResult[])[]): readonly TaskResult[];
147
106
 
148
- /**
149
- * Complete a {@link WorkflowDraft} into a strict {@link WorkflowDefinition} — synthesize
150
- * any MISSING `id` deterministically + positionally, and default any MISSING `name` to
151
- * its (now-resolved) `id`.
152
- *
153
- * @remarks
154
- * The positional id scheme is stable and human-legible: the workflow is `wf`, phase `i`
155
- * is `phase-<i>`, and task `j` of that phase is `<phaseId>-task-<j>` (so a provided phase
156
- * id flows into its tasks' synthesized ids). A PROVIDED `id` / `name` at any level is kept
157
- * VERBATIM — synthesis touches only the omitted ones. A missing `name` defaults to the
158
- * resolved `id` (never the other way round), so the result always has both. `run`,
159
- * `description`, the per-phase `concurrency` / `bail`, the per-task `retries` / `timeout`, and
160
- * the workflow `bail` carry over unchanged. The result is a complete
161
- * {@link WorkflowDefinition}; the caller still validates it against the STRICT contract.
162
- *
163
- * @param draft - The draft workflow (id/name optional at all three levels)
164
- * @returns A complete {@link WorkflowDefinition} with every id/name filled
165
- */
166
- export declare function completeDraft(draft: WorkflowDraft): WorkflowDefinition;
167
-
168
- /**
169
- * Complete one {@link PhaseDraft} into a strict {@link PhaseDefinition} — the per-phase
170
- * step of {@link completeDraft} (phase `index` → `phase-<index>` when its id is omitted).
171
- *
172
- * @param phase - The draft phase
173
- * @param index - The phase's positional index in the workflow
174
- * @returns A complete {@link PhaseDefinition}
175
- */
176
- export declare function completePhaseDraft(phase: PhaseDraft, index: number): PhaseDefinition;
177
-
178
- /**
179
- * Complete one {@link TaskDraft} into a strict {@link TaskDefinition} — the per-task leaf
180
- * step of {@link completeDraft} (task `index` of phase `<phaseId>` → `<phaseId>-task-<index>`
181
- * when its id is omitted).
182
- *
183
- * @param task - The draft task
184
- * @param phaseId - The (resolved) parent phase id, so the synthesized task id nests under it
185
- * @param index - The task's positional index within its phase
186
- * @returns A complete {@link TaskDefinition}
187
- */
188
- export declare function completeTaskDraft(task: TaskDraft, phaseId: string, index: number): TaskDefinition;
189
-
190
107
  /**
191
108
  * The per-unit handle a runner handler receives — wraps the unit's identity,
192
109
  * input, cancellation, and the run controls (`wait` / `spawn` / `abort`).
@@ -290,48 +207,6 @@ export declare interface ControllerInterface<TInput, TResult> {
290
207
  abort(reason?: unknown): void;
291
208
  }
292
209
 
293
- /**
294
- * Wrap a live `AgentInterface` (`@orkestrel/agent`) as a {@link WorkflowFunction} — the OPT-IN
295
- * adapter that runs the agent to a settled result, folding a nested workflow-authoring
296
- * depth / cycle guard into its own closure.
297
- *
298
- * @remarks
299
- * Composes into a caller's {@link WorkflowOptions.functions} registry like any other behavior;
300
- * the PURE {@link import('./WorkflowRunner.js').WorkflowRunner} has no knowledge of agents
301
- * itself. Before running the agent, the depth/cycle guard REJECTS the call (a THROWN typed
302
- * `DEPTH` {@link WorkflowError}, which the leaf `fail`s) when running it would push a nested
303
- * chain past {@link MAX_WORKFLOW_DEPTH}, OR when this agent is already an ancestor (a cycle) —
304
- * ported from the former engine-side guard. When {@link AgentFunctionOptions.runner} is
305
- * supplied, the adapter BINDS a depth/cycle-aware {@link createWorkflowTool} onto the agent's
306
- * `context.tools` (the propagation seam) — closed over `depth` and the extended ancestry (the
307
- * tool itself computes `depth + 1` internally) — so the agent can author + run a NESTED
308
- * workflow through it; the wrapped default is the CURRENT task's own workflow id (used only on
309
- * a no-args tool call). The task's cancellation folds into the agent run: an already-aborted
310
- * `controller.signal` cancels the agent up front; otherwise a one-shot listener fires
311
- * `agent.abort(reason)` when the task cancels, removed in `finally`. `agent.generate()` resolves
312
- * a partial `AgentResult` on a cancel (never rejects), returned as the task's completed value.
313
- *
314
- * A bound agent is effectively SINGLE-RUN: `context.tools.add` binds one {@link ToolInterface}
315
- * under the fixed {@link import('./constants.js').WORKFLOW_TOOL_NAME}, and `agent.generate()` /
316
- * `agent.abort()` are per-agent state. Two CONCURRENT tasks sharing the SAME `agent` instance
317
- * race on that one tool binding (last-write-wins) and on generate/abort — give each concurrent
318
- * task its OWN agent instance.
319
- *
320
- * @param agent - The live `AgentInterface` to run
321
- * @param options - The nested-workflow binding + depth/cycle bookkeeping (see {@link AgentFunctionOptions})
322
- * @returns A {@link WorkflowFunction} that runs `agent` to its settled result
323
- *
324
- * @example
325
- * ```ts
326
- * import { createAgentFunction, createWorkflowRunner } from '@src/core'
327
- *
328
- * const runner = createWorkflowRunner()
329
- * const review = createAgentFunction(myAgent, { runner })
330
- * await runner.execute(definition, { functions: { review } })
331
- * ```
332
- */
333
- export declare function createAgentFunction(agent: AgentInterface, options?: AgentFunctionOptions): WorkflowFunction;
334
-
335
210
  /**
336
211
  * Create a {@link DatabaseWorkflowStore} over any {@link DriverInterface} — the durable,
337
212
  * driver-pluggable backing for the W-d persistence seam, the opt-in twin of
@@ -495,38 +370,6 @@ export declare function createRunner<TInput, TResult>(options: RunnerOptions<TIn
495
370
  */
496
371
  export declare function createScheduler(): SchedulerInterface;
497
372
 
498
- /**
499
- * Wrap a registered tool as a {@link WorkflowFunction} — the OPT-IN adapter that lets a
500
- * `function`-form task run a `@orkestrel/agent` tool BY NAME.
501
- *
502
- * @remarks
503
- * Composes into a caller's {@link WorkflowOptions.functions} registry like any other behavior
504
- * (`{ publish: createToolFunction(tools, 'publish') }`); the PURE
505
- * {@link import('./WorkflowRunner.js').WorkflowRunner} has no knowledge of tools itself. The
506
- * returned function executes `name` against `tools` with the task's `controller.input` as the
507
- * call arguments, id-correlated to the task's own id. A `ToolManagerInterface.execute` NEVER
508
- * throws (a handler throw is isolated into `result.error`), so a failing tool is surfaced here
509
- * as a THROWN `Error` carrying the original message as `cause` — the leaf `fail`s, honouring
510
- * `bail`. An UNREGISTERED tool name is a programmer error (an explicit binding to a name that
511
- * doesn't exist) — unlike the engine's own silent auto-complete of an unresolved task handler,
512
- * this THROWS a typed `TOOL` {@link WorkflowError}.
513
- *
514
- * @param tools - The {@link ToolManagerInterface} the named tool is registered on
515
- * @param name - The registered tool's name
516
- * @returns A {@link WorkflowFunction} that runs the named tool
517
- *
518
- * @example
519
- * ```ts
520
- * import { createToolFunction, createToolManager, createWorkflowRunner } from '@src/core'
521
- *
522
- * const tools = createToolManager()
523
- * tools.add(myPublishTool)
524
- * const runner = createWorkflowRunner()
525
- * await runner.execute(definition, { functions: { publish: createToolFunction(tools, 'publish') } })
526
- * ```
527
- */
528
- export declare function createToolFunction(tools: ToolManagerInterface, name: string): WorkflowFunction;
529
-
530
373
  /**
531
374
  * Build the live W-b entity tree from a {@link WorkflowDefinition} — the whole
532
375
  * {@link WorkflowInterface} → {@link import('./types.js').PhaseInterface} →
@@ -593,32 +436,37 @@ export declare function createWorkflow(definition: WorkflowDefinition, options?:
593
436
  export declare function createWorkflowContract(): ContractInterface<WorkflowDefinition>;
594
437
 
595
438
  /**
596
- * Compile the LENIENT workflow DRAFT contract identical to
597
- * {@link createWorkflowContract} EXCEPT `id` and `name` are OPTIONAL at all three levels
598
- * (workflow / phase / task), so a small model can omit the six identity strings.
439
+ * Create a {@link WorkflowManagerInterface} the store-backed registry of
440
+ * {@link WorkflowInterface}s, the additive manager tier mirroring the `@orkestrel/agent`
441
+ * line's `createConversationManager` / `createWorkspaceManager`.
599
442
  *
600
443
  * @remarks
601
- * The widened authoring surface {@link createWorkflowTool} parses an authored blob through
602
- * before {@link import('./helpers.js').completeDraft} fills the missing ids/names. It does
603
- * NOT relax the canonical contract {@link createWorkflowContract} stays byte-for-byte
604
- * unchanged and STRICT, and the completed draft is re-validated against THAT strict gate
605
- * before running (soundness preserved). A PROVIDED `id` / `name` still carries `minLength: 1`,
606
- * so an explicitly-empty `id: ''` is REJECTED (parses to `undefined`), never auto-filled —
607
- * keeping "garbage" distinct from "omitted". `run` stays required.
444
+ * `options.functions` flows into every workflow the manager mints (`add`, via
445
+ * {@link createWorkflow}) or hydrates (`open`'s registry-miss path, via
446
+ * {@link restoreWorkflow}), so a hydrated workflow is RUNNABLE rather than a dead snapshot
447
+ * mirror. `options.store` is the EXACT analogue of the twins' `store` seam omitted the
448
+ * manager is registry-only (`open` resolves only what is registered, `save` is a no-op). This
449
+ * is PURELY ADDITIVE: direct {@link WorkflowStoreInterface} use and
450
+ * {@link restoreWorkflow} remain valid the manager is one more caller-driven persistence
451
+ * seam, not a replacement.
608
452
  *
609
- * @returns The compiled {@link WorkflowDraft} contract
453
+ * @param options - The optional `store` seam and the `functions` registry threaded into every mint/hydrate
454
+ * @returns A working {@link WorkflowManagerInterface}
610
455
  *
611
456
  * @example
612
457
  * ```ts
613
- * import { createWorkflowDraftContract, completeDraft } from '@src/core'
458
+ * import { createMemoryWorkflowStore, createWorkflowManager } from '@src/core'
614
459
  *
615
- * const draft = createWorkflowDraftContract()
616
- * const parsed = draft.parse({ phases: [{ tasks: [{ run: { via: 'function', name: 'f' } }] }] })
617
- * const definition = parsed && completeDraft(parsed) // ids/names filled positionally
618
- * draft.parse({ id: '', phases: [] }) // undefined — an explicit empty id is rejected
460
+ * const manager = createWorkflowManager({
461
+ * store: createMemoryWorkflowStore(),
462
+ * functions: { compile: async (controller) => `built ${controller.task.id}` },
463
+ * })
464
+ * const workflow = manager.add(definition) // minted, registered, RUNNABLE
465
+ * await manager.save(workflow.id) // persisted to the store
466
+ * const reopened = await manager.open(workflow.id) // already registered — no store hit
619
467
  * ```
620
468
  */
621
- export declare function createWorkflowDraftContract(): ContractInterface<WorkflowDraft>;
469
+ export declare function createWorkflowManager(options?: WorkflowManagerOptions): WorkflowManagerInterface;
622
470
 
623
471
  /**
624
472
  * Create a workflow runner — a {@link WorkflowRunnerInterface} that EXECUTES a live W-b
@@ -641,11 +489,11 @@ export declare function createWorkflowDraftContract(): ContractInterface<Workflo
641
489
  * the live entity (`start` → `complete` / `fail`), and resolves a
642
490
  * {@link import('./types.js').WorkflowResult}.
643
491
  *
644
- * Static tool / agent calling is OPT-IN, wired through the adapter factories
645
- * {@link createToolFunction} / {@link createAgentFunction} — plain
646
- * {@link import('./types.js').WorkflowFunction}s a caller composes into its OWN
647
- * {@link WorkflowOptions.functions} registry, same as any other behavior. A task with no
648
- * resolved handler AUTO-COMPLETES (the ROADMAP no-handler rule).
492
+ * Static tool / agent calling is OPT-IN: a caller wires a plain
493
+ * {@link import('./types.js').WorkflowFunction} into its OWN {@link WorkflowOptions.functions}
494
+ * registry, same as any other behavior the `@orkestrel/tool` package ships the
495
+ * tool/agent adapter factories for that. A task with no resolved handler AUTO-COMPLETES
496
+ * (the ROADMAP no-handler rule).
649
497
  *
650
498
  * @param options - An optional pacing `scheduler` (default the shipped cross-environment one).
651
499
  * See {@link WorkflowRunnerOptions}.
@@ -668,78 +516,6 @@ export declare function createWorkflowDraftContract(): ContractInterface<Workflo
668
516
  */
669
517
  export declare function createWorkflowRunner(options?: WorkflowRunnerOptions): WorkflowRunnerInterface;
670
518
 
671
- /**
672
- * Wrap a {@link WorkflowDefinition} as an LLM-callable {@link ToolInterface} — it ADVERTISES
673
- * the SIMPLE flat authoring shape (`{ name?, steps: [{ name }] }`) as its `parameters` so
674
- * even a small model can author a complete tree, and its handler EXPANDS / COMPLETES the
675
- * authored blob, validates it against the STRICT contract, runs it through `runner`, and
676
- * returns the run SUMMARY (throwing a typed {@link WorkflowError} on failure).
677
- *
678
- * @remarks
679
- * A plain {@link ToolManagerInterface}-compatible tool (so `createMCPServer` / `createMCPRoutes`
680
- * expose it for free — nothing MCP is wired here). It is ALSO the propagation carrier
681
- * {@link createAgentFunction} binds onto a wrapped agent's `context.tools`: because a tool
682
- * handler receives ONLY the model-supplied `args` (no ambient context, no signal), the run's
683
- * depth + ancestry are CLOSED OVER at bind time via {@link WorkflowToolOptions}, and the
684
- * handler enforces the SAME depth / cycle guard itself (this function owns it now — the engine
685
- * carries none) before running the nested workflow at `depth + 1` with the extended ancestry.
686
- *
687
- * **Widened authoring surface (additive — the canonical contract + runner stay STRICT and
688
- * unchanged).** A 2B model reliably CALLS the tool but cannot reliably emit the full four-level
689
- * nested {@link WorkflowDefinition} (six required `id`/`name` strings, an all-or-nothing tree).
690
- * So the tool ACCEPTS three authoring forms and converges them on the SAME strict
691
- * {@link createWorkflowContract} gate before running (soundness preserved):
692
- * - the FLAT shape `{ name?, steps: [{ name }] }` — the ADVERTISED `parameters` (the simplest
693
- * form, {@link import('./helpers.js').expandSteps}'d into one one-task phase per step);
694
- * - a nested DRAFT with any `id`/`name` OMITTED — {@link createWorkflowDraftContract}-parsed then
695
- * {@link import('./helpers.js').completeDraft}'d (missing ids synthesized positionally);
696
- * - the full nested {@link WorkflowDefinition} — the advanced escape-hatch (documented in the
697
- * description), accepted as the draft super-set.
698
- *
699
- * The handler conforms to the universal tool-handler contract (AGENTS §14): it returns the PLAIN
700
- * run-summary VALUE on success and THROWS a typed {@link WorkflowError} on every failure path. It
701
- * does NOT build a {@link ToolResult} itself — the `@orkestrel/agent` package's `ToolManager`
702
- * performs the ONE canonical wrap (`{ id, name, value }` on a return; `{ id, name, error }` on a
703
- * throw, ISOLATED so nothing escapes the run), so the outcome appears EXACTLY ONCE, identically,
704
- * over BOTH the agent loop and MCP (a throw → MCP `isError: true`):
705
- * - **No authored args** (an empty `arguments`) ⇒ runs the WRAPPED `definition`.
706
- * - **A `steps` array** ⇒ the FLAT form: parse it, {@link import('./helpers.js').expandSteps} it.
707
- * - **Otherwise** ⇒ the nested form: {@link createWorkflowDraftContract}-parse it,
708
- * {@link import('./helpers.js').completeDraft} it.
709
- * - **Strict gate** ⇒ the expanded / completed result is validated against
710
- * {@link createWorkflowContract}.`is`; a blob that can't expand, or whose result fails the strict
711
- * gate (e.g. an explicit empty `id`, `concurrency: 0`) ⇒ THROW a `TOOL` {@link WorkflowError} (no run).
712
- * - **Over-deep / cyclic** ⇒ THROW a `DEPTH` {@link WorkflowError} when the nested run would exceed
713
- * {@link MAX_WORKFLOW_DEPTH}, or the target workflow id is already an ancestor (a cycle) — the
714
- * SAME `code` {@link createAgentFunction}'s own guard raises. Enforced HERE, INSIDE this
715
- * handler, before ever calling `runner.execute` — the engine itself performs no such check.
716
- * - **Otherwise** ⇒ `runner.execute(target)`, RETURNING the plain summary of the terminal run
717
- * (`{ status, count }`, via {@link workflowToolSummary}).
718
- *
719
- * The tool executes AUTHORED STRUCTURE, not consumer behavior: a nested tree authored through
720
- * it (flat, draft, or full form) carries no {@link WorkflowFunctions} registry, so EVERY one of
721
- * its tasks auto-completes under the no-handler rule. This handler validates and synthesizes
722
- * shape — it never runs a caller's handlers.
723
- *
724
- * @param definition - The workflow the tool runs when called with no authored args
725
- * @param runner - The {@link WorkflowRunnerInterface} that executes the (nested) workflow
726
- * @param options - The depth + ancestry to run the nested workflow under (see
727
- * {@link WorkflowToolOptions}); omitted ⇒ depth `0` / empty ancestry (a top-level wrap)
728
- * @returns A {@link ToolInterface} (named {@link import('./constants.js').WORKFLOW_TOOL_NAME})
729
- * whose `parameters` advertise the FLAT authoring schema (the nested form stays accepted)
730
- *
731
- * @example
732
- * ```ts
733
- * import { createWorkflowRunner, createWorkflowTool, createToolManager } from '@src/core'
734
- *
735
- * const runner = createWorkflowRunner()
736
- * const tool = createWorkflowTool(definition, runner)
737
- * const tools = createToolManager()
738
- * tools.add(tool) // a model can now author + run a workflow in one call
739
- * ```
740
- */
741
- export declare function createWorkflowTool(definition: WorkflowDefinition, runner: WorkflowRunnerInterface, options?: WorkflowToolOptions): ToolInterface;
742
-
743
519
  /**
744
520
  * A {@link WorkflowStoreInterface} backed by one table of the `databases` layer — a
745
521
  * workflow's durable run-state IS a row, so persistence reduces to keyed point-access
@@ -952,25 +728,6 @@ export declare function derivePhaseStatus(tasks: readonly TaskStatus[]): PhaseSt
952
728
  */
953
729
  export declare function deriveWorkflowStatus(phases: readonly PhaseDerivation[]): WorkflowStatus;
954
730
 
955
- /**
956
- * Expand a flat {@link WorkflowSteps} blob into a strict {@link WorkflowDefinition} — each
957
- * step becomes a one-task phase, IN ORDER.
958
- *
959
- * @remarks
960
- * The expansion of the tool's ADVERTISED surface (AGENTS §21 — the simplest form a small
961
- * model can author). Each {@link WorkflowStep} maps to a phase holding exactly one task:
962
- * the step's `name` becomes the task's `run` (the behavior-registry key). Ids/names are
963
- * auto-filled positionally — it builds an ids-omitted {@link WorkflowDraft} and delegates
964
- * to {@link completeDraft}, so the two lenient surfaces share ONE synthesis path (step `i`
965
- * → phase `phase-<i>`, its task `phase-<i>-task-0`). The optional `name` becomes the
966
- * workflow's `name`. The result is a complete definition the caller validates against the
967
- * STRICT contract before running.
968
- *
969
- * @param flat - The flat steps blob (`{ name?, steps: [{ name }] }`)
970
- * @returns A complete {@link WorkflowDefinition} (one one-task phase per step)
971
- */
972
- export declare function expandSteps(flat: WorkflowSteps): WorkflowDefinition;
973
-
974
731
  /**
975
732
  * Box an error as a {@link Failure} — the graceful outcome half of a {@link Result}.
976
733
  *
@@ -1104,21 +861,6 @@ export declare function isWorkflowSnapshot(value: unknown): value is WorkflowSna
1104
861
  */
1105
862
  export declare type LifecycleStatus = 'pending' | 'running' | 'completed' | 'failed' | 'skipped' | 'stopped';
1106
863
 
1107
- /**
1108
- * The maximum nesting depth a workflow → agent → workflow chain may reach — the bound
1109
- * the {@link import('./factories.js').createAgentFunction} and
1110
- * {@link import('./factories.js').createWorkflowTool} adapters' depth/cycle guards enforce.
1111
- *
1112
- * @remarks
1113
- * The limit lives in ONE place. An {@link import('./factories.js').createAgentFunction}-wrapped
1114
- * agent running at this depth can no longer author + run a NESTED workflow through its bound
1115
- * workflow tool (that would be depth `MAX_WORKFLOW_DEPTH + 1`), so the over-deep invocation is
1116
- * REJECTED (a typed `DEPTH` {@link import('./errors.js').WorkflowError} throw). The chain
1117
- * therefore nests workflows down to this depth, and the nested run at
1118
- * depth `MAX_WORKFLOW_DEPTH` fails.
1119
- */
1120
- export declare const MAX_WORKFLOW_DEPTH = 8;
1121
-
1122
864
  /**
1123
865
  * The in-memory {@link WorkflowStoreInterface} — a process-lifetime `Map` of
1124
866
  * {@link WorkflowSnapshot}s keyed by workflow id, the DEFAULT store
@@ -1367,38 +1109,6 @@ export declare interface PhaseDerivation {
1367
1109
  readonly bail: boolean;
1368
1110
  }
1369
1111
 
1370
- /** A draft phase — a {@link PhaseDefinition} with OPTIONAL `id` / `name` and {@link TaskDraft} tasks. */
1371
- export declare interface PhaseDraft {
1372
- readonly id?: string;
1373
- readonly name?: string;
1374
- readonly description?: string;
1375
- readonly tasks: readonly TaskDraft[];
1376
- /** Max tasks in flight at once (a resource throttle); omitted ⇒ unbounded. */
1377
- readonly concurrency?: number;
1378
- /** The per-phase failure-policy OVERRIDE; omitted ⇒ inherits the workflow `bail` (`effectiveBail = phase.bail ?? workflow.bail`). */
1379
- readonly bail?: boolean;
1380
- }
1381
-
1382
- /**
1383
- * The shape of a PHASE in a draft workflow — identical to {@link phaseShape} EXCEPT
1384
- * `id` and `name` are OPTIONAL, and its tasks are {@link taskDraftShape}s.
1385
- */
1386
- export declare const phaseDraftShape: ObjectShape<{
1387
- id: OptionalShape<StringShape>;
1388
- name: OptionalShape<StringShape>;
1389
- description: OptionalShape<StringShape>;
1390
- tasks: ArrayShape<ObjectShape<{
1391
- id: OptionalShape<StringShape>;
1392
- name: OptionalShape<StringShape>;
1393
- description: OptionalShape<StringShape>;
1394
- run: OptionalShape<StringShape>;
1395
- retries: OptionalShape<NumberShape>;
1396
- timeout: OptionalShape<NumberShape>;
1397
- }>>;
1398
- concurrency: OptionalShape<NumberShape>;
1399
- bail: OptionalShape<LiteralShape<readonly [true, false]>>;
1400
- }>;
1401
-
1402
1112
  /**
1403
1113
  * The push observation surface (AGENTS §13) of the phase entity (W-b) — analogous
1404
1114
  * to {@link WorkflowEventMap}, scoped to one phase.
@@ -2327,19 +2037,6 @@ export declare interface SchedulerOptions {
2327
2037
  */
2328
2038
  export declare type SchedulerPriority = 'user' | 'normal' | 'background';
2329
2039
 
2330
- /**
2331
- * The shape of ONE flat step — `{ name }` — the building block of
2332
- * {@link workflowStepsShape}.
2333
- *
2334
- * @remarks
2335
- * `name` is the REGISTERED behavior name the step runs (it becomes the task's `run`). The
2336
- * tool expands each step into a one-task phase, in order
2337
- * ({@link import('./helpers.js').expandSteps}).
2338
- */
2339
- export declare const stepShape: ObjectShape<{
2340
- name: StringShape;
2341
- }>;
2342
-
2343
2040
  /**
2344
2041
  * Box a value as a {@link Success} — the graceful outcome half of a {@link Result}.
2345
2042
  *
@@ -2580,44 +2277,6 @@ export declare interface TaskDefinition {
2580
2277
  */
2581
2278
  export declare function taskDefinitionToSnapshot(task: WorkflowDefinition['phases'][number]['tasks'][number]): TaskSnapshot;
2582
2279
 
2583
- /**
2584
- * A draft task — a {@link TaskDefinition} with OPTIONAL `id` / `name`.
2585
- *
2586
- * @remarks
2587
- * The tool synthesizes a missing `id` positionally and defaults a missing `name` to
2588
- * its `id` ({@link import('./helpers.js').completeDraft}). A PROVIDED `id` / `name` is
2589
- * preserved verbatim (and must be non-empty — the draft contract's `minLength: 1`).
2590
- */
2591
- export declare interface TaskDraft {
2592
- readonly id?: string;
2593
- readonly name?: string;
2594
- readonly description?: string;
2595
- /** The behavior reference — a registry key resolved against {@link WorkflowFunctions} at construction; omitted ⇒ no handler. */
2596
- readonly run?: string;
2597
- /** Extra attempts after the first on failure (a non-negative integer); overrides the phase Runner default. Execution-only. */
2598
- readonly retries?: number;
2599
- /** The per-attempt deadline in milliseconds (a non-negative integer); overrides the phase Runner default. Execution-only. */
2600
- readonly timeout?: number;
2601
- }
2602
-
2603
- /**
2604
- * The shape of a TASK in a draft workflow — identical to {@link taskShape} EXCEPT `id`
2605
- * and `name` are OPTIONAL (the tool synthesizes any missing one positionally).
2606
- *
2607
- * @remarks
2608
- * A PROVIDED `id` / `name` still carries `minLength: 1`, so an explicitly-empty `id: ''`
2609
- * is INVALID (rejected by the draft contract), never auto-filled — keeping "garbage"
2610
- * distinct from "omitted". `run` stays optional, mirroring {@link taskShape}.
2611
- */
2612
- export declare const taskDraftShape: ObjectShape<{
2613
- id: OptionalShape<StringShape>;
2614
- name: OptionalShape<StringShape>;
2615
- description: OptionalShape<StringShape>;
2616
- run: OptionalShape<StringShape>;
2617
- retries: OptionalShape<NumberShape>;
2618
- timeout: OptionalShape<NumberShape>;
2619
- }>;
2620
-
2621
2280
  /**
2622
2281
  * The push observation surface (AGENTS §13) of the task entity (W-b) — the
2623
2282
  * lifecycle moments of one task.
@@ -3100,64 +2759,6 @@ export declare class Workflow implements WorkflowInterface {
3100
2759
  /** Every {@link WorkflowStatus} value, frozen — the lifecycle vocabulary of a workflow. */
3101
2760
  export declare const WORKFLOW_STATUSES: readonly WorkflowStatus[];
3102
2761
 
3103
- /**
3104
- * The DESCRIPTION {@link import('./factories.js').createWorkflowTool} advertises — a
3105
- * multi-line guide that teaches a small model how to author a complete workflow tree.
3106
- *
3107
- * @remarks
3108
- * Presents the SIMPLE flat shape (`{ name, steps: [{ name }] }`) as the PRIMARY way with
3109
- * one complete worked example ({@link WORKFLOW_TOOL_FLAT_EXAMPLE}), names that a step's
3110
- * `name` is a REGISTERED name (not a human label), and documents the full nested
3111
- * {@link WorkflowDefinition} as the ADVANCED form with a minimal example
3112
- * ({@link WORKFLOW_TOOL_NESTED_EXAMPLE}). Both examples are interpolated VERBATIM from the
3113
- * validated constants, so a parity test pins them — the description can never drift from a
3114
- * real, contract-valid example. The `parameters` the tool advertises are the FLAT shape's
3115
- * schema; the nested form is the documented escape-hatch (the tool accepts both). NOTE: a step's
3116
- * "registered behavior name" is authored STRUCTURE only —
3117
- * {@link import('./factories.js').createWorkflowTool} runs the authored tree with no
3118
- * {@link WorkflowFunctions} registry of its own, so every one of its tasks auto-completes under
3119
- * the no-handler rule; the tool validates/synthesizes shape, it does not dispatch behavior.
3120
- */
3121
- export declare const WORKFLOW_TOOL_DESCRIPTION: string;
3122
-
3123
- /**
3124
- * A complete FLAT authoring example — the PRIMARY way a small model authors a workflow
3125
- * through {@link import('./factories.js').createWorkflowTool}: `{ name, steps: [{ name }] }`.
3126
- *
3127
- * @remarks
3128
- * Each step becomes a one-task phase, in order; a step's `name` is a REGISTERED behavior name
3129
- * (not a label) — the registry key its task's `run` resolves against. The tool expands this
3130
- * ({@link import('./helpers.js').expandSteps}) into a valid {@link WorkflowDefinition}. It
3131
- * is embedded VERBATIM in {@link WORKFLOW_TOOL_DESCRIPTION} and guarded by a parity test
3132
- * (it must expand to a tree the STRICT contract accepts), so the doc example can never drift.
3133
- */
3134
- export declare const WORKFLOW_TOOL_FLAT_EXAMPLE: WorkflowSteps;
3135
-
3136
- /**
3137
- * The name under which {@link import('./factories.js').createAgentFunction} BINDS the
3138
- * depth/cycle-aware workflow tool onto a wrapped agent's `context.tools` (`AgentContextInterface`,
3139
- * `@orkestrel/agent`).
3140
- *
3141
- * @remarks
3142
- * The propagation seam's well-known key: when its `runner` option is supplied, the adapter adds a
3143
- * {@link import('./factories.js').createWorkflowTool}-built tool under this name to the
3144
- * agent's `context.tools`, so it can author + run a NESTED workflow (bounded by
3145
- * {@link MAX_WORKFLOW_DEPTH}). An agent that wants to fan out into a workflow calls this tool by
3146
- * this name; the bound handler runs the nested workflow at depth + 1.
3147
- */
3148
- export declare const WORKFLOW_TOOL_NAME = "workflow";
3149
-
3150
- /**
3151
- * A minimal NESTED authoring example — the ADVANCED escape-hatch form a model may use
3152
- * instead of the flat shape: a full {@link WorkflowDefinition}.
3153
- *
3154
- * @remarks
3155
- * The full four-level form, documented in {@link WORKFLOW_TOOL_DESCRIPTION} as the advanced
3156
- * alternative. It is embedded VERBATIM and guarded by a parity test (`createWorkflowContract().is`
3157
- * must accept it), so the doc example can never drift from a valid definition.
3158
- */
3159
- export declare const WORKFLOW_TOOL_NESTED_EXAMPLE: WorkflowDefinition;
3160
-
3161
2762
  /**
3162
2763
  * The ambient context of a workflow — the identity every level inherits.
3163
2764
  *
@@ -3193,60 +2794,6 @@ export declare interface WorkflowDefinition {
3193
2794
  readonly bail?: boolean;
3194
2795
  }
3195
2796
 
3196
- /**
3197
- * A draft workflow — a {@link WorkflowDefinition} with OPTIONAL `id` / `name` at all
3198
- * three levels (workflow / phase / task).
3199
- *
3200
- * @remarks
3201
- * The lenient authoring form `createWorkflowDraftContract` validates and
3202
- * {@link import('./helpers.js').completeDraft} completes into a strict
3203
- * {@link WorkflowDefinition}. `run` stays optional (a plain name string); the `bail`
3204
- * policy carries over.
3205
- */
3206
- export declare interface WorkflowDraft {
3207
- readonly id?: string;
3208
- readonly name?: string;
3209
- readonly description?: string;
3210
- readonly phases: readonly PhaseDraft[];
3211
- /** Failure policy: `false` (default) continues gracefully, `true` halts on the first failure. */
3212
- readonly bail?: boolean;
3213
- }
3214
-
3215
- /**
3216
- * The shape of a DRAFT workflow — identical to {@link workflowShape} EXCEPT `id` and
3217
- * `name` are OPTIONAL at all three levels (workflow / phase / task), so a small model
3218
- * can omit the six identity strings and let the tool synthesize them positionally.
3219
- *
3220
- * @remarks
3221
- * The lenient counterpart {@link import('./factories.js').createWorkflowDraftContract}
3222
- * compiles. `run` stays required; a provided `id` / `name` still has `minLength: 1` (so an
3223
- * explicitly-empty `id: ''` is REJECTED, not auto-filled). After
3224
- * {@link import('./helpers.js').completeDraft} fills the missing ids/names, the result is
3225
- * validated against the STRICT {@link import('./factories.js').createWorkflowContract} gate
3226
- * before running.
3227
- */
3228
- export declare const workflowDraftShape: ObjectShape<{
3229
- id: OptionalShape<StringShape>;
3230
- name: OptionalShape<StringShape>;
3231
- description: OptionalShape<StringShape>;
3232
- phases: ArrayShape<ObjectShape<{
3233
- id: OptionalShape<StringShape>;
3234
- name: OptionalShape<StringShape>;
3235
- description: OptionalShape<StringShape>;
3236
- tasks: ArrayShape<ObjectShape<{
3237
- id: OptionalShape<StringShape>;
3238
- name: OptionalShape<StringShape>;
3239
- description: OptionalShape<StringShape>;
3240
- run: OptionalShape<StringShape>;
3241
- retries: OptionalShape<NumberShape>;
3242
- timeout: OptionalShape<NumberShape>;
3243
- }>>;
3244
- concurrency: OptionalShape<NumberShape>;
3245
- bail: OptionalShape<LiteralShape<readonly [true, false]>>;
3246
- }>>;
3247
- bail: OptionalShape<LiteralShape<readonly [true, false]>>;
3248
- }>;
3249
-
3250
2797
  /**
3251
2798
  * An error thrown by the workflow entity + W-c2 recursion layer.
3252
2799
  *
@@ -3255,11 +2802,11 @@ export declare const workflowDraftShape: ObjectShape<{
3255
2802
  * offending node id / status. Thrown for an illegal lifecycle transition
3256
2803
  * (`TRANSITION`), a structurally invalid {@link import('./types.js').WorkflowSnapshot}
3257
2804
  * passed to {@link import('./factories.js').restoreWorkflow} (`RESTORE`), an over-deep /
3258
- * cyclic nested-workflow dispatch (`DEPTH`), and a malformed
3259
- * {@link import('./factories.js').createWorkflowTool} args blob (`TOOL`). On the
3260
- * workflow-tool seam the `DEPTH` / `TOOL` throw is ISOLATED by the
3261
- * `@orkestrel/agent` package's `ToolManager` into the tool result's
3262
- * top-level `error` (AGENTS §14 — the universal tool-handler contract).
2805
+ * cyclic nested-workflow dispatch (`DEPTH`), and a malformed workflow-authoring-tool args
2806
+ * blob (`TOOL`). `DEPTH` and `TOOL` are public type surface constructed by the
2807
+ * `@orkestrel/tool` package's workflow-tool / agent-function adapters; on that seam the
2808
+ * throw is ISOLATED by its `ToolManager` into the tool result's top-level `error`
2809
+ * (AGENTS §14 — the universal tool-handler contract).
3263
2810
  */
3264
2811
  export declare class WorkflowError extends Error {
3265
2812
  readonly code: WorkflowErrorCode;
@@ -3277,21 +2824,21 @@ export declare class WorkflowError extends Error {
3277
2824
  * the offending current status + requested transition in the error `context`.
3278
2825
  * - `RESTORE` — a {@link import('./factories.js').restoreWorkflow} given a structurally
3279
2826
  * invalid {@link WorkflowSnapshot} (a status outside the lifecycle vocabulary).
3280
- * - `DEPTH` — a nested-workflow dispatch (W-c2) that the runner's depth / cycle guard
3281
- * rejected: running it would push the nested-workflow chain past
3282
- * {@link import('./constants.js').MAX_WORKFLOW_DEPTH}, OR its target agent (or a
3283
- * workflow it would author) is already an ancestor of the current run (a re-entry
3284
- * cycle). Raised on BOTH seams of the W-c2 recursion an `agent`-task dispatch
3285
- * (`fail`ed with this code; it never runs) AND the
3286
- * {@link import('./factories.js').createWorkflowTool} handler (thrown, then ISOLATED
3287
- * by the `@orkestrel/agent` package's `ToolManager` into the tool
3288
- * result's `error`). The error `context` names the offending agent / workflow id + the depth.
3289
- * - `TOOL` the {@link import('./factories.js').createWorkflowTool} handler was handed
3290
- * a MALFORMED / over-constraint authored args blob (e.g. an empty `id`, `concurrency: 0`)
3291
- * that the contract rejected, so no workflow ran. The handler THROWS it (rather than
3292
- * returning a failure result), and the `@orkestrel/agent` package's `ToolManager`
3293
- * ISOLATES the throw into the canonical tool result's top-level `error` (AGENTS §14 — the
3294
- * universal tool-handler contract); the error `context` names the wrapped workflow id.
2827
+ * - `DEPTH` — a nested-workflow dispatch (W-c2) that a depth / cycle guard rejected:
2828
+ * running it would push the nested-workflow chain past a bounded max depth, OR its
2829
+ * target agent (or a workflow it would author) is already an ancestor of the current
2830
+ * run (a re-entry cycle). Public type surface consumed by the `@orkestrel/tool`
2831
+ * package's workflow-tool / agent-function adapters, which construct
2832
+ * {@link import('./errors.js').WorkflowError}s with this code (thrown, then ISOLATED
2833
+ * by that package's `ToolManager` into the tool result's `error`). The error `context`
2834
+ * names the offending agent / workflow id + the depth.
2835
+ * - `TOOL` a workflow-authoring tool handler (in `@orkestrel/tool`) was handed a
2836
+ * MALFORMED / over-constraint authored args blob (e.g. an empty `id`, `concurrency: 0`)
2837
+ * that {@link import('./factories.js').createWorkflowContract} rejected, so no workflow
2838
+ * ran. Public type surface: `@orkestrel/tool` constructs this code and THROWS it
2839
+ * (rather than returning a failure result); its `ToolManager` ISOLATES the throw into
2840
+ * the canonical tool result's top-level `error` (AGENTS §14 — the universal
2841
+ * tool-handler contract); the error `context` names the wrapped workflow id.
3295
2842
  * - `MUTATION` — a GATED structural or patch edit was refused: a duplicate id on
3296
2843
  * `append`/`add`, a target that does not exist or is not `pending`, an out-of-bounds
3297
2844
  * `index`, a patch that failed shaper validation, or a live structural edit refused by
@@ -3588,6 +3135,190 @@ export declare interface WorkflowInterface {
3588
3135
  snapshot(): WorkflowSnapshot;
3589
3136
  }
3590
3137
 
3138
+ /**
3139
+ * The store-backed registry of {@link WorkflowInterface}s keyed by `id`, in insertion order —
3140
+ * the additive manager tier mirroring the `@orkestrel/agent` line's `ConversationManager` /
3141
+ * `WorkspaceManager`. Event-free (a registry, like its twins); the observability lives on each
3142
+ * {@link WorkflowInterface}.
3143
+ *
3144
+ * @remarks
3145
+ * - **Registry.** Workflows live in an insertion-ordered `Map` keyed by `id`. `add(definition)`
3146
+ * mints a live {@link WorkflowInterface} through {@link createWorkflow} (flowing the manager's
3147
+ * `functions` registry in) and stores it under `definition.id` — an already-present id
3148
+ * OVERWRITES (last write wins). `count` is the map size, `workflow(id)` looks one up,
3149
+ * `workflows()` lists them in insertion order.
3150
+ * - **Durable open / save.** `open(id)` returns an already-registered workflow directly; on a
3151
+ * registry MISS with a `store` set it rehydrates through {@link restoreWorkflow} (flowing the
3152
+ * manager's `functions` registry in so the rehydrated tree is RUNNABLE), registers it, and
3153
+ * returns it — lenient (`undefined`) with no store or a store miss. `save(id)` persists a
3154
+ * registered workflow's `snapshot()` to the `store` — lenient (`false`) with no store or an
3155
+ * unknown id.
3156
+ * - **Removal.** `remove` drops one by id, or a batch (§9.2, array overload FIRST) — `true` when
3157
+ * any was removed. `clear` empties the registry.
3158
+ * - **No active pointer.** Unlike its `ConversationManager` / `WorkspaceManager` twins, there is
3159
+ * no `active` / `switch` — nothing in the workflow domain renders "the current workflow".
3160
+ *
3161
+ * @example
3162
+ * ```ts
3163
+ * const manager = new WorkflowManager({
3164
+ * functions: { compile: async (controller) => `built ${controller.task.id}` },
3165
+ * })
3166
+ * const workflow = manager.add(definition) // minted, registered, RUNNABLE
3167
+ * manager.workflow(workflow.id) // the same workflow
3168
+ * manager.count // 1
3169
+ * ```
3170
+ */
3171
+ export declare class WorkflowManager implements WorkflowManagerInterface {
3172
+ #private;
3173
+ constructor(options?: WorkflowManagerOptions);
3174
+ get count(): number;
3175
+ workflow(id: string): WorkflowInterface | undefined;
3176
+ workflows(): readonly WorkflowInterface[];
3177
+ add(definition: WorkflowDefinition): WorkflowInterface;
3178
+ open(id: string): Promise<WorkflowInterface | undefined>;
3179
+ save(id: string): Promise<boolean>;
3180
+ remove(ids: readonly string[]): boolean;
3181
+ remove(id: string): boolean;
3182
+ clear(): void;
3183
+ }
3184
+
3185
+ /**
3186
+ * A store-backed registry of {@link WorkflowInterface}s keyed by their `id`, in insertion
3187
+ * order — the additive manager tier mirroring `ConversationManagerInterface` /
3188
+ * `WorkspaceManagerInterface` from the `@orkestrel/agent` line, adapted for the workflow
3189
+ * domain: `add` mints from a {@link WorkflowDefinition} (not an empty `Input`, since a
3190
+ * workflow only exists relative to a definition), and the optional `store` seam's `open`
3191
+ * threads the manager's {@link WorkflowFunctions} registry so a HYDRATED workflow is
3192
+ * immediately RUNNABLE, not merely a restored state mirror. NO `active` / `switch` pointer
3193
+ * (AGENTS §21) — the workflow domain has no consumer that renders "the current workflow" the
3194
+ * way an agent context renders the active conversation/workspace.
3195
+ *
3196
+ * @remarks
3197
+ * - **Registry.** `count` is how many are stored. `add(definition)` mints a live
3198
+ * {@link WorkflowInterface} via {@link import('./factories.js').createWorkflow} (flowing
3199
+ * this manager's `functions` registry in) and registers it under `definition.id` — an
3200
+ * already-present id OVERWRITES (last write wins, since `createWorkflow` keys the tree by
3201
+ * the definition's own id). `workflow(id)` looks one up (`undefined` when absent);
3202
+ * `workflows()` lists them in insertion order.
3203
+ * - **Durable open / save (the optional `store` seam).** When a {@link WorkflowStoreInterface}
3204
+ * is supplied (the `store` option), `open(id)` resolves an already-registered workflow
3205
+ * directly (no store hit); on a registry MISS it HYDRATES one from `store.get(id)` through
3206
+ * {@link import('./factories.js').restoreWorkflow} — flowing this manager's `functions`
3207
+ * registry in so the rehydrated tree is RUNNABLE — registers it, and returns it. `save(id)`
3208
+ * PERSISTS a registered workflow's {@link WorkflowInterface.snapshot} to the store. Both are
3209
+ * LENIENT without a store — `open` resolves only registered ids, `save` is a no-op
3210
+ * (`false`) — never a throw. The EXACT analogue of
3211
+ * `ConversationManagerInterface.open` / `.save` and `WorkspaceManagerInterface.open` /
3212
+ * `.save` — this is the workflow line's caller-driven persistence gaining the standard
3213
+ * open/save seam, ADDITIVE alongside direct {@link WorkflowStoreInterface} use and
3214
+ * {@link import('./factories.js').restoreWorkflow} (both remain valid).
3215
+ * - **Removal.** `remove` drops one by id, or a batch (§9.2, array overload FIRST) — `true`
3216
+ * when any was removed. `clear` empties the registry.
3217
+ * - **Event-free.** A purely registry store — no `Emitter`, no events (each
3218
+ * {@link WorkflowInterface} owns its own {@link WorkflowEventMap} emitter).
3219
+ *
3220
+ * @example
3221
+ * ```ts
3222
+ * import { createWorkflowManager } from '@src/core'
3223
+ *
3224
+ * const manager = createWorkflowManager({
3225
+ * functions: { compile: async (controller) => `built ${controller.task.id}` },
3226
+ * })
3227
+ * const workflow = manager.add(definition) // minted, registered, RUNNABLE (functions flow in)
3228
+ * manager.count // 1
3229
+ * ```
3230
+ */
3231
+ export declare interface WorkflowManagerInterface {
3232
+ readonly count: number;
3233
+ workflow(id: string): WorkflowInterface | undefined;
3234
+ workflows(): readonly WorkflowInterface[];
3235
+ /**
3236
+ * MINT a live {@link WorkflowInterface} from `definition` (via
3237
+ * {@link import('./factories.js').createWorkflow}, flowing this manager's `functions`
3238
+ * registry in) and register it under `definition.id`.
3239
+ *
3240
+ * @remarks
3241
+ * An already-registered `definition.id` OVERWRITES (last write wins) — `createWorkflow`
3242
+ * keys the live tree by the definition's own id, so a re-`add` under the same id is
3243
+ * indistinguishable from a fresh mint at the registry level.
3244
+ *
3245
+ * @param definition - The {@link WorkflowDefinition} to build the live tree from
3246
+ * @returns The minted, registered {@link WorkflowInterface}
3247
+ */
3248
+ add(definition: WorkflowDefinition): WorkflowInterface;
3249
+ /**
3250
+ * Resolve a workflow by id — from the registry if present, else HYDRATED from the
3251
+ * optional {@link WorkflowStoreInterface} (`store`), RUNNABLE (this manager's `functions`
3252
+ * registry is threaded into the rehydration).
3253
+ *
3254
+ * @remarks
3255
+ * - If `id` is ALREADY registered, it is returned directly — no store hit.
3256
+ * - Else if a `store` is set, `store.get(id)` is awaited; on a HIT the snapshot is
3257
+ * rehydrated into a fresh {@link WorkflowInterface} via
3258
+ * {@link import('./factories.js').restoreWorkflow}, flowing this manager's `functions`
3259
+ * registry in (so the rehydrated tree carries real resolved `handler`s and can RESUME
3260
+ * real work), registers it, and returns it.
3261
+ * - Else (no store, or a store MISS) ⇒ `undefined` (lenient — no throw).
3262
+ *
3263
+ * @param id - The workflow id to open
3264
+ * @returns The resolved, RUNNABLE {@link WorkflowInterface}, or `undefined` when neither registered nor stored
3265
+ */
3266
+ open(id: string): Promise<WorkflowInterface | undefined>;
3267
+ /**
3268
+ * Persist a REGISTERED workflow's {@link WorkflowInterface.snapshot} to the optional
3269
+ * {@link WorkflowStoreInterface} (`store`).
3270
+ *
3271
+ * @remarks
3272
+ * Lenient: when a `store` is set AND `id` is registered, `store.set(workflow.snapshot())`
3273
+ * is awaited and `true` is returned; otherwise (no store, OR an unknown id) it is a NO-OP
3274
+ * returning `false` — never a throw.
3275
+ *
3276
+ * @param id - The id of the registered workflow to persist
3277
+ * @returns `true` when the snapshot was persisted; `false` when no store / unknown id
3278
+ */
3279
+ save(id: string): Promise<boolean>;
3280
+ remove(ids: readonly string[]): boolean;
3281
+ remove(id: string): boolean;
3282
+ clear(): void;
3283
+ }
3284
+
3285
+ /**
3286
+ * Options for `createWorkflowManager` — the optional durable {@link WorkflowStoreInterface}
3287
+ * seam plus the {@link WorkflowFunctions} registry every workflow the manager mints or
3288
+ * hydrates resolves its tasks' handlers against.
3289
+ *
3290
+ * @remarks
3291
+ * `store` is the EXACT analogue of `ConversationManagerOptions.store` /
3292
+ * `WorkspaceManagerOptions.store` (the `@orkestrel/agent` line's store standard) — omitted ⇒
3293
+ * the manager is registry-only: {@link WorkflowManagerInterface.open} resolves only what is
3294
+ * already registered, and {@link WorkflowManagerInterface.save} is a no-op (`false`). `functions`
3295
+ * is the workflow-specific addition: the SAME {@link WorkflowFunctions} registry threaded into
3296
+ * every {@link import('./factories.js').createWorkflow} ({@link WorkflowManagerInterface.add})
3297
+ * and every {@link import('./factories.js').restoreWorkflow}
3298
+ * ({@link WorkflowManagerInterface.open}'s hydration path) the manager performs — so a
3299
+ * hydrated workflow carries real resolved `handler`s and is RUNNABLE, not merely a restored
3300
+ * state mirror. Omitted ⇒ every minted/hydrated task resolves no `handler` (the no-handler
3301
+ * rule — it auto-completes if driven).
3302
+ */
3303
+ export declare interface WorkflowManagerOptions {
3304
+ /**
3305
+ * The optional durable {@link WorkflowStoreInterface} backing
3306
+ * {@link WorkflowManagerInterface.open} / {@link WorkflowManagerInterface.save} — a memory
3307
+ * / JSON / SQLite / IndexedDB store a workflow is HYDRATED from (`open` a registry miss)
3308
+ * and PERSISTED to (`save`). Omitted ⇒ the manager is registry-only: `open` resolves only
3309
+ * what is already registered, and `save` is a no-op (`false`).
3310
+ */
3311
+ readonly store?: WorkflowStoreInterface;
3312
+ /**
3313
+ * The {@link WorkflowFunctions} registry threaded into every workflow this manager mints
3314
+ * (`add`, via {@link import('./factories.js').createWorkflow}) or hydrates (`open`'s
3315
+ * registry-miss path, via {@link import('./factories.js').restoreWorkflow}) — so a
3316
+ * hydrated workflow is RUNNABLE, its tasks carrying real resolved `handler`s. Omitted ⇒
3317
+ * every task resolves no `handler` (the no-handler rule).
3318
+ */
3319
+ readonly functions?: WorkflowFunctions;
3320
+ }
3321
+
3591
3322
  /**
3592
3323
  * The runtime options for a {@link WorkflowInterface} — the construction bag the
3593
3324
  * live derived workflow state machine (W-b) carries, the root {@link createWorkflow}
@@ -3670,10 +3401,10 @@ export declare interface WorkflowResult {
3670
3401
  * {@link import('./types.js').TaskInterface.handler} ONCE at construction (build, restore,
3671
3402
  * or a live mint all resolve it identically, from {@link WorkflowOptions.functions}), so
3672
3403
  * dispatch is simply "invoke the task's own handler". Static tool / agent calling is an
3673
- * OPT-IN concern of `factories.ts`'s adapter factories ({@link import('./factories.js').createToolFunction},
3674
- * {@link import('./factories.js').createAgentFunction}) — plain {@link import('./types.js').WorkflowFunction}s a
3675
- * caller wires into {@link WorkflowOptions.functions} like any other behavior. This module
3676
- * never imports `@orkestrel/agent`.
3404
+ * OPT-IN concern of the `@orkestrel/tool` package's adapter factories plain
3405
+ * {@link import('./types.js').WorkflowFunction}s a caller wires into
3406
+ * {@link WorkflowOptions.functions} like any other behavior. This module never imports
3407
+ * any tool/agent package.
3677
3408
  * - **Two `execute` forms, one engine.** `execute(definition, options)` BUILDS the live tree
3678
3409
  * from a {@link WorkflowDefinition} (single source of truth for the `run` / `concurrency`
3679
3410
  * metadata); `execute(workflow, options)` DRIVES a caller-owned, ALREADY-BUILT
@@ -3910,9 +3641,8 @@ export declare interface WorkflowRunnerInterface {
3910
3641
  * The runner is a PURE engine — it carries no `functions` / `tools` / `agents` registry
3911
3642
  * (each live task already resolved its own handler at construction from
3912
3643
  * {@link WorkflowOptions.functions}); wiring a `function`-form task to a tool or an agent is
3913
- * an OPT-IN concern of `factories.ts`'s adapter factories
3914
- * ({@link import('./factories.js').createToolFunction}, {@link import('./factories.js').createAgentFunction}),
3915
- * which a caller composes into its OWN `functions` registry.
3644
+ * an OPT-IN concern of the `@orkestrel/tool` package's adapter factories, which a caller
3645
+ * composes into its OWN `functions` registry.
3916
3646
  * - `scheduler` — the {@link SchedulerInterface} that paces the tree (a cooperative
3917
3647
  * `yield` between phases). Omitted ⇒ the shipped cross-environment default
3918
3648
  * ({@link createScheduler}).
@@ -3957,8 +3687,8 @@ export declare interface WorkflowRunnerOptions {
3957
3687
  *
3958
3688
  * The engine itself carries NO nesting bookkeeping — the depth / cycle guard for a nested
3959
3689
  * `agent` → workflow-tool → workflow chain lives entirely in the OPT-IN adapter factories
3960
- * ({@link import('./factories.js').createAgentFunction}, {@link import('./factories.js').createWorkflowTool}),
3961
- * closed over their own `depth` / `ancestry`, never threaded through `execute`'s options.
3690
+ * shipped by `@orkestrel/tool`, closed over their own `depth` / `ancestry`, never threaded
3691
+ * through `execute`'s options.
3962
3692
  */
3963
3693
  export declare type WorkflowRunOptions = WorkflowOptions & {
3964
3694
  readonly signal?: AbortSignal;
@@ -4057,54 +3787,6 @@ export declare interface WorkflowSnapshotRow {
4057
3787
  */
4058
3788
  export declare type WorkflowStatus = LifecycleStatus;
4059
3789
 
4060
- /**
4061
- * One flat step — `{ name }` — the building block of a {@link WorkflowSteps} blob.
4062
- *
4063
- * @remarks
4064
- * `name` is the REGISTERED behavior name the step runs (it becomes the task's `run`,
4065
- * NOT a human label) — resolved against a workflow-level {@link WorkflowFunctions}
4066
- * registry at construction.
4067
- */
4068
- export declare interface WorkflowStep {
4069
- /** The registered behavior name this step runs (becomes the task's `run`). */
4070
- readonly name: string;
4071
- }
4072
-
4073
- /**
4074
- * The FLAT authoring blob `createWorkflowTool` advertises — `{ name?, steps }` — the
4075
- * simplest surface a small model can fill.
4076
- *
4077
- * @remarks
4078
- * Each {@link WorkflowStep} becomes a one-task phase, in order
4079
- * ({@link import('./helpers.js').expandSteps}); `name` is the optional workflow name
4080
- * (defaulted when omitted). The expanded tree is validated against the STRICT
4081
- * {@link import('./factories.js').createWorkflowContract} gate before running.
4082
- */
4083
- export declare interface WorkflowSteps {
4084
- readonly name?: string;
4085
- readonly steps: readonly WorkflowStep[];
4086
- }
4087
-
4088
- /**
4089
- * The FLAT authoring shape `createWorkflowTool` advertises as its `parameters` — the
4090
- * simplest surface a small model can fill: `{ name?, steps: [{ name }] }`.
4091
- *
4092
- * @remarks
4093
- * The deliberately-reduced surface (AGENTS §21): a flat ordered list of steps, each a
4094
- * `{ name }`. The tool EXPANDS it ({@link import('./helpers.js').expandSteps}) into a
4095
- * full {@link import('./types.js').WorkflowDefinition} — one one-task phase per step, in
4096
- * order — then validates against the STRICT
4097
- * {@link import('./factories.js').createWorkflowContract} gate. The full nested form is
4098
- * STILL accepted by the tool (it branches on the args' shape) and is documented as the
4099
- * advanced escape-hatch in the tool's description — but THIS is what `parameters` advertises.
4100
- */
4101
- export declare const workflowStepsShape: ObjectShape<{
4102
- name: OptionalShape<StringShape>;
4103
- steps: ArrayShape<ObjectShape<{
4104
- name: StringShape;
4105
- }>>;
4106
- }>;
4107
-
4108
3790
  /**
4109
3791
  * The durable persistence seam for a {@link WorkflowSnapshot} — three async primitives
4110
3792
  * (`get` / `set` / `delete`) keyed by a workflow id, the snapshot analogue of
@@ -4152,69 +3834,4 @@ export declare interface WorkflowStoreInterface {
4152
3834
  delete(id: string): Promise<void>;
4153
3835
  }
4154
3836
 
4155
- /**
4156
- * The ancestry identifier of a workflow run — `workflow:<id>`.
4157
- *
4158
- * @remarks
4159
- * The {@link import('./WorkflowRunner.js').WorkflowRunner}'s cycle guard records one of
4160
- * these per workflow in the current nested run chain (carried on
4161
- * {@link import('./types.js').WorkflowRunOptions.ancestry}). Tagging the bare id keeps a
4162
- * workflow id and an {@link agentTag} agent name in ONE namespaced set without collision,
4163
- * so re-entering a workflow OR an agent already in the chain is a single `includes` check.
4164
- *
4165
- * @param id - The workflow definition's `id`
4166
- * @returns The namespaced ancestry tag (`workflow:<id>`)
4167
- */
4168
- export declare function workflowTag(id: string): string;
4169
-
4170
- /**
4171
- * Options for {@link import('./factories.js').createWorkflowTool} — the depth + ancestry the
4172
- * wrapped {@link WorkflowDefinition} runs the NESTED workflow at when an LLM invokes the tool.
4173
- *
4174
- * @remarks
4175
- * This is the PROPAGATION carrier across the agent/tool boundary. A `Tool`'s handler receives
4176
- * ONLY the model-supplied `args` (no ambient context, no signal — see
4177
- * the `@orkestrel/agent` package's `ToolOptions`), so the run's position in the
4178
- * workflow→agent→workflow chain CANNOT be threaded through a tool call at runtime. Instead the
4179
- * runner CLOSES it over the tool at BIND time: when it dispatches an `agent` task at depth `D`
4180
- * with ancestry `A`, it builds the agent's workflow tool with `{ depth: D, ancestry: A }`, so
4181
- * the handler's closure carries them. On invocation the handler runs the nested workflow at
4182
- * `depth: D + 1` with `ancestry: A ∪ { workflow:<id> }` — bounded by
4183
- * {@link import('./constants.js').MAX_WORKFLOW_DEPTH} (an over-deep / cyclic nested run THROWS a
4184
- * typed `DEPTH` {@link import('./errors.js').WorkflowError}, which the `ToolManager` isolates into
4185
- * the tool result's top-level `error`, AGENTS §14).
4186
- *
4187
- * Both fields are OPTIONAL: a workflow tool built for a TOP-LEVEL caller (not by the runner's
4188
- * agent-task binding) omits them — its nested run starts the chain at depth `1` with the bare
4189
- * `workflow:<id>` ancestry.
4190
- */
4191
- export declare interface WorkflowToolOptions {
4192
- /** The depth the INVOKING agent runs at; the nested workflow runs at `depth + 1`. Default `0`. */
4193
- readonly depth?: number;
4194
- /** The ancestry of the invoking run; the nested run extends it with its own `workflow:<id>`. Default empty. */
4195
- readonly ancestry?: readonly string[];
4196
- }
4197
-
4198
- /**
4199
- * Summarize a terminal {@link WorkflowResult} into the PLAIN value a
4200
- * {@link import('./factories.js').createWorkflowTool} handler returns on success.
4201
- *
4202
- * @remarks
4203
- * This is the run summary the handler returns DIRECTLY — NOT a `ToolResult` (the future `@orkestrel/agent` package).
4204
- * The handler conforms to the universal tool-handler contract (AGENTS §14): it returns the plain value
4205
- * (and throws on failure), so the `@orkestrel/agent` package's `ToolManager` performs
4206
- * the ONE canonical wrap (`{ id, name, value }`) and the model reads exactly this summary — once,
4207
- * identically — over BOTH the agent loop and MCP. The summary is LEAN: the workflow's terminal `status`
4208
- * and the COUNT of settled task results — enough for a caller / model to react without serializing the
4209
- * whole live tree. (It carries no synthetic `id` / `name`: a tool handler has no call id; the manager
4210
- * supplies the canonical envelope's identity.)
4211
- *
4212
- * @param result - The terminal {@link WorkflowResult} the run produced
4213
- * @returns The plain success summary — `{ status, count }`
4214
- */
4215
- export declare function workflowToolSummary(result: WorkflowResult): Readonly<{
4216
- status: WorkflowStatus;
4217
- count: number;
4218
- }>;
4219
-
4220
3837
  export { }