@orkestrel/workflow 0.0.17 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -3
- package/dist/src/browser/index.d.ts +16 -12
- package/dist/src/browser/index.js +13 -9
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/core/index.cjs +267 -230
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +657 -547
- package/dist/src/core/index.d.ts +657 -547
- package/dist/src/core/index.js +267 -230
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +5 -3
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +7 -5
- package/dist/src/server/index.d.ts +7 -5
- package/dist/src/server/index.js +5 -3
- package/dist/src/server/index.js.map +1 -1
- package/package.json +20 -21
package/dist/src/core/index.d.ts
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
import { ArrayShape } from '@orkestrel/contract';
|
|
2
|
-
import { BudgetInterface } from '@orkestrel/budget';
|
|
3
|
-
import { ContractInterface } from '@orkestrel/contract';
|
|
4
|
-
import { DriverInterface } from '@orkestrel/database';
|
|
5
|
-
import { EmitterErrorHandler } from '@orkestrel/emitter';
|
|
6
|
-
import { EmitterHooks } from '@orkestrel/emitter';
|
|
7
|
-
import { EmitterInterface } from '@orkestrel/emitter';
|
|
8
|
-
import { Failure } from '@orkestrel/contract';
|
|
9
|
-
import { Guard } from '@orkestrel/contract';
|
|
10
|
-
import { JSONRecord } from '@orkestrel/contract';
|
|
11
|
-
import { JSONValue } from '@orkestrel/contract';
|
|
2
|
+
import type { BudgetInterface } from '@orkestrel/budget';
|
|
3
|
+
import type { ContractInterface } from '@orkestrel/contract';
|
|
4
|
+
import type { DriverInterface } from '@orkestrel/database';
|
|
5
|
+
import type { EmitterErrorHandler } from '@orkestrel/emitter';
|
|
6
|
+
import type { EmitterHooks } from '@orkestrel/emitter';
|
|
7
|
+
import type { EmitterInterface } from '@orkestrel/emitter';
|
|
8
|
+
import type { Failure } from '@orkestrel/contract';
|
|
9
|
+
import type { Guard } from '@orkestrel/contract';
|
|
10
|
+
import type { JSONRecord } from '@orkestrel/contract';
|
|
11
|
+
import type { JSONValue } from '@orkestrel/contract';
|
|
12
12
|
import { LiteralShape } from '@orkestrel/contract';
|
|
13
13
|
import { NumberShape } from '@orkestrel/contract';
|
|
14
14
|
import { ObjectShape } from '@orkestrel/contract';
|
|
15
15
|
import { OptionalShape } from '@orkestrel/contract';
|
|
16
|
-
import { Result } from '@orkestrel/contract';
|
|
16
|
+
import type { Result } from '@orkestrel/contract';
|
|
17
17
|
import { StringShape } from '@orkestrel/contract';
|
|
18
|
-
import { Success } from '@orkestrel/contract';
|
|
19
|
-
import { TableInterface } from '@orkestrel/database';
|
|
20
|
-
import { TokenUsage } from '@orkestrel/budget';
|
|
18
|
+
import type { Success } from '@orkestrel/contract';
|
|
19
|
+
import type { TableInterface } from '@orkestrel/database';
|
|
20
|
+
import type { TokenUsage } from '@orkestrel/budget';
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Names how one task attempt left the race between its handler and its cancellation.
|
|
24
24
|
*
|
|
25
25
|
* @remarks
|
|
26
26
|
* The engine races a dispatched {@link WorkflowFunction} against the attempt's folded signal, so
|
|
27
|
-
* the attempt either
|
|
27
|
+
* the attempt either settled with the handler's JSON value or did not settle at all. A tuple, not
|
|
28
28
|
* a {@link Result}: the unsettled branch is a cancellation rather than an error, so there is no
|
|
29
29
|
* error to carry, and `genuine` records what the cancellation was — `true` for a genuine cancel
|
|
30
30
|
* (a run-level bound, a task `stop` / `skip`, or a sibling fail-fast, all of which skip the leaf),
|
|
@@ -38,7 +38,7 @@ export declare type AttemptOutcome = readonly [settled: true, value: JSONValue]
|
|
|
38
38
|
* Builds a {@link PhaseContext} — a phase's own identity plus a back-reference to its
|
|
39
39
|
* workflow — from the parent {@link WorkflowContext} and the phase node's identity.
|
|
40
40
|
*
|
|
41
|
-
* @param workflow - The parent workflow context (the lineage pointer
|
|
41
|
+
* @param workflow - The parent workflow context (the lineage pointer up the tree)
|
|
42
42
|
* @param node - The phase's identity (`id` / `name` / optional `description`)
|
|
43
43
|
* @returns The {@link PhaseContext}
|
|
44
44
|
*/
|
|
@@ -49,7 +49,7 @@ export declare function buildPhaseContext(workflow: WorkflowContext, node: Workf
|
|
|
49
49
|
* (and, transitively, its workflow) — from the parent {@link PhaseContext} and the task
|
|
50
50
|
* node's identity.
|
|
51
51
|
*
|
|
52
|
-
* @param phase - The parent phase context (carrying the full lineage
|
|
52
|
+
* @param phase - The parent phase context (carrying the full lineage up the tree)
|
|
53
53
|
* @param node - The task's identity (`id` / `name` / optional `description`)
|
|
54
54
|
* @returns The {@link TaskContext}
|
|
55
55
|
*/
|
|
@@ -169,9 +169,9 @@ export declare function cloneWorkflowSnapshot(input: unknown, id?: string): Work
|
|
|
169
169
|
* (`task` / `tasks`, `phase` / `phases`). The `Map`'s insertion order is the single source of
|
|
170
170
|
* positional truth; `add` and `move` rebuild it through the pure
|
|
171
171
|
* {@link import('./helpers.js').insertEntry} / {@link import('./helpers.js').moveEntry} leaves.
|
|
172
|
-
* - **Gated mutation API.** `append` is the build-time wiring path and
|
|
172
|
+
* - **Gated mutation API.** `append` is the build-time wiring path and throws on a
|
|
173
173
|
* duplicate id; `add` / `remove` / `move` / `update` return a graceful `MUTATION`
|
|
174
|
-
* {@link WorkflowError} failure instead. Gating reads
|
|
174
|
+
* {@link WorkflowError} failure instead. Gating reads only the target's own existence, `pending`
|
|
175
175
|
* status, id, and bounds — a container's own status is the owning entity's gate, applied before
|
|
176
176
|
* it delegates here.
|
|
177
177
|
* - **Event-free.** A purely structural container; the entity that owns it emits on success.
|
|
@@ -232,12 +232,12 @@ export declare interface CollectionEntry<TPatch> {
|
|
|
232
232
|
* mutation quartet a lean manager delegates to.
|
|
233
233
|
*
|
|
234
234
|
* @remarks
|
|
235
|
-
* The
|
|
235
|
+
* The one engine behind {@link TaskManagerInterface} and {@link PhaseManagerInterface}: positional
|
|
236
236
|
* order is the backing `Map`'s insertion order, so it survives an interior `skip` (a status
|
|
237
237
|
* change, never a removal) and a snapshot restore reproduces it by re-`append`ing in order.
|
|
238
|
-
* `append` is the build-time wiring path and
|
|
238
|
+
* `append` is the build-time wiring path and throws a `MUTATION`
|
|
239
239
|
* {@link import('./errors.js').WorkflowError} on a duplicate id (a genuine programmer error);
|
|
240
|
-
* `add` / `remove` / `move` / `update` are its graceful `Result` counterparts, gating
|
|
240
|
+
* `add` / `remove` / `move` / `update` are its graceful `Result` counterparts, gating only on the
|
|
241
241
|
* target's own existence, `pending` status, id, and bounds. The store is event-free — the entity
|
|
242
242
|
* that owns it emits on success. Each refusal names the entity noun the store was built with, so
|
|
243
243
|
* a task store and a phase store report in their own vocabulary.
|
|
@@ -251,7 +251,7 @@ export declare interface CollectionInterface<TEntry, TPatch> {
|
|
|
251
251
|
* Adds `entry` at the end — the build-time wiring path.
|
|
252
252
|
*
|
|
253
253
|
* @remarks
|
|
254
|
-
*
|
|
254
|
+
* throws a `MUTATION` {@link import('./errors.js').WorkflowError} on a duplicate `id` instead
|
|
255
255
|
* of silently overwriting the existing entry.
|
|
256
256
|
*
|
|
257
257
|
* @param entry - The entity to append
|
|
@@ -332,7 +332,7 @@ export declare function collectResults(phases: ReadonlyArray<readonly TaskResult
|
|
|
332
332
|
* - `input` — the unit's work payload.
|
|
333
333
|
* - `signal` — the unit's cancellation: fires on the unit's own `abort()`, a
|
|
334
334
|
* runner-level `abort` (the runner aborts every unit), or this attempt's timeout
|
|
335
|
-
* expiring (it reflects the underlying queue attempt's signal, which
|
|
335
|
+
* expiring (it reflects the underlying queue attempt's signal, which any-combines
|
|
336
336
|
* all three).
|
|
337
337
|
* - `aborted` — whether the unit's cancellation has fired.
|
|
338
338
|
*
|
|
@@ -346,7 +346,7 @@ export declare interface ControllerInterface<TInput, TResult> {
|
|
|
346
346
|
readonly signal: AbortSignal;
|
|
347
347
|
readonly aborted: boolean;
|
|
348
348
|
/**
|
|
349
|
-
* Parks until this unit's `signal` aborts —
|
|
349
|
+
* Parks until this unit's `signal` aborts — a promise-parked wait, never a timer.
|
|
350
350
|
*
|
|
351
351
|
* @remarks
|
|
352
352
|
* Resolves the moment the unit's `signal` fires (unit abort, runner abort, or
|
|
@@ -365,10 +365,10 @@ export declare interface ControllerInterface<TInput, TResult> {
|
|
|
365
365
|
* as every declared unit, so it actually runs (in FIFO wake order) and its result
|
|
366
366
|
* joins the run's ordered output after the declared units, in spawn order. The
|
|
367
367
|
* runner's `execute` awaits the full transitive spawn closure (it tracks an
|
|
368
|
-
* outstanding-unit count, not a one-time snapshot), so a caller does
|
|
368
|
+
* outstanding-unit count, not a one-time snapshot), so a caller does not need to
|
|
369
369
|
* await the returned promise to make the sibling run.
|
|
370
370
|
*
|
|
371
|
-
* **Deadlock caveat.** On a bounded-`concurrency` runner, do
|
|
371
|
+
* **Deadlock caveat.** On a bounded-`concurrency` runner, do not `await` a
|
|
372
372
|
* `spawn`ed promise *inline* from within a handler — the handler holds a queue
|
|
373
373
|
* slot while it awaits, and if every slot is held by a handler awaiting its own
|
|
374
374
|
* spawn, no slot is free to run the spawns and the run deadlocks. The intended
|
|
@@ -389,22 +389,22 @@ export declare interface ControllerInterface<TInput, TResult> {
|
|
|
389
389
|
/**
|
|
390
390
|
* Creates a {@link DatabaseWorkflowStore} over any {@link DriverInterface} — the durable,
|
|
391
391
|
* driver-pluggable backing for the W-d persistence seam, the opt-in twin of
|
|
392
|
-
* {@link createMemoryWorkflowStore}.
|
|
392
|
+
* {@link createMemoryWorkflowStore}. It holds the snapshot as one opaque JSON column, and its
|
|
393
|
+
* `driver` defaults to memory, so it works before any durable driver is passed.
|
|
393
394
|
*
|
|
394
395
|
* @remarks
|
|
395
|
-
* Builds a one-table database (`snapshots`, keyed by `id`) over the supplied driver
|
|
396
|
-
*
|
|
396
|
+
* Builds a one-table database (`snapshots`, keyed by `id`) over the supplied driver. The column map
|
|
397
|
+
* is `{ id; snapshot }` where `snapshot` is a
|
|
397
398
|
* `rawShape` (a JSON blob), exactly as `createDatabaseQueueStore` stores its `input`. The
|
|
398
|
-
* snapshot is already a
|
|
399
|
-
*
|
|
399
|
+
* snapshot is already a complete, self-contained, pure-JSON payload, so storing it whole is lossless
|
|
400
|
+
* and keeps the row type flat — a structured multi-column snapshot table would force the contract to
|
|
400
401
|
* `Infer` the deeply-nested snapshot shape (workflow → phases → tasks → results) and trip TS2589;
|
|
401
402
|
* the opaque column sidesteps it (the column reads back as `unknown`, owned and narrowed on `get` by
|
|
402
403
|
* {@link cloneWorkflowSnapshot}, whose semantic pass is
|
|
403
|
-
* {@link import('./validators.js').isOwnedWorkflowSnapshot}).
|
|
404
|
-
*
|
|
405
|
-
* `createJSONDriver` / `createSQLiteDriver` (or a browser IndexedDB driver) for a persistent one —
|
|
404
|
+
* {@link import('./validators.js').isOwnedWorkflowSnapshot}). Pass a server `createJSONDriver` /
|
|
405
|
+
* `createSQLiteDriver` (or a browser IndexedDB driver) for a persistent one —
|
|
406
406
|
* the durability is the driver's job, the store engine is shared. It swaps in behind
|
|
407
|
-
* {@link WorkflowStoreInterface}
|
|
407
|
+
* {@link WorkflowStoreInterface} without touching the runner or the entity tree.
|
|
408
408
|
*
|
|
409
409
|
* @param driver - The storage backend the snapshots persist to (defaults to {@link createMemoryDriver})
|
|
410
410
|
* @returns A {@link WorkflowStoreInterface} over the driver
|
|
@@ -425,18 +425,17 @@ export declare function createDatabaseWorkflowStore(driver?: DriverInterface): W
|
|
|
425
425
|
|
|
426
426
|
/**
|
|
427
427
|
* Creates the in-memory durable {@link WorkflowStoreInterface} — a process-lifetime
|
|
428
|
-
* {@link MemoryWorkflowStore} persisting {@link WorkflowSnapshot}s by workflow id, the
|
|
429
|
-
* backend behind the W-d persistence seam.
|
|
428
|
+
* {@link MemoryWorkflowStore} persisting {@link WorkflowSnapshot}s by workflow id, the default
|
|
429
|
+
* backend behind the W-d persistence seam. It takes no options and expires nothing: a
|
|
430
|
+
* persisted run state lives until an explicit `delete`.
|
|
430
431
|
*
|
|
431
432
|
* @remarks
|
|
432
433
|
* The snapshot analogue of the server package's `createMemorySessionStore`
|
|
433
|
-
* (and the `createMemoryQueueStore` family)
|
|
434
|
-
*
|
|
435
|
-
* an explicit `delete`. This is
|
|
436
|
-
* the zero-plumbing DEFAULT (a plain `Map`); its driver-pluggable twin is
|
|
434
|
+
* (and the `createMemoryQueueStore` family) is the zero-plumbing default (a plain `Map`); its
|
|
435
|
+
* driver-pluggable twin is
|
|
437
436
|
* {@link createDatabaseWorkflowStore} (the snapshot as one opaque JSON column over a `databases`
|
|
438
|
-
* table) — for a
|
|
439
|
-
* driver, and it swaps in
|
|
437
|
+
* table) — for a durable store (run-state surviving a restart) pass it a JSON / SQLite / IndexedDB
|
|
438
|
+
* driver, and it swaps in without touching the runner or the entity tree. Restore stays a caller
|
|
440
439
|
* concern: read a snapshot back and rebuild the live tree with {@link createRestoredWorkflow}.
|
|
441
440
|
*
|
|
442
441
|
* @returns A memory-backed {@link WorkflowStoreInterface}
|
|
@@ -455,7 +454,8 @@ export declare function createDatabaseWorkflowStore(driver?: DriverInterface): W
|
|
|
455
454
|
export declare function createMemoryWorkflowStore(): WorkflowStoreInterface;
|
|
456
455
|
|
|
457
456
|
/**
|
|
458
|
-
* Builds an interrupted workflow back to life at its remaining retry budget
|
|
457
|
+
* Builds an interrupted workflow back to life at its remaining retry budget, normalizing a
|
|
458
|
+
* leaf whose attempts are exhausted into a recovery failure.
|
|
459
459
|
*
|
|
460
460
|
* @remarks
|
|
461
461
|
* Each phase captures every unique initial `behavior` binding once before constructing tasks. Recovery
|
|
@@ -483,11 +483,11 @@ export declare function createRecoveredWorkflow(snapshot: unknown, options?: Wor
|
|
|
483
483
|
*
|
|
484
484
|
* @remarks
|
|
485
485
|
* Round-trip fidelity is paramount: a `snapshot()` → `createRestoredWorkflow()` reproduces the
|
|
486
|
-
* same status at every node (each `#override` restored
|
|
486
|
+
* same status at every node (each `#override` restored directly from the snapshot's own
|
|
487
487
|
* `override` field, not guessed from a status divergence), the same recorded
|
|
488
488
|
* {@link import('./types.js').TaskResult}s, and the same positional order (an interior
|
|
489
|
-
* `skip` / `remove` survives). The snapshot is
|
|
490
|
-
* policy it ran under, so the restore re-derives status
|
|
489
|
+
* `skip` / `remove` survives). The snapshot is self-contained — it persists the `bail`
|
|
490
|
+
* policy it ran under, so the restore re-derives status identically without a silent
|
|
491
491
|
* default; the snapshot's `bail` is the source of truth, while an explicit `options.bail`
|
|
492
492
|
* still wins when supplied (to deliberately re-run under a different policy). A structurally
|
|
493
493
|
* invalid snapshot (a status — or override — outside the lifecycle vocabulary, or a
|
|
@@ -512,12 +512,13 @@ export declare function createRestoredWorkflow(snapshot: unknown, options?: Work
|
|
|
512
512
|
|
|
513
513
|
/**
|
|
514
514
|
* Creates a thin generic orchestrator that drives declared units — and any they
|
|
515
|
-
* `spawn` — through a bounded-concurrency queue, collecting their results in order
|
|
515
|
+
* `spawn` — through a bounded-concurrency queue, collecting their results in order and
|
|
516
|
+
* failing the run fast on the first genuine unit failure.
|
|
516
517
|
*
|
|
517
518
|
* @remarks
|
|
518
519
|
* The Runner composes the workers `Queue` for backpressure, FIFO ordering, bounded
|
|
519
520
|
* concurrency, retries, and the per-attempt timeout — it adds only orchestration, not
|
|
520
|
-
* a second concurrency engine. `execute(inputs)` runs the unit set
|
|
521
|
+
* a second concurrency engine. `execute(inputs)` runs the unit set once (a second call
|
|
521
522
|
* throws) and resolves the units' results in order: the declared inputs first, then
|
|
522
523
|
* any `spawn`ed siblings in spawn order. Each unit's handler gets a `Controller` — its
|
|
523
524
|
* `id` / `input`, a `signal` that fires on the unit's `abort`, a runner-level `abort`,
|
|
@@ -527,8 +528,8 @@ export declare function createRestoredWorkflow(snapshot: unknown, options?: Work
|
|
|
527
528
|
* typed `emitter` surfaces `start` / `unit` / `spawn` / `settle` / `fail` / `finish` / `abort`.
|
|
528
529
|
*
|
|
529
530
|
* Because `spawn` is fire-and-track (the runner awaits the whole spawn closure through an
|
|
530
|
-
* outstanding-unit count, not a one-time snapshot), a handler need
|
|
531
|
-
* for them to run — and on a bounded runner do
|
|
531
|
+
* outstanding-unit count, not a one-time snapshot), a handler need not await its spawns
|
|
532
|
+
* for them to run — and on a bounded runner do not `await` a spawn inline (a slot-holding
|
|
532
533
|
* handler awaiting its own spawn can deadlock); fan out and return instead.
|
|
533
534
|
*
|
|
534
535
|
* @typeParam TInput - The work input each unit carries
|
|
@@ -605,20 +606,20 @@ export declare function createScheduler(): SchedulerInterface;
|
|
|
605
606
|
* Builds the live W-b entity tree from a {@link WorkflowDefinition} — the whole
|
|
606
607
|
* {@link WorkflowInterface} → {@link import('./types.js').PhaseInterface} →
|
|
607
608
|
* {@link import('./types.js').TaskInterface} tree, each level wired with its lineage
|
|
608
|
-
* context, its emitter, and the cascade
|
|
609
|
+
* context, its emitter, and the cascade, and every node born `pending`.
|
|
609
610
|
*
|
|
610
611
|
* @remarks
|
|
611
|
-
* The definition is the
|
|
612
|
+
* The definition is the declarative blueprint; this seeds an initial all-`pending`
|
|
612
613
|
* {@link WorkflowSnapshot} from it ({@link definitionToSnapshot}) and constructs the live
|
|
613
614
|
* tree over that one path. The `bail` failure policy resolves to `options.bail`, else the
|
|
614
615
|
* definition's `bail`, else the graceful {@link import('./constants.js').DEFAULT_BAIL}; it
|
|
615
616
|
* feeds {@link import('./helpers.js').deriveWorkflowStatus}. Per-phase / per-task initial
|
|
616
617
|
* listeners + metadata travel through `options.phases[id].on` /
|
|
617
618
|
* `options.phases[id].tasks[id]` (the nested-by-id bag). The W-b tree is the
|
|
618
|
-
* state machine
|
|
619
|
+
* state machine only — it does not execute tasks (W-c drives the transitions).
|
|
619
620
|
*
|
|
620
621
|
* `options.functions` is the {@link import('./types.js').WorkflowRegistry} registry each live
|
|
621
|
-
* task's `behavior` name resolves against
|
|
622
|
+
* task's `behavior` name resolves against once at construction into its runtime
|
|
622
623
|
* {@link import('./types.js').TaskInterface.handler}. An omitted name is the deliberate no-op;
|
|
623
624
|
* an unresolved present name remains inspectable but is rejected if execution is attempted.
|
|
624
625
|
*
|
|
@@ -669,15 +670,17 @@ export declare function createWorkflowContract(): ContractInterface<WorkflowDefi
|
|
|
669
670
|
/**
|
|
670
671
|
* Creates a {@link WorkflowManagerInterface} — the store-backed registry of
|
|
671
672
|
* {@link WorkflowInterface}s, the additive manager tier mirroring the `@orkestrel/agent`
|
|
672
|
-
* line's `createConversationManager` / `createWorkspaceManager`.
|
|
673
|
+
* line's `createConversationManager` / `createWorkspaceManager`. The returned registry makes
|
|
674
|
+
* hydrated named work runnable when `options.functions` is supplied, and leaves it
|
|
675
|
+
* inspectable when it is not.
|
|
673
676
|
*
|
|
674
677
|
* @remarks
|
|
675
678
|
* `options.functions` flows into every workflow the manager mints (`add`, through
|
|
676
679
|
* {@link createWorkflow}) or hydrates (`open`'s registry-miss path, through
|
|
677
|
-
* {@link createRestoredWorkflow}), so a hydrated workflow is
|
|
678
|
-
* mirror. `options.store` is the
|
|
680
|
+
* {@link createRestoredWorkflow}), so a hydrated workflow is runnable rather than a dead snapshot
|
|
681
|
+
* mirror. `options.store` is the exact analogue of the twins' `store` seam — omitted ⇒ the
|
|
679
682
|
* manager is registry-only (`open` resolves only what is registered, `save` is a no-op). This
|
|
680
|
-
* is
|
|
683
|
+
* is purely additive: direct {@link WorkflowStoreInterface} use and
|
|
681
684
|
* {@link createRestoredWorkflow} remain valid — the manager is one more caller-driven persistence
|
|
682
685
|
* seam, not a replacement.
|
|
683
686
|
*
|
|
@@ -692,7 +695,7 @@ export declare function createWorkflowContract(): ContractInterface<WorkflowDefi
|
|
|
692
695
|
* store: createMemoryWorkflowStore(),
|
|
693
696
|
* functions: { compile: async (controller) => `built ${controller.task.id}` },
|
|
694
697
|
* })
|
|
695
|
-
* const workflow = manager.add(definition) // minted, registered,
|
|
698
|
+
* const workflow = manager.add(definition) // minted, registered, runnable
|
|
696
699
|
* await manager.save(workflow.id) // persisted to the store
|
|
697
700
|
* const reopened = await manager.open(workflow.id) // already registered — no store hit
|
|
698
701
|
* ```
|
|
@@ -700,22 +703,22 @@ export declare function createWorkflowContract(): ContractInterface<WorkflowDefi
|
|
|
700
703
|
export declare function createWorkflowManager(options?: WorkflowManagerOptions): WorkflowManagerInterface;
|
|
701
704
|
|
|
702
705
|
/**
|
|
703
|
-
* Creates the thin orchestrator — a {@link WorkflowRunnerInterface} — that
|
|
704
|
-
* workflow tree by
|
|
705
|
-
* task dispatched through its
|
|
706
|
+
* Creates the thin orchestrator — a {@link WorkflowRunnerInterface} — that executes a live W-b
|
|
707
|
+
* workflow tree by composing the shipped substrate: phases sequential, tasks concurrent, each
|
|
708
|
+
* task dispatched through its own resolved handler under the workflow's `bail` policy. The
|
|
709
|
+
* engine is pure — it carries no behavior or provider registry, and its only option is the
|
|
710
|
+
* scheduler it paces phase boundaries with.
|
|
706
711
|
*
|
|
707
712
|
* @remarks
|
|
708
|
-
*
|
|
709
|
-
*
|
|
710
|
-
* resolved its own {@link import('./types.js').WorkflowFunction} into
|
|
711
|
-
* {@link import('./types.js').TaskInterface.handler} ONCE at construction, from the
|
|
713
|
+
* Each live task already resolved its own {@link import('./types.js').WorkflowFunction} into
|
|
714
|
+
* {@link import('./types.js').TaskInterface.handler} once at construction, from the
|
|
712
715
|
* {@link WorkflowOptions.functions} registry supplied to `execute` / {@link createWorkflow}.
|
|
713
716
|
* Per-phase bounded concurrency is one {@link createRunner} per phase; `bail` maps onto that
|
|
714
717
|
* Runner's fail-fast (`true` — the first failure aborts the in-flight siblings + skips the
|
|
715
718
|
* rest) vs settle-all (`false` — failures are recorded, the run finishes); the run-level abort
|
|
716
719
|
* / timeout / budget ({@link import('./types.js').WorkflowRunOptions}) fold through
|
|
717
720
|
* `AbortSignal.any` (the agent runtime's pattern); pacing is the shipped scheduler.
|
|
718
|
-
* `execute(definition, options?)`
|
|
721
|
+
* `execute(definition, options?)` builds the live tree from the definition itself (through
|
|
719
722
|
* {@link createWorkflow} — one source of truth, returned in `WorkflowResult.workflow`), drives
|
|
720
723
|
* the live entity (`start` → `complete` / `fail`), and resolves a
|
|
721
724
|
* {@link import('./types.js').WorkflowResult}.
|
|
@@ -729,19 +732,43 @@ export declare function createWorkflowManager(options?: WorkflowManagerOptions):
|
|
|
729
732
|
* See {@link WorkflowRunnerOptions}.
|
|
730
733
|
* @returns A working {@link WorkflowRunnerInterface}
|
|
731
734
|
*
|
|
732
|
-
* @example
|
|
735
|
+
* @example Author a definition and run it
|
|
733
736
|
* ```ts
|
|
734
737
|
* import { createWorkflowRunner } from '@orkestrel/workflow'
|
|
738
|
+
* import type { WorkflowDefinition } from '@orkestrel/workflow'
|
|
739
|
+
*
|
|
740
|
+
* const definition: WorkflowDefinition = {
|
|
741
|
+
* id: 'release',
|
|
742
|
+
* name: 'Release',
|
|
743
|
+
* phases: [
|
|
744
|
+
* {
|
|
745
|
+
* id: 'build',
|
|
746
|
+
* name: 'Build',
|
|
747
|
+
* tasks: [
|
|
748
|
+
* { id: 'compile', name: 'Compile', behavior: 'compile' },
|
|
749
|
+
* { id: 'lint', name: 'Lint', behavior: 'lint' },
|
|
750
|
+
* ],
|
|
751
|
+
* },
|
|
752
|
+
* {
|
|
753
|
+
* id: 'ship',
|
|
754
|
+
* name: 'Ship',
|
|
755
|
+
* tasks: [{ id: 'publish', name: 'Publish', behavior: 'publish' }],
|
|
756
|
+
* },
|
|
757
|
+
* ],
|
|
758
|
+
* }
|
|
759
|
+
*
|
|
760
|
+
* const runner = createWorkflowRunner() // a pure engine — no registries
|
|
735
761
|
*
|
|
736
|
-
* const runner = createWorkflowRunner()
|
|
737
|
-
* const definition = { id: 'w', name: 'W', phases: [{ id: 'p', name: 'P', tasks: [
|
|
738
|
-
* { id: 't', name: 'T', behavior: 'compile' },
|
|
739
|
-
* ] }] }
|
|
740
762
|
* const result = await runner.execute(definition, {
|
|
741
|
-
* functions: {
|
|
763
|
+
* functions: {
|
|
764
|
+
* compile: async (controller) => `built ${controller.task.id}`,
|
|
765
|
+
* lint: async () => 'clean',
|
|
766
|
+
* publish: async () => 'published',
|
|
767
|
+
* },
|
|
742
768
|
* })
|
|
743
769
|
* result.status // 'completed'
|
|
744
|
-
* result.workflow.phase('
|
|
770
|
+
* result.workflow.phase('build')?.task('compile')?.status // 'completed'
|
|
771
|
+
* result.results // every settled task's TaskResult, in positional order
|
|
745
772
|
* ```
|
|
746
773
|
*/
|
|
747
774
|
export declare function createWorkflowRunner(options?: WorkflowRunnerOptions): WorkflowRunnerInterface;
|
|
@@ -753,14 +780,14 @@ export declare function createWorkflowRunner(options?: WorkflowRunnerOptions): W
|
|
|
753
780
|
* @remarks
|
|
754
781
|
* Seeds an initial all-`pending` {@link WorkflowSnapshot} from the definition and constructs the
|
|
755
782
|
* live {@link WorkflowInterface} over it. `bail` is the caller's own override, forwarded to
|
|
756
|
-
* {@link definitionToSnapshot} so it reaches
|
|
783
|
+
* {@link definitionToSnapshot} so it reaches both tiers: the workflow snapshot and the inheritance
|
|
757
784
|
* default of every phase that declares no `bail` of its own, while a phase declaring one still
|
|
758
785
|
* wins. Omitted, the definition's own `bail` governs, defaulting to the graceful
|
|
759
786
|
* {@link import('./constants.js').DEFAULT_BAIL}.
|
|
760
787
|
*
|
|
761
|
-
* `captured` is forwarded to the entity
|
|
788
|
+
* `captured` is forwarded to the entity unchanged — its own `bail` is deliberately not replaced
|
|
762
789
|
* with the resolved policy, because the snapshot already carries the resolved value at both tiers
|
|
763
|
-
* and an injected one would make `Workflow` read it as an
|
|
790
|
+
* and an injected one would make `Workflow` read it as an explicit uniform override and clobber
|
|
764
791
|
* the per-phase overrides. Each task's `behavior` / `retries` / `timeout` travel onto the snapshot
|
|
765
792
|
* too, so `captured.functions` resolves every handler identically whether the tree is built fresh
|
|
766
793
|
* or restored. Pass a bag {@link captureWorkflowOptions} already owns: this constructs over it
|
|
@@ -784,28 +811,28 @@ export declare function createWorkflowTree(definition: WorkflowDefinition, captu
|
|
|
784
811
|
|
|
785
812
|
/**
|
|
786
813
|
* Implements a {@link WorkflowStoreInterface} backed by one table of the `databases` layer — a
|
|
787
|
-
* workflow's durable run
|
|
814
|
+
* workflow's durable run state is a row, so persistence reduces to keyed point-access
|
|
788
815
|
* (`get` / `set` / `delete`) over a `TableInterface`, the driver-pluggable twin of the
|
|
789
816
|
* plain-`Map` {@link import('./MemoryWorkflowStore.js').MemoryWorkflowStore}.
|
|
790
817
|
*
|
|
791
818
|
* @remarks
|
|
792
819
|
* The store is driver-agnostic: it holds a single {@link TableInterface} whose backend
|
|
793
820
|
* (memory, JSON, SQLite, IndexedDB) is chosen by whoever builds it (the factories), so a
|
|
794
|
-
* JSON / SQLite / IndexedDB backend swaps in
|
|
821
|
+
* JSON / SQLite / IndexedDB backend swaps in without touching the runner or the entity tree
|
|
795
822
|
* — the same seam as `@orkestrel/queue`'s `DatabaseQueueStore`.
|
|
796
823
|
* The driver defaults to memory ({@link import('../factories.js').createDatabaseWorkflowStore}
|
|
797
|
-
* passes `createMemoryDriver()`), so it
|
|
824
|
+
* passes `createMemoryDriver()`), so it also works in memory out of the box; you opt into the
|
|
798
825
|
* durable plumbing by passing a JSON / SQLite / IndexedDB driver.
|
|
799
826
|
*
|
|
800
|
-
* The {@link WorkflowSnapshot} is stored as
|
|
827
|
+
* The {@link WorkflowSnapshot} is stored as one opaque JSON column — the table is a row of
|
|
801
828
|
* `{ id; snapshot }` ({@link WorkflowSnapshotRow}), the snapshot the whole JSON blob (a `rawShape`
|
|
802
829
|
* column the factory builds) — exactly as `DatabaseQueueStore` stores its `input`. The snapshot is
|
|
803
|
-
* already a
|
|
830
|
+
* already a complete, self-contained, pure-JSON payload, so storing it whole is lossless and
|
|
804
831
|
* sidesteps a TS2589 instantiation-depth blow-up: a structured multi-column table would force the
|
|
805
832
|
* contract to `Infer` the deeply-nested snapshot shape (workflow → phases → tasks → results),
|
|
806
833
|
* tripping the compiler — one JSON column keeps the row type flat (`snapshot` reads back as `unknown`).
|
|
807
834
|
*
|
|
808
|
-
* - **`set(snapshot)` upserts under the snapshot's
|
|
835
|
+
* - **`set(snapshot)` upserts under the snapshot's own `id`** (no separate id param) — it writes
|
|
809
836
|
* the row `{ id: snapshot.id, snapshot }`.
|
|
810
837
|
* - **`get(id)` resolves the stored snapshot for an id**, owning and narrowing the opaque JSON
|
|
811
838
|
* column back to a {@link WorkflowSnapshot} through
|
|
@@ -815,9 +842,9 @@ export declare function createWorkflowTree(definition: WorkflowDefinition, captu
|
|
|
815
842
|
* differs from the requested key rejects with normalized `RESTORE` evidence.
|
|
816
843
|
* - **`delete(id)` drops a snapshot by id**; an absent id is a no-op (no throw).
|
|
817
844
|
*
|
|
818
|
-
*
|
|
845
|
+
* unlike the server package's `SessionStoreInterface` there is no
|
|
819
846
|
* idle-TTL / eviction — a persisted run-state is durable orchestration state that lives until an
|
|
820
|
-
* explicit `delete`. The public surface is
|
|
847
|
+
* explicit `delete`. The public surface is exactly `get` / `set` / `delete` — no extra members (the
|
|
821
848
|
* guide's method bijection with {@link WorkflowStoreInterface}). Restore stays a caller concern: read a
|
|
822
849
|
* snapshot back and rebuild the live tree with {@link import('../factories.js').createRestoredWorkflow}.
|
|
823
850
|
*
|
|
@@ -845,40 +872,43 @@ export declare class DatabaseWorkflowStore implements WorkflowStoreInterface {
|
|
|
845
872
|
constructor(table: TableInterface<WorkflowSnapshotRow>);
|
|
846
873
|
/** Resolves and key-checks the snapshot for `id`, narrowing the opaque column to `WorkflowSnapshot`. */
|
|
847
874
|
get(id: string): Promise<WorkflowSnapshot | undefined>;
|
|
848
|
-
/** Inserts or replaces under the snapshot's
|
|
875
|
+
/** Inserts or replaces under the snapshot's own `id` (no separate id param) — the row is `{ id, snapshot }`. */
|
|
849
876
|
set(snapshot: WorkflowSnapshot): Promise<void>;
|
|
850
877
|
/** Drops a snapshot by id; an absent id is a no-op (no throw). */
|
|
851
878
|
delete(id: string): Promise<void>;
|
|
852
879
|
}
|
|
853
880
|
|
|
854
|
-
/**
|
|
881
|
+
/**
|
|
882
|
+
* Names the default {@link import('./types.js').WorkflowDefinition.bail}, `false` — the graceful
|
|
883
|
+
* policy that records a leaf failure and finishes every phase.
|
|
884
|
+
*/
|
|
855
885
|
export declare const DEFAULT_BAIL = false;
|
|
856
886
|
|
|
857
887
|
/**
|
|
858
888
|
* Names the default per-phase task concurrency the {@link import('./factories.js').createWorkflowRunner}
|
|
859
889
|
* runner applies when a {@link import('./types.js').PhaseDefinition} omits its `concurrency`
|
|
860
|
-
* throttle — a cap that is effectively unbounded for any realistic phase.
|
|
890
|
+
* throttle — `1024`, a cap that is effectively unbounded for any realistic phase.
|
|
861
891
|
*
|
|
862
892
|
* @remarks
|
|
863
|
-
* The determinism principle fixes that a phase's tasks run
|
|
893
|
+
* The determinism principle fixes that a phase's tasks run concurrently; `concurrency` is
|
|
864
894
|
* only an optional resource throttle (max-in-flight). With none declared, the runner runs
|
|
865
895
|
* all of a phase's tasks at once — modelled as this finite cap so the value flows straight
|
|
866
896
|
* into the substrate {@link import('./types.js').RunnerInterface}'s `concurrency` (which
|
|
867
897
|
* expects a positive integer) without a special unbounded branch. No realistic phase
|
|
868
898
|
* declares enough tasks to reach it, so it behaves as "run them all".
|
|
869
899
|
*
|
|
870
|
-
*
|
|
871
|
-
*
|
|
900
|
+
* why `1024` and not a huge sentinel like `1_000_000`: the backing `@orkestrel/queue` Runner
|
|
901
|
+
* eagerly spawns one parked worker loop per concurrency unit at construction, so this default
|
|
872
902
|
* must be a value whose eager allocation cost is negligible for every default-concurrency
|
|
873
903
|
* phase — a million-unit default meant ~1e6 promise/closure allocations per such phase. A
|
|
874
|
-
* phase may still
|
|
904
|
+
* phase may still declare a larger explicit `concurrency` and pays that allocation knowingly.
|
|
875
905
|
*/
|
|
876
906
|
export declare const DEFAULT_PHASE_CONCURRENCY = 1024;
|
|
877
907
|
|
|
878
908
|
/**
|
|
879
|
-
* Converts a {@link WorkflowDefinition} into an
|
|
880
|
-
* node `pending`, no results, empty metadata — so the live W-b tree has
|
|
881
|
-
* path
|
|
909
|
+
* Converts a {@link WorkflowDefinition} into an initial {@link WorkflowSnapshot} — every
|
|
910
|
+
* node `pending`, no results, empty metadata — so the live W-b tree has one construction
|
|
911
|
+
* path, snapshot-driven, for a fresh build and for a restore alike.
|
|
882
912
|
*
|
|
883
913
|
* @remarks
|
|
884
914
|
* The structural fields (`id` / `name` / `description` + the ordered phases / tasks)
|
|
@@ -887,20 +917,20 @@ export declare const DEFAULT_PHASE_CONCURRENCY = 1024;
|
|
|
887
917
|
* `retries` / `timeout` (persisted on the {@link TaskSnapshot}, like `bail` / `concurrency`,
|
|
888
918
|
* so a restore + a {@link import('./types.js').WorkflowOptions.functions} registry resumes
|
|
889
919
|
* real work). The `bail` policy carries over — at the
|
|
890
|
-
* workflow tier
|
|
891
|
-
*
|
|
920
|
+
* workflow tier and, per phase, the
|
|
921
|
+
* effective policy (`phase.bail ?? workflowBail`) on each {@link PhaseSnapshot} — so the seeded
|
|
892
922
|
* snapshot is self-contained; a fresh seed has no `override`. `created` / `updated` are stamped at that point.
|
|
893
923
|
* {@link import('./factories.js').createWorkflow} builds from this.
|
|
894
924
|
*
|
|
895
|
-
* The optional `bail` override is the
|
|
925
|
+
* The optional `bail` override is the effective workflow policy the tree will run under
|
|
896
926
|
* (`createWorkflow` / the runner resolve `options.bail ?? definition.bail ?? DEFAULT_BAIL` and
|
|
897
|
-
* pass it here), so an `options.bail` override reaches
|
|
927
|
+
* pass it here), so an `options.bail` override reaches both the workflow tier and the
|
|
898
928
|
* inheritance default of every phase that declares no `bail` of its own — otherwise the
|
|
899
929
|
* per-phase seeds would silently ignore the override. Omitted ⇒ the definition's own `bail`
|
|
900
930
|
* (defaulting to the graceful {@link import('./constants.js').DEFAULT_BAIL}).
|
|
901
931
|
*
|
|
902
932
|
* @param definition - The workflow definition to seed from
|
|
903
|
-
* @param bail - The
|
|
933
|
+
* @param bail - The effective workflow bail to seed both tiers with (defaults to the definition's)
|
|
904
934
|
* @returns An initial, all-`pending` {@link WorkflowSnapshot}
|
|
905
935
|
*/
|
|
906
936
|
export declare function definitionToSnapshot(definition: WorkflowDefinition, bail?: boolean): WorkflowSnapshot;
|
|
@@ -913,7 +943,7 @@ export declare function definitionToSnapshot(definition: WorkflowDefinition, bai
|
|
|
913
943
|
* {@link import('./Scheduler.js').Scheduler}, both Node primitives, and every browser backend's
|
|
914
944
|
* `delay` and macrotask fallback route here, so the timer is armed and cleared in one place. It
|
|
915
945
|
* composes {@link scheduleHost}, which owns listener safety, the cancellation race, the exact
|
|
916
|
-
* caller reason, and once-only settlement. It does
|
|
946
|
+
* caller reason, and once-only settlement. It does not validate `ms`: the value passes straight to
|
|
917
947
|
* the host `setTimeout`, which clamps a negative value or `NaN` to about zero, so an
|
|
918
948
|
* out-of-domain `ms` resumes on the next host turn rather than throwing. Pass a non-negative
|
|
919
949
|
* finite `ms`.
|
|
@@ -931,18 +961,19 @@ export declare function definitionToSnapshot(definition: WorkflowDefinition, bai
|
|
|
931
961
|
export declare function delayHost(ms: number, signal?: AbortSignal): Promise<void>;
|
|
932
962
|
|
|
933
963
|
/**
|
|
934
|
-
* Derives the
|
|
935
|
-
* the index of the first entry in the contiguous trailing run of `pending` entries
|
|
964
|
+
* Derives the pending-suffix boundary of a positional list of {@link LifecycleStatus}es —
|
|
965
|
+
* the index of the first entry in the contiguous trailing run of `pending` entries, or the
|
|
966
|
+
* list's length where it has none.
|
|
936
967
|
*
|
|
937
968
|
* @remarks
|
|
938
969
|
* The native, hook-free replacement for a runner-installed cursor: a
|
|
939
970
|
* {@link import('./types.js').WorkflowInterface}'s `add` / `remove` / `move` / `update`
|
|
940
971
|
* reads this over its live phases' statuses to decide which positions are safe to edit.
|
|
941
|
-
* Because entries run
|
|
942
|
-
* already-started entry forms a contiguous
|
|
972
|
+
* Because entries run sequentially (phases sequential, AGENTS determinism), every
|
|
973
|
+
* already-started entry forms a contiguous leading prefix and every still-`pending`
|
|
943
974
|
* entry forms the trailing suffix — so the boundary is the count of leading
|
|
944
975
|
* non-`pending` entries: the index of the first `pending` entry, or the full length when
|
|
945
|
-
* none is `pending` (nothing is safely editable). A `pending` container's entries are
|
|
976
|
+
* none is `pending` (nothing is safely editable). A `pending` container's entries are all
|
|
946
977
|
* `pending`, so the boundary is `0` and every position is naturally accepted — callers
|
|
947
978
|
* need no special case for that.
|
|
948
979
|
*
|
|
@@ -959,14 +990,14 @@ export declare function delayHost(ms: number, signal?: AbortSignal): Promise<voi
|
|
|
959
990
|
export declare function deriveBoundary(statuses: readonly LifecycleStatus[]): number;
|
|
960
991
|
|
|
961
992
|
/**
|
|
962
|
-
* Derives a phase's status from its tasks' statuses
|
|
963
|
-
* is an order-insensitive reduction).
|
|
993
|
+
* Derives a phase's status from its tasks' statuses, the most severe terminal status winning
|
|
994
|
+
* (tasks are concurrent, so this is an order-insensitive reduction).
|
|
964
995
|
*
|
|
965
996
|
* @remarks
|
|
966
997
|
* The truth table (most-severe terminal wins; `bail`-agnostic — a phase surfaces a
|
|
967
998
|
* task failure as `failed` so the workflow's `bail` policy can decide):
|
|
968
999
|
* - no tasks ⇒ `pending`.
|
|
969
|
-
* - any task `running`,
|
|
1000
|
+
* - any task `running`, or a mix of started-and-unsettled tasks (some non-`pending`
|
|
970
1001
|
* but not all terminal) ⇒ `running`.
|
|
971
1002
|
* - every task `pending` ⇒ `pending`.
|
|
972
1003
|
* - all terminal: any `failed` ⇒ `failed`; else any `stopped` ⇒ `stopped`; else any
|
|
@@ -983,23 +1014,24 @@ export declare function derivePhaseStatus(tasks: readonly LifecycleStatus[]): Li
|
|
|
983
1014
|
|
|
984
1015
|
/**
|
|
985
1016
|
* Derives a workflow's status from its phases' {@link PhaseDerivation}s — each phase's status
|
|
986
|
-
* paired with the
|
|
987
|
-
* failure outcome is
|
|
988
|
-
*
|
|
1017
|
+
* paired with the effective `bail` it ran under (`phase.bail ?? workflow.bail`) — so the
|
|
1018
|
+
* failure outcome is aware of each phase's own policy, and `failed` is reachable only where
|
|
1019
|
+
* that policy is `true` (phases are sequential, but the derivation is an order-insensitive
|
|
1020
|
+
* reduction over the settled set).
|
|
989
1021
|
*
|
|
990
1022
|
* @remarks
|
|
991
1023
|
* `bail` is a per-phase override, so it is carried on each
|
|
992
|
-
* {@link PhaseDerivation} rather than passed as one scalar. It is the
|
|
1024
|
+
* {@link PhaseDerivation} rather than passed as one scalar. It is the only axis that changes
|
|
993
1025
|
* the failure outcome, decided per phase:
|
|
994
1026
|
* - **A `failed` phase whose effective `bail` is `true` (halt)** propagates ⇒ the workflow is
|
|
995
1027
|
* `failed` (the database-transaction halt) — even when the workflow default is graceful.
|
|
996
|
-
* - **A `failed` phase whose effective `bail` is `false` (graceful)** is
|
|
997
|
-
* failure — it folds into completion like a settled phase. A graceful failed phase
|
|
1028
|
+
* - **A `failed` phase whose effective `bail` is `false` (graceful)** is data, not a workflow
|
|
1029
|
+
* failure — it folds into completion like a settled phase. A graceful failed phase never
|
|
998
1030
|
* makes the workflow `failed` — even when the workflow default is strict.
|
|
999
1031
|
*
|
|
1000
1032
|
* The rest of the table is shared:
|
|
1001
1033
|
* - no phases ⇒ `pending`.
|
|
1002
|
-
* - any phase `running`,
|
|
1034
|
+
* - any phase `running`, or a mix of started-and-unsettled phases (some non-`pending`
|
|
1003
1035
|
* but not all terminal) ⇒ `running`.
|
|
1004
1036
|
* - every phase `pending` ⇒ `pending`.
|
|
1005
1037
|
* - all terminal (a `failed` phase counts as terminal here): any `stopped` ⇒ `stopped`; else
|
|
@@ -1040,7 +1072,7 @@ export declare function failure<E>(error: E): Failure<E>;
|
|
|
1040
1072
|
*
|
|
1041
1073
|
* @remarks
|
|
1042
1074
|
* The shared leaf behind {@link import('./phases/Phase.js').Phase} and
|
|
1043
|
-
* {@link import('./Workflow.js').Workflow}'s own `#failure` — each gathers
|
|
1075
|
+
* {@link import('./Workflow.js').Workflow}'s own `#failure` — each gathers its tier's
|
|
1044
1076
|
* results (a phase's own settled tasks, a workflow's flattened `results()`) and feeds
|
|
1045
1077
|
* them here; the tier-local method keeps the invariant throw (a derived `failed`
|
|
1046
1078
|
* status means a failing result exists) because throwing on `undefined` is
|
|
@@ -1105,7 +1137,7 @@ export declare function insertEntry<T>(entries: ReadonlyArray<readonly [string,
|
|
|
1105
1137
|
* @remarks
|
|
1106
1138
|
* A run that walked every phase and still derives `pending` executed nothing — zero phases, or
|
|
1107
1139
|
* every phase empty — so it is vacuously done and the run settles it `completed`. Gated on
|
|
1108
|
-
*
|
|
1140
|
+
* exactly `pending` so a real `completed`, a `bail: true` `failed`, a `stopped`, or a derived
|
|
1109
1141
|
* `skipped` is never overridden. The tree-is-empty half of the rule is
|
|
1110
1142
|
* {@link WorkflowInterface.complete}'s own guard, which refuses a pending tree that still holds
|
|
1111
1143
|
* tasks.
|
|
@@ -1121,12 +1153,13 @@ export declare function insertEntry<T>(entries: ReadonlyArray<readonly [string,
|
|
|
1121
1153
|
export declare function isCompletable(workflow: WorkflowInterface): boolean;
|
|
1122
1154
|
|
|
1123
1155
|
/**
|
|
1124
|
-
* Tests whether a driving run must stop giving a workflow
|
|
1156
|
+
* Tests whether a driving run must stop giving a workflow — or one forced phase of it —
|
|
1157
|
+
* more work.
|
|
1125
1158
|
*
|
|
1126
1159
|
* @remarks
|
|
1127
1160
|
* The halt gate a {@link import('./WorkflowRunner.js').WorkflowRunner} consults before starting a
|
|
1128
1161
|
* phase, before dispatching a task, and after every cooperative gate. A workflow is halted after
|
|
1129
|
-
* its derived status is terminal but
|
|
1162
|
+
* its derived status is terminal but not `completed` — a `bail: true` failure, a caller's own
|
|
1130
1163
|
* graceful `stop()`, or a forced `skip`. `completed` is excluded deliberately: a workflow that
|
|
1131
1164
|
* completed vacuously is settled, not halted, and the distinction is what keeps the run from
|
|
1132
1165
|
* sweeping a finished tree. When a `phase` is supplied, its own forced `skipped` / `stopped` halts
|
|
@@ -1189,7 +1222,7 @@ export declare function isOwnedWorkflowSnapshot(value: unknown): value is Workfl
|
|
|
1189
1222
|
* running task's folded signal, and only two of them mean "skip this task": the task's own
|
|
1190
1223
|
* `signal` (its `stop` / `skip`), and the unit or run signal (a sibling fail-fast under
|
|
1191
1224
|
* `bail: true`, or a run-level abort / timeout / budget / `destroy`). A bare per-attempt timeout
|
|
1192
|
-
* fires
|
|
1225
|
+
* fires neither — it aborts only the deadline portion of the attempt signal — so it stays a
|
|
1193
1226
|
* retryable failure of that attempt instead of skipping the leaf and losing the recorded fault.
|
|
1194
1227
|
* Read fresh at each call so a cancel that lands mid-dispatch is seen.
|
|
1195
1228
|
*
|
|
@@ -1206,11 +1239,11 @@ export declare function isOwnedWorkflowSnapshot(value: unknown): value is Workfl
|
|
|
1206
1239
|
export declare function isSkipping(task: TaskInterface, controller: ControllerInterface<TaskInterface, void>, runSignal: AbortSignal): boolean;
|
|
1207
1240
|
|
|
1208
1241
|
/**
|
|
1209
|
-
* Tests whether forcing a workflow `stopped` would still record
|
|
1242
|
+
* Tests whether forcing a workflow `stopped` would still record the cancellation.
|
|
1210
1243
|
*
|
|
1211
1244
|
* @remarks
|
|
1212
1245
|
* `stop()` is a no-op after a workflow's status becomes terminal, so a run that must record a
|
|
1213
|
-
* cancellation forces it only while this holds. It is
|
|
1246
|
+
* cancellation forces it only while this holds. It is not the negation of
|
|
1214
1247
|
* {@link isTerminalStatus}: `completed` and `skipped` both pass, because a run-level cancel that
|
|
1215
1248
|
* lands on a vacuously-completed or fully-skipped tree still records `stopped` as the outcome the
|
|
1216
1249
|
* caller asked for. Only an already-`failed` or already-`stopped` workflow has a terminal state
|
|
@@ -1232,7 +1265,7 @@ export declare function isStoppable(workflow: WorkflowInterface): boolean;
|
|
|
1232
1265
|
* Tests whether an unknown value is valid persisted task activity.
|
|
1233
1266
|
*
|
|
1234
1267
|
* @remarks
|
|
1235
|
-
* The persisted counterpart of {@link isTaskActivityInput}: the same frame plus the
|
|
1268
|
+
* The persisted counterpart of {@link isTaskActivityInput}: the same frame plus the required
|
|
1236
1269
|
* `operations`, `constraints`, and a finite non-negative `updated` stamp, because a stored frame
|
|
1237
1270
|
* has already been accepted and normalized. Total — a hostile prototype or accessor answers
|
|
1238
1271
|
* `false` rather than throwing.
|
|
@@ -1313,7 +1346,7 @@ export declare function isTaskFailure(value: unknown): value is TaskFailure;
|
|
|
1313
1346
|
*
|
|
1314
1347
|
* @remarks
|
|
1315
1348
|
* The four arguments are the result and the three snapshot nodes it claims to belong to, read
|
|
1316
|
-
* from the
|
|
1349
|
+
* from the outside in: a {@link TaskResult} is self-describing, so restoring one is only safe
|
|
1317
1350
|
* when every identity it carries agrees with the tree it was found in. It checks the exact key
|
|
1318
1351
|
* set at each level, that `status` equals the owning task's, and that the `task` / `phase` /
|
|
1319
1352
|
* `workflow` contexts — including the nested `task.phase.workflow` lineage — carry the same `id`,
|
|
@@ -1340,11 +1373,11 @@ export declare function isTaskFailure(value: unknown): value is TaskFailure;
|
|
|
1340
1373
|
export declare function isTaskResult(value: unknown, workflow: unknown, phase: unknown, task: unknown): value is TaskResult;
|
|
1341
1374
|
|
|
1342
1375
|
/**
|
|
1343
|
-
* Tests whether a {@link LifecycleStatus} is
|
|
1344
|
-
*
|
|
1376
|
+
* Tests whether a {@link LifecycleStatus} is terminal — `completed`, `failed`, `skipped`, or
|
|
1377
|
+
* `stopped`, the states a node never transitions out of.
|
|
1345
1378
|
*
|
|
1346
1379
|
* @remarks
|
|
1347
|
-
* The
|
|
1380
|
+
* The one terminal check across every tier (AGENTS.md § Design laws, "one concept, one term"):
|
|
1348
1381
|
* a task, a phase, and a workflow share the same {@link LifecycleStatus} vocabulary, so a
|
|
1349
1382
|
* single predicate covers them — {@link derivePhaseStatus} and {@link deriveWorkflowStatus}
|
|
1350
1383
|
* both consult it to tell a settled node from an in-flight one. It reads the terminal set from
|
|
@@ -1381,8 +1414,8 @@ export declare function isWorkflowError(value: unknown): value is WorkflowError;
|
|
|
1381
1414
|
* The discriminator behind the overloaded
|
|
1382
1415
|
* {@link import('./types.js').WorkflowRunnerInterface.execute}: a
|
|
1383
1416
|
* {@link import('./types.js').WorkflowInterface} is the only one of the two carrying `destroyed`
|
|
1384
|
-
* (
|
|
1385
|
-
* {@link import('./types.js').WorkflowDefinition})
|
|
1417
|
+
* (runtime-only, never a field on the pure-JSON
|
|
1418
|
+
* {@link import('./types.js').WorkflowDefinition}) and a callable `snapshot`. Requiring both is
|
|
1386
1419
|
* sturdier than `destroyed` alone — a definition could coincidentally carry a `destroyed` field as
|
|
1387
1420
|
* arbitrary data, and pairing it with a function-typed `snapshot` narrows to the actual entity
|
|
1388
1421
|
* shape without an `as`. It reads a live class instance, so it tests object identity rather than a
|
|
@@ -1419,7 +1452,8 @@ export declare function isWorkflowInterface(value: unknown): value is WorkflowIn
|
|
|
1419
1452
|
export declare function isWorkflowSnapshot(value: unknown): value is WorkflowSnapshot;
|
|
1420
1453
|
|
|
1421
1454
|
/**
|
|
1422
|
-
* Lists every {@link LifecycleStatus} value, frozen — the vocabulary every tier draws from
|
|
1455
|
+
* Lists every {@link LifecycleStatus} value, frozen — the vocabulary every tier draws from,
|
|
1456
|
+
* in the order `pending`, `running`, `completed`, `failed`, `skipped`, `stopped`.
|
|
1423
1457
|
*
|
|
1424
1458
|
* @remarks
|
|
1425
1459
|
* Ordered pending → running → terminal (`completed` / `failed` / `skipped` /
|
|
@@ -1434,7 +1468,7 @@ export declare const LIFECYCLE_STATUSES: readonly LifecycleStatus[];
|
|
|
1434
1468
|
* `skipped` / `stopped`.
|
|
1435
1469
|
*
|
|
1436
1470
|
* @remarks
|
|
1437
|
-
* The
|
|
1471
|
+
* The one literal set the workflow, phase, and task tiers all draw from, so the vocabulary
|
|
1438
1472
|
* lives in one place and a signature reading `LifecycleStatus` means the same thing at
|
|
1439
1473
|
* every tier. Each member's tier-specific meaning belongs to the member that declares it:
|
|
1440
1474
|
* `skipped` is "deliberately not run" and `stopped` is "ended early", and the terminal
|
|
@@ -1451,7 +1485,7 @@ export declare type LifecycleStatus = 'pending' | 'running' | 'completed' | 'fai
|
|
|
1451
1485
|
*
|
|
1452
1486
|
* @remarks
|
|
1453
1487
|
* The equality rule a lineage check needs: two descriptions match when they are the same value
|
|
1454
|
-
*
|
|
1488
|
+
* and that value is either a string or genuine absence. Anything else — a number, an object, a
|
|
1455
1489
|
* `null` — never matches, even against itself, so a lineage stamped with a non-string description
|
|
1456
1490
|
* is rejected rather than silently accepted.
|
|
1457
1491
|
*
|
|
@@ -1469,33 +1503,31 @@ export declare type LifecycleStatus = 'pending' | 'running' | 'completed' | 'fai
|
|
|
1469
1503
|
export declare function matchesDescription(left: unknown, right: unknown): boolean;
|
|
1470
1504
|
|
|
1471
1505
|
/**
|
|
1472
|
-
* Names the largest delay representable by the host timer APIs without overflow or clamping
|
|
1506
|
+
* Names the largest delay representable by the host timer APIs without overflow or clamping,
|
|
1507
|
+
* `2_147_483_647` milliseconds.
|
|
1473
1508
|
*/
|
|
1474
1509
|
export declare const MAX_TIMER_MS = 2147483647;
|
|
1475
1510
|
|
|
1476
1511
|
/**
|
|
1477
1512
|
* Implements the in-memory {@link WorkflowStoreInterface} — a process-lifetime `Map` of
|
|
1478
|
-
* {@link WorkflowSnapshot}s keyed by workflow id, the
|
|
1479
|
-
* {@link import('../factories.js').createMemoryWorkflowStore} builds.
|
|
1513
|
+
* {@link WorkflowSnapshot}s keyed by workflow id, the default store
|
|
1514
|
+
* {@link import('../factories.js').createMemoryWorkflowStore} builds. It expires nothing: a
|
|
1515
|
+
* persisted snapshot lives until an explicit `delete`.
|
|
1480
1516
|
*
|
|
1481
1517
|
* @remarks
|
|
1482
1518
|
* A plain `Map<string, WorkflowSnapshot>` (the snapshot is already pure,
|
|
1483
|
-
* self-contained JSON, so no encoding is needed for the memory tier).
|
|
1484
|
-
*
|
|
1485
|
-
* NO idle-TTL and NO eviction: a persisted workflow run-state is durable orchestration state
|
|
1486
|
-
* that lives until an explicit `delete`, never silently aging out (a run that vanished
|
|
1487
|
-
* mid-flight would be a silent data loss, not a freed session). A durable backend (JSON /
|
|
1488
|
-
* SQLite / IndexedDB) swaps in through the SAME interface without touching the runner or the
|
|
1519
|
+
* self-contained JSON, so no encoding is needed for the memory tier). A durable backend (JSON /
|
|
1520
|
+
* SQLite / IndexedDB) swaps in through the same interface without touching the runner or the
|
|
1489
1521
|
* entity tree — its driver-pluggable twin is
|
|
1490
1522
|
* {@link import('./DatabaseWorkflowStore.js').DatabaseWorkflowStore} (the snapshot as one opaque
|
|
1491
1523
|
* JSON column), exactly as `@orkestrel/queue`'s `MemoryQueueStore`
|
|
1492
1524
|
* twins `DatabaseQueueStore`.
|
|
1493
1525
|
*
|
|
1494
1526
|
* - **`get` resolves the persisted snapshot for an id**, or `undefined` if none is stored.
|
|
1495
|
-
* - **`set` inserts / replaces under the snapshot's
|
|
1527
|
+
* - **`set` inserts / replaces under the snapshot's own `id`** (no separate id param).
|
|
1496
1528
|
* - **`delete` drops a snapshot by id**; an absent id is a no-op (no throw).
|
|
1497
1529
|
*
|
|
1498
|
-
* The public surface is
|
|
1530
|
+
* The public surface is exactly `get` / `set` / `delete` — no extra members (the guide's method
|
|
1499
1531
|
* bijection with {@link WorkflowStoreInterface}). Restore is a caller concern: read a snapshot
|
|
1500
1532
|
* back and rebuild the live tree with {@link import('../factories.js').createRestoredWorkflow}.
|
|
1501
1533
|
*
|
|
@@ -1549,7 +1581,7 @@ export declare function moveEntry<T>(entries: ReadonlyArray<readonly [string, T]
|
|
|
1549
1581
|
*
|
|
1550
1582
|
* @remarks
|
|
1551
1583
|
* A retried task is re-dispatched while an earlier attempt's handler may still be resolving, so
|
|
1552
|
-
* every settlement path re-checks ownership before touching the leaf. Ownership needs
|
|
1584
|
+
* every settlement path re-checks ownership before touching the leaf. Ownership needs both
|
|
1553
1585
|
* halves: the run-local `owners` ledger must still name this attempt, and the live task's own
|
|
1554
1586
|
* `attempts` tally must still match it. A superseded attempt reads `false` and returns without
|
|
1555
1587
|
* recording anything, so a late resolution can never overwrite the newer attempt's outcome.
|
|
@@ -1570,10 +1602,10 @@ export declare function ownsAttempt(owners: Map<string, number>, task: TaskInter
|
|
|
1570
1602
|
|
|
1571
1603
|
/**
|
|
1572
1604
|
* Parks until `signal` aborts — a promise-parked wait, never a timer or
|
|
1573
|
-
* busy-loop, that
|
|
1605
|
+
* busy-loop, that resolves on the abort event and never rejects.
|
|
1574
1606
|
*
|
|
1575
1607
|
* @remarks
|
|
1576
|
-
* Resolves
|
|
1608
|
+
* Resolves immediately when `signal` is already aborted; otherwise attaches a one-shot
|
|
1577
1609
|
* `abort` listener and resolves when it fires, removing the listener either way. The
|
|
1578
1610
|
* shared leaf behind the duplicate abort-wiring an execution engine otherwise hand-rolls
|
|
1579
1611
|
* at every fold point.
|
|
@@ -1593,7 +1625,8 @@ export declare function parkSignal(signal: AbortSignal): Promise<void>;
|
|
|
1593
1625
|
|
|
1594
1626
|
/**
|
|
1595
1627
|
* Lists the {@link WorkflowEventMap} / {@link PhaseEventMap} events that make a durable observer
|
|
1596
|
-
* re-persist the live tree, frozen
|
|
1628
|
+
* re-persist the live tree, frozen — `start`, `complete`, `fail`, `skip`, `stop`, `move`, and
|
|
1629
|
+
* `update`.
|
|
1597
1630
|
*
|
|
1598
1631
|
* @remarks
|
|
1599
1632
|
* The two maps carry the same event names, so one list serves both tiers. It is the source of
|
|
@@ -1605,7 +1638,8 @@ export declare function parkSignal(signal: AbortSignal): Promise<void>;
|
|
|
1605
1638
|
export declare const PERSISTED_NODE_EVENTS: ReadonlyArray<keyof WorkflowEventMap & keyof PhaseEventMap>;
|
|
1606
1639
|
|
|
1607
1640
|
/**
|
|
1608
|
-
* Lists the {@link TaskEventMap} events that make a durable observer re-persist the live tree,
|
|
1641
|
+
* Lists the {@link TaskEventMap} events that make a durable observer re-persist the live tree,
|
|
1642
|
+
* frozen — `start`, `complete`, `fail`, `skip`, `stop`, `report`, and `pulse`.
|
|
1609
1643
|
*
|
|
1610
1644
|
* @remarks
|
|
1611
1645
|
* The leaf counterpart of {@link PERSISTED_NODE_EVENTS}, and the source of truth behind the task
|
|
@@ -1622,21 +1656,21 @@ export declare const PERSISTED_TASK_EVENTS: ReadonlyArray<keyof TaskEventMap>;
|
|
|
1622
1656
|
*
|
|
1623
1657
|
* @remarks
|
|
1624
1658
|
* Extends {@link WorkflowContext} (so the phase carries its own `id` / `name`) and
|
|
1625
|
-
* adds `workflow`, the parent's context — the lineage pointer back
|
|
1659
|
+
* adds `workflow`, the parent's context — the lineage pointer back up the tree.
|
|
1626
1660
|
*/
|
|
1627
1661
|
export declare interface PhaseContext extends WorkflowContext {
|
|
1628
1662
|
readonly workflow: WorkflowContext;
|
|
1629
1663
|
}
|
|
1630
1664
|
|
|
1631
1665
|
/**
|
|
1632
|
-
* Represents the serializable definition of one phase — its identity, its ordered tasks,
|
|
1633
|
-
* an optional
|
|
1666
|
+
* Represents the serializable definition of one phase — its identity, its ordered tasks, an
|
|
1667
|
+
* optional resource throttle, and an optional `bail` override of the workflow policy.
|
|
1634
1668
|
*
|
|
1635
1669
|
* @remarks
|
|
1636
|
-
* Pure JSON
|
|
1670
|
+
* Pure JSON data. `tasks` are the phase's tasks, which run concurrently (the fixed
|
|
1637
1671
|
* determinism principle). `concurrency` is the optional per-phase resource throttle
|
|
1638
1672
|
* — the maximum number of tasks in flight at once (a positive integer); omitted ⇒
|
|
1639
|
-
* unbounded. It is a throttle,
|
|
1673
|
+
* unbounded. It is a throttle, not a sequencing control: phases are always
|
|
1640
1674
|
* sequential, tasks within a phase always concurrent.
|
|
1641
1675
|
*/
|
|
1642
1676
|
export declare interface PhaseDefinition {
|
|
@@ -1650,10 +1684,10 @@ export declare interface PhaseDefinition {
|
|
|
1650
1684
|
* Sets the phase's failure policy.
|
|
1651
1685
|
*
|
|
1652
1686
|
* @remarks
|
|
1653
|
-
* The per-phase failure-policy
|
|
1687
|
+
* The per-phase failure-policy override. Omitted ⇒ the phase inherits the
|
|
1654
1688
|
* workflow `bail`; supplied, it wins (`effectiveBail = phase.bail ?? workflow.bail`). A
|
|
1655
|
-
* `bail: true` phase
|
|
1656
|
-
* default; a `bail: false` phase does
|
|
1689
|
+
* `bail: true` phase halts the run on its first task failure even under a graceful workflow
|
|
1690
|
+
* default; a `bail: false` phase does not halt even under a strict workflow default.
|
|
1657
1691
|
*/
|
|
1658
1692
|
readonly bail?: boolean;
|
|
1659
1693
|
}
|
|
@@ -1663,7 +1697,7 @@ export declare interface PhaseDefinition {
|
|
|
1663
1697
|
* {@link PhaseSnapshot} — the per-phase step of {@link definitionToSnapshot}.
|
|
1664
1698
|
*
|
|
1665
1699
|
* @remarks
|
|
1666
|
-
* The snapshot persists the
|
|
1700
|
+
* The snapshot persists the effective failure policy this phase runs under: the phase's own
|
|
1667
1701
|
* `bail` when it declares one, else the `workflowBail` it inherits — so a restore reinstates
|
|
1668
1702
|
* the same per-phase policy without a silent default (`effectiveBail = phase.bail ?? workflowBail`).
|
|
1669
1703
|
* `concurrency` (the resource throttle) carries over verbatim, omitted when undefined.
|
|
@@ -1676,14 +1710,14 @@ export declare function phaseDefinitionToSnapshot(phase: WorkflowDefinition['pha
|
|
|
1676
1710
|
|
|
1677
1711
|
/**
|
|
1678
1712
|
* Represents one phase's contribution to the workflow-status derivation — its
|
|
1679
|
-
* {@link LifecycleStatus} paired with the
|
|
1680
|
-
* (`phase.bail ?? workflow.bail`).
|
|
1713
|
+
* {@link LifecycleStatus} paired with the effective `bail` policy it ran under
|
|
1714
|
+
* (`phase.bail ?? workflow.bail`) — the input shape {@link deriveWorkflowStatus} reduces.
|
|
1681
1715
|
*
|
|
1682
1716
|
* @remarks
|
|
1683
|
-
*
|
|
1684
|
-
* per-phase
|
|
1685
|
-
* must carry its
|
|
1686
|
-
* `failed` phase propagates `failed` to the workflow only when
|
|
1717
|
+
* Because `bail` is a per-phase override, the workflow `failed` derivation is
|
|
1718
|
+
* per-phase-bail-aware, so each phase
|
|
1719
|
+
* must carry its own effective policy rather than the derivation taking one scalar `bail`. A
|
|
1720
|
+
* `failed` phase propagates `failed` to the workflow only when its `bail` is `true`; a `failed`
|
|
1687
1721
|
* phase whose `bail` is `false` folds into completion. {@link import('./Workflow.js').Workflow}
|
|
1688
1722
|
* builds one per live phase (`{ status: phase.status, bail: phase.bail }`).
|
|
1689
1723
|
*/
|
|
@@ -1738,19 +1772,19 @@ export declare type PhaseInput = Partial<PhaseContext>;
|
|
|
1738
1772
|
|
|
1739
1773
|
/**
|
|
1740
1774
|
* Declares the live derived state machine (W-b) for one {@link PhaseDefinition} — an
|
|
1741
|
-
* observable phase whose {@link LifecycleStatus} is
|
|
1775
|
+
* observable phase whose {@link LifecycleStatus} is derived from its tasks
|
|
1742
1776
|
* (never set directly) and recomputed reactively as a task transitions (the cascade).
|
|
1743
1777
|
*
|
|
1744
1778
|
* @remarks
|
|
1745
1779
|
* - **Derived status.** `status` is computed through
|
|
1746
1780
|
* {@link import('./helpers.js').derivePhaseStatus} over the live tasks' statuses,
|
|
1747
|
-
*
|
|
1748
|
-
*
|
|
1781
|
+
* unless an override is in force. It recomputes whenever a child task transitions; a
|
|
1782
|
+
* change emits.
|
|
1749
1783
|
* - **Children.** `tasks` is the lean {@link TaskManagerInterface} (an
|
|
1750
1784
|
* accessor + `count`, no batch matrix); `task(id)` / `tasks().tasks()` read in positional
|
|
1751
1785
|
* order. `results` collects the settled tasks' {@link TaskResult}s (the phase tier of the
|
|
1752
|
-
* result tree); `workflow` navigates
|
|
1753
|
-
* - **Override.** `skip` / `stop`
|
|
1786
|
+
* result tree); `workflow` navigates up to the live parent.
|
|
1787
|
+
* - **Override.** `skip` / `stop` force the phase's status, overriding the
|
|
1754
1788
|
* derived value (for example, skipping a whole phase); the override survives a snapshot.
|
|
1755
1789
|
* - **Observable.** The owned {@link emitter} ({@link PhaseEventMap}) fires
|
|
1756
1790
|
* `start` / `complete` / `fail` / `pause` / `resume` / `stop` after the corresponding
|
|
@@ -1758,8 +1792,8 @@ export declare type PhaseInput = Partial<PhaseContext>;
|
|
|
1758
1792
|
* its `error` handler (the `error` option).
|
|
1759
1793
|
* - **Runtime lifecycle.** `pause` / `resume` / `wait` mirror
|
|
1760
1794
|
* {@link WorkflowInterface.pause} / `resume` / `wait`, scoped to this phase — a driving
|
|
1761
|
-
* {@link WorkflowRunnerInterface.execute} gates a task's own pre-dispatch on
|
|
1762
|
-
* workflow's and its phase's gate. `paused` is
|
|
1795
|
+
* {@link WorkflowRunnerInterface.execute} gates a task's own pre-dispatch on both the
|
|
1796
|
+
* workflow's and its phase's gate. `paused` is runtime-only, never persisted; idempotent;
|
|
1763
1797
|
* released by `resume` and by this phase's own `stop` / `skip` forcing a terminal status
|
|
1764
1798
|
* (a permanently-ended phase has nothing left to pause for).
|
|
1765
1799
|
*/
|
|
@@ -1773,12 +1807,12 @@ export declare interface PhaseInterface {
|
|
|
1773
1807
|
readonly workflow: WorkflowInterface;
|
|
1774
1808
|
/** Holds this phase's effective lifecycle status, derived from its tasks unless an override is in force. */
|
|
1775
1809
|
readonly status: LifecycleStatus;
|
|
1776
|
-
/** Reports the
|
|
1810
|
+
/** Reports the resolved effective failure policy this phase runs under (`phase.bail ?? workflow.bail`); mirrors {@link WorkflowInterface.bail}. */
|
|
1777
1811
|
readonly bail: boolean;
|
|
1778
1812
|
/** Caps the tasks in flight at once (a resource throttle); mirrors {@link PhaseSnapshot.concurrency}. `undefined` ⇒ unbounded. */
|
|
1779
1813
|
readonly concurrency: number | undefined;
|
|
1780
1814
|
/**
|
|
1781
|
-
* Reports whether the phase is paused (resumable);
|
|
1815
|
+
* Reports whether the phase is paused (resumable); runtime-only — never a
|
|
1782
1816
|
* {@link LifecycleStatus}, never persisted in a {@link PhaseSnapshot} (a paused phase's
|
|
1783
1817
|
* `status` still reports its ordinary derived value).
|
|
1784
1818
|
*/
|
|
@@ -1792,7 +1826,7 @@ export declare interface PhaseInterface {
|
|
|
1792
1826
|
* Forces this phase to `skipped`, overriding the derived value; idempotent.
|
|
1793
1827
|
*
|
|
1794
1828
|
* @remarks
|
|
1795
|
-
* A
|
|
1829
|
+
* A no-op after `status` becomes terminal — a settled phase cannot be re-forced. Always
|
|
1796
1830
|
* releases a parked {@link wait} waiter regardless (a terminal phase has nothing left to
|
|
1797
1831
|
* pause for).
|
|
1798
1832
|
*/
|
|
@@ -1801,7 +1835,7 @@ export declare interface PhaseInterface {
|
|
|
1801
1835
|
* Forces this phase to `stopped`, overriding the derived value; idempotent.
|
|
1802
1836
|
*
|
|
1803
1837
|
* @remarks
|
|
1804
|
-
* A
|
|
1838
|
+
* A no-op after `status` becomes terminal (a settled phase cannot be re-forced). Always
|
|
1805
1839
|
* releases a parked {@link wait} waiter regardless (a terminal phase has nothing left to
|
|
1806
1840
|
* pause for).
|
|
1807
1841
|
*/
|
|
@@ -1810,10 +1844,10 @@ export declare interface PhaseInterface {
|
|
|
1810
1844
|
* Suspends the phase (resumable); idempotent.
|
|
1811
1845
|
*
|
|
1812
1846
|
* @remarks
|
|
1813
|
-
* A no-op when already `paused` or when `status` is terminal.
|
|
1847
|
+
* A no-op when already `paused` or when `status` is terminal. Runtime-only —
|
|
1814
1848
|
* never a {@link LifecycleStatus}, never persisted in a {@link PhaseSnapshot}. A driving
|
|
1815
1849
|
* {@link WorkflowRunnerInterface.execute} gates a task's own pre-dispatch on this phase's
|
|
1816
|
-
* gate (after the workflow's own gate). **Pausing does
|
|
1850
|
+
* gate (after the workflow's own gate). **Pausing does not suspend a driving run's
|
|
1817
1851
|
* timeout / budget / abort clocks** — those bounds keep ticking while paused, so a long
|
|
1818
1852
|
* pause can still fire a run-level cancel and stop the workflow while parked.
|
|
1819
1853
|
*
|
|
@@ -1835,47 +1869,45 @@ export declare interface PhaseInterface {
|
|
|
1835
1869
|
*/
|
|
1836
1870
|
resume(): void;
|
|
1837
1871
|
/**
|
|
1838
|
-
* Parks until this phase is not paused —
|
|
1839
|
-
* (mirrors {@link WorkflowInterface.wait}).
|
|
1872
|
+
* Parks until this phase is not paused — a promise-parked wait, never a timer or busy-loop.
|
|
1840
1873
|
*
|
|
1841
1874
|
* @remarks
|
|
1842
|
-
* Resolves
|
|
1875
|
+
* Resolves immediately when not {@link paused}. While paused, parks until `resume` or
|
|
1843
1876
|
* this phase's own `stop` / `skip` forcing a terminal status — all release a parked
|
|
1844
|
-
* waiter.
|
|
1877
|
+
* waiter. Never rejects.
|
|
1845
1878
|
*
|
|
1846
1879
|
* @returns A promise that resolves after the phase is no longer paused
|
|
1847
1880
|
*/
|
|
1848
1881
|
wait(): Promise<void>;
|
|
1849
1882
|
/**
|
|
1850
1883
|
* Mints a live {@link TaskInterface} from `definition` and inserts it into this phase
|
|
1851
|
-
* (the entity structural API) — gated
|
|
1852
|
-
* manager.
|
|
1884
|
+
* (the entity structural API) — gated before it delegates to the {@link tasks} manager.
|
|
1853
1885
|
*
|
|
1854
1886
|
* @remarks
|
|
1855
1887
|
* Converts `definition` → {@link TaskSnapshot} and constructs the live task (wired to
|
|
1856
|
-
*
|
|
1888
|
+
* this phase, its recompute cascade, and its emitter hooks), carrying its `behavior` /
|
|
1857
1889
|
* `retries` / `timeout` from `definition` and resolving its {@link TaskInterface.handler}
|
|
1858
|
-
* against the workflow-level {@link WorkflowOptions.functions} registry — the
|
|
1890
|
+
* against the workflow-level {@link WorkflowOptions.functions} registry — the same
|
|
1859
1891
|
* resolution {@link import('./factories.js').createWorkflow} performs at build time.
|
|
1860
|
-
* Requires `definition.id` to be
|
|
1892
|
+
* Requires `definition.id` to be unique among this phase's existing
|
|
1861
1893
|
* task ids — a duplicate is a `MUTATION` failure (mirrors
|
|
1862
1894
|
* {@link TaskManagerInterface.add}'s own duplicate-id gate).
|
|
1863
1895
|
*
|
|
1864
|
-
*
|
|
1865
|
-
* runner-installed hook),
|
|
1896
|
+
* native gating, purely from this phase's own derived `status` (no
|
|
1897
|
+
* runner-installed hook), unchanged from the entity-taking predecessor. While
|
|
1866
1898
|
* `pending`: any valid `index` is accepted (delegates the minted task to
|
|
1867
|
-
* {@link TaskManagerInterface.add} then emits `add`). While `running`: accepted
|
|
1899
|
+
* {@link TaskManagerInterface.add} then emits `add`). While `running`: accepted only as
|
|
1868
1900
|
* a pure append (`index` omitted or `=== tasks.count`) — a live runner subscribed to
|
|
1869
1901
|
* the `add` event picks the new task up for same-run execution; the derived-status
|
|
1870
1902
|
* model keeps this phase from reaching a terminal status while the accepted task is
|
|
1871
1903
|
* still `pending` (its status feeds `status` through {@link import('./helpers.js').derivePhaseStatus}).
|
|
1872
1904
|
* While terminal: always refused.
|
|
1873
1905
|
*
|
|
1874
|
-
* **Abort edge.** An append
|
|
1906
|
+
* **Abort edge.** An append accepted while `running` can still settle `skipped` rather
|
|
1875
1907
|
* than run — if the driving run is cancelled (abort / timeout / budget / `workflow.destroy()`)
|
|
1876
1908
|
* before the substrate actually dispatches the newly-minted task, the runner's halt sweep
|
|
1877
1909
|
* `skip`s it like any other not-yet-started task. Acceptance here means only that the task
|
|
1878
|
-
* is
|
|
1910
|
+
* is wired into the live tree, not that it will execute.
|
|
1879
1911
|
*
|
|
1880
1912
|
* @param definition - The {@link TaskDefinition} to mint a live task from
|
|
1881
1913
|
* @param index - The insertion position; omitted inserts at the end
|
|
@@ -1886,7 +1918,7 @@ export declare interface PhaseInterface {
|
|
|
1886
1918
|
* Removes the `pending` task `id` from this phase.
|
|
1887
1919
|
*
|
|
1888
1920
|
* @remarks
|
|
1889
|
-
*
|
|
1921
|
+
* native gating: allowed only while this phase's own `status` is `pending`. While
|
|
1890
1922
|
* `running` or terminal, always a `MUTATION` failure — a running phase's tasks are
|
|
1891
1923
|
* already handed to the execution substrate and only a pure {@link add} append remains
|
|
1892
1924
|
* possible.
|
|
@@ -1899,7 +1931,7 @@ export declare interface PhaseInterface {
|
|
|
1899
1931
|
* Repositions the `pending` task `id` to `index` within this phase.
|
|
1900
1932
|
*
|
|
1901
1933
|
* @remarks
|
|
1902
|
-
*
|
|
1934
|
+
* native gating: allowed only while this phase's own `status` is `pending`; `running` /
|
|
1903
1935
|
* terminal always fail (see {@link remove}).
|
|
1904
1936
|
*
|
|
1905
1937
|
* @param id - The task id to move
|
|
@@ -1911,7 +1943,7 @@ export declare interface PhaseInterface {
|
|
|
1911
1943
|
* Applies a validated {@link TaskUpdate} patch to the `pending` task `id` in this phase.
|
|
1912
1944
|
*
|
|
1913
1945
|
* @remarks
|
|
1914
|
-
*
|
|
1946
|
+
* native gating: allowed only while this phase's own `status` is `pending`; `running` /
|
|
1915
1947
|
* terminal always fail (see {@link remove}).
|
|
1916
1948
|
*
|
|
1917
1949
|
* @param id - The task id to patch
|
|
@@ -1920,12 +1952,12 @@ export declare interface PhaseInterface {
|
|
|
1920
1952
|
*/
|
|
1921
1953
|
update(id: string, patch: TaskUpdate): Result<TaskInterface, WorkflowError>;
|
|
1922
1954
|
/**
|
|
1923
|
-
* Applies a validated declarative patch to
|
|
1955
|
+
* Applies a validated declarative patch to this phase itself (`name` / `description` /
|
|
1924
1956
|
* `concurrency` / `bail`).
|
|
1925
1957
|
*
|
|
1926
1958
|
* @remarks
|
|
1927
1959
|
* Defense-in-depth: the owning {@link WorkflowInterface.update} gates
|
|
1928
|
-
*
|
|
1960
|
+
* first, so a direct call here throws a `MUTATION`
|
|
1929
1961
|
* {@link import('./errors.js').WorkflowError} unless this phase's own `status` is
|
|
1930
1962
|
* `pending`.
|
|
1931
1963
|
*
|
|
@@ -1936,6 +1968,11 @@ export declare interface PhaseInterface {
|
|
|
1936
1968
|
* ```
|
|
1937
1969
|
*/
|
|
1938
1970
|
patch(value: PhaseUpdate): void;
|
|
1971
|
+
/**
|
|
1972
|
+
* Serializes this phase and its tasks.
|
|
1973
|
+
*
|
|
1974
|
+
* @returns The pure-JSON {@link PhaseSnapshot} of this phase
|
|
1975
|
+
*/
|
|
1939
1976
|
snapshot(): PhaseSnapshot;
|
|
1940
1977
|
}
|
|
1941
1978
|
|
|
@@ -1953,7 +1990,7 @@ export declare interface PhaseInterface {
|
|
|
1953
1990
|
* looks one up, `phases()` lists them in positional order, `count` is the tally. A snapshot
|
|
1954
1991
|
* RESTORE re-`append`s in the snapshot's order, reproducing it exactly.
|
|
1955
1992
|
* - **Gated mutation API.** `add` / `remove` / `move` / `update` are the graceful
|
|
1956
|
-
* `Result` counterparts to `append`, gating
|
|
1993
|
+
* `Result` counterparts to `append`, gating only on the target's own existence/status/id/bounds
|
|
1957
1994
|
* — a duplicate id, an absent/non-`pending` target, an out-of-bounds `index`, or a patch that
|
|
1958
1995
|
* fails {@link phaseUpdateShape} validation all fail gracefully with a `MUTATION`
|
|
1959
1996
|
* {@link WorkflowError} instead of throwing.
|
|
@@ -1990,10 +2027,10 @@ export declare class PhaseManager implements PhaseManagerInterface {
|
|
|
1990
2027
|
* @remarks
|
|
1991
2028
|
* `append` adds one live {@link PhaseInterface} at the end; `phase(id)` looks one up;
|
|
1992
2029
|
* `phases()` lists them in positional order; `count` is the tally. No batch matrix.
|
|
1993
|
-
* `add` / `remove` / `move` / `update` are the
|
|
2030
|
+
* `add` / `remove` / `move` / `update` are the gated mutation
|
|
1994
2031
|
* counterparts a {@link WorkflowInterface.add} / `remove` / `move` / `update`
|
|
1995
|
-
* delegates to
|
|
1996
|
-
* on the target's
|
|
2032
|
+
* delegates to after its own container-status/hook gating — the manager gates only
|
|
2033
|
+
* on the target's own existence/status/id/bounds and stays event-free (the entity
|
|
1997
2034
|
* emits on success).
|
|
1998
2035
|
*/
|
|
1999
2036
|
export declare interface PhaseManagerInterface {
|
|
@@ -2002,7 +2039,7 @@ export declare interface PhaseManagerInterface {
|
|
|
2002
2039
|
* Adds `phase` at the end (the build-time wiring path).
|
|
2003
2040
|
*
|
|
2004
2041
|
* @remarks
|
|
2005
|
-
*
|
|
2042
|
+
* throws a `MUTATION` {@link import('./errors.js').WorkflowError} on a duplicate
|
|
2006
2043
|
* `id` (a genuine programmer error — a build-time wiring bug) instead of
|
|
2007
2044
|
* silently overwriting the existing entry.
|
|
2008
2045
|
*
|
|
@@ -2010,7 +2047,7 @@ export declare interface PhaseManagerInterface {
|
|
|
2010
2047
|
*/
|
|
2011
2048
|
append(phase: PhaseInterface): void;
|
|
2012
2049
|
/**
|
|
2013
|
-
* Inserts `phase` at `index` (default the end) — the
|
|
2050
|
+
* Inserts `phase` at `index` (default the end) — the gated mutation counterpart to
|
|
2014
2051
|
* {@link append}: a duplicate `id` or an out-of-bounds `index` fails gracefully
|
|
2015
2052
|
* instead of throwing.
|
|
2016
2053
|
*
|
|
@@ -2045,7 +2082,18 @@ export declare interface PhaseManagerInterface {
|
|
|
2045
2082
|
* `id` is absent, not `pending`, or `patch` fails validation
|
|
2046
2083
|
*/
|
|
2047
2084
|
update(id: string, patch: PhaseUpdate): Result<PhaseInterface, WorkflowError>;
|
|
2085
|
+
/**
|
|
2086
|
+
* Looks up one held phase by its `id`.
|
|
2087
|
+
*
|
|
2088
|
+
* @param id - The phase id to resolve
|
|
2089
|
+
* @returns The live phase, or `undefined` when none is held under that id
|
|
2090
|
+
*/
|
|
2048
2091
|
phase(id: string): PhaseInterface | undefined;
|
|
2092
|
+
/**
|
|
2093
|
+
* Lists the held phases in positional order.
|
|
2094
|
+
*
|
|
2095
|
+
* @returns Every live phase, in the order the store holds them
|
|
2096
|
+
*/
|
|
2049
2097
|
phases(): readonly PhaseInterface[];
|
|
2050
2098
|
}
|
|
2051
2099
|
|
|
@@ -2072,32 +2120,33 @@ export declare interface PhaseOptions {
|
|
|
2072
2120
|
* {@link taskShape} tasks, and an optional positive-integer `concurrency` throttle
|
|
2073
2121
|
* (max tasks in flight; omitted ⇒ unbounded).
|
|
2074
2122
|
*/
|
|
2075
|
-
export declare const phaseShape: ObjectShape<{
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2123
|
+
export declare const phaseShape: ObjectShape< {
|
|
2124
|
+
id: StringShape;
|
|
2125
|
+
name: StringShape;
|
|
2126
|
+
description: OptionalShape<StringShape>;
|
|
2127
|
+
tasks: ArrayShape<ObjectShape< {
|
|
2128
|
+
id: StringShape;
|
|
2129
|
+
name: StringShape;
|
|
2130
|
+
description: OptionalShape<StringShape>;
|
|
2131
|
+
behavior: OptionalShape<StringShape>;
|
|
2132
|
+
retries: OptionalShape<NumberShape>;
|
|
2133
|
+
timeout: OptionalShape<NumberShape>;
|
|
2134
|
+
}, false>>;
|
|
2135
|
+
concurrency: OptionalShape<NumberShape>;
|
|
2136
|
+
bail: OptionalShape<LiteralShape<readonly [true, false]>>;
|
|
2089
2137
|
}, false>;
|
|
2090
2138
|
|
|
2091
2139
|
/**
|
|
2092
|
-
* Represents a JSON-serializable snapshot of one phase's state — its identity, status,
|
|
2093
|
-
* override
|
|
2140
|
+
* Represents a JSON-serializable snapshot of one phase's state — its identity, status, the
|
|
2141
|
+
* forced override a whole-phase `skip` or `stop` left, the effective `bail` and `concurrency`
|
|
2142
|
+
* it ran under, and its nested task snapshots.
|
|
2094
2143
|
*
|
|
2095
2144
|
* @remarks
|
|
2096
|
-
* Pure JSON
|
|
2097
|
-
* `override` is the forced status of a whole-phase `skip` / `stop` —
|
|
2098
|
-
* when one is in force, so a restore reinstates it
|
|
2145
|
+
* Pure JSON data. `status` is the effective status (override-or-derived) at snapshot time.
|
|
2146
|
+
* `override` is the forced status of a whole-phase `skip` / `stop` — present only
|
|
2147
|
+
* when one is in force, so a restore reinstates it directly (no fragile derivation comparison)
|
|
2099
2148
|
* and a genuinely-derived phase carries none. A leaf {@link TaskSnapshot} needs no `override`
|
|
2100
|
-
* field — a task's terminal status
|
|
2149
|
+
* field — a task's terminal status is its forced marker. `tasks` are the phase's
|
|
2101
2150
|
* {@link TaskSnapshot}s in order.
|
|
2102
2151
|
*/
|
|
2103
2152
|
export declare interface PhaseSnapshot {
|
|
@@ -2109,8 +2158,8 @@ export declare interface PhaseSnapshot {
|
|
|
2109
2158
|
/** Records the forced status of a whole-phase `skip` / `stop`; present only when an override is in force. */
|
|
2110
2159
|
readonly override?: LifecycleStatus;
|
|
2111
2160
|
/**
|
|
2112
|
-
* Records the
|
|
2113
|
-
* — persisted (
|
|
2161
|
+
* Records the effective failure policy this phase ran under (`phase.bail ?? workflow.bail`)
|
|
2162
|
+
* — persisted (required, like {@link WorkflowSnapshot.bail}) so a restore reinstates the same
|
|
2114
2163
|
* per-phase policy identically without a silent default.
|
|
2115
2164
|
*/
|
|
2116
2165
|
readonly bail: boolean;
|
|
@@ -2155,11 +2204,11 @@ export declare interface PhaseUpdate {
|
|
|
2155
2204
|
* `tasks` (structural children change through the phase's own `add` / `remove` /
|
|
2156
2205
|
* `move`, not a patch).
|
|
2157
2206
|
*/
|
|
2158
|
-
export declare const phaseUpdateShape: ObjectShape<{
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2207
|
+
export declare const phaseUpdateShape: ObjectShape< {
|
|
2208
|
+
name: OptionalShape<StringShape>;
|
|
2209
|
+
description: OptionalShape<StringShape>;
|
|
2210
|
+
concurrency: OptionalShape<NumberShape>;
|
|
2211
|
+
bail: OptionalShape<LiteralShape<readonly [true, false]>>;
|
|
2163
2212
|
}, false>;
|
|
2164
2213
|
|
|
2165
2214
|
/**
|
|
@@ -2172,7 +2221,8 @@ export declare const phaseUpdateShape: ObjectShape<{
|
|
|
2172
2221
|
export declare function recoverWorkflowSnapshot(snapshot: WorkflowSnapshot): WorkflowSnapshot;
|
|
2173
2222
|
|
|
2174
2223
|
/**
|
|
2175
|
-
* Resolves a task's runtime silence window against its workflow default
|
|
2224
|
+
* Resolves a task's runtime silence window against its workflow default, to a host-safe
|
|
2225
|
+
* `1..MAX_TIMER_MS` window or to `undefined` where the task disables it.
|
|
2176
2226
|
*
|
|
2177
2227
|
* @param value - The task-level override; any present non-positive or non-finite value disables
|
|
2178
2228
|
* @param fallback - The workflow-level default
|
|
@@ -2250,13 +2300,13 @@ export declare interface RunHolderInterface {
|
|
|
2250
2300
|
* bounded concurrency, retries, and the per-attempt timeout are all the Queue's —
|
|
2251
2301
|
* the Runner adds only orchestration (launching, ordering, draining, fail-fast).
|
|
2252
2302
|
* - **Spawns actually run, results stay ordered (the B2 fix).** Declared inputs and
|
|
2253
|
-
* `spawn`ed siblings flow through the
|
|
2303
|
+
* `spawn`ed siblings flow through the same `#launch`, which appends the unit's `id`
|
|
2254
2304
|
* to an ordered `#order` list and records its settled value into `#values` by `id`.
|
|
2255
2305
|
* Results are read back as `#order.map(id => #values.get(id))` — declared first (in
|
|
2256
2306
|
* input order), then spawns (in spawn order). There is no one-time task snapshot,
|
|
2257
2307
|
* so a unit spawned mid-handler is run and ordered like any other.
|
|
2258
2308
|
* - **`execute` awaits the full spawn closure through a count gate.** `#launch` increments
|
|
2259
|
-
* an outstanding-unit `#count`
|
|
2309
|
+
* an outstanding-unit `#count` before enqueuing and every settle decrements it,
|
|
2260
2310
|
* resolving the `#drained` deferred at zero. Because `spawn` calls `#launch` (so
|
|
2261
2311
|
* `#count += 1`) before the parent handler returns, the count never reaches zero
|
|
2262
2312
|
* mid-run — `execute` parks on `#drained` and so awaits the entire transitive
|
|
@@ -2268,26 +2318,26 @@ export declare interface RunHolderInterface {
|
|
|
2268
2318
|
* spawn by a bounded handler can still deadlock — that caveat is the caller's.)
|
|
2269
2319
|
* - **Per-unit Controller + signal.** Each unit gets a `Controller` carrying its `id`,
|
|
2270
2320
|
* `input`, the unit's `Abort` (so `aborted` / `abort` delegate to it), and the queue
|
|
2271
|
-
* attempt's `signal` (which
|
|
2321
|
+
* attempt's `signal` (which any-combines the unit abort + runner abort + timeout). A
|
|
2272
2322
|
* `spawn` callback is injected so `controller.spawn(input)` delegates to `#launch`.
|
|
2273
2323
|
* - **One-shot + fail-fast.** `execute` runs once (a second call throws). The first
|
|
2274
2324
|
* unit failure (after its retries) records the error and `abort()`s the run, so every
|
|
2275
2325
|
* sibling's signal fires; later failures are ignored and `execute` rejects with the
|
|
2276
2326
|
* first error. A user `abort(reason)` likewise rejects a running `execute`.
|
|
2277
2327
|
* - **`pause` / `resume` / `stop` ride the backing Queue.** `pause` / `resume`
|
|
2278
|
-
* delegate straight to the Queue's own pause/resume (holding/releasing the
|
|
2328
|
+
* delegate straight to the Queue's own pause/resume (holding/releasing the next
|
|
2279
2329
|
* dispatch while an in-flight unit finishes); `paused` mirrors the Queue's. `stop` is a
|
|
2280
|
-
*
|
|
2281
|
-
* units are rejected by the Queue's own stop
|
|
2330
|
+
* graceful permanent end, distinct from `abort`: still-pending (never-dispatched)
|
|
2331
|
+
* units are rejected by the Queue's own stop without their handler ever running, and
|
|
2282
2332
|
* `#settle` reads that fact (`#dispatched`) to treat the rejection as a stop artifact —
|
|
2283
2333
|
* not a failure, never tripping fail-fast — while an in-flight unit still runs to
|
|
2284
|
-
* completion and settles normally. `execute`
|
|
2334
|
+
* completion and settles normally. `execute` resolves (never rejects) after every unit
|
|
2285
2335
|
* has settled, with whatever results actually completed.
|
|
2286
2336
|
* - **Observable.** The owned {@link emitter} ({@link RunnerEventMap}) carries the run
|
|
2287
2337
|
* lifecycle — `start` / `unit` / `spawn` / `settle` / `fail` / `finish` / `abort` — for
|
|
2288
|
-
* fire-and-forget observers. Every event is emitted directly, strictly
|
|
2338
|
+
* fire-and-forget observers. Every event is emitted directly, strictly after the relevant
|
|
2289
2339
|
* launch / settle / drain transition; the emitter isolates a listener throw and routes it
|
|
2290
|
-
* to its `error` handler (the `error` option), so a buggy observer can
|
|
2340
|
+
* to its `error` handler (the `error` option), so a buggy observer can never reorder, throw
|
|
2291
2341
|
* into, or corrupt the one-shot / fail-fast / spawn-tracking engine: the outstanding-unit
|
|
2292
2342
|
* count gate stays balanced and fail-fast still fires regardless of what a listener does.
|
|
2293
2343
|
* Observation is purely a side-channel.
|
|
@@ -2300,15 +2350,15 @@ export declare class Runner<TInput, TResult> implements RunnerInterface<TInput,
|
|
|
2300
2350
|
get stopped(): boolean;
|
|
2301
2351
|
get paused(): boolean;
|
|
2302
2352
|
/**
|
|
2303
|
-
* Injects one more unit into an
|
|
2304
|
-
* `Controller.spawn`, called from
|
|
2353
|
+
* Injects one more unit into an in-flight `execute` run — a live counterpart to a
|
|
2354
|
+
* `Controller.spawn`, called from outside any unit's handler.
|
|
2305
2355
|
*
|
|
2306
2356
|
* @remarks
|
|
2307
2357
|
* Returns `undefined` synchronously (graceful, non-throwing) unless the
|
|
2308
2358
|
* runner is mid-`execute` and not yet stopped — covering "never started",
|
|
2309
2359
|
* "already drained", "aborted", and "destroyed". Otherwise the unit is routed through
|
|
2310
|
-
* the
|
|
2311
|
-
* unit count gate increments
|
|
2360
|
+
* the same backing queue as a declared/`spawn`ed unit through `#launch` — the outstanding-
|
|
2361
|
+
* unit count gate increments before this call returns, so an in-flight `execute`
|
|
2312
2362
|
* keeps awaiting it (the drain race: `#running` flips to `false` as the very first
|
|
2313
2363
|
* step after `execute`'s `await drained.promise` settles, so a `spawn` reaching this
|
|
2314
2364
|
* method after the run has fully drained is cleanly rejected with `undefined` —
|
|
@@ -2330,7 +2380,7 @@ export declare class Runner<TInput, TResult> implements RunnerInterface<TInput,
|
|
|
2330
2380
|
abort(reason?: unknown): Promise<void>;
|
|
2331
2381
|
/**
|
|
2332
2382
|
* Suspends dispatch (resumable): delegates to the backing queue's own
|
|
2333
|
-
* `pause`, which holds the
|
|
2383
|
+
* `pause`, which holds the next dispatch while any in-flight unit finishes.
|
|
2334
2384
|
*
|
|
2335
2385
|
* @remarks
|
|
2336
2386
|
* A no-op after the runner is `stopped` — a stopped runner has no dispatch left to
|
|
@@ -2348,10 +2398,10 @@ export declare class Runner<TInput, TResult> implements RunnerInterface<TInput,
|
|
|
2348
2398
|
*/
|
|
2349
2399
|
resume(): void;
|
|
2350
2400
|
/**
|
|
2351
|
-
* Ends the runner permanently — a
|
|
2401
|
+
* Ends the runner permanently — a graceful stop, distinct from `abort`.
|
|
2352
2402
|
* Marks the runner `stopping` + `stopped`, then stops the backing queue: every
|
|
2353
|
-
* still-
|
|
2354
|
-
* "queue is stopped" error,
|
|
2403
|
+
* still-pending (never-dispatched) unit is rejected by the queue with its own
|
|
2404
|
+
* "queue is stopped" error, without running its handler; every already-in-flight unit
|
|
2355
2405
|
* keeps running to completion and settles normally. `#settle` reads `#stopping` to
|
|
2356
2406
|
* classify a never-dispatched unit's rejection as a stop artifact (decrement the count
|
|
2357
2407
|
* gate, no recorded failure, no fail-fast trip) rather than a genuine failure — a
|
|
@@ -2362,12 +2412,13 @@ export declare class Runner<TInput, TResult> implements RunnerInterface<TInput,
|
|
|
2362
2412
|
}
|
|
2363
2413
|
|
|
2364
2414
|
/**
|
|
2365
|
-
* Declares the per-entry reliability
|
|
2366
|
-
* per-attempt deadline, resolved from the unit's input through
|
|
2415
|
+
* Declares the per-entry reliability overrides for one unit — its extra attempts on failure
|
|
2416
|
+
* and its per-attempt deadline, resolved from the unit's input through
|
|
2417
|
+
* {@link RunnerOptions.entries}.
|
|
2367
2418
|
*
|
|
2368
2419
|
* @remarks
|
|
2369
2420
|
* The unit's `id` and `signal` stay Runner-managed (it mints the id and owns the per-unit
|
|
2370
|
-
* abort), so only the two reliability knobs are exposed here. Each field
|
|
2421
|
+
* abort), so only the two reliability knobs are exposed here. Each field overrides the
|
|
2371
2422
|
* runner-level `retries` / `timeout` default for that one unit; an omitted field falls back
|
|
2372
2423
|
* to the default. This is the per-unit slice of the backing Queue's
|
|
2373
2424
|
* `@orkestrel/queue` `QueueEntryOptions` surfaced cleanly — the Queue already
|
|
@@ -2380,8 +2431,8 @@ export declare interface RunnerEntryOptions {
|
|
|
2380
2431
|
|
|
2381
2432
|
/**
|
|
2382
2433
|
* Declares the push observation surface of a {@link RunnerInterface} — the run
|
|
2383
|
-
* lifecycle a fire-and-forget observer (logging, metrics, tracing) subscribes to,
|
|
2384
|
-
*
|
|
2434
|
+
* lifecycle a fire-and-forget observer (logging, metrics, tracing) subscribes to, beside
|
|
2435
|
+
* the eventual `execute` result.
|
|
2385
2436
|
*
|
|
2386
2437
|
* @typeParam TResult - The value a unit resolves; the `finish` payload is the run's ordered
|
|
2387
2438
|
* `readonly TResult[]`, so the map is `RunnerEventMap<TResult>` — mirroring how the
|
|
@@ -2389,9 +2440,9 @@ export declare interface RunnerEntryOptions {
|
|
|
2389
2440
|
*
|
|
2390
2441
|
* @remarks
|
|
2391
2442
|
* Listener isolation is the emitter's: every event is emitted directly and a
|
|
2392
|
-
* listener throw is routed to the emitter's
|
|
2443
|
+
* listener throw is routed to the emitter's own `error` handler (the `error` option), never
|
|
2393
2444
|
* onto this domain map and never into the one-shot / fail-fast / spawn-tracking engine — so a
|
|
2394
|
-
* buggy observer can never reorder, throw into, or corrupt the run. Every emit sits
|
|
2445
|
+
* buggy observer can never reorder, throw into, or corrupt the run. Every emit sits after the
|
|
2395
2446
|
* relevant unit-launch / settle / drain transition, so a throwing observer cannot unbalance
|
|
2396
2447
|
* the outstanding-unit count gate or break fail-fast. Subscribe through `runner.emitter.on(...)`.
|
|
2397
2448
|
*
|
|
@@ -2436,8 +2487,8 @@ export declare type RunnerHandler<TInput, TResult> = (controller: ControllerInte
|
|
|
2436
2487
|
* spawned) through it so spawned work actually runs.
|
|
2437
2488
|
*
|
|
2438
2489
|
* Exposes a typed {@link emitter} carrying its run lifecycle moments
|
|
2439
|
-
* ({@link RunnerEventMap}) for fire-and-forget observers,
|
|
2440
|
-
* result. Emitting is observation-only — every event fires
|
|
2490
|
+
* ({@link RunnerEventMap}) for fire-and-forget observers, alongside the eventual `execute`
|
|
2491
|
+
* result. Emitting is observation-only — every event fires after the relevant unit-launch /
|
|
2441
2492
|
* settle / drain transition, so a buggy observer can never reorder or corrupt the one-shot /
|
|
2442
2493
|
* fail-fast / spawn-tracking engine: the emitter isolates a listener throw and routes it to
|
|
2443
2494
|
* its `error` handler (the `error` option), never the run. Subscribe through
|
|
@@ -2467,16 +2518,16 @@ export declare interface RunnerInterface<TInput, TResult> {
|
|
|
2467
2518
|
*/
|
|
2468
2519
|
execute(inputs: readonly TInput[]): Promise<readonly TResult[]>;
|
|
2469
2520
|
/**
|
|
2470
|
-
* Injects one more unit into
|
|
2471
|
-
* `Controller.spawn`, called from
|
|
2472
|
-
* `running` {@link PhaseInterface}
|
|
2473
|
-
*
|
|
2521
|
+
* Injects one more unit into a run already in flight — the live counterpart to a
|
|
2522
|
+
* `Controller.spawn`, called from outside any unit's handler (the seam through which a
|
|
2523
|
+
* subscribed run offers a newly added task of a `running` {@link PhaseInterface} to the same
|
|
2524
|
+
* execution substrate).
|
|
2474
2525
|
*
|
|
2475
2526
|
* @remarks
|
|
2476
2527
|
* Returns `undefined` synchronously (graceful, non-throwing) when the
|
|
2477
2528
|
* runner is not mid-`execute`, or the run has already fully drained — the
|
|
2478
2529
|
* caller reads `undefined` as "not accepted". Otherwise the unit is routed through
|
|
2479
|
-
* the
|
|
2530
|
+
* the same backing queue as a declared/`spawn`ed unit (the runner's
|
|
2480
2531
|
* outstanding-unit count gate keeps the in-flight `execute` awaiting it) and emits
|
|
2481
2532
|
* the {@link RunnerEventMap.spawn} event; its result promise resolves after the unit
|
|
2482
2533
|
* settles.
|
|
@@ -2494,7 +2545,7 @@ export declare interface RunnerInterface<TInput, TResult> {
|
|
|
2494
2545
|
*/
|
|
2495
2546
|
abort(reason?: unknown): Promise<void>;
|
|
2496
2547
|
/**
|
|
2497
|
-
* Suspends dispatch (resumable): the backing queue holds the
|
|
2548
|
+
* Suspends dispatch (resumable): the backing queue holds the next dispatch
|
|
2498
2549
|
* while any in-flight unit finishes; idempotent.
|
|
2499
2550
|
*
|
|
2500
2551
|
* @example
|
|
@@ -2515,12 +2566,12 @@ export declare interface RunnerInterface<TInput, TResult> {
|
|
|
2515
2566
|
*/
|
|
2516
2567
|
resume(): void;
|
|
2517
2568
|
/**
|
|
2518
|
-
* Ends the runner permanently — a
|
|
2569
|
+
* Ends the runner permanently — a graceful stop: no further unit is
|
|
2519
2570
|
* dispatched, but every already-in-flight unit runs to completion and settles
|
|
2520
2571
|
* normally. A never-dispatched (still-pending) unit is rejected by the backing queue
|
|
2521
|
-
* and is
|
|
2522
|
-
* failure still
|
|
2523
|
-
* settled, with whatever results
|
|
2572
|
+
* and is not recorded as a failure, so it never trips fail-fast, while a genuine in-flight
|
|
2573
|
+
* failure still does. `execute`'s promise resolves rather than rejects after every unit has
|
|
2574
|
+
* settled, with whatever results completed. Idempotent.
|
|
2524
2575
|
*
|
|
2525
2576
|
* @example
|
|
2526
2577
|
* ```ts
|
|
@@ -2541,7 +2592,9 @@ export declare interface RunnerInterface<TInput, TResult> {
|
|
|
2541
2592
|
}
|
|
2542
2593
|
|
|
2543
2594
|
/**
|
|
2544
|
-
* Declares the options for `createRunner
|
|
2595
|
+
* Declares the options for `createRunner` — the `handler` every unit runs, the queue bounds
|
|
2596
|
+
* `concurrency`, `retries`, and `timeout`, the per-entry `entries` resolver, and the emitter
|
|
2597
|
+
* `on` hooks and `error` handler.
|
|
2545
2598
|
*
|
|
2546
2599
|
* @remarks
|
|
2547
2600
|
* - `handler` — runs each unit's work against its {@link ControllerInterface};
|
|
@@ -2638,13 +2691,13 @@ export declare function scheduleHost(start: (complete: () => void, failure: (err
|
|
|
2638
2691
|
* browser and Node.
|
|
2639
2692
|
*
|
|
2640
2693
|
* @remarks
|
|
2641
|
-
* - **Cross-environment.** Uses
|
|
2694
|
+
* - **Cross-environment.** Uses only `setTimeout` / `clearTimeout` — universally
|
|
2642
2695
|
* available. It deliberately avoids env-specific fast paths (`setImmediate`,
|
|
2643
2696
|
* `scheduler.yield`, `requestAnimationFrame`, `node:timers/promises`,
|
|
2644
2697
|
* `MessageChannel`); those belong to the environment backends, built with the
|
|
2645
2698
|
* agent loop that consumes them.
|
|
2646
2699
|
* - **`yield` is a macrotask host-turn, not a microtask.** `yield()` waits on a
|
|
2647
|
-
* `setTimeout(0)`,
|
|
2700
|
+
* `setTimeout(0)`, not `queueMicrotask`. A microtask drains before the host
|
|
2648
2701
|
* regains control, so it would not actually let pending I/O, timers, or
|
|
2649
2702
|
* rendering run — it only defers within the current task. A zero-delay timer is
|
|
2650
2703
|
* the correct cross-environment "give the host a turn".
|
|
@@ -2666,10 +2719,10 @@ export declare function scheduleHost(start: (complete: () => void, failure: (err
|
|
|
2666
2719
|
* }
|
|
2667
2720
|
* ```
|
|
2668
2721
|
*/
|
|
2669
|
-
declare class
|
|
2722
|
+
export declare class Scheduler implements SchedulerInterface {
|
|
2670
2723
|
/**
|
|
2671
2724
|
* Yields control back to the host so other tasks (I/O, timers, rendering) can
|
|
2672
|
-
* run, then resumes — a macrotask turn through `setTimeout(0)` (
|
|
2725
|
+
* run, then resumes — a macrotask turn through `setTimeout(0)` (not a microtask,
|
|
2673
2726
|
* which would resume before the host regains control).
|
|
2674
2727
|
*/
|
|
2675
2728
|
yield(options?: SchedulerOptions): Promise<void>;
|
|
@@ -2684,11 +2737,10 @@ declare class Scheduler_2 implements SchedulerInterface {
|
|
|
2684
2737
|
*/
|
|
2685
2738
|
delay(ms: number, options?: SchedulerOptions): Promise<void>;
|
|
2686
2739
|
}
|
|
2687
|
-
export { Scheduler_2 as Scheduler }
|
|
2688
2740
|
|
|
2689
2741
|
/**
|
|
2690
|
-
* Declares a cooperative host-yield primitive: a loop decides
|
|
2691
|
-
* decides
|
|
2742
|
+
* Declares a cooperative host-yield primitive: a loop decides what to do; the scheduler
|
|
2743
|
+
* decides when the host regains control. It is abort-aware — a pending yield or delay
|
|
2692
2744
|
* rejects with the signal's reason when aborted.
|
|
2693
2745
|
*/
|
|
2694
2746
|
export declare interface SchedulerInterface {
|
|
@@ -2759,12 +2811,13 @@ export declare interface TaskActivity {
|
|
|
2759
2811
|
}
|
|
2760
2812
|
|
|
2761
2813
|
/**
|
|
2762
|
-
* Represents one complete replacement of a running task's observable activity
|
|
2814
|
+
* Represents one complete replacement of a running task's observable activity, an omitted
|
|
2815
|
+
* collection meaning an empty one.
|
|
2763
2816
|
*
|
|
2764
2817
|
* @remarks
|
|
2765
2818
|
* `note` describes the frame while `progress.message` describes the progress value.
|
|
2766
|
-
* Omitted `
|
|
2767
|
-
*
|
|
2819
|
+
* Omitted `progress` clears the previous aggregate progress. Use {@link TaskInterface.report} to
|
|
2820
|
+
* commit the replacement.
|
|
2768
2821
|
*/
|
|
2769
2822
|
export declare interface TaskActivityInput {
|
|
2770
2823
|
readonly note?: string;
|
|
@@ -2774,11 +2827,12 @@ export declare interface TaskActivityInput {
|
|
|
2774
2827
|
}
|
|
2775
2828
|
|
|
2776
2829
|
/**
|
|
2777
|
-
* Represents one identified thing a running task claims active, with the moment the claim
|
|
2830
|
+
* Represents one identified thing a running task claims active, with the moment the claim
|
|
2831
|
+
* began — the shape {@link TaskOperation} and {@link TaskConstraint} share.
|
|
2778
2832
|
*
|
|
2779
2833
|
* @remarks
|
|
2780
|
-
*
|
|
2781
|
-
*
|
|
2834
|
+
* `id` is unique within one complete activity report, `name` is the human-readable label, and
|
|
2835
|
+
* `started` is a finite
|
|
2782
2836
|
* non-negative reporter timestamp. The two claim lists are validated by one guard
|
|
2783
2837
|
* ({@link import('./validators.js').isTaskClaimList}) and owned by one cloner
|
|
2784
2838
|
* ({@link import('./cloners.js').cloneTaskClaims}) over this type, while each list keeps its own
|
|
@@ -2807,7 +2861,7 @@ export declare interface TaskConstraint extends TaskClaim {
|
|
|
2807
2861
|
*
|
|
2808
2862
|
* @remarks
|
|
2809
2863
|
* Extends {@link WorkflowContext} and adds `phase`, the parent {@link PhaseContext}
|
|
2810
|
-
* — so a task carries its
|
|
2864
|
+
* — so a task carries its full lineage (workflow → phase → task) for a
|
|
2811
2865
|
* {@link TaskResult} or a runner.
|
|
2812
2866
|
*/
|
|
2813
2867
|
export declare interface TaskContext extends WorkflowContext {
|
|
@@ -2816,10 +2870,11 @@ export declare interface TaskContext extends WorkflowContext {
|
|
|
2816
2870
|
|
|
2817
2871
|
/**
|
|
2818
2872
|
* Declares the per-task handle a {@link WorkflowFunction} receives — the running task's
|
|
2819
|
-
* cancellation, its input, its lineage, and read
|
|
2873
|
+
* cancellation, its input, its lineage, and read access up the tree to the results already
|
|
2874
|
+
* settled.
|
|
2820
2875
|
*
|
|
2821
2876
|
* @remarks
|
|
2822
|
-
* A lean handle (
|
|
2877
|
+
* A lean handle (not the runner `Controller` — it carries no `spawn`; a workflow task
|
|
2823
2878
|
* is a leaf of the declarative tree, not a fan-out unit). It exposes:
|
|
2824
2879
|
* - `signal` — this attempt's folded cancellation: its per-attempt deadline, task
|
|
2825
2880
|
* stop/skip, workflow abort/timeout/budget/destroy, or a sibling fail-fast.
|
|
@@ -2827,7 +2882,7 @@ export declare interface TaskContext extends WorkflowContext {
|
|
|
2827
2882
|
* - `input` — the task's `metadata` bag (the open consumer payload from its
|
|
2828
2883
|
* {@link TaskInput}); `{}` when none.
|
|
2829
2884
|
* - `task` — the task's full {@link TaskContext} (so `task.phase` / `task.phase.workflow`
|
|
2830
|
-
* navigate
|
|
2885
|
+
* navigate up the lineage).
|
|
2831
2886
|
* - `wait()` — a cooperative checkpoint for the workflow, phase, and task pause gates.
|
|
2832
2887
|
* - `results()` — every settled task's {@link TaskResult} across already-finished phases,
|
|
2833
2888
|
* so a `function` task can read an earlier phase's output (the W-b result tree, read-only).
|
|
@@ -2867,14 +2922,14 @@ export declare interface TaskControllerInterface {
|
|
|
2867
2922
|
}
|
|
2868
2923
|
|
|
2869
2924
|
/**
|
|
2870
|
-
* Represents the serializable definition of one task — its identity
|
|
2871
|
-
* the behavior it runs.
|
|
2925
|
+
* Represents the serializable definition of one task — its identity, an optional reference to
|
|
2926
|
+
* the behavior it runs, and its optional per-task `retries` and `timeout` overrides.
|
|
2872
2927
|
*
|
|
2873
2928
|
* @remarks
|
|
2874
|
-
* Pure JSON
|
|
2875
|
-
* (factories.ts), and it carries
|
|
2929
|
+
* Pure JSON data: a UI or an LLM authors it, it round-trips through the contract
|
|
2930
|
+
* (factories.ts), and it carries no functions. `id` is the positional identity within
|
|
2876
2931
|
* its phase; `name` is the human label; `description` is optional prose. `behavior` is a
|
|
2877
|
-
*
|
|
2932
|
+
* plain name — a key resolved once at construction against a workflow-level
|
|
2878
2933
|
* {@link WorkflowRegistry} registry into a runtime {@link TaskInterface.handler}
|
|
2879
2934
|
* carried on the live task. An omitted `behavior` is the deliberate no-op form and completes
|
|
2880
2935
|
* with JSON `null`; an unresolved present name remains inspectable but is not executable.
|
|
@@ -2889,8 +2944,8 @@ export declare interface TaskDefinition {
|
|
|
2889
2944
|
*
|
|
2890
2945
|
* @remarks
|
|
2891
2946
|
* Extra attempts after the first on failure (a non-negative integer); the runner threads it
|
|
2892
|
-
* to this task's substrate unit,
|
|
2893
|
-
* the default (no extra attempts).
|
|
2947
|
+
* to this task's substrate unit, overriding the phase Runner's `retries` default. Omitted ⇒
|
|
2948
|
+
* the default (no extra attempts). Persisted in a {@link TaskSnapshot} (like `bail` and
|
|
2894
2949
|
* `concurrency`), so `createRestoredWorkflow(snapshot, { functions })` resumes with the same
|
|
2895
2950
|
* reliability config; only the resolved handler itself is runtime-only.
|
|
2896
2951
|
*/
|
|
@@ -2900,7 +2955,7 @@ export declare interface TaskDefinition {
|
|
|
2900
2955
|
*
|
|
2901
2956
|
* @remarks
|
|
2902
2957
|
* The workflow-owned per-attempt deadline in milliseconds, an integer from `0` through
|
|
2903
|
-
* `MAX_TIMER_MS`. Zero or omission means no deadline.
|
|
2958
|
+
* `MAX_TIMER_MS`. Zero or omission means no deadline. Persisted in a {@link TaskSnapshot},
|
|
2904
2959
|
* so `createRestoredWorkflow(snapshot, { functions })` resumes with the same reliability config;
|
|
2905
2960
|
* only the resolved handler itself is runtime-only.
|
|
2906
2961
|
*/
|
|
@@ -2980,12 +3035,10 @@ export declare type TaskFailureOrigin = 'handler' | 'timeout' | 'recovery';
|
|
|
2980
3035
|
|
|
2981
3036
|
/**
|
|
2982
3037
|
* Represents the minimal data to create a task context — a partial {@link TaskContext} plus
|
|
2983
|
-
*
|
|
3038
|
+
* the open `metadata` bag the task stores and snapshots without interpreting it.
|
|
2984
3039
|
*
|
|
2985
3040
|
* @remarks
|
|
2986
|
-
*
|
|
2987
|
-
* {@link TaskSnapshot} but never interprets. All members are optional (the storing
|
|
2988
|
-
* layer fills identity / lineage).
|
|
3041
|
+
* All members are optional (the storing layer fills identity / lineage).
|
|
2989
3042
|
*/
|
|
2990
3043
|
export declare interface TaskInput extends Partial<TaskContext> {
|
|
2991
3044
|
/** Holds an open consumer bag — stored and snapshotted, never interpreted by the workflow. */
|
|
@@ -3000,13 +3053,13 @@ export declare interface TaskInput extends Partial<TaskContext> {
|
|
|
3000
3053
|
* @remarks
|
|
3001
3054
|
* - **Identity + lineage.** `id` / `name` / `description` mirror the definition;
|
|
3002
3055
|
* `context` is the task's full {@link TaskContext} (so `context.phase` /
|
|
3003
|
-
* `context.phase.workflow` navigate
|
|
3056
|
+
* `context.phase.workflow` navigate up the tree), and `phase` / `workflow` are the
|
|
3004
3057
|
* live parent entities for direct lineage navigation.
|
|
3005
3058
|
* - **State machine.** `status` is the explicit current state. `start`
|
|
3006
3059
|
* moves `pending → running`; the terminal transitions are `complete(value)` (records
|
|
3007
3060
|
* a {@link import('@orkestrel/contract').Success}), `fail(error)` (records a
|
|
3008
3061
|
* {@link import('@orkestrel/contract').Failure}), `skip` (intentionally not run),
|
|
3009
|
-
* and `stop` (ended early). Each is
|
|
3062
|
+
* and `stop` (ended early). Each is guarded: an illegal transition (for example,
|
|
3010
3063
|
* completing a non-`running` task) throws a {@link import('./errors.js').WorkflowError}.
|
|
3011
3064
|
* A leaf needs no override: `skipped` / `stopped` are explicit terminal statuses and
|
|
3012
3065
|
* restore directly from {@link TaskSnapshot.status}.
|
|
@@ -3014,7 +3067,7 @@ export declare interface TaskInput extends Partial<TaskContext> {
|
|
|
3014
3067
|
* outcome (`completed` / `failed`), else `undefined` — the lineage-navigable leaf of the
|
|
3015
3068
|
* result tree.
|
|
3016
3069
|
* - **Observable.** The owned {@link emitter} ({@link TaskEventMap}) fires
|
|
3017
|
-
* `start` / `complete` / `fail` / `pause` / `resume` / `skip` / `stop` strictly
|
|
3070
|
+
* `start` / `complete` / `fail` / `pause` / `resume` / `skip` / `stop` strictly after
|
|
3018
3071
|
* each state change; the emitter isolates a listener throw and routes it to its `error`
|
|
3019
3072
|
* handler (the `error` option).
|
|
3020
3073
|
*/
|
|
@@ -3034,14 +3087,14 @@ export declare interface TaskInterface {
|
|
|
3034
3087
|
/** Holds the recorded outcome after the task settled with one (`completed` / `failed`), else `undefined`. */
|
|
3035
3088
|
readonly result: TaskResult | undefined;
|
|
3036
3089
|
/**
|
|
3037
|
-
* Names the behavior reference — a plain registry key name,
|
|
3090
|
+
* Names the behavior reference — a plain registry key name, persisted (mirrors
|
|
3038
3091
|
* {@link TaskDefinition.behavior} / {@link TaskSnapshot.behavior}), like {@link PhaseInterface.bail}.
|
|
3039
3092
|
* `undefined` when this task has no behavior reference.
|
|
3040
3093
|
*/
|
|
3041
3094
|
readonly behavior: string | undefined;
|
|
3042
3095
|
/**
|
|
3043
|
-
* Holds the
|
|
3044
|
-
* Resolved
|
|
3096
|
+
* Holds the resolved runtime handler — runtime-only, never persisted in a {@link TaskSnapshot}.
|
|
3097
|
+
* Resolved once at construction (build, restore, or a live mint) by looking `behavior` up in the
|
|
3045
3098
|
* workflow-level {@link WorkflowOptions.functions} registry: `functions?.[behavior]` when `behavior`
|
|
3046
3099
|
* is defined, else `undefined`. An omitted `behavior` is the deliberate no-op form. A present,
|
|
3047
3100
|
* unresolved `behavior` remains visible on exact restore, but the runner rejects it before
|
|
@@ -3049,12 +3102,12 @@ export declare interface TaskInterface {
|
|
|
3049
3102
|
*/
|
|
3050
3103
|
readonly handler: WorkflowFunction | undefined;
|
|
3051
3104
|
/**
|
|
3052
|
-
* Holds the extra attempts after the first on failure —
|
|
3105
|
+
* Holds the extra attempts after the first on failure — persisted (mirrors {@link TaskDefinition.retries}
|
|
3053
3106
|
* / {@link TaskSnapshot.retries}), like {@link PhaseInterface.concurrency}. `undefined` ⇒ none.
|
|
3054
3107
|
*/
|
|
3055
3108
|
readonly retries: number | undefined;
|
|
3056
3109
|
/**
|
|
3057
|
-
* Holds the workflow-owned per-attempt deadline in milliseconds (`0..MAX_TIMER_MS`) —
|
|
3110
|
+
* Holds the workflow-owned per-attempt deadline in milliseconds (`0..MAX_TIMER_MS`) — persisted
|
|
3058
3111
|
* (mirrors {@link TaskDefinition.timeout} / {@link TaskSnapshot.timeout}). Zero or
|
|
3059
3112
|
* `undefined` means no deadline.
|
|
3060
3113
|
*/
|
|
@@ -3069,10 +3122,28 @@ export declare interface TaskInterface {
|
|
|
3069
3122
|
readonly paused: boolean;
|
|
3070
3123
|
/** Holds this task's own cancellation signal; running/pending {@link stop} or {@link skip} fires it. */
|
|
3071
3124
|
readonly signal: AbortSignal;
|
|
3125
|
+
/**
|
|
3126
|
+
* Launches the next persisted attempt of this task, from `pending` or from a retrying
|
|
3127
|
+
* `running`, clearing the activity frame and emitting `start` before the cascade.
|
|
3128
|
+
*/
|
|
3072
3129
|
start(): void;
|
|
3130
|
+
/**
|
|
3131
|
+
* Settles this running task as `completed`, boxing its produced value as a `Success`.
|
|
3132
|
+
*
|
|
3133
|
+
* @param value - The JSON result the handler produced
|
|
3134
|
+
*/
|
|
3073
3135
|
complete(value: JSONValue): void;
|
|
3136
|
+
/**
|
|
3137
|
+
* Settles this running task as `failed`, boxing a normalized failure as a `Failure`.
|
|
3138
|
+
*
|
|
3139
|
+
* @param error - The normalized {@link TaskFailure} to persist
|
|
3140
|
+
*/
|
|
3074
3141
|
fail(error: TaskFailure): void;
|
|
3142
|
+
/** Moves this task to `skipped` — work intentionally not run — and emits `skip`. */
|
|
3075
3143
|
skip(): void;
|
|
3144
|
+
/**
|
|
3145
|
+
* Moves this task to `stopped`, fires its own signal, releases its gate, and emits `stop`.
|
|
3146
|
+
*/
|
|
3076
3147
|
stop(): void;
|
|
3077
3148
|
/**
|
|
3078
3149
|
* Replaces the complete observable activity of this running task.
|
|
@@ -3098,12 +3169,12 @@ export declare interface TaskInterface {
|
|
|
3098
3169
|
*/
|
|
3099
3170
|
wait(): Promise<void>;
|
|
3100
3171
|
/**
|
|
3101
|
-
* Applies a validated declarative patch to
|
|
3172
|
+
* Applies a validated declarative patch to this task itself (`name` / `description`).
|
|
3102
3173
|
*
|
|
3103
3174
|
* @remarks
|
|
3104
3175
|
* Defense-in-depth: the owning {@link TaskManagerInterface.update} gates
|
|
3105
|
-
*
|
|
3106
|
-
* check — it
|
|
3176
|
+
* first (target exists + `pending`), so a direct call here is the second, redundant
|
|
3177
|
+
* check — it throws a `MUTATION` {@link import('./errors.js').WorkflowError} unless
|
|
3107
3178
|
* this task's own `status` is `pending`.
|
|
3108
3179
|
*
|
|
3109
3180
|
* @param value - The {@link TaskUpdate} fields to apply
|
|
@@ -3113,6 +3184,12 @@ export declare interface TaskInterface {
|
|
|
3113
3184
|
* ```
|
|
3114
3185
|
*/
|
|
3115
3186
|
patch(value: TaskUpdate): void;
|
|
3187
|
+
/**
|
|
3188
|
+
* Serializes this task's identity, status, result, owned metadata, consumed `attempts`,
|
|
3189
|
+
* reliability settings, and activity.
|
|
3190
|
+
*
|
|
3191
|
+
* @returns The pure-JSON {@link TaskSnapshot} of this leaf
|
|
3192
|
+
*/
|
|
3116
3193
|
snapshot(): TaskSnapshot;
|
|
3117
3194
|
}
|
|
3118
3195
|
|
|
@@ -3129,10 +3206,10 @@ export declare interface TaskInterface {
|
|
|
3129
3206
|
* drift apart.
|
|
3130
3207
|
* - **Positional store.** `append` adds one live {@link TaskInterface} at the end (the build-time
|
|
3131
3208
|
* wiring path), `task(id)` looks one up, `tasks()` lists them in positional order, `count` is
|
|
3132
|
-
* the tally. A `skip` is a
|
|
3209
|
+
* the tally. A `skip` is a status change on a stored task (never a removal), so order survives
|
|
3133
3210
|
* it; a snapshot RESTORE re-`append`s in the snapshot's order, reproducing it exactly.
|
|
3134
3211
|
* - **Gated mutation API.** `add` / `remove` / `move` / `update` are the graceful
|
|
3135
|
-
* `Result` counterparts to `append`, gating
|
|
3212
|
+
* `Result` counterparts to `append`, gating only on the target's own existence/status/id/bounds
|
|
3136
3213
|
* — a duplicate id, an absent/non-`pending` target, an out-of-bounds `index`, or a patch that
|
|
3137
3214
|
* fails {@link taskUpdateShape} validation all fail gracefully with a `MUTATION`
|
|
3138
3215
|
* {@link WorkflowError} instead of throwing.
|
|
@@ -3172,9 +3249,9 @@ export declare class TaskManager implements TaskManagerInterface {
|
|
|
3172
3249
|
* `task(id)` looks one up; `tasks()` lists them in positional order; `count` is the
|
|
3173
3250
|
* tally. No batch matrix (`.claude/rules/patterns.md` § Batch operations is deliberately omitted —
|
|
3174
3251
|
* a phase's tasks are a fixed positional set, not a bulk-mutated collection). `add` / `remove` / `move` /
|
|
3175
|
-
* `update` are the
|
|
3176
|
-
* {@link PhaseInterface.add} / `remove` / `move` / `update` delegates to
|
|
3177
|
-
* container-status/hook gating — the manager gates
|
|
3252
|
+
* `update` are the gated mutation counterparts a
|
|
3253
|
+
* {@link PhaseInterface.add} / `remove` / `move` / `update` delegates to after its own
|
|
3254
|
+
* container-status/hook gating — the manager gates only on the target's own
|
|
3178
3255
|
* existence/status/id/bounds and stays event-free (the entity emits on success).
|
|
3179
3256
|
*/
|
|
3180
3257
|
export declare interface TaskManagerInterface {
|
|
@@ -3183,7 +3260,7 @@ export declare interface TaskManagerInterface {
|
|
|
3183
3260
|
* Adds `task` at the end (the build-time wiring path).
|
|
3184
3261
|
*
|
|
3185
3262
|
* @remarks
|
|
3186
|
-
*
|
|
3263
|
+
* throws a `MUTATION` {@link import('./errors.js').WorkflowError} on a duplicate
|
|
3187
3264
|
* `id` (a genuine programmer error — a build-time wiring bug) instead of
|
|
3188
3265
|
* silently overwriting the existing entry.
|
|
3189
3266
|
*
|
|
@@ -3191,7 +3268,7 @@ export declare interface TaskManagerInterface {
|
|
|
3191
3268
|
*/
|
|
3192
3269
|
append(task: TaskInterface): void;
|
|
3193
3270
|
/**
|
|
3194
|
-
* Inserts `task` at `index` (default the end) — the
|
|
3271
|
+
* Inserts `task` at `index` (default the end) — the gated mutation counterpart to
|
|
3195
3272
|
* {@link append}: a duplicate `id` or an out-of-bounds `index` fails gracefully
|
|
3196
3273
|
* instead of throwing.
|
|
3197
3274
|
*
|
|
@@ -3226,7 +3303,18 @@ export declare interface TaskManagerInterface {
|
|
|
3226
3303
|
* `id` is absent, not `pending`, or `patch` fails validation
|
|
3227
3304
|
*/
|
|
3228
3305
|
update(id: string, patch: TaskUpdate): Result<TaskInterface, WorkflowError>;
|
|
3306
|
+
/**
|
|
3307
|
+
* Looks up one held task by its `id`.
|
|
3308
|
+
*
|
|
3309
|
+
* @param id - The task id to resolve
|
|
3310
|
+
* @returns The live task, or `undefined` when none is held under that id
|
|
3311
|
+
*/
|
|
3229
3312
|
task(id: string): TaskInterface | undefined;
|
|
3313
|
+
/**
|
|
3314
|
+
* Lists the held tasks in positional order.
|
|
3315
|
+
*
|
|
3316
|
+
* @returns Every live task, in the order the store holds them
|
|
3317
|
+
*/
|
|
3230
3318
|
tasks(): readonly TaskInterface[];
|
|
3231
3319
|
}
|
|
3232
3320
|
|
|
@@ -3248,7 +3336,7 @@ export declare interface TaskOperation extends TaskClaim {
|
|
|
3248
3336
|
* The reserved `on` wires initial {@link TaskEventMap} listeners; a
|
|
3249
3337
|
* {@link import('./factories.js').createWorkflow}-built tree threads each level's `on`
|
|
3250
3338
|
* from its parent options, the same way a {@link WorkflowInterface.add} /
|
|
3251
|
-
* {@link PhaseInterface.add} mint threads a leaf's `on` from
|
|
3339
|
+
* {@link PhaseInterface.add} mint threads a leaf's `on` from its options. `metadata` is
|
|
3252
3340
|
* the open consumer bag carried verbatim into a {@link TaskSnapshot} (mirrors
|
|
3253
3341
|
* {@link TaskInput.metadata}), never interpreted by the workflow.
|
|
3254
3342
|
*/
|
|
@@ -3283,12 +3371,12 @@ export declare interface TaskProgress {
|
|
|
3283
3371
|
* @remarks
|
|
3284
3372
|
* Carries the complete lineage (`task` / `phase` / `workflow` contexts) so a result
|
|
3285
3373
|
* is self-describing wherever it travels. `status` is the terminal state this
|
|
3286
|
-
* result records. `result`
|
|
3287
|
-
*
|
|
3288
|
-
* or `failed` (a {@link import('@orkestrel/contract').Failure}), and
|
|
3374
|
+
* result records. `result` boxes the produced outcome in a {@link Result}: it is
|
|
3375
|
+
* present exactly when `status` is `completed` (a {@link import('@orkestrel/contract').Success})
|
|
3376
|
+
* or `failed` (a {@link import('@orkestrel/contract').Failure}), and absent when `status` is
|
|
3289
3377
|
* `skipped` or `stopped` (terminal, but produced no outcome) — a pending/running
|
|
3290
3378
|
* task has no result at all (a non-terminal status, per
|
|
3291
|
-
* {@link import('./helpers.js').isTerminalStatus}). This boxed `result`
|
|
3379
|
+
* {@link import('./helpers.js').isTerminalStatus}). This boxed `result` replaces separate
|
|
3292
3380
|
* `value?` / `error?` fields: a success's payload is `result.value`, a failure's reason is `result.error`.
|
|
3293
3381
|
* `timestamp` is when the result was created (ms since epoch).
|
|
3294
3382
|
*/
|
|
@@ -3308,13 +3396,13 @@ export declare interface TaskResult {
|
|
|
3308
3396
|
* `behavior` behavior reference (a plain registry-key string, min length 1). `description` is
|
|
3309
3397
|
* optional prose.
|
|
3310
3398
|
*/
|
|
3311
|
-
export declare const taskShape: ObjectShape<{
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3399
|
+
export declare const taskShape: ObjectShape< {
|
|
3400
|
+
id: StringShape;
|
|
3401
|
+
name: StringShape;
|
|
3402
|
+
description: OptionalShape<StringShape>;
|
|
3403
|
+
behavior: OptionalShape<StringShape>;
|
|
3404
|
+
retries: OptionalShape<NumberShape>;
|
|
3405
|
+
timeout: OptionalShape<NumberShape>;
|
|
3318
3406
|
}, false>;
|
|
3319
3407
|
|
|
3320
3408
|
/**
|
|
@@ -3322,10 +3410,10 @@ export declare const taskShape: ObjectShape<{
|
|
|
3322
3410
|
* the durable store (W-d) persists.
|
|
3323
3411
|
*
|
|
3324
3412
|
* @remarks
|
|
3325
|
-
* Pure JSON
|
|
3413
|
+
* Pure JSON data (no class instances, no functions). `result` is the task's
|
|
3326
3414
|
* {@link TaskResult} when it has settled with an outcome, else `undefined`.
|
|
3327
3415
|
* `metadata` is the open consumer bag carried from the task's {@link TaskInput}.
|
|
3328
|
-
* `behavior` / `retries` / `timeout` are the
|
|
3416
|
+
* `behavior` / `retries` / `timeout` are the declarative config the task carries — persisted
|
|
3329
3417
|
* like a {@link PhaseSnapshot}'s `bail` / `concurrency`, so a restore reinstates the same
|
|
3330
3418
|
* behavior reference and reliability overrides (`behavior` re-resolves against the
|
|
3331
3419
|
* {@link WorkflowOptions.functions} registry supplied to
|
|
@@ -3382,14 +3470,14 @@ export declare interface TaskUpdate {
|
|
|
3382
3470
|
* `name` still has `minLength: 1`); never `id` / `behavior` / `retries` / `timeout` (those
|
|
3383
3471
|
* are not patchable fields).
|
|
3384
3472
|
*/
|
|
3385
|
-
export declare const taskUpdateShape: ObjectShape<{
|
|
3386
|
-
|
|
3387
|
-
|
|
3473
|
+
export declare const taskUpdateShape: ObjectShape< {
|
|
3474
|
+
name: OptionalShape<StringShape>;
|
|
3475
|
+
description: OptionalShape<StringShape>;
|
|
3388
3476
|
}, false>;
|
|
3389
3477
|
|
|
3390
3478
|
/**
|
|
3391
|
-
* Lists the {@link LifecycleStatus} values
|
|
3392
|
-
*
|
|
3479
|
+
* Lists the terminal {@link LifecycleStatus} values, frozen — `completed`, `failed`, `skipped`,
|
|
3480
|
+
* and `stopped`, each a state a node never transitions out of.
|
|
3393
3481
|
*
|
|
3394
3482
|
* @remarks
|
|
3395
3483
|
* The source of truth behind {@link import('./helpers.js').isTerminalStatus}.
|
|
@@ -3398,7 +3486,7 @@ export declare const taskUpdateShape: ObjectShape<{
|
|
|
3398
3486
|
export declare const TERMINAL_STATUSES: readonly LifecycleStatus[];
|
|
3399
3487
|
|
|
3400
3488
|
/**
|
|
3401
|
-
* Implements the live
|
|
3489
|
+
* Implements the live derived state machine (W-b) for a whole workflow — the observable root
|
|
3402
3490
|
* whose {@link LifecycleStatus} is computed from its phases under the `bail` policy and
|
|
3403
3491
|
* recomputed reactively as the cascade propagates up from a task transition.
|
|
3404
3492
|
*
|
|
@@ -3409,16 +3497,16 @@ export declare const TERMINAL_STATUSES: readonly LifecycleStatus[];
|
|
|
3409
3497
|
* passes a persisted one). Each child {@link Phase} is wired to escalate to `#recompute`.
|
|
3410
3498
|
* - **Derived status.** `status` is `#override` when forced, else
|
|
3411
3499
|
* {@link deriveWorkflowStatus} over the live phases' statuses feeding `bail`. `failed` is
|
|
3412
|
-
* reachable
|
|
3500
|
+
* reachable only under `bail: true` (a single failed task halts the workflow); under
|
|
3413
3501
|
* `bail: false` a failed phase folds into `completed`. `#recompute` diffs on each phase
|
|
3414
|
-
* change; a
|
|
3415
|
-
* - **Override.** `skip` / `stop`
|
|
3416
|
-
* may also be force-completed vacuously. The override is
|
|
3417
|
-
* `override` field and restored
|
|
3502
|
+
* change; a change emits.
|
|
3503
|
+
* - **Override.** `skip` / `stop` force the status; an executed task-free pending tree
|
|
3504
|
+
* may also be force-completed vacuously. The override is persisted in the snapshot's own
|
|
3505
|
+
* `override` field and restored directly (no divergence guess). The snapshot also persists
|
|
3418
3506
|
* `bail`, so a restore re-derives status identically without a silent policy default.
|
|
3419
3507
|
* - **Result tree.** `results()` flattens every phase's `results()` ({@link collectResults}) — the
|
|
3420
|
-
* workflow tier; `phase(id)` + each `phase.task(id)` navigate
|
|
3421
|
-
* navigate
|
|
3508
|
+
* workflow tier; `phase(id)` + each `phase.task(id)` navigate down, a task's `phase` / `workflow`
|
|
3509
|
+
* navigate up.
|
|
3422
3510
|
* - **Snapshot.** `snapshot()` serializes the whole live tree to a {@link WorkflowSnapshot} (pure
|
|
3423
3511
|
* JSON); {@link import('./factories.js').createRestoredWorkflow} rebuilds an equivalent live tree.
|
|
3424
3512
|
* - **Observable.** The owned {@link emitter} ({@link WorkflowEventMap}) fires
|
|
@@ -3426,17 +3514,17 @@ export declare const TERMINAL_STATUSES: readonly LifecycleStatus[];
|
|
|
3426
3514
|
* corresponding status or runtime-gate change; the emitter isolates a listener throw and
|
|
3427
3515
|
* routes it to its `error` handler (the `error` option); `fail` carries the failing task's
|
|
3428
3516
|
* {@link TaskResult}.
|
|
3429
|
-
* - **Structural API.** `add` / `remove` / `move` / `update` gate
|
|
3517
|
+
* - **Structural API.** `add` / `remove` / `move` / `update` gate before
|
|
3430
3518
|
* delegating to {@link phases} (the manager gates the target's own existence/status/id/
|
|
3431
|
-
* bounds), then emit the matching {@link WorkflowEventMap} event on success only.
|
|
3519
|
+
* bounds), then emit the matching {@link WorkflowEventMap} event on success only. Native,
|
|
3432
3520
|
* bottom-up gating (no runner-installed hook): refused outright while this workflow's own
|
|
3433
|
-
* `status` is terminal; otherwise a target position must fall within the
|
|
3521
|
+
* `status` is terminal; otherwise a target position must fall within the pending suffix —
|
|
3434
3522
|
* the contiguous trailing run of `pending` phases — whose boundary is
|
|
3435
3523
|
* {@link import('./helpers.js').deriveBoundary} over the live phases' statuses. A `pending`
|
|
3436
3524
|
* workflow's phases are all `pending`, so the boundary is `0` and every position is
|
|
3437
3525
|
* naturally accepted.
|
|
3438
3526
|
* - **Runtime lifecycle.** `pause` / `resume` / `wait` gate execution at the runner's
|
|
3439
|
-
* phase/task boundaries
|
|
3527
|
+
* phase/task boundaries without touching {@link status} — `paused` is runtime-only, never
|
|
3440
3528
|
* persisted. `destroy` is a terminal teardown: it `stop`s every non-terminal task and
|
|
3441
3529
|
* phase (releasing their gates and liveness resources), aborts {@link signal}, forces the
|
|
3442
3530
|
* workflow `stop` override when needed, releases its parked waiter, and marks
|
|
@@ -3509,11 +3597,11 @@ export declare interface WorkflowContext {
|
|
|
3509
3597
|
* phases, and the `bail` failure policy.
|
|
3510
3598
|
*
|
|
3511
3599
|
* @remarks
|
|
3512
|
-
* Pure JSON
|
|
3513
|
-
* are the workflow's phases, which run
|
|
3514
|
-
* (a boolean behavioral toggle): `false` (the default) is
|
|
3600
|
+
* Pure JSON data — the root a UI/LLM authors and the contract validates. `phases`
|
|
3601
|
+
* are the workflow's phases, which run sequentially. `bail` is the failure policy
|
|
3602
|
+
* (a boolean behavioral toggle): `false` (the default) is graceful —
|
|
3515
3603
|
* a failed leaf task is recorded as data and the workflow still completes; `true`
|
|
3516
|
-
* is a database-transaction
|
|
3604
|
+
* is a database-transaction halt — a single failed task propagates `failed` to the
|
|
3517
3605
|
* whole workflow. See {@link import('./helpers.js').deriveWorkflowStatus}.
|
|
3518
3606
|
*/
|
|
3519
3607
|
export declare interface WorkflowDefinition {
|
|
@@ -3526,11 +3614,12 @@ export declare interface WorkflowDefinition {
|
|
|
3526
3614
|
}
|
|
3527
3615
|
|
|
3528
3616
|
/**
|
|
3529
|
-
* Represents an error
|
|
3617
|
+
* Represents an error the workflow runtime raises for an operation it refuses — a
|
|
3618
|
+
* {@link WorkflowErrorCode} (`TRANSITION`, `RESTORE`, `MUTATION`, `SCHEDULE`, or `INVARIANT`)
|
|
3619
|
+
* beside an optional `context` naming the node or the parameter at fault.
|
|
3530
3620
|
*
|
|
3531
3621
|
* @remarks
|
|
3532
|
-
*
|
|
3533
|
-
* offending node id / status / parameter. Raised for an illegal lifecycle transition
|
|
3622
|
+
* Raised for an illegal lifecycle transition
|
|
3534
3623
|
* (`TRANSITION`), a structurally invalid {@link import('./types.js').WorkflowSnapshot}
|
|
3535
3624
|
* boundary (`RESTORE`), a refused structural/activity edit (`MUTATION`), a host
|
|
3536
3625
|
* schedule refused before arming because the caller's `signal` is not a native
|
|
@@ -3553,21 +3642,21 @@ export declare class WorkflowError extends Error {
|
|
|
3553
3642
|
* the offending current status + requested transition in the error `context`.
|
|
3554
3643
|
* - `RESTORE` — a {@link import('./factories.js').createRestoredWorkflow} given a structurally
|
|
3555
3644
|
* invalid {@link WorkflowSnapshot} (a status outside the lifecycle vocabulary).
|
|
3556
|
-
* - `MUTATION` — a
|
|
3645
|
+
* - `MUTATION` — a gated structural or patch edit was refused: a duplicate id on
|
|
3557
3646
|
* `append`/`add`, a target that does not exist or is not `pending`, an out-of-bounds
|
|
3558
3647
|
* `index`, a patch that failed shaper validation, or a live structural edit refused by
|
|
3559
|
-
* the
|
|
3560
|
-
* a position
|
|
3648
|
+
* the native bottom-up gate — a terminal container, an edit targeting (or destined for)
|
|
3649
|
+
* a position before the container's own pending-suffix boundary, or (a running phase)
|
|
3561
3650
|
* anything other than a pure append. The manager /
|
|
3562
3651
|
* entity structural API returns it as a graceful `Result` `failure` —
|
|
3563
|
-
* it
|
|
3652
|
+
* it never throws for this code except {@link TaskInterface.patch} /
|
|
3564
3653
|
* {@link PhaseInterface.patch}'s defense-in-depth self-check and the build-time
|
|
3565
3654
|
* {@link TaskManagerInterface.append} / {@link PhaseManagerInterface.append} duplicate-id
|
|
3566
3655
|
* guard (both genuine programmer-error paths). The error `context` names
|
|
3567
3656
|
* the offending id / index / status.
|
|
3568
3657
|
* - `SCHEDULE` — {@link import('./helpers.js').scheduleHost} refused to arm host work
|
|
3569
3658
|
* because the caller passed a `signal` that is not a native `AbortSignal`. The refusal
|
|
3570
|
-
* is a
|
|
3659
|
+
* is a rejected promise, never a synchronous throw, so every scheduler backend settles
|
|
3571
3660
|
* the same way whatever the caller passed. The error `context` names the offending
|
|
3572
3661
|
* parameter (`signal`) and the `typeof` the caller supplied.
|
|
3573
3662
|
* - `INVARIANT` — an internal invariant did not hold: a derived
|
|
@@ -3592,7 +3681,7 @@ export declare type WorkflowErrorCode = 'TRANSITION' | 'RESTORE' | 'MUTATION' |
|
|
|
3592
3681
|
* / `move` / `update` fire on a successful
|
|
3593
3682
|
* structural or patch edit through {@link WorkflowInterface.add} / `remove` / `move` /
|
|
3594
3683
|
* `update` — never on a refused/gated one. A throwing listener never
|
|
3595
|
-
* reaches the domain surface — the emitter isolates it and routes it to its
|
|
3684
|
+
* reaches the domain surface — the emitter isolates it and routes it to its own
|
|
3596
3685
|
* `error` handler (the `error` option). Declared as a `type` alias (not
|
|
3597
3686
|
* `interface extends EventMap`) so the type-literal satisfies `EventMap`
|
|
3598
3687
|
* structurally.
|
|
@@ -3632,12 +3721,12 @@ export declare interface WorkflowFault {
|
|
|
3632
3721
|
|
|
3633
3722
|
/**
|
|
3634
3723
|
* Declares the registered behavior a `function`-form
|
|
3635
|
-
* {@link TaskDefinition} runs, resolved
|
|
3724
|
+
* {@link TaskDefinition} runs, resolved by name through the {@link WorkflowRegistry}
|
|
3636
3725
|
* registry — a function type the framework invokes.
|
|
3637
3726
|
*
|
|
3638
3727
|
* @remarks
|
|
3639
3728
|
* Receives a {@link TaskControllerInterface} — the running task's folded `signal`, its
|
|
3640
|
-
* `input` (the task's `metadata` bag), its lineage {@link TaskContext}, and read-
|
|
3729
|
+
* `input` (the task's `metadata` bag), its lineage {@link TaskContext}, and read-up access
|
|
3641
3730
|
* to earlier phases' {@link TaskResult}s. A returned value becomes the task's
|
|
3642
3731
|
* {@link import('@orkestrel/contract').Success} ({@link TaskInterface.complete}); a throw / rejection
|
|
3643
3732
|
* becomes its {@link import('@orkestrel/contract').Failure} ({@link TaskInterface.fail}). Long work
|
|
@@ -3651,19 +3740,19 @@ export declare type WorkflowInput = Partial<WorkflowContext>;
|
|
|
3651
3740
|
|
|
3652
3741
|
/**
|
|
3653
3742
|
* Declares the live derived state machine (W-b) for a whole {@link WorkflowDefinition} — the
|
|
3654
|
-
* observable root whose {@link LifecycleStatus} is
|
|
3743
|
+
* observable root whose {@link LifecycleStatus} is derived from its phases
|
|
3655
3744
|
* under the `bail` policy and recomputed reactively as the cascade propagates up.
|
|
3656
3745
|
*
|
|
3657
3746
|
* @remarks
|
|
3658
3747
|
* - **Derived status.** `status` is computed through
|
|
3659
3748
|
* {@link import('./helpers.js').deriveWorkflowStatus} over the live phases' statuses,
|
|
3660
|
-
* feeding the definition's `bail`,
|
|
3661
|
-
* phase's status changes (the top of the cascade); a
|
|
3749
|
+
* feeding the definition's `bail`, unless an override is in force. It recomputes when a
|
|
3750
|
+
* phase's status changes (the top of the cascade); a change emits — `fail` carries the
|
|
3662
3751
|
* failing {@link TaskResult} (under `bail: true`).
|
|
3663
3752
|
* - **Children.** `phases` is the lean {@link PhaseManagerInterface};
|
|
3664
|
-
* `phase(id)` / `phases().phases()` read in positional order. `results` collects
|
|
3753
|
+
* `phase(id)` / `phases().phases()` read in positional order. `results` collects all
|
|
3665
3754
|
* tasks' results across every phase (the workflow tier of the result tree).
|
|
3666
|
-
* - **Override.** `skip` / `stop`
|
|
3755
|
+
* - **Override.** `skip` / `stop` force the workflow's status; `complete`
|
|
3667
3756
|
* may force only a task-free, otherwise-pending tree. The override survives a snapshot.
|
|
3668
3757
|
* - **Snapshot.** `snapshot()` serializes the whole live tree to a {@link WorkflowSnapshot}
|
|
3669
3758
|
* (pure JSON — structure + each node's status + recorded results + positional order);
|
|
@@ -3685,15 +3774,15 @@ export declare interface WorkflowInterface {
|
|
|
3685
3774
|
readonly status: LifecycleStatus;
|
|
3686
3775
|
readonly phases: PhaseManagerInterface;
|
|
3687
3776
|
/**
|
|
3688
|
-
* Reports whether the workflow is paused (resumable);
|
|
3777
|
+
* Reports whether the workflow is paused (resumable); runtime-only —
|
|
3689
3778
|
* never a {@link LifecycleStatus}, never persisted in a {@link WorkflowSnapshot} (a
|
|
3690
3779
|
* paused workflow's `status` still reports its ordinary `pending` / `running` value).
|
|
3691
3780
|
*/
|
|
3692
3781
|
readonly paused: boolean;
|
|
3693
|
-
/** Reports whether {@link destroy} has torn this workflow down;
|
|
3782
|
+
/** Reports whether {@link destroy} has torn this workflow down; runtime-only, never persisted. */
|
|
3694
3783
|
readonly destroyed: boolean;
|
|
3695
3784
|
/**
|
|
3696
|
-
* Holds this workflow's own cancellation signal — fires on {@link destroy}.
|
|
3785
|
+
* Holds this workflow's own cancellation signal — fires on {@link destroy}. Runtime-only
|
|
3697
3786
|
* (implemented over `@orkestrel/abort`, AGENTS core precedent), never persisted.
|
|
3698
3787
|
*/
|
|
3699
3788
|
readonly signal: AbortSignal;
|
|
@@ -3705,7 +3794,7 @@ export declare interface WorkflowInterface {
|
|
|
3705
3794
|
* Forces this workflow to `skipped`, overriding the derived value; idempotent.
|
|
3706
3795
|
*
|
|
3707
3796
|
* @remarks
|
|
3708
|
-
* A
|
|
3797
|
+
* A no-op after `status` becomes terminal — a settled workflow cannot be re-forced.
|
|
3709
3798
|
* Always releases a parked {@link wait} waiter regardless (a terminal workflow has nothing
|
|
3710
3799
|
* left to pause for).
|
|
3711
3800
|
*/
|
|
@@ -3714,7 +3803,7 @@ export declare interface WorkflowInterface {
|
|
|
3714
3803
|
* Forces this workflow to `stopped`, overriding the derived value; idempotent.
|
|
3715
3804
|
*
|
|
3716
3805
|
* @remarks
|
|
3717
|
-
* A
|
|
3806
|
+
* A no-op after `status` becomes terminal — a settled workflow cannot be re-forced. Always
|
|
3718
3807
|
* releases a parked {@link wait} waiter regardless (a terminal workflow has nothing left to
|
|
3719
3808
|
* pause for).
|
|
3720
3809
|
*/
|
|
@@ -3723,8 +3812,8 @@ export declare interface WorkflowInterface {
|
|
|
3723
3812
|
* Forces this workflow to `completed`, overriding the derived value.
|
|
3724
3813
|
*
|
|
3725
3814
|
* @remarks
|
|
3726
|
-
* A
|
|
3727
|
-
* every phase contains zero tasks. Its
|
|
3815
|
+
* A no-op unless `status` is `pending` and the tree is genuinely vacuous: zero phases or
|
|
3816
|
+
* every phase contains zero tasks. Its only legitimate use is settling an executed no-op
|
|
3728
3817
|
* tree. It never overrides pending work or any started/terminal state.
|
|
3729
3818
|
*/
|
|
3730
3819
|
complete(): void;
|
|
@@ -3733,10 +3822,10 @@ export declare interface WorkflowInterface {
|
|
|
3733
3822
|
*
|
|
3734
3823
|
* @remarks
|
|
3735
3824
|
* A no-op when already `paused`, when `status` is terminal, or after {@link destroyed} becomes true.
|
|
3736
|
-
*
|
|
3825
|
+
* runtime-only — never a {@link LifecycleStatus}, never persisted in a
|
|
3737
3826
|
* {@link WorkflowSnapshot}. A driving {@link WorkflowRunnerInterface.execute} gates at the
|
|
3738
3827
|
* next phase boundary and before each task's own dispatch; an in-flight task body is
|
|
3739
|
-
* never suspended mid-flight. **Pausing does
|
|
3828
|
+
* never suspended mid-flight. **Pausing does not suspend the run's timeout / budget /
|
|
3740
3829
|
* abort clocks** — those bounds keep ticking while paused, so a run parked on
|
|
3741
3830
|
* `pause()` can still be cancelled (and settle `stopped`) by its own deadline / budget /
|
|
3742
3831
|
* abort while parked.
|
|
@@ -3759,7 +3848,7 @@ export declare interface WorkflowInterface {
|
|
|
3759
3848
|
*/
|
|
3760
3849
|
resume(): void;
|
|
3761
3850
|
/**
|
|
3762
|
-
* Tears this workflow down —
|
|
3851
|
+
* Tears this workflow down — one atomic terminal teardown: mark
|
|
3763
3852
|
* {@link destroyed}, pin non-terminal workflow/phase overrides to `stopped`, stop every
|
|
3764
3853
|
* non-terminal task, release gates and liveness resources, abort {@link signal}, then
|
|
3765
3854
|
* destroy task, phase, and workflow emitters in ownership order; idempotent.
|
|
@@ -3777,42 +3866,42 @@ export declare interface WorkflowInterface {
|
|
|
3777
3866
|
*/
|
|
3778
3867
|
destroy(): void;
|
|
3779
3868
|
/**
|
|
3780
|
-
* Parks until this workflow is not paused —
|
|
3781
|
-
* busy-loop
|
|
3869
|
+
* Parks until this workflow is not paused — a promise-parked wait, never a timer or
|
|
3870
|
+
* busy-loop.
|
|
3782
3871
|
*
|
|
3783
3872
|
* @remarks
|
|
3784
|
-
* Resolves
|
|
3873
|
+
* Resolves immediately when not {@link paused}. While paused, parks until `resume` /
|
|
3785
3874
|
* `skip` / `stop` / `destroy` — each always releases a parked waiter (a permanently
|
|
3786
|
-
* ended workflow has nothing left to pause for).
|
|
3875
|
+
* ended workflow has nothing left to pause for). Never rejects.
|
|
3787
3876
|
*
|
|
3788
3877
|
* @returns A promise that resolves after the workflow is no longer paused
|
|
3789
3878
|
*/
|
|
3790
3879
|
wait(): Promise<void>;
|
|
3791
3880
|
/**
|
|
3792
3881
|
* Mints a live {@link PhaseInterface} (and its tasks) from `definition` and inserts it
|
|
3793
|
-
* into this workflow (the entity structural API) — gated
|
|
3794
|
-
*
|
|
3882
|
+
* into this workflow (the entity structural API) — gated before it delegates to the
|
|
3883
|
+
* {@link phases} manager.
|
|
3795
3884
|
*
|
|
3796
3885
|
* @remarks
|
|
3797
3886
|
* Converts `definition` → {@link PhaseSnapshot} and constructs the live phase (wired to
|
|
3798
|
-
*
|
|
3887
|
+
* this workflow, its recompute cascade, and its emitter hooks) plus each of its live
|
|
3799
3888
|
* tasks — each task's `behavior` / `retries` / `timeout` carried from its {@link TaskDefinition}
|
|
3800
3889
|
* and its {@link TaskInterface.handler} resolved against the workflow-level
|
|
3801
3890
|
* {@link WorkflowOptions.functions} registry (mirrors
|
|
3802
3891
|
* {@link import('./factories.js').createWorkflow}'s build-time resolution). The
|
|
3803
3892
|
* phase's effective `bail` resolves exactly as the build path does
|
|
3804
|
-
* (`definition.bail ?? this.bail`). Requires `definition.id` to be
|
|
3893
|
+
* (`definition.bail ?? this.bail`). Requires `definition.id` to be unique among this
|
|
3805
3894
|
* workflow's existing phase ids — a duplicate is a `MUTATION` failure (mirrors
|
|
3806
3895
|
* {@link PhaseManagerInterface.add}'s own duplicate-id gate).
|
|
3807
3896
|
*
|
|
3808
|
-
*
|
|
3809
|
-
* positions (no runner-installed hook),
|
|
3897
|
+
* native gating, purely from this workflow's own derived `status` and the phase list's
|
|
3898
|
+
* positions (no runner-installed hook), unchanged from the entity-taking
|
|
3810
3899
|
* predecessor: refused outright while this workflow's own `status` is terminal or after
|
|
3811
3900
|
* {@link destroyed} becomes true. Otherwise the effective target position (`index ?? phases.count`)
|
|
3812
|
-
* must fall within the
|
|
3901
|
+
* must fall within the pending suffix — the contiguous trailing run of `pending` phases
|
|
3813
3902
|
* (phases run sequentially, so every already-started phase forms a contiguous leading
|
|
3814
3903
|
* prefix); its boundary is {@link import('./helpers.js').deriveBoundary}. A `pending`
|
|
3815
|
-
* workflow's phases are
|
|
3904
|
+
* workflow's phases are all `pending`, so the boundary is `0` and every index is
|
|
3816
3905
|
* naturally accepted — no special case needed. Delegates the minted phase to
|
|
3817
3906
|
* {@link PhaseManagerInterface.add} then emits `add` on success.
|
|
3818
3907
|
*
|
|
@@ -3825,7 +3914,7 @@ export declare interface WorkflowInterface {
|
|
|
3825
3914
|
* Removes the `pending` phase `id` from this workflow.
|
|
3826
3915
|
*
|
|
3827
3916
|
* @remarks
|
|
3828
|
-
*
|
|
3917
|
+
* native gating: refused while this workflow's own `status` is terminal. Otherwise the
|
|
3829
3918
|
* target must exist at an index within the pending suffix (at or past
|
|
3830
3919
|
* {@link import('./helpers.js').deriveBoundary}) — the manager separately gates the
|
|
3831
3920
|
* target's own `pending` status.
|
|
@@ -3838,7 +3927,7 @@ export declare interface WorkflowInterface {
|
|
|
3838
3927
|
* Repositions the `pending` phase `id` to `index` within this workflow.
|
|
3839
3928
|
*
|
|
3840
3929
|
* @remarks
|
|
3841
|
-
*
|
|
3930
|
+
* native gating: refused while this workflow's own `status` is terminal. Otherwise both
|
|
3842
3931
|
* the target's current index and the destination `index` must fall within the pending
|
|
3843
3932
|
* suffix (see {@link remove}).
|
|
3844
3933
|
*
|
|
@@ -3851,7 +3940,7 @@ export declare interface WorkflowInterface {
|
|
|
3851
3940
|
* Applies a validated {@link PhaseUpdate} patch to the `pending` phase `id` in this workflow.
|
|
3852
3941
|
*
|
|
3853
3942
|
* @remarks
|
|
3854
|
-
*
|
|
3943
|
+
* native gating: refused while this workflow's own `status` is terminal. Otherwise the
|
|
3855
3944
|
* target must exist at an index within the pending suffix (see {@link remove}).
|
|
3856
3945
|
*
|
|
3857
3946
|
* @param id - The phase id to patch
|
|
@@ -3859,6 +3948,11 @@ export declare interface WorkflowInterface {
|
|
|
3859
3948
|
* @returns A {@link Result} boxing the patched phase, or a `MUTATION` failure
|
|
3860
3949
|
*/
|
|
3861
3950
|
update(id: string, patch: PhaseUpdate): Result<PhaseInterface, WorkflowError>;
|
|
3951
|
+
/**
|
|
3952
|
+
* Serializes the whole live tree — this workflow, its phases, and their tasks.
|
|
3953
|
+
*
|
|
3954
|
+
* @returns The pure-JSON {@link WorkflowSnapshot} a durable store persists
|
|
3955
|
+
*/
|
|
3862
3956
|
snapshot(): WorkflowSnapshot;
|
|
3863
3957
|
}
|
|
3864
3958
|
|
|
@@ -3873,14 +3967,14 @@ export declare interface WorkflowInterface {
|
|
|
3873
3967
|
* mints a live {@link WorkflowInterface} through the same construction path
|
|
3874
3968
|
* {@link import('./factories.js').createWorkflow} takes (flowing the manager's
|
|
3875
3969
|
* `functions` registry in) and stores it under `definition.id` — an already-present id
|
|
3876
|
-
*
|
|
3970
|
+
* overwrites (last write wins). `count` is the map size, `workflow(id)` looks one up,
|
|
3877
3971
|
* `workflows()` lists them in insertion order.
|
|
3878
3972
|
* - **Durable open / save.** `open(id)` returns an already-registered workflow directly; same-id
|
|
3879
3973
|
* misses share one hydration. A concurrent `add` wins, while `remove` / `clear` invalidate
|
|
3880
3974
|
* earlier reads; wrong-key payloads reject with `RESTORE`. `save(id)` captures a registered
|
|
3881
3975
|
* workflow's snapshot at invocation and serializes same-id writes without coupling other ids.
|
|
3882
3976
|
* Both remain lenient without a store or registered id.
|
|
3883
|
-
* - **Removal.** `remove` drops one by id, or a batch (array overload
|
|
3977
|
+
* - **Removal.** `remove` drops one by id, or a batch (array overload first) — `true` only when
|
|
3884
3978
|
* every id was removed. `clear` empties the registry.
|
|
3885
3979
|
* - **No active pointer.** Unlike its `ConversationManager` / `WorkspaceManager` twins, there is
|
|
3886
3980
|
* no `active` / `switch` — nothing in the workflow domain renders "the current workflow".
|
|
@@ -3890,7 +3984,7 @@ export declare interface WorkflowInterface {
|
|
|
3890
3984
|
* const manager = new WorkflowManager({
|
|
3891
3985
|
* functions: { compile: async (controller) => `built ${controller.task.id}` },
|
|
3892
3986
|
* })
|
|
3893
|
-
* const workflow = manager.add(definition) // minted, registered,
|
|
3987
|
+
* const workflow = manager.add(definition) // minted, registered, runnable
|
|
3894
3988
|
* manager.workflow(workflow.id) // the same workflow
|
|
3895
3989
|
* manager.count // 1
|
|
3896
3990
|
* ```
|
|
@@ -3913,43 +4007,44 @@ export declare class WorkflowManager implements WorkflowManagerInterface {
|
|
|
3913
4007
|
* Declares a store-backed registry of {@link WorkflowInterface}s keyed by their `id`, in insertion
|
|
3914
4008
|
* order — the additive manager tier mirroring `ConversationManagerInterface` /
|
|
3915
4009
|
* `WorkspaceManagerInterface` from the `@orkestrel/agent` line, adapted for the workflow
|
|
3916
|
-
* domain: `add` mints from a {@link WorkflowDefinition}
|
|
3917
|
-
*
|
|
3918
|
-
*
|
|
3919
|
-
* immediately RUNNABLE, not merely a restored state mirror. NO `active` / `switch` pointer
|
|
3920
|
-
* — the workflow domain has no consumer that renders "the current workflow" the
|
|
3921
|
-
* way an agent context renders the active conversation/workspace.
|
|
4010
|
+
* domain: `add` mints from a {@link WorkflowDefinition}, and the optional `store` seam's
|
|
4011
|
+
* `open` threads the manager's {@link WorkflowRegistry} registry, so a hydrated workflow is
|
|
4012
|
+
* immediately runnable rather than a restored state mirror.
|
|
3922
4013
|
*
|
|
3923
4014
|
* @remarks
|
|
3924
4015
|
* - **Registry.** `count` is how many are stored. `add(definition)` mints a live
|
|
3925
4016
|
* {@link WorkflowInterface} through {@link import('./factories.js').createWorkflow} (flowing
|
|
3926
4017
|
* this manager's `functions` registry in) and registers it under `definition.id` — an
|
|
3927
|
-
* already-present id
|
|
4018
|
+
* already-present id overwrites (last write wins, because `createWorkflow` keys the tree by
|
|
3928
4019
|
* the definition's own id). `workflow(id)` looks one up (`undefined` when absent);
|
|
3929
4020
|
* `workflows()` lists them in insertion order.
|
|
3930
4021
|
* - **Durable open / save (the optional `store` seam).** When a {@link WorkflowStoreInterface}
|
|
3931
4022
|
* is supplied (the `store` option), `open(id)` resolves an already-registered workflow
|
|
3932
|
-
* directly (no store hit); same-id registry misses share one in-flight hydration. On a
|
|
3933
|
-
* it
|
|
4023
|
+
* directly (no store hit); same-id registry misses share one in-flight hydration. On a miss
|
|
4024
|
+
* it hydrates one from `store.get(id)` through
|
|
3934
4025
|
* {@link import('./factories.js').createRestoredWorkflow} — flowing this manager's `functions`
|
|
3935
|
-
* registry in so the rehydrated tree is
|
|
4026
|
+
* registry in so the rehydrated tree is runnable — registers it, and returns it. Registry
|
|
3936
4027
|
* mutation wins over an earlier pending hydration: `add` supplies the live result, while
|
|
3937
4028
|
* `remove` (even for an absent id) and `clear` invalidate the earlier read. Missed and failed
|
|
3938
4029
|
* reads leave no stale in-flight entry, and a payload whose own id differs from the requested
|
|
3939
4030
|
* key rejects with `RESTORE` instead of registering under either id. `save(id)` captures a
|
|
3940
|
-
* registered workflow's {@link WorkflowInterface.snapshot} at invocation, then
|
|
4031
|
+
* registered workflow's {@link WorkflowInterface.snapshot} at invocation, then persists it.
|
|
3941
4032
|
* Same-id writes run serially in invocation order; different ids remain independent, and an
|
|
3942
4033
|
* earlier rejection reaches its caller without preventing a later queued write. Both are
|
|
3943
|
-
*
|
|
3944
|
-
* (`false`) — never a throw. The
|
|
4034
|
+
* lenient without a store — `open` resolves only registered ids, `save` is a no-op
|
|
4035
|
+
* (`false`) — never a throw. The exact analogue of
|
|
3945
4036
|
* `ConversationManagerInterface.open` / `.save` and `WorkspaceManagerInterface.open` /
|
|
3946
4037
|
* `.save` — this is the workflow line's caller-driven persistence gaining the standard
|
|
3947
|
-
* open/save seam,
|
|
4038
|
+
* open/save seam, additive alongside direct {@link WorkflowStoreInterface} use and
|
|
3948
4039
|
* {@link import('./factories.js').createRestoredWorkflow} (both remain valid).
|
|
3949
|
-
* - **Removal.** `remove` drops one by id, or a batch (array overload
|
|
4040
|
+
* - **Removal.** `remove` drops one by id, or a batch (array overload first) — `true` only
|
|
3950
4041
|
* when every id was removed. `clear` empties the registry.
|
|
3951
4042
|
* - **Event-free.** A purely registry store — no `Emitter`, no events (each
|
|
3952
4043
|
* {@link WorkflowInterface} owns its own {@link WorkflowEventMap} emitter).
|
|
4044
|
+
* - **No pointer.** There is no `active` / `switch` pointer: no consumer of this domain renders
|
|
4045
|
+
* "the current workflow" the way an agent context renders the active conversation or
|
|
4046
|
+
* workspace. `add` mints from a {@link WorkflowDefinition} rather than from an empty `Input`,
|
|
4047
|
+
* because a workflow exists only relative to a definition.
|
|
3953
4048
|
*
|
|
3954
4049
|
* @example
|
|
3955
4050
|
* ```ts
|
|
@@ -3958,21 +4053,32 @@ export declare class WorkflowManager implements WorkflowManagerInterface {
|
|
|
3958
4053
|
* const manager = createWorkflowManager({
|
|
3959
4054
|
* functions: { compile: async (controller) => `built ${controller.task.id}` },
|
|
3960
4055
|
* })
|
|
3961
|
-
* const workflow = manager.add(definition) // minted, registered,
|
|
4056
|
+
* const workflow = manager.add(definition) // minted, registered, runnable (functions flow in)
|
|
3962
4057
|
* manager.count // 1
|
|
3963
4058
|
* ```
|
|
3964
4059
|
*/
|
|
3965
4060
|
export declare interface WorkflowManagerInterface {
|
|
3966
4061
|
readonly count: number;
|
|
4062
|
+
/**
|
|
4063
|
+
* Looks up one registered workflow by its `id`.
|
|
4064
|
+
*
|
|
4065
|
+
* @param id - The workflow id to resolve
|
|
4066
|
+
* @returns The registered workflow, or `undefined` when none is registered under that id
|
|
4067
|
+
*/
|
|
3967
4068
|
workflow(id: string): WorkflowInterface | undefined;
|
|
4069
|
+
/**
|
|
4070
|
+
* Lists the registered workflows in insertion order.
|
|
4071
|
+
*
|
|
4072
|
+
* @returns Every registered workflow, in the order it was added
|
|
4073
|
+
*/
|
|
3968
4074
|
workflows(): readonly WorkflowInterface[];
|
|
3969
4075
|
/**
|
|
3970
4076
|
* Mints a live {@link WorkflowInterface} from `definition` (through
|
|
3971
4077
|
* {@link import('./factories.js').createWorkflow}, flowing this manager's `functions`
|
|
3972
|
-
* registry in) and
|
|
4078
|
+
* registry in) and registers it under `definition.id`, overwriting an already-registered id.
|
|
3973
4079
|
*
|
|
3974
4080
|
* @remarks
|
|
3975
|
-
* An already-registered `definition.id`
|
|
4081
|
+
* An already-registered `definition.id` overwrites (last write wins) — `createWorkflow`
|
|
3976
4082
|
* keys the live tree by the definition's own id, so a re-`add` under the same id is
|
|
3977
4083
|
* indistinguishable from a fresh mint at the registry level.
|
|
3978
4084
|
*
|
|
@@ -3981,38 +4087,38 @@ export declare interface WorkflowManagerInterface {
|
|
|
3981
4087
|
*/
|
|
3982
4088
|
add(definition: WorkflowDefinition): WorkflowInterface;
|
|
3983
4089
|
/**
|
|
3984
|
-
* Resolves a workflow by id — from the registry
|
|
3985
|
-
* optional {@link WorkflowStoreInterface} (`store`),
|
|
3986
|
-
* registry is threaded into the rehydration
|
|
4090
|
+
* Resolves a workflow by id — from the registry when it holds one, otherwise hydrated from
|
|
4091
|
+
* the optional {@link WorkflowStoreInterface} (`store`) and runnable, because this manager's
|
|
4092
|
+
* `functions` registry is threaded into the rehydration.
|
|
3987
4093
|
*
|
|
3988
4094
|
* @remarks
|
|
3989
|
-
* - If `id` is
|
|
4095
|
+
* - If `id` is already registered, it is returned directly — no store hit.
|
|
3990
4096
|
* - Same-id registry misses share one in-flight `store.get(id)` and resolve to the same live
|
|
3991
|
-
* object. On a
|
|
4097
|
+
* object. On a hit the snapshot is
|
|
3992
4098
|
* rehydrated into a fresh {@link WorkflowInterface} through
|
|
3993
4099
|
* {@link import('./factories.js').createRestoredWorkflow}, flowing this manager's `functions`
|
|
3994
|
-
* registry in (so the rehydrated tree carries real resolved `handler`s and can
|
|
4100
|
+
* registry in (so the rehydrated tree carries real resolved `handler`s and can resume
|
|
3995
4101
|
* real work), registers it, and returns it. A payload whose own id differs from `id` rejects
|
|
3996
4102
|
* with a normalized `RESTORE` error carrying the requested and payload ids.
|
|
3997
4103
|
* - Registry mutation after the store read starts has precedence: `add(definition)` for the
|
|
3998
4104
|
* same id wins and becomes every pending caller's result; `remove(id)` invalidates that read
|
|
3999
4105
|
* even when the id was absent; `clear()` invalidates every earlier read. A miss or rejection
|
|
4000
4106
|
* clears the in-flight entry so a later call retries.
|
|
4001
|
-
* - Else (no store, or a store
|
|
4107
|
+
* - Else (no store, or a store miss) ⇒ `undefined` (lenient — no throw).
|
|
4002
4108
|
*
|
|
4003
4109
|
* @param id - The workflow id to open
|
|
4004
|
-
* @returns The resolved,
|
|
4110
|
+
* @returns The resolved, runnable {@link WorkflowInterface}, or `undefined` when neither registered nor stored
|
|
4005
4111
|
*/
|
|
4006
4112
|
open(id: string): Promise<WorkflowInterface | undefined>;
|
|
4007
4113
|
/**
|
|
4008
|
-
* Persists a
|
|
4114
|
+
* Persists a registered workflow's {@link WorkflowInterface.snapshot} to the optional
|
|
4009
4115
|
* {@link WorkflowStoreInterface} (`store`).
|
|
4010
4116
|
*
|
|
4011
4117
|
* @remarks
|
|
4012
|
-
* When a `store` is set
|
|
4118
|
+
* When a `store` is set and `id` is registered, the snapshot is captured synchronously at
|
|
4013
4119
|
* invocation. Same-id `store.set` calls are serialized in invocation order; different ids are
|
|
4014
4120
|
* independent. A rejected write reaches that caller unchanged but does not poison a later
|
|
4015
|
-
* queued write. Otherwise (no store,
|
|
4121
|
+
* queued write. Otherwise (no store, or an unknown id) it is a no-op returning `false`.
|
|
4016
4122
|
*
|
|
4017
4123
|
* @param id - The id of the registered workflow to persist
|
|
4018
4124
|
* @returns True if the snapshot was persisted; false otherwise (no store, or an unknown id)
|
|
@@ -4022,7 +4128,7 @@ export declare interface WorkflowManagerInterface {
|
|
|
4022
4128
|
* Drops a batch of registered workflows, one per id.
|
|
4023
4129
|
*
|
|
4024
4130
|
* @remarks
|
|
4025
|
-
* The array overload is declared
|
|
4131
|
+
* The array overload is declared first, so a list resolves to the batch form. Every id is
|
|
4026
4132
|
* invalidated whether or not it was registered, so an absent id changes nothing else. An
|
|
4027
4133
|
* empty list returns `true` vacuously — no id failed to be removed.
|
|
4028
4134
|
*
|
|
@@ -4037,6 +4143,7 @@ export declare interface WorkflowManagerInterface {
|
|
|
4037
4143
|
* @returns True if the id was registered and removed; false otherwise
|
|
4038
4144
|
*/
|
|
4039
4145
|
remove(id: string): boolean;
|
|
4146
|
+
/** Empties the registry, dropping every registered workflow. */
|
|
4040
4147
|
clear(): void;
|
|
4041
4148
|
}
|
|
4042
4149
|
|
|
@@ -4046,23 +4153,23 @@ export declare interface WorkflowManagerInterface {
|
|
|
4046
4153
|
* hydrates resolves its tasks' handlers against.
|
|
4047
4154
|
*
|
|
4048
4155
|
* @remarks
|
|
4049
|
-
* `store` is the
|
|
4156
|
+
* `store` is the exact analogue of `ConversationManagerOptions.store` /
|
|
4050
4157
|
* `WorkspaceManagerOptions.store` (the `@orkestrel/agent` line's store standard) — omitted ⇒
|
|
4051
4158
|
* the manager is registry-only: {@link WorkflowManagerInterface.open} resolves only what is
|
|
4052
4159
|
* already registered, and {@link WorkflowManagerInterface.save} is a no-op (`false`). `functions`
|
|
4053
|
-
* is the workflow-specific addition: the
|
|
4160
|
+
* is the workflow-specific addition: the same {@link WorkflowRegistry} registry threaded into
|
|
4054
4161
|
* every {@link import('./factories.js').createWorkflow} ({@link WorkflowManagerInterface.add})
|
|
4055
4162
|
* and every {@link import('./factories.js').createRestoredWorkflow}
|
|
4056
4163
|
* ({@link WorkflowManagerInterface.open}'s hydration path) the manager performs — so a
|
|
4057
|
-
* hydrated workflow carries real resolved `handler`s and is
|
|
4164
|
+
* hydrated workflow carries real resolved `handler`s and is runnable. Omitted ⇒ named work
|
|
4058
4165
|
* remains inspectable but cannot be driven; omitted-`behavior` tasks remain deliberate no-ops.
|
|
4059
4166
|
*/
|
|
4060
4167
|
export declare interface WorkflowManagerOptions {
|
|
4061
4168
|
/**
|
|
4062
4169
|
* Holds the optional durable {@link WorkflowStoreInterface} backing
|
|
4063
4170
|
* {@link WorkflowManagerInterface.open} / {@link WorkflowManagerInterface.save} — a memory
|
|
4064
|
-
* / JSON / SQLite / IndexedDB store a workflow is
|
|
4065
|
-
* and
|
|
4171
|
+
* / JSON / SQLite / IndexedDB store a workflow is hydrated from (`open` a registry miss)
|
|
4172
|
+
* and persisted to (`save`). Omitted ⇒ the manager is registry-only: `open` resolves only
|
|
4066
4173
|
* what is already registered, and `save` is a no-op (`false`).
|
|
4067
4174
|
*/
|
|
4068
4175
|
readonly store?: WorkflowStoreInterface;
|
|
@@ -4070,7 +4177,7 @@ export declare interface WorkflowManagerOptions {
|
|
|
4070
4177
|
* Holds the {@link WorkflowRegistry} registry threaded into every workflow this manager mints
|
|
4071
4178
|
* (`add`, through {@link import('./factories.js').createWorkflow}) or hydrates (`open`'s
|
|
4072
4179
|
* registry-miss path, through {@link import('./factories.js').createRestoredWorkflow}) — so a
|
|
4073
|
-
* hydrated workflow is
|
|
4180
|
+
* hydrated workflow is runnable, its tasks carrying real resolved `handler`s. Omitted ⇒
|
|
4074
4181
|
* named tasks remain inspectable but execution rejects them.
|
|
4075
4182
|
*/
|
|
4076
4183
|
readonly functions?: WorkflowRegistry;
|
|
@@ -4094,7 +4201,7 @@ export declare interface WorkflowOptions {
|
|
|
4094
4201
|
* Sets the failure policy the live tree applies — the same boolean toggle as
|
|
4095
4202
|
* {@link WorkflowDefinition.bail}, fed to {@link import('./helpers.js').deriveWorkflowStatus}.
|
|
4096
4203
|
* {@link import('./factories.js').createWorkflow} defaults it to the definition's `bail`. A
|
|
4097
|
-
* {@link WorkflowSnapshot}
|
|
4204
|
+
* {@link WorkflowSnapshot} persists the policy, so {@link import('./factories.js').createRestoredWorkflow}
|
|
4098
4205
|
* takes it from the snapshot (the source of truth); an explicit `options.bail` on restore still
|
|
4099
4206
|
* wins when supplied. Omitted on a fresh build ⇒ the graceful {@link import('./constants.js').DEFAULT_BAIL}.
|
|
4100
4207
|
*/
|
|
@@ -4105,8 +4212,8 @@ export declare interface WorkflowOptions {
|
|
|
4105
4212
|
readonly phases?: Readonly<Record<string, PhaseOptions>>;
|
|
4106
4213
|
/**
|
|
4107
4214
|
* Holds the `function`-task behavior registry ({@link WorkflowRegistry}) each live task's
|
|
4108
|
-
* {@link TaskDefinition.behavior} / {@link TaskSnapshot.behavior} name resolves against
|
|
4109
|
-
* construction into its runtime {@link TaskInterface.handler} — the
|
|
4215
|
+
* {@link TaskDefinition.behavior} / {@link TaskSnapshot.behavior} name resolves against once at
|
|
4216
|
+
* construction into its runtime {@link TaskInterface.handler} — the same registry a
|
|
4110
4217
|
* fresh build ({@link import('./factories.js').createWorkflow}) and a restore
|
|
4111
4218
|
* ({@link import('./factories.js').createRestoredWorkflow}) both consume, and the same shape a
|
|
4112
4219
|
* live {@link WorkflowInterface.add} / {@link PhaseInterface.add} mint resolves a newly
|
|
@@ -4121,11 +4228,12 @@ export declare interface WorkflowOptions {
|
|
|
4121
4228
|
}
|
|
4122
4229
|
|
|
4123
4230
|
/**
|
|
4124
|
-
* Coordinates advanced run-local snapshot persistence with one writer and one coalesced most
|
|
4231
|
+
* Coordinates advanced run-local snapshot persistence with one writer and one coalesced most
|
|
4232
|
+
* recent obligation, normally composed through `execute({ store })` rather than built directly.
|
|
4125
4233
|
*
|
|
4126
4234
|
* @remarks
|
|
4127
|
-
*
|
|
4128
|
-
*
|
|
4235
|
+
* Exported for hosts that need to coordinate the same required boundaries around their own runner
|
|
4236
|
+
* integration.
|
|
4129
4237
|
*
|
|
4130
4238
|
* @example
|
|
4131
4239
|
* ```ts
|
|
@@ -4188,7 +4296,7 @@ export declare interface WorkflowPersistenceInterface {
|
|
|
4188
4296
|
* {@link WorkflowFunction} handlers.
|
|
4189
4297
|
*
|
|
4190
4298
|
* @remarks
|
|
4191
|
-
* A live {@link TaskInterface} resolves its `behavior` name against this registry
|
|
4299
|
+
* A live {@link TaskInterface} resolves its `behavior` name against this registry once at
|
|
4192
4300
|
* construction into its {@link TaskInterface.handler}. An omitted `behavior` is the deliberate
|
|
4193
4301
|
* no-op case. A present name absent from the registry remains inspectable but makes the tree
|
|
4194
4302
|
* non-drivable until restored with a matching handler. A plain record (not a manager) — the
|
|
@@ -4198,12 +4306,13 @@ export declare type WorkflowRegistry = Readonly<Record<string, WorkflowFunction>
|
|
|
4198
4306
|
|
|
4199
4307
|
/**
|
|
4200
4308
|
* Represents the structured outcome of a {@link WorkflowRunnerInterface.execute} run — the settled
|
|
4201
|
-
* live workflow, its final status,
|
|
4309
|
+
* live workflow, its final status, the flattened result tree, and the persistence outcome a
|
|
4310
|
+
* supplied store produced.
|
|
4202
4311
|
*
|
|
4203
4312
|
* @remarks
|
|
4204
4313
|
* Boxes the settled {@link WorkflowInterface} itself (so a caller can navigate the whole
|
|
4205
4314
|
* live tree — every phase / task's final `status`, its recorded {@link TaskResult}, its
|
|
4206
|
-
* lineage)
|
|
4315
|
+
* lineage) alongside the two read-throughs the run produced: `status` is the workflow's
|
|
4207
4316
|
* derived {@link LifecycleStatus} at settle (`completed` under graceful mode even with
|
|
4208
4317
|
* failed leaves; `failed` under `bail: true`; `stopped` on a workflow-level abort /
|
|
4209
4318
|
* timeout / budget), and `results` is the workflow-tier {@link TaskResult} list (every
|
|
@@ -4225,8 +4334,8 @@ export declare interface WorkflowResult {
|
|
|
4225
4334
|
}
|
|
4226
4335
|
|
|
4227
4336
|
/**
|
|
4228
|
-
* Implements the thin orchestrator that
|
|
4229
|
-
* substrate — phases sequential, tasks concurrent — dispatching each task through its
|
|
4337
|
+
* Implements the thin orchestrator that executes a live W-b workflow tree by composing the shipped
|
|
4338
|
+
* substrate — phases sequential, tasks concurrent — dispatching each task through its own
|
|
4230
4339
|
* resolved handler under the `bail` policy.
|
|
4231
4340
|
*
|
|
4232
4341
|
* @remarks
|
|
@@ -4237,33 +4346,33 @@ export declare interface WorkflowResult {
|
|
|
4237
4346
|
* timeout / budget / entity `signal` fold through the `@orkestrel/abort` signal contract,
|
|
4238
4347
|
* {@link createTimeout}, and `AbortSignal.any` (exactly as the agent runtime folds its bounds);
|
|
4239
4348
|
* pacing is the shipped
|
|
4240
|
-
* {@link SchedulerInterface}. The runner writes
|
|
4349
|
+
* {@link SchedulerInterface}. The runner writes zero concurrency / retry / abort logic of
|
|
4241
4350
|
* its own — it only sequences phases, dispatches a task's own handler, and drives the live
|
|
4242
4351
|
* entity. The workflow layer owns per-task deadlines because timeout settlement must
|
|
4243
4352
|
* update the live leaf under the phase's `bail` policy before the substrate unit settles.
|
|
4244
4353
|
* - **Pure engine — no integration registry.** The runner carries no behavior or provider
|
|
4245
4354
|
* registry: each live {@link TaskInterface} already
|
|
4246
4355
|
* resolved its own {@link import('./types.js').WorkflowFunction} into
|
|
4247
|
-
* {@link import('./types.js').TaskInterface.handler}
|
|
4356
|
+
* {@link import('./types.js').TaskInterface.handler} once at construction (build, restore,
|
|
4248
4357
|
* or a live mint all resolve it identically, from {@link WorkflowOptions.functions}), so
|
|
4249
4358
|
* dispatch is "invoke the task's own handler". Provider, protocol, and tool
|
|
4250
4359
|
* integrations remain application-owned {@link import('./types.js').WorkflowFunction}s
|
|
4251
4360
|
* composed into {@link WorkflowOptions.functions}. This module imports none of them.
|
|
4252
|
-
* - **Two `execute` forms, one engine.** `execute(definition, options)`
|
|
4361
|
+
* - **Two `execute` forms, one engine.** `execute(definition, options)` builds the live tree
|
|
4253
4362
|
* from a {@link WorkflowDefinition} (single source of truth for the `behavior` / `concurrency`
|
|
4254
|
-
* metadata); `execute(workflow, options)`
|
|
4363
|
+
* metadata); `execute(workflow, options)` drives a caller-owned, already-built
|
|
4255
4364
|
* {@link WorkflowInterface} instead — the entity-native control surface
|
|
4256
4365
|
* (`pause` / `resume` / `add` / `stop` / `destroy` live on the entity itself). Both forms
|
|
4257
|
-
* converge on the
|
|
4258
|
-
* exists — `#runTask` reads each task's
|
|
4259
|
-
* / `retries` / `timeout`, and `#runPhase` reads each phase's
|
|
4366
|
+
* converge on the same `#execute` engine: neither reads a `WorkflowDefinition` after the tree
|
|
4367
|
+
* exists — `#runTask` reads each task's own {@link import('./types.js').TaskInterface.handler}
|
|
4368
|
+
* / `retries` / `timeout`, and `#runPhase` reads each phase's own
|
|
4260
4369
|
* {@link PhaseInterface.concurrency} / `bail`, so a live `add`-minted phase or task (V5)
|
|
4261
|
-
* runs under
|
|
4262
|
-
* - **Phases sequential, tasks concurrent —
|
|
4263
|
-
* order,
|
|
4370
|
+
* runs under exactly the same rules as one built from the original definition.
|
|
4371
|
+
* - **Phases sequential, tasks concurrent — live continuity.** `#execute` drives the phases in
|
|
4372
|
+
* order, re-reading `workflow.phases.phases()` every iteration (a cursor over the live
|
|
4264
4373
|
* manager, not a one-time snapshot) so a caller's `workflow.add(phaseDefinition)` mid-run is
|
|
4265
|
-
* picked up. Within a phase, `#runPhase` subscribes to that phase's `add` event
|
|
4266
|
-
* capturing its task list, then `spawn`s any task added mid-phase onto the
|
|
4374
|
+
* picked up. Within a phase, `#runPhase` subscribes to that phase's `add` event before
|
|
4375
|
+
* capturing its task list, then `spawn`s any task added mid-phase onto the same substrate
|
|
4267
4376
|
* Runner (so it is actually dispatched, under the same `concurrency`); a task added too late
|
|
4268
4377
|
* for `spawn` to accept (the runner already drained) is swept `skip`ped afterward so the
|
|
4269
4378
|
* phase always reaches a coherent terminal state.
|
|
@@ -4272,30 +4381,30 @@ export declare interface WorkflowResult {
|
|
|
4272
4381
|
* auto-completes with JSON `null`; a present unresolved name is rejected by the synchronous
|
|
4273
4382
|
* execution claim and never false-completes.
|
|
4274
4383
|
* - **`bail` → substrate.** Under `bail: true` (halt) a genuine task failure `fail`s the leaf
|
|
4275
|
-
*
|
|
4384
|
+
* then re-throws, so the substrate Runner fail-fasts — it aborts the in-flight siblings
|
|
4276
4385
|
* (their `controller.signal` fires; a mid-flight sibling `skip`s) and rejects the phase run;
|
|
4277
4386
|
* `#execute` then `skip`s the remaining tasks / phases (the workflow derives `failed`).
|
|
4278
|
-
* Under `bail: false` (graceful) a failure `fail`s the leaf and
|
|
4387
|
+
* Under `bail: false` (graceful) a failure `fail`s the leaf and resolves (never throws), so
|
|
4279
4388
|
* the Runner settles every unit (allSettled) and the run finishes (the workflow derives
|
|
4280
4389
|
* `completed`, the failure recorded in the result tree).
|
|
4281
4390
|
* - **Pause / stop / destroy gates.** Workflow, phase, and task gates are checked before
|
|
4282
4391
|
* dispatch, and a running handler can checkpoint their folded state through
|
|
4283
4392
|
* {@link import('./types.js').TaskControllerInterface.wait}. Because the substrate acquires
|
|
4284
4393
|
* concurrency before this handler gate, a paused task occupies one phase slot until resume;
|
|
4285
|
-
* already-running siblings continue and its per-attempt timeout keeps counting. A
|
|
4394
|
+
* already-running siblings continue and its per-attempt timeout keeps counting. A graceful
|
|
4286
4395
|
* `workflow.stop()` (no signal involved) is caught at
|
|
4287
4396
|
* those same gates: not-yet-started work is `skip`ped, in-flight work finishes naturally. A
|
|
4288
|
-
*
|
|
4397
|
+
* hard `workflow.destroy()` aborts {@link WorkflowInterface.signal}, which `#fold` has folded
|
|
4289
4398
|
* into the run's composed signal — so it cancels the active phase Runner (and every
|
|
4290
|
-
* in-flight task) exactly like an external abort / timeout / budget fire.
|
|
4291
|
-
* `wait()` gate is
|
|
4292
|
-
*
|
|
4399
|
+
* in-flight task) exactly like an external abort / timeout / budget fire. Every park on a
|
|
4400
|
+
* `wait()` gate is raced against that same run signal (`#raceWait`, S2) — so a cancel firing
|
|
4401
|
+
* while parked unparks the engine promptly instead of hanging until `resume`; the existing
|
|
4293
4402
|
* halt / abort re-checks after the gate then decide the outcome.
|
|
4294
4403
|
* - **Abort / Timeout / Budget / entity-signal fold.** `#execute` folds the live workflow's
|
|
4295
4404
|
* own {@link WorkflowInterface.signal}, the run's external `signal`, a
|
|
4296
4405
|
* {@link TimeoutInterface}, and the `@orkestrel/budget` package's `BudgetInterface`'s
|
|
4297
4406
|
* `signal` into one `runSignal` (`AbortSignal.any`); a fire aborts the active phase's Runner
|
|
4298
|
-
* (cancelling every in-flight task) and
|
|
4407
|
+
* (cancelling every in-flight task) and halts the run — the remaining tasks / phases `skip`
|
|
4299
4408
|
* and the workflow is force-`stop`ped (settles `stopped`). Each task's
|
|
4300
4409
|
* {@link TaskController} signal `AbortSignal.any`-combines the substrate per-unit signal with
|
|
4301
4410
|
* `runSignal`, so a handler observes either cause directly.
|
|
@@ -4307,12 +4416,12 @@ export declare class WorkflowRunner implements WorkflowRunnerInterface {
|
|
|
4307
4416
|
#private;
|
|
4308
4417
|
constructor(scheduler: SchedulerInterface);
|
|
4309
4418
|
/**
|
|
4310
|
-
* Executes a workflow definition to completion —
|
|
4419
|
+
* Executes a workflow definition to completion — builds its live tree, runs the phases
|
|
4311
4420
|
* sequentially with each phase's tasks concurrent — resolving its terminal
|
|
4312
4421
|
* {@link WorkflowResult} (whose `workflow` is the freshly-built live tree).
|
|
4313
4422
|
*
|
|
4314
4423
|
* @remarks
|
|
4315
|
-
* One-shot. The runner
|
|
4424
|
+
* One-shot. The runner builds the live tree from `definition` internally (one source of
|
|
4316
4425
|
* truth — the per-task `behavior` and per-phase `concurrency` come from the same definition
|
|
4317
4426
|
* the tree is constructed from, so the executed tree can never drift from the metadata).
|
|
4318
4427
|
* The {@link WorkflowOptions} part of `options` (initial `on` listeners, a `bail` override,
|
|
@@ -4320,7 +4429,7 @@ export declare class WorkflowRunner implements WorkflowRunnerInterface {
|
|
|
4320
4429
|
* `behavior` resolves against) is forwarded to the build. Under `bail: false` (graceful) every
|
|
4321
4430
|
* task settles (a failure is recorded on its {@link TaskInterface}) and the workflow
|
|
4322
4431
|
* reaches `completed`; under `bail: true` (halt) the first failure aborts the in-flight
|
|
4323
|
-
* sibling tasks
|
|
4432
|
+
* sibling tasks and `skip`s the remaining tasks / phases, settling the workflow `failed`. A
|
|
4324
4433
|
* {@link WorkflowRunOptions} abort / timeout / budget fires every in-flight task's signal
|
|
4325
4434
|
* and `stop`s the run. `execute` resolves (never rejects) on a cancel — the partial outcome
|
|
4326
4435
|
* is read from the returned {@link WorkflowResult} (its `workflow` / `status` / `results`).
|
|
@@ -4329,7 +4438,7 @@ export declare class WorkflowRunner implements WorkflowRunnerInterface {
|
|
|
4329
4438
|
*
|
|
4330
4439
|
* @param definition - The {@link WorkflowDefinition} to build the live tree from and drive
|
|
4331
4440
|
* @param options - The construction options ({@link WorkflowOptions}: `on` / `bail` /
|
|
4332
|
-
* `phases` / `functions`)
|
|
4441
|
+
* `phases` / `functions`) plus the per-run bounds (`signal` / `timeout` / `budget`) and the
|
|
4333
4442
|
* durable `store`
|
|
4334
4443
|
* @returns The run's terminal {@link WorkflowResult} (its `workflow` is the built tree)
|
|
4335
4444
|
* @example
|
|
@@ -4340,25 +4449,25 @@ export declare class WorkflowRunner implements WorkflowRunnerInterface {
|
|
|
4340
4449
|
*/
|
|
4341
4450
|
execute(definition: WorkflowDefinition, options?: WorkflowRunOptions): Promise<WorkflowResult>;
|
|
4342
4451
|
/**
|
|
4343
|
-
* Drives an
|
|
4452
|
+
* Drives an already-built, caller-owned live {@link WorkflowInterface} — the entity-native
|
|
4344
4453
|
* counterpart to the definition-building {@link execute} overload.
|
|
4345
4454
|
*
|
|
4346
4455
|
* @remarks
|
|
4347
4456
|
* `createWorkflow` mints the live tree, this overload drives it, and the caller controls
|
|
4348
|
-
* the
|
|
4457
|
+
* the same entity mid-run through its own `pause` / `resume` / `add` / `stop` / `destroy`.
|
|
4349
4458
|
* Requires `workflow.status === 'pending'`, `!workflow.destroyed`, and no
|
|
4350
4459
|
* prior execution claim. A process-local object-identity claim shared by all runner instances
|
|
4351
4460
|
* is acquired synchronously and never released, so a same-object second call throws a `TRANSITION`
|
|
4352
4461
|
* {@link WorkflowError} before any asynchronous status change. After acceptance, observable
|
|
4353
4462
|
* semantics are byte-identical to the `definition` form —
|
|
4354
|
-
* except the phase loop
|
|
4463
|
+
* except the phase loop re-reads the live tree every iteration, so a caller's live `add`
|
|
4355
4464
|
* mid-run is picked up and actually dispatched. `options` carries only the per-run run
|
|
4356
4465
|
* controls — the bounds (`signal` / `timeout` / `budget`) and the durable `store` — because the
|
|
4357
4466
|
* construction half of {@link WorkflowRunOptions} does not apply to a tree that already exists.
|
|
4358
4467
|
*
|
|
4359
4468
|
* @param workflow - The live {@link WorkflowInterface} to drive
|
|
4360
4469
|
* @param options - The per-run bounds (`signal` / `timeout` / `budget`) and the durable `store`
|
|
4361
|
-
* @returns The run's terminal {@link WorkflowResult} (its `workflow` is the
|
|
4470
|
+
* @returns The run's terminal {@link WorkflowResult} (its `workflow` is the same entity passed in)
|
|
4362
4471
|
* @example
|
|
4363
4472
|
* ```ts
|
|
4364
4473
|
* const workflow = createWorkflow(definition)
|
|
@@ -4372,42 +4481,42 @@ export declare class WorkflowRunner implements WorkflowRunnerInterface {
|
|
|
4372
4481
|
}
|
|
4373
4482
|
|
|
4374
4483
|
/**
|
|
4375
|
-
* Declares a thin orchestrator that
|
|
4484
|
+
* Declares a thin orchestrator that executes a live {@link WorkflowInterface} tree by composing the
|
|
4376
4485
|
* shipped substrate — phases sequential, tasks concurrent, each task dispatched through its
|
|
4377
|
-
*
|
|
4486
|
+
* own resolved handler under the `bail` policy.
|
|
4378
4487
|
*
|
|
4379
4488
|
* @remarks
|
|
4380
|
-
* `execute(definition, options?)`
|
|
4489
|
+
* `execute(definition, options?)` builds the live W-b entity tree from the definition itself
|
|
4381
4490
|
* (through {@link import('./factories.js').createWorkflow}) and drives it to a terminal
|
|
4382
|
-
* {@link WorkflowResult} — phases
|
|
4383
|
-
* through
|
|
4384
|
-
* the phase's {@link PhaseDefinition.concurrency}). The definition is the
|
|
4491
|
+
* {@link WorkflowResult} — phases sequentially and, within each phase, the tasks concurrently
|
|
4492
|
+
* through one substrate {@link RunnerInterface} (concurrency =
|
|
4493
|
+
* the phase's {@link PhaseDefinition.concurrency}). The definition is the single source of
|
|
4385
4494
|
* truth: the runner owns both the declarative state (the live tree it constructs) and the
|
|
4386
|
-
*
|
|
4495
|
+
* execution-only field the snapshot deliberately dropped — each task's `behavior` (resolved into
|
|
4387
4496
|
* its {@link TaskInterface.handler} once at construction, against
|
|
4388
4497
|
* {@link WorkflowOptions.functions}) and each phase's `concurrency` (so there is no
|
|
4389
4498
|
* separately-supplied workflow to drift from the definition). The freshly-built live tree is
|
|
4390
|
-
* returned in {@link WorkflowResult.workflow}. The runner carries
|
|
4391
|
-
* invokes each task's
|
|
4392
|
-
* auto-completing no-op. The runner
|
|
4499
|
+
* returned in {@link WorkflowResult.workflow}. The runner carries no registry of its own — it
|
|
4500
|
+
* invokes each task's own {@link TaskInterface.handler}; an omitted `behavior` is the only
|
|
4501
|
+
* auto-completing no-op. The runner drives the live entity (`start` → `complete` / `fail`), never
|
|
4393
4502
|
* re-implementing status. The `bail` policy maps onto the substrate's fail-fast (`bail: true`
|
|
4394
4503
|
* — the first failure aborts in-flight siblings and skips the rest) vs settle-all (`bail:
|
|
4395
4504
|
* false` — failures are recorded and the run finishes). The {@link WorkflowOptions} half of
|
|
4396
4505
|
* the options is forwarded to `createWorkflow` (initial listeners, a `bail` override,
|
|
4397
4506
|
* per-node options, the `functions` registry); the Abort / Timeout / Budget bounds fold per
|
|
4398
4507
|
* run through `AbortSignal.any`, halting the run and `stop`ping the workflow. A second
|
|
4399
|
-
* `execute(workflow, options?)` overload drives a
|
|
4508
|
+
* `execute(workflow, options?)` overload drives a caller-built live tree instead — the
|
|
4400
4509
|
* entity-native control surface (`pause` / `resume` / `add` / `stop` /
|
|
4401
4510
|
* `destroy` live on {@link WorkflowInterface} itself); see its own doc for details.
|
|
4402
4511
|
*/
|
|
4403
4512
|
export declare interface WorkflowRunnerInterface {
|
|
4404
4513
|
/**
|
|
4405
|
-
* Executes a workflow
|
|
4406
|
-
* sequentially with each phase's
|
|
4407
|
-
*
|
|
4514
|
+
* Executes a workflow to completion — building the live tree from a definition, or driving
|
|
4515
|
+
* an already-built caller-owned tree — running the phases sequentially with each phase's
|
|
4516
|
+
* tasks concurrent, and resolving its terminal {@link WorkflowResult}.
|
|
4408
4517
|
*
|
|
4409
4518
|
* @remarks
|
|
4410
|
-
* One-shot. The runner
|
|
4519
|
+
* One-shot. The runner builds the live tree from `definition` internally (one source of
|
|
4411
4520
|
* truth — the per-task `behavior` (resolved into its {@link TaskInterface.handler}) and per-phase
|
|
4412
4521
|
* `concurrency` come from the same definition the tree is constructed from, so the executed
|
|
4413
4522
|
* tree can never drift from the metadata). The {@link WorkflowOptions} part of `options`
|
|
@@ -4415,17 +4524,17 @@ export declare interface WorkflowRunnerInterface {
|
|
|
4415
4524
|
* registry) is forwarded to the build.
|
|
4416
4525
|
* Under `bail: false` (graceful) every task settles (a failure is recorded on its
|
|
4417
4526
|
* {@link TaskInterface}) and the workflow reaches `completed`; under `bail: true` (halt)
|
|
4418
|
-
* the first failure aborts the in-flight sibling tasks
|
|
4527
|
+
* the first failure aborts the in-flight sibling tasks and `skip`s the remaining tasks /
|
|
4419
4528
|
* phases, settling the workflow `failed`. A {@link WorkflowRunOptions} abort / timeout /
|
|
4420
4529
|
* budget fires every in-flight task's signal and `stop`s the run. `execute` resolves
|
|
4421
4530
|
* (never rejects) on a cancel — the partial outcome is read from the returned
|
|
4422
4531
|
* {@link WorkflowResult} (its `workflow` / `status` / `results`). A run-level cancel
|
|
4423
|
-
* (abort / timeout / budget) that fires on the
|
|
4532
|
+
* (abort / timeout / budget) that fires on the same tick as a genuine task failure resolves
|
|
4424
4533
|
* the run as `stopped` — the cancel supersedes the same-tick failure, and that task's error
|
|
4425
4534
|
* is not recorded.
|
|
4426
4535
|
*
|
|
4427
|
-
* **Programmer-error exception.** A
|
|
4428
|
-
* duplicate phase or task `id`)
|
|
4536
|
+
* **Programmer-error exception.** A pathological `definition` (for example, a
|
|
4537
|
+
* duplicate phase or task `id`) throws synchronously at construction — before any phase
|
|
4429
4538
|
* runs, and before the returned `Promise` is even created — rather than resolving a
|
|
4430
4539
|
* failed/partial {@link WorkflowResult}. Unexpected scheduler or engine-infrastructure
|
|
4431
4540
|
* failures may reject asynchronously after remaining work is stopped, swept, and final
|
|
@@ -4433,40 +4542,40 @@ export declare interface WorkflowRunnerInterface {
|
|
|
4433
4542
|
*
|
|
4434
4543
|
* @param definition - The {@link WorkflowDefinition} to build the live tree from and drive
|
|
4435
4544
|
* @param options - The construction options ({@link WorkflowOptions}: `on` / `bail` /
|
|
4436
|
-
* `phases`)
|
|
4545
|
+
* `phases`) plus the per-run bounds (`signal` / `timeout` / `budget`) and the durable `store`
|
|
4437
4546
|
* @returns The run's terminal {@link WorkflowResult} (its `workflow` is the built tree)
|
|
4438
4547
|
*/
|
|
4439
4548
|
execute(definition: WorkflowDefinition, options?: WorkflowRunOptions): Promise<WorkflowResult>;
|
|
4440
4549
|
/**
|
|
4441
|
-
* Drives an
|
|
4442
|
-
*
|
|
4550
|
+
* Drives an already-built, caller-owned live {@link WorkflowInterface} — the
|
|
4551
|
+
* entity-native counterpart to the definition-building {@link execute} overload.
|
|
4443
4552
|
*
|
|
4444
4553
|
* @remarks
|
|
4445
4554
|
* The entity itself is the single control surface (no separate run handle):
|
|
4446
4555
|
* `createWorkflow` mints the live tree, this overload drives it, and the caller
|
|
4447
|
-
* controls the
|
|
4556
|
+
* controls the same entity mid-run through its own `pause` / `resume` / `add` / `stop` /
|
|
4448
4557
|
* `destroy`. Requires `workflow.status === 'pending'`,
|
|
4449
4558
|
* `!workflow.destroyed`, and no prior execution claim. A process-local object-identity claim
|
|
4450
4559
|
* shared by every runner instance is acquired synchronously and never released, so a same-object
|
|
4451
4560
|
* call throws a `TRANSITION` {@link import('./errors.js').WorkflowError} even before an
|
|
4452
4561
|
* asynchronous status change. After acceptance, phases run
|
|
4453
|
-
*
|
|
4454
|
-
* semantics to the `definition`-form `execute` — except the phase loop
|
|
4562
|
+
* sequentially and, within each phase, tasks concurrently — byte-identical observable
|
|
4563
|
+
* semantics to the `definition`-form `execute` — except the phase loop re-reads the
|
|
4455
4564
|
* live `workflow.phases` / each phase's live `tasks` every iteration (a cursor over
|
|
4456
4565
|
* the live managers, not a one-time snapshot), so a caller's live `add` mid-run is
|
|
4457
4566
|
* picked up and actually dispatched. `workflow.pause()` gates the run at the next
|
|
4458
|
-
* phase boundary
|
|
4567
|
+
* phase boundary and before each task's dispatch (an in-flight task body is never
|
|
4459
4568
|
* suspended); `workflow.stop()` skips not-yet-started work gracefully; `workflow.destroy()`
|
|
4460
4569
|
* folds `workflow.signal` into the run's cancellation, aborting in-flight work
|
|
4461
|
-
* immediately. `options` carries only the per-run
|
|
4570
|
+
* immediately. `options` carries only the per-run run controls — the bounds (`signal` /
|
|
4462
4571
|
* `timeout` / `budget`) and the durable `store` — because the construction half of
|
|
4463
4572
|
* {@link WorkflowRunOptions} does not apply to a tree that already exists.
|
|
4464
4573
|
*
|
|
4465
4574
|
* **Run round-trips through the snapshot.** Driving a tree rebuilt by
|
|
4466
4575
|
* {@link import('./factories.js').createRestoredWorkflow} behaves according to whether a
|
|
4467
|
-
* {@link WorkflowRegistry} registry was supplied at that build:
|
|
4576
|
+
* {@link WorkflowRegistry} registry was supplied at that build: with a registry,
|
|
4468
4577
|
* each task's `behavior` name is re-resolved against it, so a matched task carries a real
|
|
4469
|
-
* handler and this overload actually
|
|
4578
|
+
* handler and this overload actually dispatches it, resuming real work. Without a registry,
|
|
4470
4579
|
* the persisted {@link TaskInterface.behavior} remains visible for inspection while `handler` is
|
|
4471
4580
|
* `undefined`, and this overload rejects the tree before dispatch. A quiescent recovered tree may contain
|
|
4472
4581
|
* terminal work plus pending work; a tree with any `running` leaf is not drivable.
|
|
@@ -4476,7 +4585,7 @@ export declare interface WorkflowRunnerInterface {
|
|
|
4476
4585
|
* @param options - The per-run bounds (`signal` / `timeout` / `budget`) and the durable
|
|
4477
4586
|
* `store`; the construction half of {@link WorkflowRunOptions} does not apply (the tree
|
|
4478
4587
|
* already exists)
|
|
4479
|
-
* @returns The run's terminal {@link WorkflowResult} (its `workflow` is the
|
|
4588
|
+
* @returns The run's terminal {@link WorkflowResult} (its `workflow` is the same entity passed in)
|
|
4480
4589
|
*/
|
|
4481
4590
|
execute(workflow: WorkflowInterface, options?: Omit<WorkflowRunOptions, keyof WorkflowOptions>): Promise<WorkflowResult>;
|
|
4482
4591
|
}
|
|
@@ -4486,15 +4595,15 @@ export declare interface WorkflowRunnerInterface {
|
|
|
4486
4595
|
* paces phase boundaries with.
|
|
4487
4596
|
*
|
|
4488
4597
|
* @remarks
|
|
4489
|
-
* The runner is a
|
|
4598
|
+
* The runner is a pure engine — it carries no `functions` / `tools` / `agents` registry
|
|
4490
4599
|
* (each live task already resolved its own handler at construction from
|
|
4491
4600
|
* {@link WorkflowOptions.functions}).
|
|
4492
4601
|
* - `scheduler` — the {@link SchedulerInterface} that paces the tree (a cooperative
|
|
4493
4602
|
* `yield` between phases). Omitted ⇒ the shipped cross-environment default
|
|
4494
4603
|
* ({@link createScheduler}).
|
|
4495
4604
|
*
|
|
4496
|
-
* The reserved `on` key is intentionally
|
|
4497
|
-
* the W-b entities'
|
|
4605
|
+
* The reserved `on` key is intentionally absent: the runner is thin and drives
|
|
4606
|
+
* the W-b entities' own emitters (subscribe through `workflow.emitter` / `phase.emitter` /
|
|
4498
4607
|
* `task.emitter`), so it owns no event map of its own — there is nothing for an `on` to
|
|
4499
4608
|
* wire. A future runner-level emitter would introduce its own `EmitterHooks` here.
|
|
4500
4609
|
*/
|
|
@@ -4504,13 +4613,13 @@ export declare interface WorkflowRunnerOptions {
|
|
|
4504
4613
|
|
|
4505
4614
|
/**
|
|
4506
4615
|
* Declares the options for one {@link WorkflowRunnerInterface.execute} call — the live tree's
|
|
4507
|
-
*
|
|
4616
|
+
* construction options ({@link WorkflowOptions}) beside the per-run controls: the bounds
|
|
4508
4617
|
* (an external abort, a deadline, and a cost ceiling), each folded into every task's
|
|
4509
4618
|
* cancellation, and the optional durable `store`.
|
|
4510
4619
|
*
|
|
4511
4620
|
* @remarks
|
|
4512
|
-
* `execute` is single-source: it
|
|
4513
|
-
* {@link import('./factories.js').createWorkflow}), so these options carry
|
|
4621
|
+
* `execute` is single-source: it builds the live tree from the definition internally (through
|
|
4622
|
+
* {@link import('./factories.js').createWorkflow}), so these options carry both halves of
|
|
4514
4623
|
* that one call —
|
|
4515
4624
|
* - the **construction** half is {@link WorkflowOptions} (`on` initial listeners, the `bail`
|
|
4516
4625
|
* override, the per-node `phases` bag); `execute` forwards it straight to `createWorkflow`,
|
|
@@ -4521,8 +4630,8 @@ export declare interface WorkflowRunnerOptions {
|
|
|
4521
4630
|
* fold and the store makes the run durable.
|
|
4522
4631
|
*
|
|
4523
4632
|
* The three bounds compose through `AbortSignal.any` (exactly as the agent runtime folds its
|
|
4524
|
-
* own): a fire of
|
|
4525
|
-
* {@link TaskControllerInterface.signal} fires) and
|
|
4633
|
+
* own): a fire of any of them cancels every in-flight task (its
|
|
4634
|
+
* {@link TaskControllerInterface.signal} fires) and halts the run — the remaining tasks
|
|
4526
4635
|
* and phases are `skip`ped and the workflow settles `stopped`.
|
|
4527
4636
|
* - `signal` — an external cancellation (a caller `AbortController`).
|
|
4528
4637
|
* - `timeout` — a whole-run deadline in milliseconds. A non-positive, non-finite, or
|
|
@@ -4530,19 +4639,19 @@ export declare interface WorkflowRunnerOptions {
|
|
|
4530
4639
|
* - `budget` — a whole-run cost ceiling (a {@link BudgetInterface} over {@link TokenUsage}
|
|
4531
4640
|
* — its `signal` fires when a task-reported usage crosses `max`); the runner folds its
|
|
4532
4641
|
* `signal` and `start`s it. (A `max: 0` budget is exhausted from its first `start`, so it
|
|
4533
|
-
* cancels the run at entry — a
|
|
4642
|
+
* cancels the run at entry — a different primitive from the `timeout: 0` "no deadline" case.)
|
|
4534
4643
|
*
|
|
4535
|
-
* `store` is not a bound. Supplying a {@link WorkflowStoreInterface} makes the run
|
|
4644
|
+
* `store` is not a bound. Supplying a {@link WorkflowStoreInterface} makes the run durable: the
|
|
4536
4645
|
* runner composes a {@link WorkflowPersistenceInterface} over it and writes the live
|
|
4537
4646
|
* {@link WorkflowSnapshot} at each required checkpoint — before the first phase, around every
|
|
4538
4647
|
* attempt and settlement, and once more when the run finishes — so an interrupted run is
|
|
4539
4648
|
* recoverable from the store through
|
|
4540
4649
|
* {@link import('./factories.js').createRecoveredWorkflow}. It also adds the two durability
|
|
4541
|
-
* read-throughs to the result: {@link WorkflowResult.durable} reports whether the
|
|
4650
|
+
* read-throughs to the result: {@link WorkflowResult.durable} reports whether the final state
|
|
4542
4651
|
* reached the store, and {@link WorkflowResult.fault} carries the first required write that
|
|
4543
|
-
* failed. Both are
|
|
4652
|
+
* failed. Both are omitted without a store, because a run that was never asked to persist has
|
|
4544
4653
|
* nothing to report. A required checkpoint that fails stops the run rather than continuing work
|
|
4545
|
-
* whose state is no longer recoverable. This half applies to
|
|
4654
|
+
* whose state is no longer recoverable. This half applies to both `execute` overloads.
|
|
4546
4655
|
*/
|
|
4547
4656
|
export declare type WorkflowRunOptions = WorkflowOptions & {
|
|
4548
4657
|
readonly signal?: AbortSignal;
|
|
@@ -4557,26 +4666,26 @@ export declare type WorkflowRunOptions = WorkflowOptions & {
|
|
|
4557
4666
|
* failure policy (the literal pair `true`/`false`, the runtime mirror of the boolean
|
|
4558
4667
|
* toggle; omitted ⇒ the graceful default).
|
|
4559
4668
|
*/
|
|
4560
|
-
export declare const workflowShape: ObjectShape<{
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4669
|
+
export declare const workflowShape: ObjectShape< {
|
|
4670
|
+
id: StringShape;
|
|
4671
|
+
name: StringShape;
|
|
4672
|
+
description: OptionalShape<StringShape>;
|
|
4673
|
+
phases: ArrayShape<ObjectShape< {
|
|
4674
|
+
id: StringShape;
|
|
4675
|
+
name: StringShape;
|
|
4676
|
+
description: OptionalShape<StringShape>;
|
|
4677
|
+
tasks: ArrayShape<ObjectShape< {
|
|
4678
|
+
id: StringShape;
|
|
4679
|
+
name: StringShape;
|
|
4680
|
+
description: OptionalShape<StringShape>;
|
|
4681
|
+
behavior: OptionalShape<StringShape>;
|
|
4682
|
+
retries: OptionalShape<NumberShape>;
|
|
4683
|
+
timeout: OptionalShape<NumberShape>;
|
|
4684
|
+
}, false>>;
|
|
4685
|
+
concurrency: OptionalShape<NumberShape>;
|
|
4686
|
+
bail: OptionalShape<LiteralShape<readonly [true, false]>>;
|
|
4687
|
+
}, false>>;
|
|
4688
|
+
bail: OptionalShape<LiteralShape<readonly [true, false]>>;
|
|
4580
4689
|
}, false>;
|
|
4581
4690
|
|
|
4582
4691
|
/**
|
|
@@ -4585,16 +4694,16 @@ export declare const workflowShape: ObjectShape<{
|
|
|
4585
4694
|
* and creation / update timestamps.
|
|
4586
4695
|
*
|
|
4587
4696
|
* @remarks
|
|
4588
|
-
* Pure JSON
|
|
4697
|
+
* Pure JSON data — the complete, self-contained payload the durable store (W-d) persists,
|
|
4589
4698
|
* designed in full at W-a so its shape is fixed from the start. It can be written to disk,
|
|
4590
4699
|
* sent to a prompt companion, loaded across conversations, or reviewed by an agent. Because
|
|
4591
4700
|
* it is self-contained, it carries the policy it ran under: `bail` is the
|
|
4592
4701
|
* failure policy, so {@link import('./factories.js').createRestoredWorkflow} re-derives status
|
|
4593
|
-
*
|
|
4702
|
+
* identically without a silent default. `status` is the effective status (override-or-derived)
|
|
4594
4703
|
* at snapshot time; `override` is the forced status of a whole-workflow `skip` / `stop` or
|
|
4595
4704
|
* vacuous `completed`. The completed override is valid only for an otherwise-derived pending
|
|
4596
|
-
* tree containing no tasks. An override is
|
|
4597
|
-
* reinstates it
|
|
4705
|
+
* tree containing no tasks. An override is present only when one is in force (so a restore
|
|
4706
|
+
* reinstates it directly rather than guessing from a status divergence). `phases` are the
|
|
4598
4707
|
* workflow's {@link PhaseSnapshot}s in order; `created` / `updated` are ms since epoch.
|
|
4599
4708
|
*/
|
|
4600
4709
|
export declare interface WorkflowSnapshot {
|
|
@@ -4614,13 +4723,14 @@ export declare interface WorkflowSnapshot {
|
|
|
4614
4723
|
|
|
4615
4724
|
/**
|
|
4616
4725
|
* Represents one row of the table a {@link import('./stores/DatabaseWorkflowStore.js').DatabaseWorkflowStore}
|
|
4617
|
-
* persists — a workflow `id` plus its {@link WorkflowSnapshot} held as
|
|
4726
|
+
* persists — a workflow `id` plus its {@link WorkflowSnapshot} held as one opaque JSON column,
|
|
4727
|
+
* read back as `unknown` and narrowed on `get`.
|
|
4618
4728
|
*
|
|
4619
4729
|
* @remarks
|
|
4620
4730
|
* The Database twin of {@link WorkflowStoreInterface} stores the snapshot whole (the `snapshot`
|
|
4621
4731
|
* column is a `rawShape`, an opaque JSON blob — exactly as
|
|
4622
4732
|
* `@orkestrel/queue`'s `StoredEntry` stores a queue entry's `input`), so the row
|
|
4623
|
-
* type stays
|
|
4733
|
+
* type stays flat and the deeply-nested snapshot shape (workflow → phases → tasks → results) never
|
|
4624
4734
|
* forces the contract to `Infer` it — sidestepping a TS2589 instantiation-depth blow-up. The column
|
|
4625
4735
|
* therefore reads back as the broad `unknown`; the store owns and narrows it to a
|
|
4626
4736
|
* {@link WorkflowSnapshot} on `get` through {@link import('./cloners.js').cloneWorkflowSnapshot},
|
|
@@ -4637,28 +4747,28 @@ export declare interface WorkflowSnapshotRow {
|
|
|
4637
4747
|
}
|
|
4638
4748
|
|
|
4639
4749
|
/**
|
|
4640
|
-
* Declares the durable persistence seam for a {@link WorkflowSnapshot} —
|
|
4641
|
-
*
|
|
4750
|
+
* Declares the durable persistence seam for a {@link WorkflowSnapshot} — the async `get` / `set` /
|
|
4751
|
+
* `delete` primitives keyed by a workflow id, the snapshot analogue of
|
|
4642
4752
|
* the server package's `SessionStoreInterface` (and the `@orkestrel/queue`
|
|
4643
4753
|
* `QueueStoreInterface` driver-swap pattern).
|
|
4644
4754
|
*
|
|
4645
4755
|
* @remarks
|
|
4646
|
-
* The store persists the W-a {@link WorkflowSnapshot} — the
|
|
4647
|
-
* pure-JSON run state — so a JSON / SQLite / IndexedDB backend swaps in
|
|
4756
|
+
* The store persists the W-a {@link WorkflowSnapshot} — the complete, self-contained,
|
|
4757
|
+
* pure-JSON run state — so a JSON / SQLite / IndexedDB backend swaps in without touching the
|
|
4648
4758
|
* runner or the entity tree: the in-memory default
|
|
4649
4759
|
* {@link import('./stores/MemoryWorkflowStore.js').MemoryWorkflowStore} and its driver-pluggable
|
|
4650
4760
|
* twin {@link import('./stores/DatabaseWorkflowStore.js').DatabaseWorkflowStore} (the snapshot as
|
|
4651
|
-
* one opaque JSON column) share
|
|
4761
|
+
* one opaque JSON column) share this one interface. Restore is not a store concern — a caller reads
|
|
4652
4762
|
* a snapshot back and rebuilds the live tree with the shipped {@link import('./factories.js').createRestoredWorkflow}.
|
|
4653
4763
|
*
|
|
4654
4764
|
* Every primitive is async (a `Promise`), so a durable backend (a database round-trip) fits the
|
|
4655
|
-
* same shape as the memory one. The snapshot carries its
|
|
4765
|
+
* same shape as the memory one. The snapshot carries its own id, so `set` takes no separate id
|
|
4656
4766
|
* param (mirroring `QueueStoreInterface.save` from `@orkestrel/queue` / the server package's
|
|
4657
4767
|
* `SessionStoreInterface.set`, which key off the value's own
|
|
4658
|
-
* `id`).
|
|
4768
|
+
* `id`). Unlike a session store there is no idle-TTL / eviction — a persisted workflow run-state
|
|
4659
4769
|
* lives until an explicit `delete`, never silently expiring (it is durable orchestration state,
|
|
4660
4770
|
* not an ephemeral session). It is concrete over {@link WorkflowSnapshot} — no generic parameter
|
|
4661
|
-
* (the smallest interface the capability requires), because the snapshot is the
|
|
4771
|
+
* (the smallest interface the capability requires), because the snapshot is the one payload a
|
|
4662
4772
|
* workflow store persists.
|
|
4663
4773
|
*/
|
|
4664
4774
|
export declare interface WorkflowStoreInterface {
|