@orkestrel/workflow 0.0.1 → 0.0.3
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 +17 -6
- package/dist/src/core/index.cjs +985 -835
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +1308 -867
- package/dist/src/core/index.d.ts +1308 -867
- package/dist/src/core/index.js +978 -812
- package/dist/src/core/index.js.map +1 -1
- package/package.json +1 -2
package/dist/src/core/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { AbortInterface } from '@orkestrel/abort';
|
|
2
|
-
import { AgentInterface } from '@orkestrel/agent';
|
|
3
2
|
import { ArrayShape } from '@orkestrel/contract';
|
|
4
3
|
import { BudgetInterface } from '@orkestrel/budget';
|
|
5
4
|
import { ContractInterface } from '@orkestrel/contract';
|
|
@@ -7,31 +6,16 @@ import { DriverInterface } from '@orkestrel/database';
|
|
|
7
6
|
import { EmitterErrorHandler } from '@orkestrel/emitter';
|
|
8
7
|
import { EmitterHooks } from '@orkestrel/emitter';
|
|
9
8
|
import { EmitterInterface } from '@orkestrel/emitter';
|
|
9
|
+
import { Failure } from '@orkestrel/contract';
|
|
10
10
|
import { LiteralShape } from '@orkestrel/contract';
|
|
11
11
|
import { NumberShape } from '@orkestrel/contract';
|
|
12
12
|
import { ObjectShape } from '@orkestrel/contract';
|
|
13
13
|
import { OptionalShape } from '@orkestrel/contract';
|
|
14
14
|
import { Result } from '@orkestrel/contract';
|
|
15
15
|
import { StringShape } from '@orkestrel/contract';
|
|
16
|
+
import { Success } from '@orkestrel/contract';
|
|
16
17
|
import { TableInterface } from '@orkestrel/database';
|
|
17
18
|
import { TokenUsage } from '@orkestrel/budget';
|
|
18
|
-
import { ToolInterface } from '@orkestrel/agent';
|
|
19
|
-
import { ToolManagerInterface } from '@orkestrel/agent';
|
|
20
|
-
import { UnionShape } from '@orkestrel/contract';
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* The ancestry identifier of an agent in a run chain — `agent:<name>`.
|
|
24
|
-
*
|
|
25
|
-
* @remarks
|
|
26
|
-
* The agent counterpart of {@link workflowTag}: the runner adds one when it dispatches an
|
|
27
|
-
* `agent` task, and rejects the task (a typed `DEPTH` `task.fail`) when the same tag is
|
|
28
|
-
* already in the ancestry (a re-entry cycle). The `agent:` namespace keeps it distinct
|
|
29
|
-
* from a same-string workflow id.
|
|
30
|
-
*
|
|
31
|
-
* @param name - The agent's registry name (the `agent`-form's `name`)
|
|
32
|
-
* @returns The namespaced ancestry tag (`agent:<name>`)
|
|
33
|
-
*/
|
|
34
|
-
export declare function agentTag(name: string): string;
|
|
35
19
|
|
|
36
20
|
/**
|
|
37
21
|
* Assert that a {@link WorkflowSnapshot} carries a `boolean` `bail` — at the workflow tier AND
|
|
@@ -43,10 +27,13 @@ export declare function agentTag(name: string): string;
|
|
|
43
27
|
* untrusted JSON, so a status (or an override) outside
|
|
44
28
|
* {@link import('./constants.js').WORKFLOW_STATUSES} /
|
|
45
29
|
* {@link import('./constants.js').PHASE_STATUSES} / {@link import('./constants.js').TASK_STATUSES},
|
|
46
|
-
*
|
|
30
|
+
* a non-boolean `bail` (the workflow's OR any phase's — both are REQUIRED persisted policy), a
|
|
31
|
+
* present-but-invalid phase `concurrency` (not a positive integer), or a present-but-invalid task
|
|
32
|
+
* `run` (an empty string) / `retries` / `timeout` (not a non-negative integer),
|
|
47
33
|
* is rejected loudly (naming the offending node) rather than silently producing a broken tree.
|
|
48
|
-
* The `override`
|
|
49
|
-
* fields is the contract's concern; this
|
|
34
|
+
* The `override` / `concurrency` / `run` / `retries` / `timeout` are optional, so each is only
|
|
35
|
+
* checked WHEN present. Structural shape beyond these fields is the contract's concern; this
|
|
36
|
+
* guards exactly the fields the live state machine reads back.
|
|
50
37
|
*
|
|
51
38
|
* @param snapshot - The snapshot to validate
|
|
52
39
|
*/
|
|
@@ -117,48 +104,6 @@ export declare function canTransitionTask(from: TaskStatus, to: TaskStatus): boo
|
|
|
117
104
|
*/
|
|
118
105
|
export declare function collectResults(phases: readonly (readonly TaskResult[])[]): readonly TaskResult[];
|
|
119
106
|
|
|
120
|
-
/**
|
|
121
|
-
* Complete a {@link WorkflowDraft} into a strict {@link WorkflowDefinition} — synthesize
|
|
122
|
-
* any MISSING `id` deterministically + positionally, and default any MISSING `name` to
|
|
123
|
-
* its (now-resolved) `id`.
|
|
124
|
-
*
|
|
125
|
-
* @remarks
|
|
126
|
-
* The positional id scheme is stable and human-legible: the workflow is `wf`, phase `i`
|
|
127
|
-
* is `phase-<i>`, and task `j` of that phase is `<phaseId>-task-<j>` (so a provided phase
|
|
128
|
-
* id flows into its tasks' synthesized ids). A PROVIDED `id` / `name` at any level is kept
|
|
129
|
-
* VERBATIM — synthesis touches only the omitted ones. A missing `name` defaults to the
|
|
130
|
-
* resolved `id` (never the other way round), so the result always has both. `run`,
|
|
131
|
-
* `description`, the per-phase `concurrency` / `bail`, the per-task `retries` / `timeout`, and
|
|
132
|
-
* the workflow `bail` carry over unchanged. The result is a complete
|
|
133
|
-
* {@link WorkflowDefinition}; the caller still validates it against the STRICT contract.
|
|
134
|
-
*
|
|
135
|
-
* @param draft - The draft workflow (id/name optional at all three levels)
|
|
136
|
-
* @returns A complete {@link WorkflowDefinition} with every id/name filled
|
|
137
|
-
*/
|
|
138
|
-
export declare function completeDraft(draft: WorkflowDraft): WorkflowDefinition;
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Complete one {@link PhaseDraft} into a strict {@link PhaseDefinition} — the per-phase
|
|
142
|
-
* step of {@link completeDraft} (phase `index` → `phase-<index>` when its id is omitted).
|
|
143
|
-
*
|
|
144
|
-
* @param phase - The draft phase
|
|
145
|
-
* @param index - The phase's positional index in the workflow
|
|
146
|
-
* @returns A complete {@link PhaseDefinition}
|
|
147
|
-
*/
|
|
148
|
-
export declare function completePhaseDraft(phase: PhaseDraft, index: number): PhaseDefinition;
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Complete one {@link TaskDraft} into a strict {@link TaskDefinition} — the per-task leaf
|
|
152
|
-
* step of {@link completeDraft} (task `index` of phase `<phaseId>` → `<phaseId>-task-<index>`
|
|
153
|
-
* when its id is omitted).
|
|
154
|
-
*
|
|
155
|
-
* @param task - The draft task
|
|
156
|
-
* @param phaseId - The (resolved) parent phase id, so the synthesized task id nests under it
|
|
157
|
-
* @param index - The task's positional index within its phase
|
|
158
|
-
* @returns A complete {@link TaskDefinition}
|
|
159
|
-
*/
|
|
160
|
-
export declare function completeTaskDraft(task: TaskDraft, phaseId: string, index: number): TaskDefinition;
|
|
161
|
-
|
|
162
107
|
/**
|
|
163
108
|
* The per-unit handle a runner handler receives — wraps the unit's identity,
|
|
164
109
|
* input, cancellation, and the run controls (`wait` / `spawn` / `abort`).
|
|
@@ -441,6 +386,11 @@ export declare function createScheduler(): SchedulerInterface;
|
|
|
441
386
|
* `options.phases[id].tasks[id]` (the AGENTS §8 nested-by-id bag). The W-b tree is the
|
|
442
387
|
* state machine ONLY — it does not execute tasks (W-c drives the transitions).
|
|
443
388
|
*
|
|
389
|
+
* `options.functions` is the {@link import('./types.js').WorkflowFunctions} registry each live
|
|
390
|
+
* task's `run` name resolves against ONCE at construction into its runtime
|
|
391
|
+
* {@link import('./types.js').TaskInterface.handler} — a name omitted or absent from the
|
|
392
|
+
* registry resolves to no handler (the no-handler rule).
|
|
393
|
+
*
|
|
444
394
|
* @param definition - The workflow definition to bring to life
|
|
445
395
|
* @param options - Runtime options (initial listeners, `bail` override, per-node options)
|
|
446
396
|
* @returns The live {@link WorkflowInterface} root
|
|
@@ -485,152 +435,54 @@ export declare function createWorkflow(definition: WorkflowDefinition, options?:
|
|
|
485
435
|
*/
|
|
486
436
|
export declare function createWorkflowContract(): ContractInterface<WorkflowDefinition>;
|
|
487
437
|
|
|
488
|
-
/**
|
|
489
|
-
* Compile the LENIENT workflow DRAFT contract — identical to
|
|
490
|
-
* {@link createWorkflowContract} EXCEPT `id` and `name` are OPTIONAL at all three levels
|
|
491
|
-
* (workflow / phase / task), so a small model can omit the six identity strings.
|
|
492
|
-
*
|
|
493
|
-
* @remarks
|
|
494
|
-
* The widened authoring surface {@link createWorkflowTool} parses an authored blob through
|
|
495
|
-
* before {@link import('./helpers.js').completeDraft} fills the missing ids/names. It does
|
|
496
|
-
* NOT relax the canonical contract — {@link createWorkflowContract} stays byte-for-byte
|
|
497
|
-
* unchanged and STRICT, and the completed draft is re-validated against THAT strict gate
|
|
498
|
-
* before running (soundness preserved). A PROVIDED `id` / `name` still carries `minLength: 1`,
|
|
499
|
-
* so an explicitly-empty `id: ''` is REJECTED (parses to `undefined`), never auto-filled —
|
|
500
|
-
* keeping "garbage" distinct from "omitted". `run` stays required.
|
|
501
|
-
*
|
|
502
|
-
* @returns The compiled {@link WorkflowDraft} contract
|
|
503
|
-
*
|
|
504
|
-
* @example
|
|
505
|
-
* ```ts
|
|
506
|
-
* import { createWorkflowDraftContract, completeDraft } from '@src/core'
|
|
507
|
-
*
|
|
508
|
-
* const draft = createWorkflowDraftContract()
|
|
509
|
-
* const parsed = draft.parse({ phases: [{ tasks: [{ run: { via: 'function', name: 'f' } }] }] })
|
|
510
|
-
* const definition = parsed && completeDraft(parsed) // ids/names filled positionally
|
|
511
|
-
* draft.parse({ id: '', phases: [] }) // undefined — an explicit empty id is rejected
|
|
512
|
-
* ```
|
|
513
|
-
*/
|
|
514
|
-
export declare function createWorkflowDraftContract(): ContractInterface<WorkflowDraft>;
|
|
515
|
-
|
|
516
438
|
/**
|
|
517
439
|
* Create a workflow runner — a {@link WorkflowRunnerInterface} that EXECUTES a live W-b
|
|
518
440
|
* workflow tree by COMPOSING the shipped substrate: phases sequential, tasks concurrent,
|
|
519
|
-
* each task dispatched
|
|
520
|
-
*
|
|
521
|
-
* @remarks
|
|
522
|
-
* The runner is
|
|
523
|
-
*
|
|
524
|
-
*
|
|
525
|
-
*
|
|
526
|
-
*
|
|
527
|
-
*
|
|
528
|
-
*
|
|
529
|
-
*
|
|
530
|
-
*
|
|
441
|
+
* each task dispatched through its OWN resolved handler under the workflow's `bail` policy.
|
|
442
|
+
*
|
|
443
|
+
* @remarks
|
|
444
|
+
* The runner is a PURE engine — it re-implements no concurrency / retry / abort logic, AND it
|
|
445
|
+
* carries no `functions` / `tools` / `agents` registry of its own: each live task already
|
|
446
|
+
* resolved its own {@link import('./types.js').WorkflowFunction} into
|
|
447
|
+
* {@link import('./types.js').TaskInterface.handler} ONCE at construction, from the
|
|
448
|
+
* {@link WorkflowOptions.functions} registry supplied to `execute` / {@link createWorkflow}.
|
|
449
|
+
* Per-phase bounded concurrency is one {@link createRunner} per phase; `bail` maps onto that
|
|
450
|
+
* Runner's fail-fast (`true` — the first failure aborts the in-flight siblings + skips the
|
|
451
|
+
* rest) vs settle-all (`false` — failures are recorded, the run finishes); the run-level abort
|
|
452
|
+
* / timeout / budget ({@link import('./types.js').WorkflowRunOptions}) fold through
|
|
453
|
+
* `AbortSignal.any` (the agent runtime's pattern); pacing is the shipped scheduler.
|
|
454
|
+
* `execute(definition, options?)` BUILDS the live tree from the definition itself (via
|
|
455
|
+
* {@link createWorkflow} — one source of truth, returned in `WorkflowResult.workflow`), drives
|
|
456
|
+
* the live entity (`start` → `complete` / `fail`), and resolves a
|
|
531
457
|
* {@link import('./types.js').WorkflowResult}.
|
|
532
458
|
*
|
|
533
|
-
*
|
|
534
|
-
*
|
|
535
|
-
*
|
|
536
|
-
*
|
|
459
|
+
* Static tool / agent calling is OPT-IN: a caller wires a plain
|
|
460
|
+
* {@link import('./types.js').WorkflowFunction} into its OWN {@link WorkflowOptions.functions}
|
|
461
|
+
* registry, same as any other behavior — the `@orkestrel/tool` package ships the
|
|
462
|
+
* tool/agent adapter factories for that. A task with no resolved handler AUTO-COMPLETES
|
|
537
463
|
* (the ROADMAP no-handler rule).
|
|
538
464
|
*
|
|
539
|
-
*
|
|
540
|
-
*
|
|
541
|
-
* — the propagation seam — WITHOUT this module's classes importing its own `factories.ts` (the
|
|
542
|
-
* factories→classes direction; the binder is injected as a value at construction).
|
|
543
|
-
*
|
|
544
|
-
* @param options - The behavior registries (`functions` / `tools` / `agents`) the runner
|
|
545
|
-
* dispatches a task by name through, plus an optional pacing `scheduler` (default the shipped
|
|
546
|
-
* cross-environment one). Omitting `functions` / `tools` / `agents` makes those task forms
|
|
547
|
-
* auto-complete (no handler). See {@link WorkflowRunnerOptions}.
|
|
465
|
+
* @param options - An optional pacing `scheduler` (default the shipped cross-environment one).
|
|
466
|
+
* See {@link WorkflowRunnerOptions}.
|
|
548
467
|
* @returns A working {@link WorkflowRunnerInterface}
|
|
549
468
|
*
|
|
550
469
|
* @example
|
|
551
470
|
* ```ts
|
|
552
|
-
* import { createWorkflowRunner
|
|
471
|
+
* import { createWorkflowRunner } from '@src/core'
|
|
553
472
|
*
|
|
554
|
-
* const
|
|
555
|
-
* const runner = createWorkflowRunner({
|
|
556
|
-
* functions: { compile: async (controller) => `built ${controller.task.id}` },
|
|
557
|
-
* tools,
|
|
558
|
-
* })
|
|
473
|
+
* const runner = createWorkflowRunner()
|
|
559
474
|
* const definition = { id: 'w', name: 'W', phases: [{ id: 'p', name: 'P', tasks: [
|
|
560
|
-
* { id: 't', name: 'T', run:
|
|
475
|
+
* { id: 't', name: 'T', run: 'compile' },
|
|
561
476
|
* ] }] }
|
|
562
|
-
* const result = await runner.execute(definition
|
|
477
|
+
* const result = await runner.execute(definition, {
|
|
478
|
+
* functions: { compile: async (controller) => `built ${controller.task.id}` },
|
|
479
|
+
* })
|
|
563
480
|
* result.status // 'completed'
|
|
564
481
|
* result.workflow.phase('p')?.task('t')?.status // 'completed'
|
|
565
482
|
* ```
|
|
566
483
|
*/
|
|
567
484
|
export declare function createWorkflowRunner(options?: WorkflowRunnerOptions): WorkflowRunnerInterface;
|
|
568
485
|
|
|
569
|
-
/**
|
|
570
|
-
* Wrap a {@link WorkflowDefinition} as an LLM-callable {@link ToolInterface} — it ADVERTISES
|
|
571
|
-
* the SIMPLE flat authoring shape (`{ name?, steps: [{ name, via? }] }`) as its `parameters` so
|
|
572
|
-
* even a small model can author a complete tree, and its handler EXPANDS / COMPLETES the
|
|
573
|
-
* authored blob, validates it against the STRICT contract, runs it through `runner`, and
|
|
574
|
-
* returns the run SUMMARY (throwing a typed {@link WorkflowError} on failure).
|
|
575
|
-
*
|
|
576
|
-
* @remarks
|
|
577
|
-
* A plain {@link ToolManagerInterface}-compatible tool (so `createMCPServer` / `createMCPRoutes`
|
|
578
|
-
* expose it for free — nothing MCP is wired here). It is ALSO the propagation carrier the
|
|
579
|
-
* {@link WorkflowRunner} binds onto a dispatched subagent (W-c2): because a tool handler receives
|
|
580
|
-
* ONLY the model-supplied `args` (no ambient context, no signal), the run's depth + ancestry are
|
|
581
|
-
* CLOSED OVER at bind time via {@link WorkflowToolOptions}, and the handler runs the nested
|
|
582
|
-
* workflow at `depth + 1` with the extended ancestry.
|
|
583
|
-
*
|
|
584
|
-
* **Widened authoring surface (additive — the canonical contract + runner stay STRICT and
|
|
585
|
-
* unchanged).** A 2B model reliably CALLS the tool but cannot reliably emit the full four-level
|
|
586
|
-
* nested {@link WorkflowDefinition} (six required `id`/`name` strings, a nested tagged union,
|
|
587
|
-
* all-or-nothing). So the tool ACCEPTS three authoring forms and converges them on the SAME
|
|
588
|
-
* strict {@link createWorkflowContract} gate before running (soundness preserved):
|
|
589
|
-
* - the FLAT shape `{ name?, steps: [{ name, via? }] }` — the ADVERTISED `parameters` (the simplest
|
|
590
|
-
* form, {@link import('./helpers.js').expandSteps}'d into one one-task phase per step);
|
|
591
|
-
* - a nested DRAFT with any `id`/`name` OMITTED — {@link createWorkflowDraftContract}-parsed then
|
|
592
|
-
* {@link import('./helpers.js').completeDraft}'d (missing ids synthesized positionally);
|
|
593
|
-
* - the full nested {@link WorkflowDefinition} — the advanced escape-hatch (documented in the
|
|
594
|
-
* description), accepted as the draft super-set.
|
|
595
|
-
*
|
|
596
|
-
* The handler conforms to the universal tool-handler contract (AGENTS §14): it returns the PLAIN
|
|
597
|
-
* run-summary VALUE on success and THROWS a typed {@link WorkflowError} on every failure path. It
|
|
598
|
-
* does NOT build a {@link ToolResult} itself — the `@orkestrel/agent` package's `ToolManager`
|
|
599
|
-
* performs the ONE canonical wrap (`{ id, name, value }` on a return; `{ id, name, error }` on a
|
|
600
|
-
* throw, ISOLATED so nothing escapes the run), so the outcome appears EXACTLY ONCE, identically,
|
|
601
|
-
* over BOTH the agent loop and MCP (a throw → MCP `isError: true`):
|
|
602
|
-
* - **No authored args** (an empty `arguments`) ⇒ runs the WRAPPED `definition`.
|
|
603
|
-
* - **A `steps` array** ⇒ the FLAT form: parse it, {@link import('./helpers.js').expandSteps} it.
|
|
604
|
-
* - **Otherwise** ⇒ the nested form: {@link createWorkflowDraftContract}-parse it,
|
|
605
|
-
* {@link import('./helpers.js').completeDraft} it.
|
|
606
|
-
* - **Strict gate** ⇒ the expanded / completed result is validated against
|
|
607
|
-
* {@link createWorkflowContract}.`is`; a blob that can't expand, or whose result fails the strict
|
|
608
|
-
* gate (e.g. an explicit empty `id`, `concurrency: 0`) ⇒ THROW a `TOOL` {@link WorkflowError} (no run).
|
|
609
|
-
* - **Over-deep / cyclic** ⇒ THROW a `DEPTH` {@link WorkflowError} when the nested run would exceed
|
|
610
|
-
* {@link MAX_WORKFLOW_DEPTH}, or the target workflow id is already an ancestor (a cycle) — the
|
|
611
|
-
* same `code` the agent-task guard raises.
|
|
612
|
-
* - **Otherwise** ⇒ `runner.execute(target, { depth: depth + 1, ancestry: … })`, RETURNING the
|
|
613
|
-
* plain summary of the terminal run (`{ status, count }`, via {@link workflowToolSummary}).
|
|
614
|
-
*
|
|
615
|
-
* @param definition - The workflow the tool runs when called with no authored args
|
|
616
|
-
* @param runner - The {@link WorkflowRunnerInterface} that executes the (nested) workflow
|
|
617
|
-
* @param options - The depth + ancestry to run the nested workflow under (see
|
|
618
|
-
* {@link WorkflowToolOptions}); omitted ⇒ depth `0` / empty ancestry (a top-level wrap)
|
|
619
|
-
* @returns A {@link ToolInterface} (named {@link import('./constants.js').WORKFLOW_TOOL_NAME})
|
|
620
|
-
* whose `parameters` advertise the FLAT authoring schema (the nested form stays accepted)
|
|
621
|
-
*
|
|
622
|
-
* @example
|
|
623
|
-
* ```ts
|
|
624
|
-
* import { createWorkflowRunner, createWorkflowTool, createToolManager } from '@src/core'
|
|
625
|
-
*
|
|
626
|
-
* const runner = createWorkflowRunner()
|
|
627
|
-
* const tool = createWorkflowTool(definition, runner)
|
|
628
|
-
* const tools = createToolManager()
|
|
629
|
-
* tools.add(tool) // a model can now author + run a workflow in one call
|
|
630
|
-
* ```
|
|
631
|
-
*/
|
|
632
|
-
export declare function createWorkflowTool(definition: WorkflowDefinition, runner: WorkflowRunnerInterface, options?: WorkflowToolOptions): ToolInterface;
|
|
633
|
-
|
|
634
486
|
/**
|
|
635
487
|
* A {@link WorkflowStoreInterface} backed by one table of the `databases` layer — a
|
|
636
488
|
* workflow's durable run-state IS a row, so persistence reduces to keyed point-access
|
|
@@ -702,17 +554,23 @@ export declare const DEFAULT_BAIL = false;
|
|
|
702
554
|
/**
|
|
703
555
|
* The default per-phase task concurrency the {@link import('./factories.js').createWorkflowRunner}
|
|
704
556
|
* runner applies when a {@link import('./types.js').PhaseDefinition} omits its `concurrency`
|
|
705
|
-
* throttle — a
|
|
557
|
+
* throttle — a cap that is effectively unbounded for any realistic phase.
|
|
706
558
|
*
|
|
707
559
|
* @remarks
|
|
708
560
|
* The determinism principle fixes that a phase's tasks run CONCURRENTLY; `concurrency` is
|
|
709
561
|
* only an optional resource throttle (max-in-flight). With none declared, the runner runs
|
|
710
|
-
* all of a phase's tasks at once — modelled as this
|
|
711
|
-
*
|
|
712
|
-
*
|
|
713
|
-
*
|
|
562
|
+
* all of a phase's tasks at once — modelled as this finite cap so the value flows straight
|
|
563
|
+
* into the substrate {@link import('./types.js').RunnerInterface}'s `concurrency` (which
|
|
564
|
+
* expects a positive integer) without a special unbounded branch. No realistic phase
|
|
565
|
+
* declares enough tasks to reach it, so it behaves as "run them all".
|
|
566
|
+
*
|
|
567
|
+
* WHY `1024` and not a huge sentinel like `1_000_000`: the backing `@orkestrel/queue` Runner
|
|
568
|
+
* EAGERLY spawns one parked worker loop per concurrency unit AT CONSTRUCTION, so this default
|
|
569
|
+
* must be a value whose eager allocation cost is negligible for every default-concurrency
|
|
570
|
+
* phase — a million-unit default meant ~1e6 promise/closure allocations per such phase. A
|
|
571
|
+
* phase may still DECLARE a larger explicit `concurrency` and pays that allocation knowingly.
|
|
714
572
|
*/
|
|
715
|
-
export declare const DEFAULT_PHASE_CONCURRENCY =
|
|
573
|
+
export declare const DEFAULT_PHASE_CONCURRENCY = 1024;
|
|
716
574
|
|
|
717
575
|
/**
|
|
718
576
|
* A promise paired with its externally-callable `resolve`/`reject` — the settle path
|
|
@@ -733,10 +591,12 @@ export declare interface DeferredInterface<T> {
|
|
|
733
591
|
*
|
|
734
592
|
* @remarks
|
|
735
593
|
* The structural fields (`id` / `name` / `description` + the ordered phases / tasks)
|
|
736
|
-
* carry over verbatim
|
|
737
|
-
*
|
|
738
|
-
* `
|
|
739
|
-
*
|
|
594
|
+
* carry over verbatim, as does each phase's `concurrency` (persisted on the
|
|
595
|
+
* {@link PhaseSnapshot} so a restore reinstates the same throttle) and each task's `run` /
|
|
596
|
+
* `retries` / `timeout` (persisted on the {@link TaskSnapshot}, like `bail` / `concurrency`,
|
|
597
|
+
* so a restore + a {@link import('./types.js').WorkflowOptions.functions} registry resumes
|
|
598
|
+
* real work). The `bail` policy carries over — at the
|
|
599
|
+
* workflow tier AND, per phase, the
|
|
740
600
|
* EFFECTIVE policy (`phase.bail ?? workflowBail`) on each {@link PhaseSnapshot} — so the seeded
|
|
741
601
|
* snapshot is self-contained; a fresh seed has no `override`. `created` / `updated` are stamped now.
|
|
742
602
|
* {@link import('./factories.js').createWorkflow} builds from this.
|
|
@@ -754,6 +614,34 @@ export declare interface DeferredInterface<T> {
|
|
|
754
614
|
*/
|
|
755
615
|
export declare function definitionToSnapshot(definition: WorkflowDefinition, bail?: boolean): WorkflowSnapshot;
|
|
756
616
|
|
|
617
|
+
/**
|
|
618
|
+
* Derive the PENDING SUFFIX boundary of a positional list of {@link LifecycleStatus}es —
|
|
619
|
+
* the index of the first entry in the contiguous trailing run of `pending` entries.
|
|
620
|
+
*
|
|
621
|
+
* @remarks
|
|
622
|
+
* The native, hook-free replacement for a runner-installed cursor (AGENTS §12): a
|
|
623
|
+
* {@link import('./types.js').WorkflowInterface}'s `add` / `remove` / `move` / `update`
|
|
624
|
+
* reads this over its live phases' statuses to decide which positions are safe to edit.
|
|
625
|
+
* Because entries run SEQUENTIALLY (phases sequential, AGENTS determinism), every
|
|
626
|
+
* already-started entry forms a contiguous LEADING prefix and every still-`pending`
|
|
627
|
+
* entry forms the trailing suffix — so the boundary is simply the count of leading
|
|
628
|
+
* non-`pending` entries: the index of the first `pending` entry, or the full length when
|
|
629
|
+
* none is `pending` (nothing is safely editable). A `pending` container's entries are ALL
|
|
630
|
+
* `pending`, so the boundary is `0` and every position is naturally accepted — callers
|
|
631
|
+
* need no special case for that.
|
|
632
|
+
*
|
|
633
|
+
* @param statuses - The positional list of statuses to derive the boundary from
|
|
634
|
+
* @returns The index of the first `pending` entry, or `statuses.length` when none is `pending`
|
|
635
|
+
*
|
|
636
|
+
* @example
|
|
637
|
+
* ```ts
|
|
638
|
+
* deriveBoundary(['completed', 'running', 'pending', 'pending']) // 2
|
|
639
|
+
* deriveBoundary(['pending', 'pending']) // 0
|
|
640
|
+
* deriveBoundary(['completed', 'completed']) // 2 (nothing pending)
|
|
641
|
+
* ```
|
|
642
|
+
*/
|
|
643
|
+
export declare function deriveBoundary(statuses: readonly LifecycleStatus[]): number;
|
|
644
|
+
|
|
757
645
|
/**
|
|
758
646
|
* Derive a phase's status from its tasks' statuses (tasks are concurrent, so this
|
|
759
647
|
* is an order-insensitive reduction).
|
|
@@ -808,47 +696,67 @@ export declare function derivePhaseStatus(tasks: readonly TaskStatus[]): PhaseSt
|
|
|
808
696
|
export declare function deriveWorkflowStatus(phases: readonly PhaseDerivation[]): WorkflowStatus;
|
|
809
697
|
|
|
810
698
|
/**
|
|
811
|
-
*
|
|
812
|
-
* step becomes a one-task phase, IN ORDER.
|
|
699
|
+
* Box an error as a {@link Failure} — the graceful outcome half of a {@link Result}.
|
|
813
700
|
*
|
|
814
|
-
* @
|
|
815
|
-
*
|
|
816
|
-
*
|
|
817
|
-
* the step's `name` becomes the task's `run.name`, and its `via` becomes the task's `run.via`
|
|
818
|
-
* (defaulting to `'function'` when omitted). Ids/names are auto-filled positionally — it
|
|
819
|
-
* builds an ids-omitted {@link WorkflowDraft} and delegates to {@link completeDraft}, so the
|
|
820
|
-
* two lenient surfaces share ONE synthesis path (step `i` → phase `phase-<i>`, its task
|
|
821
|
-
* `phase-<i>-task-0`). The optional `name` becomes the workflow's `name`. The result is a
|
|
822
|
-
* complete definition the caller validates against the STRICT contract before running.
|
|
701
|
+
* @typeParam E - The boxed error's type
|
|
702
|
+
* @param error - The error to box
|
|
703
|
+
* @returns A {@link Failure} wrapping `error`
|
|
823
704
|
*
|
|
824
|
-
* @
|
|
825
|
-
*
|
|
705
|
+
* @example
|
|
706
|
+
* ```ts
|
|
707
|
+
* const result = failure(new WorkflowError('MUTATION', 'refused')) // { success: false, error }
|
|
708
|
+
* ```
|
|
826
709
|
*/
|
|
827
|
-
export declare function
|
|
710
|
+
export declare function failure<E>(error: E): Failure<E>;
|
|
828
711
|
|
|
829
712
|
/**
|
|
830
|
-
*
|
|
831
|
-
*
|
|
713
|
+
* Find the first {@link TaskResult} in a positional list whose boxed outcome is a
|
|
714
|
+
* `Failure` — the pure scan shared by a phase's and a workflow's derived-`failed`
|
|
715
|
+
* `fail`-event lookup.
|
|
716
|
+
*
|
|
717
|
+
* @remarks
|
|
718
|
+
* The shared leaf behind {@link import('./phases/Phase.js').Phase} and
|
|
719
|
+
* {@link import('./Workflow.js').Workflow}'s own `#failure` — each gathers ITS tier's
|
|
720
|
+
* results (a phase's own settled tasks, a workflow's flattened `results()`) and feeds
|
|
721
|
+
* them here; the tier-local method keeps the §12 invariant throw (a derived `failed`
|
|
722
|
+
* status guarantees a failing result exists) since throwing on `undefined` is
|
|
723
|
+
* orchestration, not a leaf concern.
|
|
832
724
|
*
|
|
833
|
-
* @param
|
|
834
|
-
* @returns
|
|
725
|
+
* @param results - The results to scan, in any order
|
|
726
|
+
* @returns The first result whose `result.success` is `false`, or `undefined` if none
|
|
727
|
+
*
|
|
728
|
+
* @example
|
|
729
|
+
* ```ts
|
|
730
|
+
* findFailure([completedResult, failedResult]) // failedResult
|
|
731
|
+
* ```
|
|
835
732
|
*/
|
|
836
|
-
export declare function
|
|
837
|
-
readonly via: 'agent';
|
|
838
|
-
readonly name: string;
|
|
839
|
-
};
|
|
733
|
+
export declare function findFailure(results: readonly TaskResult[]): TaskResult | undefined;
|
|
840
734
|
|
|
841
735
|
/**
|
|
842
|
-
*
|
|
843
|
-
*
|
|
736
|
+
* Insert one `[key, value]` entry at a positional index into a readonly entries array —
|
|
737
|
+
* the pure splice-in step behind an insertion-ordered registry's `add`.
|
|
738
|
+
*
|
|
739
|
+
* @remarks
|
|
740
|
+
* Shared by {@link import('./tasks/TaskManager.js').TaskManager} and
|
|
741
|
+
* {@link import('./phases/PhaseManager.js').PhaseManager}: both convert their
|
|
742
|
+
* insertion-ordered `Map` to `[...map.entries()]`, call this to splice the new entry
|
|
743
|
+
* in at the target index, then rebuild the `Map` from the result (a stateful step that
|
|
744
|
+
* stays a `#` private method — this helper does no `Map` construction). Does not
|
|
745
|
+
* mutate `entries`; returns a new array.
|
|
844
746
|
*
|
|
845
|
-
* @
|
|
846
|
-
* @
|
|
747
|
+
* @typeParam T - The entry's value type
|
|
748
|
+
* @param entries - The current positional entries, in order
|
|
749
|
+
* @param index - The index to insert at (`0` prepends, `entries.length` appends)
|
|
750
|
+
* @param key - The new entry's key
|
|
751
|
+
* @param value - The new entry's value
|
|
752
|
+
* @returns A new entries array with `[key, value]` inserted at `index`
|
|
753
|
+
*
|
|
754
|
+
* @example
|
|
755
|
+
* ```ts
|
|
756
|
+
* insertEntry([['a', 1], ['b', 2]], 1, 'c', 3) // [['a', 1], ['c', 3], ['b', 2]]
|
|
757
|
+
* ```
|
|
847
758
|
*/
|
|
848
|
-
export declare function
|
|
849
|
-
readonly via: 'function';
|
|
850
|
-
readonly name: string;
|
|
851
|
-
};
|
|
759
|
+
export declare function insertEntry<T>(entries: readonly (readonly [string, T])[], index: number, key: string, value: T): readonly (readonly [string, T])[];
|
|
852
760
|
|
|
853
761
|
/**
|
|
854
762
|
* Test whether a {@link LifecycleStatus} is TERMINAL — a node in this state will not
|
|
@@ -867,17 +775,6 @@ export declare function isFunctionTask(form: TaskForm): form is {
|
|
|
867
775
|
*/
|
|
868
776
|
export declare function isTerminalStatus(status: LifecycleStatus): boolean;
|
|
869
777
|
|
|
870
|
-
/**
|
|
871
|
-
* Narrow a {@link TaskForm} to the `tool` form — a task that runs a registered tool.
|
|
872
|
-
*
|
|
873
|
-
* @param form - The task form to test
|
|
874
|
-
* @returns `true` when `form.via` is `'tool'`
|
|
875
|
-
*/
|
|
876
|
-
export declare function isToolTask(form: TaskForm): form is {
|
|
877
|
-
readonly via: 'tool';
|
|
878
|
-
readonly name: string;
|
|
879
|
-
};
|
|
880
|
-
|
|
881
778
|
/**
|
|
882
779
|
* Narrow an unknown caught value to a {@link WorkflowError}.
|
|
883
780
|
*
|
|
@@ -931,20 +828,6 @@ export declare function isWorkflowSnapshot(value: unknown): value is WorkflowSna
|
|
|
931
828
|
*/
|
|
932
829
|
export declare type LifecycleStatus = 'pending' | 'running' | 'completed' | 'failed' | 'skipped' | 'stopped';
|
|
933
830
|
|
|
934
|
-
/**
|
|
935
|
-
* The maximum nesting depth a workflow's `agent` task may spawn into (W-c) — the
|
|
936
|
-
* bound the runner's depth/cycle guard enforces.
|
|
937
|
-
*
|
|
938
|
-
* @remarks
|
|
939
|
-
* The limit lives in ONE place. The `agent` {@link import('./types.js').TaskForm} is
|
|
940
|
-
* bounded by it when the {@link import('./WorkflowRunner.js').WorkflowRunner} resolves a
|
|
941
|
-
* subagent: an agent running at this depth can no longer author + run a nested workflow
|
|
942
|
-
* (that would be depth `MAX_WORKFLOW_DEPTH + 1`), so the over-deep `agent` task is
|
|
943
|
-
* rejected (a typed `DEPTH` `task.fail`). The chain therefore nests workflows down to
|
|
944
|
-
* this depth, and the `agent` task in the depth-`MAX_WORKFLOW_DEPTH` workflow fails.
|
|
945
|
-
*/
|
|
946
|
-
export declare const MAX_WORKFLOW_DEPTH = 8;
|
|
947
|
-
|
|
948
831
|
/**
|
|
949
832
|
* The in-memory {@link WorkflowStoreInterface} — a process-lifetime `Map` of
|
|
950
833
|
* {@link WorkflowSnapshot}s keyed by workflow id, the DEFAULT store
|
|
@@ -990,6 +873,54 @@ export declare class MemoryWorkflowStore implements WorkflowStoreInterface {
|
|
|
990
873
|
delete(id: string): Promise<void>;
|
|
991
874
|
}
|
|
992
875
|
|
|
876
|
+
/**
|
|
877
|
+
* Reposition the entry keyed `key` to a new positional index in a readonly entries
|
|
878
|
+
* array — the pure remove-then-reinsert step behind an insertion-ordered registry's
|
|
879
|
+
* `move`.
|
|
880
|
+
*
|
|
881
|
+
* @remarks
|
|
882
|
+
* The move counterpart of {@link insertEntry}: finds the entry by `key`, splices it
|
|
883
|
+
* out, then splices it back in at `index`. An absent `key` is a no-op (returns a copy
|
|
884
|
+
* of `entries` unchanged) — the caller (`TaskManager.move` / `PhaseManager.move`)
|
|
885
|
+
* already gates on the target's existence before calling this, so the no-op branch is
|
|
886
|
+
* defensive, never reached in practice. Does not mutate `entries`; returns a new array.
|
|
887
|
+
*
|
|
888
|
+
* @typeParam T - The entry's value type
|
|
889
|
+
* @param entries - The current positional entries, in order
|
|
890
|
+
* @param key - The key of the entry to reposition
|
|
891
|
+
* @param index - The new index for the entry
|
|
892
|
+
* @returns A new entries array with the `key` entry repositioned to `index`
|
|
893
|
+
*
|
|
894
|
+
* @example
|
|
895
|
+
* ```ts
|
|
896
|
+
* moveEntry([['a', 1], ['b', 2], ['c', 3]], 'a', 2) // [['b', 2], ['c', 3], ['a', 1]]
|
|
897
|
+
* ```
|
|
898
|
+
*/
|
|
899
|
+
export declare function moveEntry<T>(entries: readonly (readonly [string, T])[], key: string, index: number): readonly (readonly [string, T])[];
|
|
900
|
+
|
|
901
|
+
/**
|
|
902
|
+
* Park until `signal` aborts — a promise-parked wait (AGENTS §21), never a timer or
|
|
903
|
+
* busy-loop, that NEVER rejects.
|
|
904
|
+
*
|
|
905
|
+
* @remarks
|
|
906
|
+
* Resolves IMMEDIATELY when `signal` is already aborted; otherwise attaches a one-shot
|
|
907
|
+
* `abort` listener and resolves when it fires, removing the listener either way. The
|
|
908
|
+
* shared leaf behind the duplicate abort-wiring an execution engine otherwise hand-rolls
|
|
909
|
+
* at every fold point.
|
|
910
|
+
*
|
|
911
|
+
* @param signal - The signal to park on
|
|
912
|
+
* @returns A promise that resolves once `signal` has aborted
|
|
913
|
+
*
|
|
914
|
+
* @example
|
|
915
|
+
* ```ts
|
|
916
|
+
* const controller = new AbortController()
|
|
917
|
+
* const parked = parkSignal(controller.signal)
|
|
918
|
+
* controller.abort()
|
|
919
|
+
* await parked // resolves
|
|
920
|
+
* ```
|
|
921
|
+
*/
|
|
922
|
+
export declare function parkSignal(signal: AbortSignal): Promise<void>;
|
|
923
|
+
|
|
993
924
|
/**
|
|
994
925
|
* The live DERIVED state machine (W-b) for one phase — an observable (AGENTS §13) whose
|
|
995
926
|
* {@link PhaseStatus} is computed from its tasks (never set directly) and recomputed
|
|
@@ -1011,10 +942,38 @@ export declare class MemoryWorkflowStore implements WorkflowStoreInterface {
|
|
|
1011
942
|
* `start` / `complete` / `fail` / `stop` on a derived-status CHANGE, strictly AFTER the
|
|
1012
943
|
* recompute + escalate; the emitter isolates a listener throw and routes it to its `error`
|
|
1013
944
|
* handler (the `error` option); `fail` carries the failing task's {@link TaskResult}.
|
|
945
|
+
* - **Structural API (AGENTS §7).** `add` / `remove` / `move` / `update` gate BEFORE
|
|
946
|
+
* delegating to {@link tasks} (the manager gates the target's own existence/status/id/
|
|
947
|
+
* bounds), then emit the matching {@link PhaseEventMap} event on success only. NATIVE
|
|
948
|
+
* gating, purely from this phase's own derived `status` (no runner-installed hook): while
|
|
949
|
+
* `pending`, any valid `index` is accepted; while `running`, `add` accepts ONLY a pure
|
|
950
|
+
* append (a live runner subscribed to the `add` event picks it up), and `remove` / `move` /
|
|
951
|
+
* `update` always fail gracefully (the tasks are already handed to the execution
|
|
952
|
+
* substrate); while terminal, everything is refused.
|
|
953
|
+
* - **Patch (AGENTS §12).** `patch` applies a validated {@link PhaseUpdate} to SELF
|
|
954
|
+
* (`name` / `description` / `concurrency` / `bail`) — defense-in-depth: it throws a
|
|
955
|
+
* `MUTATION` {@link WorkflowError} unless this phase's own `status` is `pending`, mirroring
|
|
956
|
+
* the owning {@link WorkflowInterface.update}'s gate.
|
|
957
|
+
* - **Minting (AGENTS §7).** {@link add} MINTS a live {@link Task} from a {@link TaskDefinition}
|
|
958
|
+
* (converts it to a {@link TaskSnapshot}, builds the task wired to THIS phase) — the same
|
|
959
|
+
* construction path {@link #append} uses at build time, so a live mint and a restored/built
|
|
960
|
+
* task are wired IDENTICALLY. At construction, the workflow-level
|
|
961
|
+
* {@link import('../types.js').WorkflowFunctions} registry (threaded from
|
|
962
|
+
* {@link import('../types.js').WorkflowOptions.functions}) resolves each task's `run` name into
|
|
963
|
+
* its runtime {@link import('../types.js').TaskInterface.handler} ONCE; a `run` that is omitted
|
|
964
|
+
* or unregistered resolves to no handler (the no-handler rule).
|
|
965
|
+
* - **Runtime lifecycle (AGENTS §10).** `pause` / `resume` / `wait` mirror the workflow's own
|
|
966
|
+
* quartet, scoped to this phase — a driving
|
|
967
|
+
* {@link import('../types.js').WorkflowRunnerInterface.execute} gates a task's own
|
|
968
|
+
* pre-dispatch on the workflow's gate FIRST, then this phase's gate, WITHOUT touching
|
|
969
|
+
* {@link status} — `paused` is runtime-only, never persisted. `skip` / `stop` (this phase's
|
|
970
|
+
* own terminal forcing) always release a parked {@link wait} waiter, mirroring
|
|
971
|
+
* {@link import('../Workflow.js').Workflow.destroy}'s cascade — a permanently-ended phase
|
|
972
|
+
* has nothing left to pause for.
|
|
1014
973
|
*/
|
|
1015
974
|
export declare class Phase implements PhaseInterface {
|
|
1016
975
|
#private;
|
|
1017
|
-
constructor(snapshot: PhaseSnapshot, workflow: WorkflowInterface, escalate: () => void, options?: PhaseOptions, bail?: boolean);
|
|
976
|
+
constructor(snapshot: PhaseSnapshot, workflow: WorkflowInterface, escalate: () => void, options?: PhaseOptions, bail?: boolean, functions?: WorkflowFunctions);
|
|
1018
977
|
get emitter(): EmitterInterface<PhaseEventMap>;
|
|
1019
978
|
get id(): string;
|
|
1020
979
|
get name(): string;
|
|
@@ -1022,12 +981,22 @@ export declare class Phase implements PhaseInterface {
|
|
|
1022
981
|
get context(): PhaseContext;
|
|
1023
982
|
get workflow(): WorkflowInterface;
|
|
1024
983
|
get bail(): boolean;
|
|
984
|
+
get concurrency(): number | undefined;
|
|
985
|
+
get paused(): boolean;
|
|
1025
986
|
get status(): PhaseStatus;
|
|
1026
987
|
get tasks(): TaskManagerInterface;
|
|
1027
988
|
task(id: string): TaskInterface | undefined;
|
|
1028
989
|
results(): readonly TaskResult[];
|
|
1029
990
|
skip(): void;
|
|
1030
991
|
stop(): void;
|
|
992
|
+
pause(): void;
|
|
993
|
+
resume(): void;
|
|
994
|
+
wait(): Promise<void>;
|
|
995
|
+
add(definition: TaskDefinition, index?: number): Result<TaskInterface, WorkflowError>;
|
|
996
|
+
remove(id: string): Result<TaskInterface, WorkflowError>;
|
|
997
|
+
move(id: string, index: number): Result<TaskInterface, WorkflowError>;
|
|
998
|
+
update(id: string, patch: TaskUpdate): Result<TaskInterface, WorkflowError>;
|
|
999
|
+
patch(value: PhaseUpdate): void;
|
|
1031
1000
|
snapshot(): PhaseSnapshot;
|
|
1032
1001
|
}
|
|
1033
1002
|
|
|
@@ -1082,6 +1051,7 @@ export declare interface PhaseDefinition {
|
|
|
1082
1051
|
* The snapshot persists the EFFECTIVE failure policy this phase runs under: the phase's own
|
|
1083
1052
|
* `bail` when it declares one, else the `workflowBail` it inherits — so a restore reinstates
|
|
1084
1053
|
* the same per-phase policy without a silent default (`effectiveBail = phase.bail ?? workflowBail`).
|
|
1054
|
+
* `concurrency` (the resource throttle) carries over verbatim, omitted when undefined.
|
|
1085
1055
|
*
|
|
1086
1056
|
* @param phase - The phase definition to seed from
|
|
1087
1057
|
* @param workflowBail - The workflow-level `bail` default the phase inherits when it declares none
|
|
@@ -1106,47 +1076,6 @@ export declare interface PhaseDerivation {
|
|
|
1106
1076
|
readonly bail: boolean;
|
|
1107
1077
|
}
|
|
1108
1078
|
|
|
1109
|
-
/** A draft phase — a {@link PhaseDefinition} with OPTIONAL `id` / `name` and {@link TaskDraft} tasks. */
|
|
1110
|
-
export declare interface PhaseDraft {
|
|
1111
|
-
readonly id?: string;
|
|
1112
|
-
readonly name?: string;
|
|
1113
|
-
readonly description?: string;
|
|
1114
|
-
readonly tasks: readonly TaskDraft[];
|
|
1115
|
-
/** Max tasks in flight at once (a resource throttle); omitted ⇒ unbounded. */
|
|
1116
|
-
readonly concurrency?: number;
|
|
1117
|
-
/** The per-phase failure-policy OVERRIDE; omitted ⇒ inherits the workflow `bail` (`effectiveBail = phase.bail ?? workflow.bail`). */
|
|
1118
|
-
readonly bail?: boolean;
|
|
1119
|
-
}
|
|
1120
|
-
|
|
1121
|
-
/**
|
|
1122
|
-
* The shape of a PHASE in a draft workflow — identical to {@link phaseShape} EXCEPT
|
|
1123
|
-
* `id` and `name` are OPTIONAL, and its tasks are {@link taskDraftShape}s.
|
|
1124
|
-
*/
|
|
1125
|
-
export declare const phaseDraftShape: ObjectShape<{
|
|
1126
|
-
id: OptionalShape<StringShape>;
|
|
1127
|
-
name: OptionalShape<StringShape>;
|
|
1128
|
-
description: OptionalShape<StringShape>;
|
|
1129
|
-
tasks: ArrayShape<ObjectShape<{
|
|
1130
|
-
id: OptionalShape<StringShape>;
|
|
1131
|
-
name: OptionalShape<StringShape>;
|
|
1132
|
-
description: OptionalShape<StringShape>;
|
|
1133
|
-
run: UnionShape<[ ObjectShape<{
|
|
1134
|
-
via: LiteralShape<readonly ["function"]>;
|
|
1135
|
-
name: StringShape;
|
|
1136
|
-
}>, ObjectShape<{
|
|
1137
|
-
via: LiteralShape<readonly ["tool"]>;
|
|
1138
|
-
name: StringShape;
|
|
1139
|
-
}>, ObjectShape<{
|
|
1140
|
-
via: LiteralShape<readonly ["agent"]>;
|
|
1141
|
-
name: StringShape;
|
|
1142
|
-
}>]>;
|
|
1143
|
-
retries: OptionalShape<NumberShape>;
|
|
1144
|
-
timeout: OptionalShape<NumberShape>;
|
|
1145
|
-
}>>;
|
|
1146
|
-
concurrency: OptionalShape<NumberShape>;
|
|
1147
|
-
bail: OptionalShape<LiteralShape<readonly [true, false]>>;
|
|
1148
|
-
}>;
|
|
1149
|
-
|
|
1150
1079
|
/**
|
|
1151
1080
|
* The push observation surface (AGENTS §13) of the phase entity (W-b) — analogous
|
|
1152
1081
|
* to {@link WorkflowEventMap}, scoped to one phase.
|
|
@@ -1154,9 +1083,12 @@ export declare const phaseDraftShape: ObjectShape<{
|
|
|
1154
1083
|
* @remarks
|
|
1155
1084
|
* `start` fires when the phase begins; `complete` when all its tasks settled
|
|
1156
1085
|
* successfully; `fail` when a task failed under `bail` (carrying the
|
|
1157
|
-
* {@link TaskResult}); `stop` when the phase was ended.
|
|
1158
|
-
*
|
|
1159
|
-
*
|
|
1086
|
+
* {@link TaskResult}); `stop` when the phase was ended. `add` / `remove` / `move` /
|
|
1087
|
+
* `update` fire on a successful structural or patch edit through
|
|
1088
|
+
* {@link PhaseInterface.add} / `remove` / `move` / `update` (AGENTS §7) — never on a
|
|
1089
|
+
* refused/gated one. A throwing listener is isolated by the emitter and routed to its
|
|
1090
|
+
* `error` handler, not the domain surface (AGENTS §13). A `type` alias (AGENTS §4.5)
|
|
1091
|
+
* so it satisfies `EventMap`.
|
|
1160
1092
|
*/
|
|
1161
1093
|
export declare type PhaseEventMap = {
|
|
1162
1094
|
/** The phase began — its `id`. */
|
|
@@ -1167,6 +1099,14 @@ export declare type PhaseEventMap = {
|
|
|
1167
1099
|
readonly fail: readonly [result: TaskResult];
|
|
1168
1100
|
/** The phase was permanently stopped. */
|
|
1169
1101
|
readonly stop: readonly [];
|
|
1102
|
+
/** A task was inserted — the inserted task + its final index. */
|
|
1103
|
+
readonly add: readonly [task: TaskInterface, index: number];
|
|
1104
|
+
/** A task was removed — the removed task. */
|
|
1105
|
+
readonly remove: readonly [task: TaskInterface];
|
|
1106
|
+
/** A task was repositioned — the moved task + its new index. */
|
|
1107
|
+
readonly move: readonly [task: TaskInterface, index: number];
|
|
1108
|
+
/** A task was patched — the patched task. */
|
|
1109
|
+
readonly update: readonly [task: TaskInterface];
|
|
1170
1110
|
};
|
|
1171
1111
|
|
|
1172
1112
|
/** Initial {@link PhaseEventMap} listeners — the reserved `on` option (AGENTS §8). */
|
|
@@ -1194,6 +1134,12 @@ export declare type PhaseInput = Partial<PhaseContext>;
|
|
|
1194
1134
|
* - **Observable (AGENTS §13).** The owned {@link emitter} ({@link PhaseEventMap}) fires
|
|
1195
1135
|
* `start` / `complete` / `fail` / `stop` on a derived-status change; the emitter isolates a
|
|
1196
1136
|
* listener throw and routes it to its `error` handler (the `error` option).
|
|
1137
|
+
* - **Runtime lifecycle (AGENTS §10).** `pause` / `resume` / `wait` mirror
|
|
1138
|
+
* {@link WorkflowInterface.pause} / `resume` / `wait`, scoped to this phase — a driving
|
|
1139
|
+
* {@link WorkflowRunnerInterface.execute} gates a task's own pre-dispatch on BOTH the
|
|
1140
|
+
* workflow's and its phase's gate. `paused` is RUNTIME-ONLY, never persisted; idempotent;
|
|
1141
|
+
* released by `resume` and by this phase's own `stop` / `skip` forcing a terminal status
|
|
1142
|
+
* (a permanently-ended phase has nothing left to pause for).
|
|
1197
1143
|
*/
|
|
1198
1144
|
export declare interface PhaseInterface {
|
|
1199
1145
|
readonly emitter: EmitterInterface<PhaseEventMap>;
|
|
@@ -1205,13 +1151,167 @@ export declare interface PhaseInterface {
|
|
|
1205
1151
|
readonly status: PhaseStatus;
|
|
1206
1152
|
/** The RESOLVED effective failure policy this phase runs under (`phase.bail ?? workflow.bail`); mirrors {@link WorkflowInterface.bail}. */
|
|
1207
1153
|
readonly bail: boolean;
|
|
1154
|
+
/** Max tasks in flight at once (a resource throttle); mirrors {@link PhaseSnapshot.concurrency}. `undefined` ⇒ unbounded. */
|
|
1155
|
+
readonly concurrency: number | undefined;
|
|
1156
|
+
/**
|
|
1157
|
+
* Whether the phase is currently paused (AGENTS §10 — resumable); RUNTIME-ONLY — never a
|
|
1158
|
+
* {@link PhaseStatus}, never persisted in a {@link PhaseSnapshot} (a paused phase's
|
|
1159
|
+
* `status` still reports its ordinary derived value).
|
|
1160
|
+
*/
|
|
1161
|
+
readonly paused: boolean;
|
|
1208
1162
|
readonly tasks: TaskManagerInterface;
|
|
1209
1163
|
/** Look up one live task by its `id`. */
|
|
1210
1164
|
task(id: string): TaskInterface | undefined;
|
|
1211
1165
|
/** The settled tasks' results, in positional order — the phase tier of the result tree. */
|
|
1212
1166
|
results(): readonly TaskResult[];
|
|
1167
|
+
/**
|
|
1168
|
+
* FORCE this phase to `skipped` (AGENTS §10), overriding the derived value; idempotent.
|
|
1169
|
+
*
|
|
1170
|
+
* @remarks
|
|
1171
|
+
* A NO-OP once `status` is already terminal — a settled phase cannot be re-forced. Always
|
|
1172
|
+
* releases a parked {@link wait} waiter regardless (a terminal phase has nothing left to
|
|
1173
|
+
* pause for).
|
|
1174
|
+
*/
|
|
1213
1175
|
skip(): void;
|
|
1176
|
+
/**
|
|
1177
|
+
* FORCE this phase to `stopped` (AGENTS §10), overriding the derived value; idempotent.
|
|
1178
|
+
*
|
|
1179
|
+
* @remarks
|
|
1180
|
+
* A NO-OP once `status` is already terminal (a settled phase cannot be re-forced). Always
|
|
1181
|
+
* releases a parked {@link wait} waiter regardless (a terminal phase has nothing left to
|
|
1182
|
+
* pause for).
|
|
1183
|
+
*/
|
|
1214
1184
|
stop(): void;
|
|
1185
|
+
/**
|
|
1186
|
+
* Suspend the phase (AGENTS §10 — resumable); idempotent.
|
|
1187
|
+
*
|
|
1188
|
+
* @remarks
|
|
1189
|
+
* A no-op when already `paused` or when `status` is terminal. RUNTIME-ONLY (AGENTS §10) —
|
|
1190
|
+
* never a {@link PhaseStatus}, never persisted in a {@link PhaseSnapshot}. A driving
|
|
1191
|
+
* {@link WorkflowRunnerInterface.execute} gates a task's own pre-dispatch on this phase's
|
|
1192
|
+
* gate (after the workflow's own gate). **Pausing does NOT suspend a driving run's
|
|
1193
|
+
* timeout / budget / abort clocks** — those bounds keep ticking while paused, so a long
|
|
1194
|
+
* pause can still fire a run-level cancel and stop the workflow while parked.
|
|
1195
|
+
*
|
|
1196
|
+
* @example
|
|
1197
|
+
* ```ts
|
|
1198
|
+
* phase.pause()
|
|
1199
|
+
* phase.paused // true
|
|
1200
|
+
* ```
|
|
1201
|
+
*/
|
|
1202
|
+
pause(): void;
|
|
1203
|
+
/**
|
|
1204
|
+
* Continue a paused phase (AGENTS §10); idempotent — a no-op unless {@link paused}.
|
|
1205
|
+
*
|
|
1206
|
+
* @example
|
|
1207
|
+
* ```ts
|
|
1208
|
+
* phase.resume()
|
|
1209
|
+
* phase.paused // false
|
|
1210
|
+
* ```
|
|
1211
|
+
*/
|
|
1212
|
+
resume(): void;
|
|
1213
|
+
/**
|
|
1214
|
+
* Park until this phase is not paused — **promise-parked**, never a timer or busy-loop
|
|
1215
|
+
* (AGENTS §21; mirrors {@link WorkflowInterface.wait}).
|
|
1216
|
+
*
|
|
1217
|
+
* @remarks
|
|
1218
|
+
* Resolves IMMEDIATELY when not {@link paused}. While paused, parks until `resume` or
|
|
1219
|
+
* this phase's own `stop` / `skip` forcing a terminal status — all release a parked
|
|
1220
|
+
* waiter. NEVER rejects.
|
|
1221
|
+
*
|
|
1222
|
+
* @returns A promise that resolves once the phase is no longer paused
|
|
1223
|
+
*/
|
|
1224
|
+
wait(): Promise<void>;
|
|
1225
|
+
/**
|
|
1226
|
+
* MINT a live {@link TaskInterface} from `definition` and insert it into this phase
|
|
1227
|
+
* (AGENTS §7 the entity structural API) — gated BEFORE delegating to {@link tasks}'
|
|
1228
|
+
* manager.
|
|
1229
|
+
*
|
|
1230
|
+
* @remarks
|
|
1231
|
+
* Converts `definition` → {@link TaskSnapshot} and constructs the live task (wired to
|
|
1232
|
+
* THIS phase, its recompute cascade, and its emitter hooks), carrying its `run` /
|
|
1233
|
+
* `retries` / `timeout` from `definition` and resolving its {@link TaskInterface.handler}
|
|
1234
|
+
* against the workflow-level {@link WorkflowOptions.functions} registry — the SAME
|
|
1235
|
+
* resolution {@link import('./factories.js').createWorkflow} performs at build time.
|
|
1236
|
+
* Requires `definition.id` to be UNIQUE among this phase's existing
|
|
1237
|
+
* task ids — a duplicate is a `MUTATION` failure (mirrors
|
|
1238
|
+
* {@link TaskManagerInterface.add}'s own duplicate-id gate).
|
|
1239
|
+
*
|
|
1240
|
+
* NATIVE gating, purely from this phase's own derived `status` (AGENTS §12 — no
|
|
1241
|
+
* runner-installed hook), UNCHANGED from the entity-taking predecessor. While
|
|
1242
|
+
* `pending`: any valid `index` is accepted (delegates the minted task to
|
|
1243
|
+
* {@link TaskManagerInterface.add} then emits `add`). While `running`: accepted ONLY as
|
|
1244
|
+
* a pure append (`index` omitted or `=== tasks.count`) — a live runner subscribed to
|
|
1245
|
+
* the `add` event picks the new task up for same-run execution; the derived-status
|
|
1246
|
+
* model guarantees this phase cannot reach a terminal status while the accepted task is
|
|
1247
|
+
* still `pending` (its status feeds `status` via {@link import('./helpers.js').derivePhaseStatus}).
|
|
1248
|
+
* While terminal: always refused.
|
|
1249
|
+
*
|
|
1250
|
+
* **Abort edge.** An append ACCEPTED while `running` can still settle `skipped` rather
|
|
1251
|
+
* than run — if the driving run is cancelled (abort / timeout / budget / `workflow.destroy()`)
|
|
1252
|
+
* before the substrate actually dispatches the newly-minted task, the runner's halt sweep
|
|
1253
|
+
* `skip`s it like any other not-yet-started task. Acceptance here only guarantees the task
|
|
1254
|
+
* is WIRED into the live tree, not that it will execute.
|
|
1255
|
+
*
|
|
1256
|
+
* @param definition - The {@link TaskDefinition} to mint a live task from
|
|
1257
|
+
* @param index - The insertion position; omitted inserts at the end
|
|
1258
|
+
* @returns A {@link Result} boxing the minted, inserted task, or a `MUTATION` failure
|
|
1259
|
+
*/
|
|
1260
|
+
add(definition: TaskDefinition, index?: number): Result<TaskInterface, WorkflowError>;
|
|
1261
|
+
/**
|
|
1262
|
+
* Remove the `pending` task `id` from this phase.
|
|
1263
|
+
*
|
|
1264
|
+
* @remarks
|
|
1265
|
+
* NATIVE gating: allowed only while this phase's own `status` is `pending`. While
|
|
1266
|
+
* `running` or terminal, always a `MUTATION` failure — a running phase's tasks are
|
|
1267
|
+
* already handed to the execution substrate and only a pure {@link add} append remains
|
|
1268
|
+
* possible.
|
|
1269
|
+
*
|
|
1270
|
+
* @param id - The task id to remove
|
|
1271
|
+
* @returns A {@link Result} boxing the removed task, or a `MUTATION` failure
|
|
1272
|
+
*/
|
|
1273
|
+
remove(id: string): Result<TaskInterface, WorkflowError>;
|
|
1274
|
+
/**
|
|
1275
|
+
* Reposition the `pending` task `id` to `index` within this phase.
|
|
1276
|
+
*
|
|
1277
|
+
* @remarks
|
|
1278
|
+
* NATIVE gating: allowed only while this phase's own `status` is `pending`; `running` /
|
|
1279
|
+
* terminal always fail (see {@link remove}).
|
|
1280
|
+
*
|
|
1281
|
+
* @param id - The task id to move
|
|
1282
|
+
* @param index - The destination position
|
|
1283
|
+
* @returns A {@link Result} boxing the moved task, or a `MUTATION` failure
|
|
1284
|
+
*/
|
|
1285
|
+
move(id: string, index: number): Result<TaskInterface, WorkflowError>;
|
|
1286
|
+
/**
|
|
1287
|
+
* Apply a validated {@link TaskUpdate} patch to the `pending` task `id` in this phase.
|
|
1288
|
+
*
|
|
1289
|
+
* @remarks
|
|
1290
|
+
* NATIVE gating: allowed only while this phase's own `status` is `pending`; `running` /
|
|
1291
|
+
* terminal always fail (see {@link remove}).
|
|
1292
|
+
*
|
|
1293
|
+
* @param id - The task id to patch
|
|
1294
|
+
* @param patch - The fields to update
|
|
1295
|
+
* @returns A {@link Result} boxing the patched task, or a `MUTATION` failure
|
|
1296
|
+
*/
|
|
1297
|
+
update(id: string, patch: TaskUpdate): Result<TaskInterface, WorkflowError>;
|
|
1298
|
+
/**
|
|
1299
|
+
* Apply a validated declarative patch to SELF (`name` / `description` /
|
|
1300
|
+
* `concurrency` / `bail`).
|
|
1301
|
+
*
|
|
1302
|
+
* @remarks
|
|
1303
|
+
* Defense-in-depth (AGENTS §12): the owning {@link WorkflowInterface.update} gates
|
|
1304
|
+
* FIRST, so a direct call here THROWS a `MUTATION`
|
|
1305
|
+
* {@link import('./errors.js').WorkflowError} unless this phase's own `status` is
|
|
1306
|
+
* `pending`.
|
|
1307
|
+
*
|
|
1308
|
+
* @param value - The {@link PhaseUpdate} fields to apply
|
|
1309
|
+
* @example
|
|
1310
|
+
* ```ts
|
|
1311
|
+
* phase.patch({ concurrency: 4 })
|
|
1312
|
+
* ```
|
|
1313
|
+
*/
|
|
1314
|
+
patch(value: PhaseUpdate): void;
|
|
1215
1315
|
snapshot(): PhaseSnapshot;
|
|
1216
1316
|
}
|
|
1217
1317
|
|
|
@@ -1225,6 +1325,11 @@ export declare interface PhaseInterface {
|
|
|
1225
1325
|
* `append` adds one at the end, `phase(id)` looks one up, `phases()` lists them in
|
|
1226
1326
|
* positional order, `count` is the size. A snapshot RESTORE re-`append`s in the
|
|
1227
1327
|
* snapshot's order, reproducing it exactly.
|
|
1328
|
+
* - **Gated mutation API (AGENTS §12).** `add` / `remove` / `move` / `update` are the
|
|
1329
|
+
* graceful `Result` counterparts to `append`, gating ONLY on the target's OWN
|
|
1330
|
+
* existence/status/id/bounds — a duplicate id, an absent/non-`pending` target, an
|
|
1331
|
+
* out-of-bounds `index`, or a patch that fails {@link phaseUpdateShape} validation
|
|
1332
|
+
* all fail gracefully with a `MUTATION` {@link WorkflowError} instead of throwing.
|
|
1228
1333
|
* - **No batch matrix.** A workflow's phases are a fixed positional set, so AGENTS §9.2
|
|
1229
1334
|
* is deliberately omitted.
|
|
1230
1335
|
* - **Event-free.** A purely structural container — the live {@link PhaseInterface}s own
|
|
@@ -1242,6 +1347,10 @@ export declare class PhaseManager implements PhaseManagerInterface {
|
|
|
1242
1347
|
#private;
|
|
1243
1348
|
get count(): number;
|
|
1244
1349
|
append(phase: PhaseInterface): void;
|
|
1350
|
+
add(phase: PhaseInterface, index?: number): Result<PhaseInterface, WorkflowError>;
|
|
1351
|
+
remove(id: string): Result<PhaseInterface, WorkflowError>;
|
|
1352
|
+
move(id: string, index: number): Result<PhaseInterface, WorkflowError>;
|
|
1353
|
+
update(id: string, patch: PhaseUpdate): Result<PhaseInterface, WorkflowError>;
|
|
1245
1354
|
phase(id: string): PhaseInterface | undefined;
|
|
1246
1355
|
phases(): readonly PhaseInterface[];
|
|
1247
1356
|
}
|
|
@@ -1253,10 +1362,61 @@ export declare class PhaseManager implements PhaseManagerInterface {
|
|
|
1253
1362
|
* @remarks
|
|
1254
1363
|
* `append` adds one live {@link PhaseInterface} at the end; `phase(id)` looks one up;
|
|
1255
1364
|
* `phases()` lists them in positional order; `count` is the tally. No batch matrix.
|
|
1365
|
+
* `add` / `remove` / `move` / `update` (AGENTS §12) are the GATED mutation
|
|
1366
|
+
* counterparts a {@link WorkflowInterface.add} / `remove` / `move` / `update`
|
|
1367
|
+
* delegates to AFTER its own container-status/hook gating — the manager gates ONLY
|
|
1368
|
+
* on the target's OWN existence/status/id/bounds and stays event-free (the entity
|
|
1369
|
+
* emits on success).
|
|
1256
1370
|
*/
|
|
1257
1371
|
export declare interface PhaseManagerInterface {
|
|
1258
1372
|
readonly count: number;
|
|
1373
|
+
/**
|
|
1374
|
+
* Add `phase` at the end (the build-time wiring path).
|
|
1375
|
+
*
|
|
1376
|
+
* @remarks
|
|
1377
|
+
* THROWS a `MUTATION` {@link import('./errors.js').WorkflowError} on a duplicate
|
|
1378
|
+
* `id` (a genuine programmer error — a build-time wiring bug, AGENTS §12) instead of
|
|
1379
|
+
* silently overwriting the existing entry.
|
|
1380
|
+
*
|
|
1381
|
+
* @param phase - The live phase to append
|
|
1382
|
+
*/
|
|
1259
1383
|
append(phase: PhaseInterface): void;
|
|
1384
|
+
/**
|
|
1385
|
+
* Insert `phase` at `index` (default the end) — the GATED mutation counterpart to
|
|
1386
|
+
* {@link append}: a duplicate `id` or an out-of-bounds `index` fails gracefully
|
|
1387
|
+
* instead of throwing.
|
|
1388
|
+
*
|
|
1389
|
+
* @param phase - The live phase to insert
|
|
1390
|
+
* @param index - The insertion position (`[0, count]`); omitted inserts at the end
|
|
1391
|
+
* @returns A {@link Result} boxing the inserted phase, or a `MUTATION` failure
|
|
1392
|
+
*/
|
|
1393
|
+
add(phase: PhaseInterface, index?: number): Result<PhaseInterface, WorkflowError>;
|
|
1394
|
+
/**
|
|
1395
|
+
* Remove the `pending` phase `id`.
|
|
1396
|
+
*
|
|
1397
|
+
* @param id - The phase id to remove
|
|
1398
|
+
* @returns A {@link Result} boxing the removed phase, or a `MUTATION` failure when
|
|
1399
|
+
* `id` is absent or not `pending`
|
|
1400
|
+
*/
|
|
1401
|
+
remove(id: string): Result<PhaseInterface, WorkflowError>;
|
|
1402
|
+
/**
|
|
1403
|
+
* Reposition the `pending` phase `id` to `index`.
|
|
1404
|
+
*
|
|
1405
|
+
* @param id - The phase id to move
|
|
1406
|
+
* @param index - The destination position (`[0, count)`)
|
|
1407
|
+
* @returns A {@link Result} boxing the moved phase, or a `MUTATION` failure when
|
|
1408
|
+
* `id` is absent, not `pending`, or `index` is out of bounds
|
|
1409
|
+
*/
|
|
1410
|
+
move(id: string, index: number): Result<PhaseInterface, WorkflowError>;
|
|
1411
|
+
/**
|
|
1412
|
+
* Apply a validated {@link PhaseUpdate} patch to the `pending` phase `id`.
|
|
1413
|
+
*
|
|
1414
|
+
* @param id - The phase id to patch
|
|
1415
|
+
* @param patch - The fields to update
|
|
1416
|
+
* @returns A {@link Result} boxing the patched phase, or a `MUTATION` failure when
|
|
1417
|
+
* `id` is absent, not `pending`, or `patch` fails validation
|
|
1418
|
+
*/
|
|
1419
|
+
update(id: string, patch: PhaseUpdate): Result<PhaseInterface, WorkflowError>;
|
|
1260
1420
|
phase(id: string): PhaseInterface | undefined;
|
|
1261
1421
|
phases(): readonly PhaseInterface[];
|
|
1262
1422
|
}
|
|
@@ -1292,16 +1452,7 @@ export declare const phaseShape: ObjectShape<{
|
|
|
1292
1452
|
id: StringShape;
|
|
1293
1453
|
name: StringShape;
|
|
1294
1454
|
description: OptionalShape<StringShape>;
|
|
1295
|
-
run:
|
|
1296
|
-
via: LiteralShape<readonly ["function"]>;
|
|
1297
|
-
name: StringShape;
|
|
1298
|
-
}>, ObjectShape<{
|
|
1299
|
-
via: LiteralShape<readonly ["tool"]>;
|
|
1300
|
-
name: StringShape;
|
|
1301
|
-
}>, ObjectShape<{
|
|
1302
|
-
via: LiteralShape<readonly ["agent"]>;
|
|
1303
|
-
name: StringShape;
|
|
1304
|
-
}>]>;
|
|
1455
|
+
run: OptionalShape<StringShape>;
|
|
1305
1456
|
retries: OptionalShape<NumberShape>;
|
|
1306
1457
|
timeout: OptionalShape<NumberShape>;
|
|
1307
1458
|
}>>;
|
|
@@ -1334,6 +1485,12 @@ export declare interface PhaseSnapshot {
|
|
|
1334
1485
|
* per-phase policy identically without a silent default.
|
|
1335
1486
|
*/
|
|
1336
1487
|
readonly bail: boolean;
|
|
1488
|
+
/**
|
|
1489
|
+
* Max tasks in flight at once (a resource throttle), persisted so a restore reinstates the
|
|
1490
|
+
* same per-phase throttle — mirrors {@link import('./types.js').PhaseDefinition.concurrency}.
|
|
1491
|
+
* Omitted ⇒ unbounded.
|
|
1492
|
+
*/
|
|
1493
|
+
readonly concurrency?: number;
|
|
1337
1494
|
readonly tasks: readonly TaskSnapshot[];
|
|
1338
1495
|
}
|
|
1339
1496
|
|
|
@@ -1349,6 +1506,45 @@ export declare interface PhaseSnapshot {
|
|
|
1349
1506
|
*/
|
|
1350
1507
|
export declare type PhaseStatus = LifecycleStatus;
|
|
1351
1508
|
|
|
1509
|
+
/**
|
|
1510
|
+
* A declarative partial update to a {@link PhaseInterface} — the fields a `pending`
|
|
1511
|
+
* phase's {@link PhaseInterface.patch} (and the owning {@link PhaseManagerInterface.update})
|
|
1512
|
+
* accept, runtime-validated via {@link import('./shapers.js').phaseUpdateShape}.
|
|
1513
|
+
*
|
|
1514
|
+
* @remarks
|
|
1515
|
+
* Mirrors the identity + throttle/policy fields of {@link PhaseDefinition} (`name` /
|
|
1516
|
+
* `description` / `concurrency` / `bail`) — never `id` / `tasks` (structural children
|
|
1517
|
+
* change through {@link PhaseInterface.add} / `remove` / `move`, not a patch). Every
|
|
1518
|
+
* field is optional; an omitted field is left unchanged.
|
|
1519
|
+
*
|
|
1520
|
+
* @example
|
|
1521
|
+
* ```ts
|
|
1522
|
+
* const result = workflow.phases.update(phase.id, { concurrency: 4, bail: true })
|
|
1523
|
+
* ```
|
|
1524
|
+
*/
|
|
1525
|
+
export declare interface PhaseUpdate {
|
|
1526
|
+
readonly name?: string;
|
|
1527
|
+
readonly description?: string;
|
|
1528
|
+
readonly concurrency?: number;
|
|
1529
|
+
readonly bail?: boolean;
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
/**
|
|
1533
|
+
* The shape of a {@link import('./types.js').PhaseUpdate} — a partial edit to a
|
|
1534
|
+
* `pending` phase's `name` / `description` / `concurrency` / `bail`, all optional.
|
|
1535
|
+
*
|
|
1536
|
+
* @remarks
|
|
1537
|
+
* Mirrors {@link phaseShape}'s corresponding field constraints exactly; never `id` /
|
|
1538
|
+
* `tasks` (structural children change through the phase's own `add` / `remove` /
|
|
1539
|
+
* `move`, not a patch, AGENTS §12).
|
|
1540
|
+
*/
|
|
1541
|
+
export declare const phaseUpdateShape: ObjectShape<{
|
|
1542
|
+
name: OptionalShape<StringShape>;
|
|
1543
|
+
description: OptionalShape<StringShape>;
|
|
1544
|
+
concurrency: OptionalShape<NumberShape>;
|
|
1545
|
+
bail: OptionalShape<LiteralShape<readonly [true, false]>>;
|
|
1546
|
+
}>;
|
|
1547
|
+
|
|
1352
1548
|
/**
|
|
1353
1549
|
* Rebuild an equivalent live W-b entity tree from a {@link WorkflowSnapshot} — the
|
|
1354
1550
|
* inverse of {@link WorkflowInterface.snapshot}, restoring structure + each node's status
|
|
@@ -1414,6 +1610,15 @@ export declare function restoreWorkflow(snapshot: WorkflowSnapshot, options?: Wo
|
|
|
1414
1610
|
* unit failure (after its retries) records the error and `abort()`s the run, so every
|
|
1415
1611
|
* sibling's signal fires; later failures are ignored and `execute` rejects with the
|
|
1416
1612
|
* first error. A user `abort(reason)` likewise rejects a running `execute`.
|
|
1613
|
+
* - **`pause` / `resume` / `stop` (§10) ride the backing Queue.** `pause` / `resume`
|
|
1614
|
+
* delegate straight to the Queue's own pause/resume (holding/releasing the NEXT
|
|
1615
|
+
* dispatch while an in-flight unit finishes); `paused` mirrors the Queue's. `stop` is a
|
|
1616
|
+
* GRACEFUL permanent end, distinct from `abort`: still-pending (never-dispatched)
|
|
1617
|
+
* units are rejected by the Queue's own stop WITHOUT their handler ever running, and
|
|
1618
|
+
* `#settle` reads that fact (`#dispatched`) to treat the rejection as a stop artifact —
|
|
1619
|
+
* not a failure, never tripping fail-fast — while an in-flight unit still runs to
|
|
1620
|
+
* completion and settles normally. `execute` RESOLVES (never rejects) once every unit
|
|
1621
|
+
* has settled, with whatever results actually completed.
|
|
1417
1622
|
* - **Observable (§13).** The owned {@link emitter} ({@link RunnerEventMap}) carries the run
|
|
1418
1623
|
* lifecycle — `start` / `unit` / `spawn` / `settle` / `fail` / `finish` / `abort` — for
|
|
1419
1624
|
* fire-and-forget observers. Every event is emitted directly, strictly AFTER the relevant
|
|
@@ -1429,8 +1634,66 @@ export declare class Runner<TInput, TResult> implements RunnerInterface<TInput,
|
|
|
1429
1634
|
get emitter(): EmitterInterface<RunnerEventMap<TResult>>;
|
|
1430
1635
|
get active(): number;
|
|
1431
1636
|
get stopped(): boolean;
|
|
1637
|
+
get paused(): boolean;
|
|
1638
|
+
/**
|
|
1639
|
+
* Inject one more unit into an IN-FLIGHT `execute` run — a LIVE counterpart to a
|
|
1640
|
+
* `Controller.spawn`, called from OUTSIDE any unit's handler.
|
|
1641
|
+
*
|
|
1642
|
+
* @remarks
|
|
1643
|
+
* Returns `undefined` synchronously (graceful, non-throwing — AGENTS §12) unless the
|
|
1644
|
+
* runner is currently mid-`execute` and not yet stopped — covering "never started",
|
|
1645
|
+
* "already drained", "aborted", and "destroyed". Otherwise the unit is routed through
|
|
1646
|
+
* the SAME backing queue as a declared/`spawn`ed unit via `#launch` — the outstanding-
|
|
1647
|
+
* unit count gate increments BEFORE this call returns, so an in-flight `execute`
|
|
1648
|
+
* keeps awaiting it (the drain race: `#running` flips to `false` as the very first
|
|
1649
|
+
* step after `execute`'s `await drained.promise` settles, so a `spawn` reaching this
|
|
1650
|
+
* method after the run has fully drained is cleanly rejected with `undefined` —
|
|
1651
|
+
* never silently dropped, never hangs `execute`). Emits {@link RunnerEventMap.spawn}
|
|
1652
|
+
* with a `parent` of `undefined` (this call has no spawning unit) once accepted.
|
|
1653
|
+
*
|
|
1654
|
+
* @param input - The unit's work payload
|
|
1655
|
+
* @returns The unit's result promise, or `undefined` when no in-flight run can accept it
|
|
1656
|
+
* @example
|
|
1657
|
+
* ```ts
|
|
1658
|
+
* const runner = createRunner({ handler: (c) => c.input })
|
|
1659
|
+
* const result = runner.execute([1, 2])
|
|
1660
|
+
* const extra = runner.spawn(3) // Promise<number> | undefined
|
|
1661
|
+
* await result
|
|
1662
|
+
* ```
|
|
1663
|
+
*/
|
|
1664
|
+
spawn(input: TInput): Promise<TResult> | undefined;
|
|
1432
1665
|
execute(inputs: readonly TInput[]): Promise<readonly TResult[]>;
|
|
1433
1666
|
abort(reason?: unknown): void;
|
|
1667
|
+
/**
|
|
1668
|
+
* Suspend dispatch (AGENTS §10 — resumable): delegates to the backing queue's own
|
|
1669
|
+
* `pause`, which holds the NEXT dispatch while any in-flight unit finishes.
|
|
1670
|
+
*
|
|
1671
|
+
* @remarks
|
|
1672
|
+
* A no-op once the runner is `stopped` — a stopped runner has no dispatch left to
|
|
1673
|
+
* suspend, mirroring the guard `stop()` itself applies. Also a no-op when already
|
|
1674
|
+
* `paused` (the queue's own `pause` is idempotent), so calling it repeatedly is safe.
|
|
1675
|
+
*/
|
|
1676
|
+
pause(): void;
|
|
1677
|
+
/**
|
|
1678
|
+
* Continue a paused runner (AGENTS §10); delegates to the backing queue's `resume`.
|
|
1679
|
+
*
|
|
1680
|
+
* @remarks
|
|
1681
|
+
* A no-op once the runner is `stopped` (nothing left to resume) and a no-op when the
|
|
1682
|
+
* runner is not currently `paused`, so calling it repeatedly or on a never-paused
|
|
1683
|
+
* runner is safe.
|
|
1684
|
+
*/
|
|
1685
|
+
resume(): void;
|
|
1686
|
+
/**
|
|
1687
|
+
* Permanently end the runner (AGENTS §10) — a GRACEFUL stop, distinct from `abort`.
|
|
1688
|
+
* Marks the runner `stopping` + `stopped`, then stops the backing queue: every
|
|
1689
|
+
* still-PENDING (never-dispatched) unit is rejected by the queue with its own
|
|
1690
|
+
* "queue is stopped" error, WITHOUT running its handler; every already-in-flight unit
|
|
1691
|
+
* keeps running to completion and settles normally. `#settle` reads `#stopping` to
|
|
1692
|
+
* classify a never-dispatched unit's rejection as a stop artifact (decrement the count
|
|
1693
|
+
* gate, no recorded failure, no fail-fast trip) rather than a genuine failure — a
|
|
1694
|
+
* dispatched unit's rejection while stopping is still a real failure. Idempotent.
|
|
1695
|
+
*/
|
|
1696
|
+
stop(): void;
|
|
1434
1697
|
destroy(): void;
|
|
1435
1698
|
}
|
|
1436
1699
|
|
|
@@ -1523,6 +1786,8 @@ export declare interface RunnerInterface<TInput, TResult> {
|
|
|
1523
1786
|
readonly emitter: EmitterInterface<RunnerEventMap<TResult>>;
|
|
1524
1787
|
readonly active: number;
|
|
1525
1788
|
readonly stopped: boolean;
|
|
1789
|
+
/** Whether the runner is currently paused (AGENTS §10 — resumable, no new dispatch); rides the backing queue's own `paused`. */
|
|
1790
|
+
readonly paused: boolean;
|
|
1526
1791
|
/**
|
|
1527
1792
|
* Run all `inputs` — and anything they `spawn` — to completion; resolve their
|
|
1528
1793
|
* results in order: the declared inputs first (in input order), then the spawned
|
|
@@ -1537,6 +1802,25 @@ export declare interface RunnerInterface<TInput, TResult> {
|
|
|
1537
1802
|
* @returns The units' results, in order (declared first, then spawns)
|
|
1538
1803
|
*/
|
|
1539
1804
|
execute(inputs: readonly TInput[]): Promise<readonly TResult[]>;
|
|
1805
|
+
/**
|
|
1806
|
+
* Inject one more unit into an IN-FLIGHT `execute` run — a LIVE counterpart to a
|
|
1807
|
+
* `Controller.spawn`, called from OUTSIDE any unit's handler (the seam a live
|
|
1808
|
+
* `running` {@link PhaseInterface}'s `add` event lets a subscribed run offer a newly
|
|
1809
|
+
* added task to the SAME execution substrate).
|
|
1810
|
+
*
|
|
1811
|
+
* @remarks
|
|
1812
|
+
* Returns `undefined` synchronously (graceful, non-throwing — AGENTS §12) when the
|
|
1813
|
+
* runner is not currently mid-`execute`, or the run has already fully drained — the
|
|
1814
|
+
* caller reads `undefined` as "not accepted". Otherwise the unit is routed through
|
|
1815
|
+
* the SAME backing queue as a declared/`spawn`ed unit (the runner's
|
|
1816
|
+
* outstanding-unit count gate keeps the in-flight `execute` awaiting it) and emits
|
|
1817
|
+
* the {@link RunnerEventMap.spawn} event; its result promise resolves once the unit
|
|
1818
|
+
* settles.
|
|
1819
|
+
*
|
|
1820
|
+
* @param input - The unit's work payload
|
|
1821
|
+
* @returns The unit's result promise, or `undefined` when no in-flight run can accept it
|
|
1822
|
+
*/
|
|
1823
|
+
spawn(input: TInput): Promise<TResult> | undefined;
|
|
1540
1824
|
/**
|
|
1541
1825
|
* Cancel every in-flight + pending unit (and the backing queue), making a running
|
|
1542
1826
|
* `execute` reject.
|
|
@@ -1544,10 +1828,48 @@ export declare interface RunnerInterface<TInput, TResult> {
|
|
|
1544
1828
|
* @param reason - An optional cancellation reason propagated to every unit's signal
|
|
1545
1829
|
*/
|
|
1546
1830
|
abort(reason?: unknown): void;
|
|
1547
|
-
/**
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1831
|
+
/**
|
|
1832
|
+
* Suspend dispatch (AGENTS §10 — resumable): the backing queue holds the NEXT dispatch
|
|
1833
|
+
* while any in-flight unit finishes; idempotent.
|
|
1834
|
+
*
|
|
1835
|
+
* @example
|
|
1836
|
+
* ```ts
|
|
1837
|
+
* runner.pause()
|
|
1838
|
+
* runner.paused // true
|
|
1839
|
+
* ```
|
|
1840
|
+
*/
|
|
1841
|
+
pause(): void;
|
|
1842
|
+
/**
|
|
1843
|
+
* Continue a paused runner (AGENTS §10); idempotent.
|
|
1844
|
+
*
|
|
1845
|
+
* @example
|
|
1846
|
+
* ```ts
|
|
1847
|
+
* runner.resume()
|
|
1848
|
+
* runner.paused // false
|
|
1849
|
+
* ```
|
|
1850
|
+
*/
|
|
1851
|
+
resume(): void;
|
|
1852
|
+
/**
|
|
1853
|
+
* Permanently end the runner (AGENTS §10) — a GRACEFUL stop: no further unit is
|
|
1854
|
+
* dispatched, but every already-in-flight unit runs to completion and settles
|
|
1855
|
+
* normally. A never-dispatched (still-pending) unit is rejected by the backing queue
|
|
1856
|
+
* and is NOT recorded as a failure (it never trips fail-fast); a genuine in-flight
|
|
1857
|
+
* failure still is. `execute`'s promise RESOLVES (never rejects) once every unit has
|
|
1858
|
+
* settled, with whatever results actually completed. Idempotent.
|
|
1859
|
+
*
|
|
1860
|
+
* @example
|
|
1861
|
+
* ```ts
|
|
1862
|
+
* const runner = createRunner({ handler: (c) => c.input, concurrency: 1 })
|
|
1863
|
+
* const results = runner.execute([1, 2, 3])
|
|
1864
|
+
* runner.stop() // the in-flight unit finishes; the rest are gracefully dropped
|
|
1865
|
+
* await results // resolves with whatever settled — never rejects
|
|
1866
|
+
* ```
|
|
1867
|
+
*/
|
|
1868
|
+
stop(): void;
|
|
1869
|
+
/** Tear the runner down — `abort` plus stop the backing queue; idempotent. */
|
|
1870
|
+
destroy(): void;
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1551
1873
|
/**
|
|
1552
1874
|
* Options for `createRunner`.
|
|
1553
1875
|
*
|
|
@@ -1683,28 +2005,18 @@ export declare interface SchedulerOptions {
|
|
|
1683
2005
|
export declare type SchedulerPriority = 'user' | 'normal' | 'background';
|
|
1684
2006
|
|
|
1685
2007
|
/**
|
|
1686
|
-
*
|
|
1687
|
-
* {@link workflowStepsShape}.
|
|
2008
|
+
* Box a value as a {@link Success} — the graceful outcome half of a {@link Result}.
|
|
1688
2009
|
*
|
|
1689
|
-
* @
|
|
1690
|
-
*
|
|
1691
|
-
*
|
|
1692
|
-
* tool expands each step into a one-task phase, in order
|
|
1693
|
-
* ({@link import('./helpers.js').expandSteps}).
|
|
1694
|
-
*/
|
|
1695
|
-
export declare const stepShape: ObjectShape<{
|
|
1696
|
-
name: StringShape;
|
|
1697
|
-
via: OptionalShape<LiteralShape<readonly ["function", "tool", "agent"]>>;
|
|
1698
|
-
}>;
|
|
1699
|
-
|
|
1700
|
-
/**
|
|
1701
|
-
* Convert one flat {@link WorkflowStep} into a {@link TaskForm} — `name` → the form's `name`,
|
|
1702
|
-
* `via` → the form's discriminant (defaulting to `'function'`).
|
|
2010
|
+
* @typeParam T - The boxed value's type
|
|
2011
|
+
* @param value - The value to box
|
|
2012
|
+
* @returns A {@link Success} wrapping `value`
|
|
1703
2013
|
*
|
|
1704
|
-
* @
|
|
1705
|
-
*
|
|
2014
|
+
* @example
|
|
2015
|
+
* ```ts
|
|
2016
|
+
* const result = success(task) // { success: true, value: task }
|
|
2017
|
+
* ```
|
|
1706
2018
|
*/
|
|
1707
|
-
export declare function
|
|
2019
|
+
export declare function success<T>(value: T): Success<T>;
|
|
1708
2020
|
|
|
1709
2021
|
/**
|
|
1710
2022
|
* The live leaf state machine (W-b) for one task — an observable (AGENTS §13), guarded
|
|
@@ -1731,10 +2043,16 @@ export declare function stepToForm(step: WorkflowStep): TaskForm;
|
|
|
1731
2043
|
* matching event strictly AFTER the state change, BEFORE the cascade; the emitter isolates
|
|
1732
2044
|
* a listener throw and routes it to its `error` handler (the `error` option), so a buggy
|
|
1733
2045
|
* observer can never corrupt a transition.
|
|
2046
|
+
* - **Declarative config (AGENTS §12).** `run` / `retries` / `timeout` PERSIST in a
|
|
2047
|
+
* {@link TaskSnapshot} (like a phase's `bail` / `concurrency`), carried verbatim from the
|
|
2048
|
+
* matching {@link import('../types.js').TaskDefinition} / {@link TaskSnapshot} field. `handler`
|
|
2049
|
+
* is the RUNTIME-ONLY counterpart — `run` resolved ONCE at construction against the
|
|
2050
|
+
* workflow-level {@link import('../types.js').WorkflowOptions.functions} registry — and is
|
|
2051
|
+
* NEVER persisted; `undefined` when `run` is omitted or unregistered (the no-handler rule).
|
|
1734
2052
|
*/
|
|
1735
2053
|
export declare class Task implements TaskInterface {
|
|
1736
2054
|
#private;
|
|
1737
|
-
constructor(context: TaskContext, phase: PhaseInterface, workflow: WorkflowInterface, recompute: () => void, options?: TaskOptions, status?: TaskStatus, result?: TaskResult);
|
|
2055
|
+
constructor(context: TaskContext, phase: PhaseInterface, workflow: WorkflowInterface, recompute: () => void, options?: TaskOptions, status?: TaskStatus, result?: TaskResult, run?: string, retries?: number, timeout?: number, handler?: WorkflowFunction);
|
|
1738
2056
|
get emitter(): EmitterInterface<TaskEventMap>;
|
|
1739
2057
|
get id(): string;
|
|
1740
2058
|
get name(): string;
|
|
@@ -1744,11 +2062,31 @@ export declare class Task implements TaskInterface {
|
|
|
1744
2062
|
get workflow(): WorkflowInterface;
|
|
1745
2063
|
get status(): TaskStatus;
|
|
1746
2064
|
get result(): TaskResult | undefined;
|
|
2065
|
+
get run(): string | undefined;
|
|
2066
|
+
get handler(): WorkflowFunction | undefined;
|
|
2067
|
+
get retries(): number | undefined;
|
|
2068
|
+
get timeout(): number | undefined;
|
|
1747
2069
|
start(): void;
|
|
1748
2070
|
complete(value: unknown): void;
|
|
1749
2071
|
fail(error: unknown): void;
|
|
1750
2072
|
skip(): void;
|
|
1751
2073
|
stop(): void;
|
|
2074
|
+
/**
|
|
2075
|
+
* Apply a validated declarative patch to SELF (`name` / `description`).
|
|
2076
|
+
*
|
|
2077
|
+
* @remarks
|
|
2078
|
+
* Defense-in-depth (AGENTS §12): the owning
|
|
2079
|
+
* {@link import('../types.js').TaskManagerInterface.update} gates FIRST (target
|
|
2080
|
+
* exists + `pending`), so this is the second, redundant check — it THROWS a
|
|
2081
|
+
* `MUTATION` {@link WorkflowError} unless this task's own `status` is `pending`.
|
|
2082
|
+
*
|
|
2083
|
+
* @param value - The {@link TaskUpdate} fields to apply
|
|
2084
|
+
* @example
|
|
2085
|
+
* ```ts
|
|
2086
|
+
* task.patch({ name: 'Renamed task' })
|
|
2087
|
+
* ```
|
|
2088
|
+
*/
|
|
2089
|
+
patch(value: TaskUpdate): void;
|
|
1752
2090
|
snapshot(): TaskSnapshot;
|
|
1753
2091
|
}
|
|
1754
2092
|
|
|
@@ -1776,15 +2114,6 @@ export declare const TASK_STATUSES: readonly TaskStatus[];
|
|
|
1776
2114
|
*/
|
|
1777
2115
|
export declare const TASK_TRANSITIONS: Readonly<Record<TaskStatus, readonly TaskStatus[]>>;
|
|
1778
2116
|
|
|
1779
|
-
/**
|
|
1780
|
-
* The three task-form mechanisms (the {@link TaskVia} discriminant), frozen.
|
|
1781
|
-
*
|
|
1782
|
-
* @remarks
|
|
1783
|
-
* The runtime source of truth for the `via` axis — drive the contract's literal
|
|
1784
|
-
* shape and any guard from this array rather than repeating the literals.
|
|
1785
|
-
*/
|
|
1786
|
-
export declare const TASK_VIAS: readonly TaskVia[];
|
|
1787
|
-
|
|
1788
2117
|
/**
|
|
1789
2118
|
* The ambient context of a task — its own identity plus a back-reference to the
|
|
1790
2119
|
* phase (and, transitively, the workflow) it belongs to.
|
|
@@ -1862,32 +2191,39 @@ export declare interface TaskControllerInterface {
|
|
|
1862
2191
|
}
|
|
1863
2192
|
|
|
1864
2193
|
/**
|
|
1865
|
-
* The serializable definition of one task — its identity plus
|
|
1866
|
-
*
|
|
2194
|
+
* The serializable definition of one task — its identity plus an optional reference to
|
|
2195
|
+
* the behavior it runs.
|
|
1867
2196
|
*
|
|
1868
2197
|
* @remarks
|
|
1869
2198
|
* Pure JSON DATA: a UI or an LLM authors it, it round-trips through the contract
|
|
1870
|
-
* (factories.ts), and it carries NO functions. `id` is the positional identity
|
|
1871
|
-
*
|
|
1872
|
-
*
|
|
2199
|
+
* (factories.ts), and it carries NO functions. `id` is the positional identity within
|
|
2200
|
+
* its phase; `name` is the human label; `description` is optional prose. `run` is a
|
|
2201
|
+
* PLAIN NAME — a key resolved ONCE at construction against a workflow-level
|
|
2202
|
+
* {@link WorkflowFunctions} registry into a runtime {@link TaskInterface.handler}
|
|
2203
|
+
* carried on the live task. A task whose `run` is omitted, or whose name is unregistered,
|
|
2204
|
+
* has no handler and AUTO-COMPLETES (the no-handler rule).
|
|
1873
2205
|
*/
|
|
1874
2206
|
export declare interface TaskDefinition {
|
|
1875
2207
|
readonly id: string;
|
|
1876
2208
|
readonly name: string;
|
|
1877
2209
|
readonly description?: string;
|
|
1878
|
-
readonly run
|
|
2210
|
+
readonly run?: string;
|
|
1879
2211
|
/**
|
|
1880
2212
|
* @remarks
|
|
1881
2213
|
* Extra attempts after the first on failure (a non-negative integer); the runner threads it
|
|
1882
2214
|
* to this task's substrate unit, OVERRIDING the phase Runner's `retries` default. Omitted ⇒
|
|
1883
|
-
* the default (no extra attempts).
|
|
2215
|
+
* the default (no extra attempts). PERSISTED in a {@link TaskSnapshot} (like `bail` and
|
|
2216
|
+
* `concurrency`), so `restoreWorkflow(snapshot, { functions })` resumes with the same
|
|
2217
|
+
* reliability config; only the resolved handler itself is runtime-only.
|
|
1884
2218
|
*/
|
|
1885
2219
|
readonly retries?: number;
|
|
1886
2220
|
/**
|
|
1887
2221
|
* @remarks
|
|
1888
2222
|
* The per-attempt deadline in milliseconds (a non-negative integer); the runner threads it to
|
|
1889
2223
|
* this task's substrate unit, OVERRIDING the phase Runner's `timeout` default. Omitted (or a
|
|
1890
|
-
* non-positive value) ⇒ no deadline.
|
|
2224
|
+
* non-positive value) ⇒ no deadline. PERSISTED in a {@link TaskSnapshot} (like `bail` and
|
|
2225
|
+
* `concurrency`), so `restoreWorkflow(snapshot, { functions })` resumes with the same
|
|
2226
|
+
* reliability config; only the resolved handler itself is runtime-only.
|
|
1891
2227
|
*/
|
|
1892
2228
|
readonly timeout?: number;
|
|
1893
2229
|
}
|
|
@@ -1897,57 +2233,17 @@ export declare interface TaskDefinition {
|
|
|
1897
2233
|
* {@link TaskSnapshot} — the per-task leaf step of {@link definitionToSnapshot} (no
|
|
1898
2234
|
* result yet, empty metadata).
|
|
1899
2235
|
*
|
|
2236
|
+
* @remarks
|
|
2237
|
+
* `run` / `retries` / `timeout` carry over verbatim (persisted declarative config, like a
|
|
2238
|
+
* phase's `bail` / `concurrency`) — a restore reinstates the same behavior reference and
|
|
2239
|
+
* reliability overrides once paired with a {@link import('./types.js').WorkflowOptions.functions}
|
|
2240
|
+
* registry.
|
|
2241
|
+
*
|
|
1900
2242
|
* @param task - The task definition to seed from
|
|
1901
2243
|
* @returns An initial {@link TaskSnapshot}
|
|
1902
2244
|
*/
|
|
1903
2245
|
export declare function taskDefinitionToSnapshot(task: WorkflowDefinition['phases'][number]['tasks'][number]): TaskSnapshot;
|
|
1904
2246
|
|
|
1905
|
-
/**
|
|
1906
|
-
* A draft task — a {@link TaskDefinition} with OPTIONAL `id` / `name`.
|
|
1907
|
-
*
|
|
1908
|
-
* @remarks
|
|
1909
|
-
* The tool synthesizes a missing `id` positionally and defaults a missing `name` to
|
|
1910
|
-
* its `id` ({@link import('./helpers.js').completeDraft}). A PROVIDED `id` / `name` is
|
|
1911
|
-
* preserved verbatim (and must be non-empty — the draft contract's `minLength: 1`).
|
|
1912
|
-
*/
|
|
1913
|
-
export declare interface TaskDraft {
|
|
1914
|
-
readonly id?: string;
|
|
1915
|
-
readonly name?: string;
|
|
1916
|
-
readonly description?: string;
|
|
1917
|
-
readonly run: TaskForm;
|
|
1918
|
-
/** Extra attempts after the first on failure (a non-negative integer); overrides the phase Runner default. Execution-only. */
|
|
1919
|
-
readonly retries?: number;
|
|
1920
|
-
/** The per-attempt deadline in milliseconds (a non-negative integer); overrides the phase Runner default. Execution-only. */
|
|
1921
|
-
readonly timeout?: number;
|
|
1922
|
-
}
|
|
1923
|
-
|
|
1924
|
-
/**
|
|
1925
|
-
* The shape of a TASK in a draft workflow — identical to {@link taskShape} EXCEPT `id`
|
|
1926
|
-
* and `name` are OPTIONAL (the tool synthesizes any missing one positionally).
|
|
1927
|
-
*
|
|
1928
|
-
* @remarks
|
|
1929
|
-
* A PROVIDED `id` / `name` still carries `minLength: 1`, so an explicitly-empty `id: ''`
|
|
1930
|
-
* is INVALID (rejected by the draft contract), never auto-filled — keeping "garbage"
|
|
1931
|
-
* distinct from "omitted". `run` stays required.
|
|
1932
|
-
*/
|
|
1933
|
-
export declare const taskDraftShape: ObjectShape<{
|
|
1934
|
-
id: OptionalShape<StringShape>;
|
|
1935
|
-
name: OptionalShape<StringShape>;
|
|
1936
|
-
description: OptionalShape<StringShape>;
|
|
1937
|
-
run: UnionShape<[ ObjectShape<{
|
|
1938
|
-
via: LiteralShape<readonly ["function"]>;
|
|
1939
|
-
name: StringShape;
|
|
1940
|
-
}>, ObjectShape<{
|
|
1941
|
-
via: LiteralShape<readonly ["tool"]>;
|
|
1942
|
-
name: StringShape;
|
|
1943
|
-
}>, ObjectShape<{
|
|
1944
|
-
via: LiteralShape<readonly ["agent"]>;
|
|
1945
|
-
name: StringShape;
|
|
1946
|
-
}>]>;
|
|
1947
|
-
retries: OptionalShape<NumberShape>;
|
|
1948
|
-
timeout: OptionalShape<NumberShape>;
|
|
1949
|
-
}>;
|
|
1950
|
-
|
|
1951
2247
|
/**
|
|
1952
2248
|
* The push observation surface (AGENTS §13) of the task entity (W-b) — the
|
|
1953
2249
|
* lifecycle moments of one task.
|
|
@@ -1973,58 +2269,6 @@ export declare type TaskEventMap = {
|
|
|
1973
2269
|
readonly stop: readonly [];
|
|
1974
2270
|
};
|
|
1975
2271
|
|
|
1976
|
-
/**
|
|
1977
|
-
* A {@link TaskDefinition}'s behavior reference — a descriptive tagged union over
|
|
1978
|
-
* the three execution forms a task can take, discriminated by `via` (the axis is
|
|
1979
|
-
* the execution MECHANISM, never a bare `kind`; AGENTS §4.4). Each form references
|
|
1980
|
-
* its behavior BY NAME through a registry (the runner resolves the name at W-b);
|
|
1981
|
-
* a definition NEVER inlines a function, so the whole tree stays JSON-serializable.
|
|
1982
|
-
*
|
|
1983
|
-
* @remarks
|
|
1984
|
-
* - `function` — a registered function the runner invokes directly.
|
|
1985
|
-
* - `tool` — a registered {@link ToolInterface} the
|
|
1986
|
-
* runner executes as a tool call.
|
|
1987
|
-
* - `agent` — a registered agent (a subagent). It will later carry a depth/cycle
|
|
1988
|
-
* guard (W-c, bounded by {@link import('./constants.js').MAX_WORKFLOW_DEPTH}); in
|
|
1989
|
-
* W-a it is purely the typed reference.
|
|
1990
|
-
*
|
|
1991
|
-
* `name` is the registry key (it identifies the behavior the form runs). A
|
|
1992
|
-
* descriptive `via` literal (not `kind`) names the axis that varies, and the
|
|
1993
|
-
* `is*` guards narrow on `run.via` cleanly.
|
|
1994
|
-
*/
|
|
1995
|
-
export declare type TaskForm = {
|
|
1996
|
-
readonly via: 'function';
|
|
1997
|
-
readonly name: string;
|
|
1998
|
-
} | {
|
|
1999
|
-
readonly via: 'tool';
|
|
2000
|
-
readonly name: string;
|
|
2001
|
-
} | {
|
|
2002
|
-
readonly via: 'agent';
|
|
2003
|
-
readonly name: string;
|
|
2004
|
-
};
|
|
2005
|
-
|
|
2006
|
-
/**
|
|
2007
|
-
* The shape of a {@link import('./types.js').TaskForm} — a descriptive tagged union
|
|
2008
|
-
* over the three execution mechanisms, discriminated by the `via` literal (never a
|
|
2009
|
-
* bare `kind`; AGENTS §4.4). Each variant pairs the `via` discriminant with a `name`
|
|
2010
|
-
* (the registry key for the behavior).
|
|
2011
|
-
*
|
|
2012
|
-
* @remarks
|
|
2013
|
-
* The union and each `via` literal + `name` carry a `description` so the emitted JSON
|
|
2014
|
-
* Schema spells out what the discriminant means and that `name` is a REGISTERED key
|
|
2015
|
-
* (not a human label) — the field-level guidance a small model needs to fill `run`.
|
|
2016
|
-
*/
|
|
2017
|
-
export declare const taskFormShape: UnionShape<[ ObjectShape<{
|
|
2018
|
-
via: LiteralShape<readonly ["function"]>;
|
|
2019
|
-
name: StringShape;
|
|
2020
|
-
}>, ObjectShape<{
|
|
2021
|
-
via: LiteralShape<readonly ["tool"]>;
|
|
2022
|
-
name: StringShape;
|
|
2023
|
-
}>, ObjectShape<{
|
|
2024
|
-
via: LiteralShape<readonly ["agent"]>;
|
|
2025
|
-
name: StringShape;
|
|
2026
|
-
}>]>;
|
|
2027
|
-
|
|
2028
2272
|
/** Initial {@link TaskEventMap} listeners — the reserved `on` option (AGENTS §8). */
|
|
2029
2273
|
export declare type TaskHooks = EmitterHooks<TaskEventMap>;
|
|
2030
2274
|
|
|
@@ -2077,11 +2321,52 @@ export declare interface TaskInterface {
|
|
|
2077
2321
|
readonly status: TaskStatus;
|
|
2078
2322
|
/** The recorded outcome once the task settled with one (`completed` / `failed`), else `undefined`. */
|
|
2079
2323
|
readonly result: TaskResult | undefined;
|
|
2324
|
+
/**
|
|
2325
|
+
* The behavior reference — a plain registry key name, PERSISTED (mirrors
|
|
2326
|
+
* {@link TaskDefinition.run} / {@link TaskSnapshot.run}), like {@link PhaseInterface.bail}.
|
|
2327
|
+
* `undefined` when this task has no behavior reference.
|
|
2328
|
+
*/
|
|
2329
|
+
readonly run: string | undefined;
|
|
2330
|
+
/**
|
|
2331
|
+
* The RESOLVED runtime handler — RUNTIME-ONLY, NEVER persisted in a {@link TaskSnapshot}.
|
|
2332
|
+
* Resolved ONCE at construction (build, restore, or a live mint) by looking `run` up in the
|
|
2333
|
+
* workflow-level {@link WorkflowOptions.functions} registry: `functions?.[run]` when `run`
|
|
2334
|
+
* is defined, else `undefined`. A task with no `handler` (an omitted `run`, or a `run` name
|
|
2335
|
+
* absent from the registry) AUTO-COMPLETES (the no-handler rule) — its phase/workflow still
|
|
2336
|
+
* reaches a terminal status, just with no dispatched behavior.
|
|
2337
|
+
*/
|
|
2338
|
+
readonly handler: WorkflowFunction | undefined;
|
|
2339
|
+
/**
|
|
2340
|
+
* Extra attempts after the first on failure — PERSISTED (mirrors {@link TaskDefinition.retries}
|
|
2341
|
+
* / {@link TaskSnapshot.retries}), like {@link PhaseInterface.concurrency}. `undefined` ⇒ none.
|
|
2342
|
+
*/
|
|
2343
|
+
readonly retries: number | undefined;
|
|
2344
|
+
/**
|
|
2345
|
+
* The per-attempt deadline in milliseconds — PERSISTED (mirrors {@link TaskDefinition.timeout}
|
|
2346
|
+
* / {@link TaskSnapshot.timeout}). `undefined` ⇒ no deadline.
|
|
2347
|
+
*/
|
|
2348
|
+
readonly timeout: number | undefined;
|
|
2080
2349
|
start(): void;
|
|
2081
2350
|
complete(value: unknown): void;
|
|
2082
2351
|
fail(error: unknown): void;
|
|
2083
2352
|
skip(): void;
|
|
2084
2353
|
stop(): void;
|
|
2354
|
+
/**
|
|
2355
|
+
* Apply a validated declarative patch to SELF (`name` / `description`).
|
|
2356
|
+
*
|
|
2357
|
+
* @remarks
|
|
2358
|
+
* Defense-in-depth (AGENTS §12): the owning {@link TaskManagerInterface.update} gates
|
|
2359
|
+
* FIRST (target exists + `pending`), so a direct call here is the second, redundant
|
|
2360
|
+
* check — it THROWS a `MUTATION` {@link import('./errors.js').WorkflowError} unless
|
|
2361
|
+
* this task's own `status` is `pending`.
|
|
2362
|
+
*
|
|
2363
|
+
* @param value - The {@link TaskUpdate} fields to apply
|
|
2364
|
+
* @example
|
|
2365
|
+
* ```ts
|
|
2366
|
+
* task.patch({ name: 'Renamed task' })
|
|
2367
|
+
* ```
|
|
2368
|
+
*/
|
|
2369
|
+
patch(value: TaskUpdate): void;
|
|
2085
2370
|
snapshot(): TaskSnapshot;
|
|
2086
2371
|
}
|
|
2087
2372
|
|
|
@@ -2096,6 +2381,11 @@ export declare interface TaskInterface {
|
|
|
2096
2381
|
* `tasks()` lists them in positional order, `count` is the size. A `skip` is a STATUS
|
|
2097
2382
|
* change on a stored task (never a removal), so order survives it; a snapshot RESTORE
|
|
2098
2383
|
* re-`append`s in the snapshot's order, reproducing it exactly.
|
|
2384
|
+
* - **Gated mutation API (AGENTS §12).** `add` / `remove` / `move` / `update` are the
|
|
2385
|
+
* graceful `Result` counterparts to `append`, gating ONLY on the target's OWN
|
|
2386
|
+
* existence/status/id/bounds — a duplicate id, an absent/non-`pending` target, an
|
|
2387
|
+
* out-of-bounds `index`, or a patch that fails {@link taskUpdateShape} validation all
|
|
2388
|
+
* fail gracefully with a `MUTATION` {@link WorkflowError} instead of throwing.
|
|
2099
2389
|
* - **No batch matrix.** A phase's tasks are a fixed positional set, so AGENTS §9.2 (the
|
|
2100
2390
|
* bulk verb overloads) is deliberately omitted — there is no `remove` family here.
|
|
2101
2391
|
* - **Event-free.** A purely structural container — the live {@link TaskInterface}s own
|
|
@@ -2113,6 +2403,10 @@ export declare class TaskManager implements TaskManagerInterface {
|
|
|
2113
2403
|
#private;
|
|
2114
2404
|
get count(): number;
|
|
2115
2405
|
append(task: TaskInterface): void;
|
|
2406
|
+
add(task: TaskInterface, index?: number): Result<TaskInterface, WorkflowError>;
|
|
2407
|
+
remove(id: string): Result<TaskInterface, WorkflowError>;
|
|
2408
|
+
move(id: string, index: number): Result<TaskInterface, WorkflowError>;
|
|
2409
|
+
update(id: string, patch: TaskUpdate): Result<TaskInterface, WorkflowError>;
|
|
2116
2410
|
task(id: string): TaskInterface | undefined;
|
|
2117
2411
|
tasks(): readonly TaskInterface[];
|
|
2118
2412
|
}
|
|
@@ -2126,11 +2420,61 @@ export declare class TaskManager implements TaskManagerInterface {
|
|
|
2126
2420
|
* `append` adds one live {@link TaskInterface} at the end (the build-time wiring path);
|
|
2127
2421
|
* `task(id)` looks one up; `tasks()` lists them in positional order; `count` is the
|
|
2128
2422
|
* tally. No batch matrix (AGENTS §9.2 is deliberately omitted — a phase's tasks are a
|
|
2129
|
-
* fixed positional set, not a bulk-mutated collection).
|
|
2423
|
+
* fixed positional set, not a bulk-mutated collection). `add` / `remove` / `move` /
|
|
2424
|
+
* `update` (AGENTS §12) are the GATED mutation counterparts a
|
|
2425
|
+
* {@link PhaseInterface.add} / `remove` / `move` / `update` delegates to AFTER its own
|
|
2426
|
+
* container-status/hook gating — the manager gates ONLY on the target's OWN
|
|
2427
|
+
* existence/status/id/bounds and stays event-free (the entity emits on success).
|
|
2130
2428
|
*/
|
|
2131
2429
|
export declare interface TaskManagerInterface {
|
|
2132
2430
|
readonly count: number;
|
|
2431
|
+
/**
|
|
2432
|
+
* Add `task` at the end (the build-time wiring path).
|
|
2433
|
+
*
|
|
2434
|
+
* @remarks
|
|
2435
|
+
* THROWS a `MUTATION` {@link import('./errors.js').WorkflowError} on a duplicate
|
|
2436
|
+
* `id` (a genuine programmer error — a build-time wiring bug, AGENTS §12) instead of
|
|
2437
|
+
* silently overwriting the existing entry.
|
|
2438
|
+
*
|
|
2439
|
+
* @param task - The live task to append
|
|
2440
|
+
*/
|
|
2133
2441
|
append(task: TaskInterface): void;
|
|
2442
|
+
/**
|
|
2443
|
+
* Insert `task` at `index` (default the end) — the GATED mutation counterpart to
|
|
2444
|
+
* {@link append}: a duplicate `id` or an out-of-bounds `index` fails gracefully
|
|
2445
|
+
* instead of throwing.
|
|
2446
|
+
*
|
|
2447
|
+
* @param task - The live task to insert
|
|
2448
|
+
* @param index - The insertion position (`[0, count]`); omitted inserts at the end
|
|
2449
|
+
* @returns A {@link Result} boxing the inserted task, or a `MUTATION` failure
|
|
2450
|
+
*/
|
|
2451
|
+
add(task: TaskInterface, index?: number): Result<TaskInterface, WorkflowError>;
|
|
2452
|
+
/**
|
|
2453
|
+
* Remove the `pending` task `id`.
|
|
2454
|
+
*
|
|
2455
|
+
* @param id - The task id to remove
|
|
2456
|
+
* @returns A {@link Result} boxing the removed task, or a `MUTATION` failure when
|
|
2457
|
+
* `id` is absent or not `pending`
|
|
2458
|
+
*/
|
|
2459
|
+
remove(id: string): Result<TaskInterface, WorkflowError>;
|
|
2460
|
+
/**
|
|
2461
|
+
* Reposition the `pending` task `id` to `index`.
|
|
2462
|
+
*
|
|
2463
|
+
* @param id - The task id to move
|
|
2464
|
+
* @param index - The destination position (`[0, count)`)
|
|
2465
|
+
* @returns A {@link Result} boxing the moved task, or a `MUTATION` failure when `id`
|
|
2466
|
+
* is absent, not `pending`, or `index` is out of bounds
|
|
2467
|
+
*/
|
|
2468
|
+
move(id: string, index: number): Result<TaskInterface, WorkflowError>;
|
|
2469
|
+
/**
|
|
2470
|
+
* Apply a validated {@link TaskUpdate} patch to the `pending` task `id`.
|
|
2471
|
+
*
|
|
2472
|
+
* @param id - The task id to patch
|
|
2473
|
+
* @param patch - The fields to update
|
|
2474
|
+
* @returns A {@link Result} boxing the patched task, or a `MUTATION` failure when
|
|
2475
|
+
* `id` is absent, not `pending`, or `patch` fails validation
|
|
2476
|
+
*/
|
|
2477
|
+
update(id: string, patch: TaskUpdate): Result<TaskInterface, WorkflowError>;
|
|
2134
2478
|
task(id: string): TaskInterface | undefined;
|
|
2135
2479
|
tasks(): readonly TaskInterface[];
|
|
2136
2480
|
}
|
|
@@ -2141,9 +2485,11 @@ export declare interface TaskManagerInterface {
|
|
|
2141
2485
|
*
|
|
2142
2486
|
* @remarks
|
|
2143
2487
|
* The reserved `on` (AGENTS §8) wires initial {@link TaskEventMap} listeners; a
|
|
2144
|
-
* {@link
|
|
2145
|
-
*
|
|
2146
|
-
*
|
|
2488
|
+
* {@link import('./factories.js').createWorkflow}-built tree threads each level's `on`
|
|
2489
|
+
* from its parent options, the same way a {@link WorkflowInterface.add} /
|
|
2490
|
+
* {@link PhaseInterface.add} mint threads a leaf's `on` from ITS options. `metadata` is
|
|
2491
|
+
* the open consumer bag carried verbatim into a {@link TaskSnapshot} (mirrors
|
|
2492
|
+
* {@link TaskInput.metadata}), never interpreted by the workflow.
|
|
2147
2493
|
*/
|
|
2148
2494
|
export declare interface TaskOptions {
|
|
2149
2495
|
readonly on?: TaskHooks;
|
|
@@ -2180,23 +2526,15 @@ export declare interface TaskResult {
|
|
|
2180
2526
|
}
|
|
2181
2527
|
|
|
2182
2528
|
/**
|
|
2183
|
-
* The shape of a {@link import('./types.js').TaskDefinition} — identity plus
|
|
2184
|
-
* behavior reference (
|
|
2529
|
+
* The shape of a {@link import('./types.js').TaskDefinition} — identity plus an optional
|
|
2530
|
+
* `run` behavior reference (a plain registry-key string, min length 1). `description` is
|
|
2531
|
+
* optional prose.
|
|
2185
2532
|
*/
|
|
2186
2533
|
export declare const taskShape: ObjectShape<{
|
|
2187
2534
|
id: StringShape;
|
|
2188
2535
|
name: StringShape;
|
|
2189
2536
|
description: OptionalShape<StringShape>;
|
|
2190
|
-
run:
|
|
2191
|
-
via: LiteralShape<readonly ["function"]>;
|
|
2192
|
-
name: StringShape;
|
|
2193
|
-
}>, ObjectShape<{
|
|
2194
|
-
via: LiteralShape<readonly ["tool"]>;
|
|
2195
|
-
name: StringShape;
|
|
2196
|
-
}>, ObjectShape<{
|
|
2197
|
-
via: LiteralShape<readonly ["agent"]>;
|
|
2198
|
-
name: StringShape;
|
|
2199
|
-
}>]>;
|
|
2537
|
+
run: OptionalShape<StringShape>;
|
|
2200
2538
|
retries: OptionalShape<NumberShape>;
|
|
2201
2539
|
timeout: OptionalShape<NumberShape>;
|
|
2202
2540
|
}>;
|
|
@@ -2209,6 +2547,12 @@ export declare const taskShape: ObjectShape<{
|
|
|
2209
2547
|
* Pure JSON DATA (no class instances, no functions). `result` is the task's
|
|
2210
2548
|
* {@link TaskResult} when it has settled with an outcome, else `undefined`.
|
|
2211
2549
|
* `metadata` is the open consumer bag carried from the task's {@link TaskInput}.
|
|
2550
|
+
* `run` / `retries` / `timeout` are the DECLARATIVE config the task carries — persisted
|
|
2551
|
+
* like a {@link PhaseSnapshot}'s `bail` / `concurrency`, so a restore reinstates the same
|
|
2552
|
+
* behavior reference and reliability overrides (`run` re-resolves against the
|
|
2553
|
+
* {@link WorkflowOptions.functions} registry supplied to
|
|
2554
|
+
* {@link import('./factories.js').restoreWorkflow}); each omitted ⇒ the corresponding
|
|
2555
|
+
* unset default.
|
|
2212
2556
|
*/
|
|
2213
2557
|
export declare interface TaskSnapshot {
|
|
2214
2558
|
readonly id: string;
|
|
@@ -2217,6 +2561,12 @@ export declare interface TaskSnapshot {
|
|
|
2217
2561
|
readonly status: TaskStatus;
|
|
2218
2562
|
readonly result?: TaskResult;
|
|
2219
2563
|
readonly metadata: Readonly<Record<string, unknown>>;
|
|
2564
|
+
/** The behavior reference — a registry key resolved against {@link WorkflowFunctions} on restore/build. */
|
|
2565
|
+
readonly run?: string;
|
|
2566
|
+
/** Extra attempts after the first on failure (a non-negative integer); overrides the phase Runner default. */
|
|
2567
|
+
readonly retries?: number;
|
|
2568
|
+
/** The per-attempt deadline in milliseconds (a non-negative integer); overrides the phase Runner default. */
|
|
2569
|
+
readonly timeout?: number;
|
|
2220
2570
|
}
|
|
2221
2571
|
|
|
2222
2572
|
/**
|
|
@@ -2235,8 +2585,40 @@ export declare interface TaskSnapshot {
|
|
|
2235
2585
|
*/
|
|
2236
2586
|
export declare type TaskStatus = LifecycleStatus;
|
|
2237
2587
|
|
|
2238
|
-
/**
|
|
2239
|
-
|
|
2588
|
+
/**
|
|
2589
|
+
* A declarative partial update to a {@link TaskInterface} — the fields a `pending`
|
|
2590
|
+
* task's {@link TaskInterface.patch} (and the owning {@link TaskManagerInterface.update})
|
|
2591
|
+
* accept, runtime-validated via {@link import('./shapers.js').taskUpdateShape}.
|
|
2592
|
+
*
|
|
2593
|
+
* @remarks
|
|
2594
|
+
* Mirrors the identity fields of {@link TaskDefinition} (`name` / `description`) —
|
|
2595
|
+
* never `run` / `retries` / `timeout` (a form/reliability change is a structural
|
|
2596
|
+
* replace, not a patch) and never `id` (identity is immutable once created). Every
|
|
2597
|
+
* field is optional; an omitted field is left unchanged.
|
|
2598
|
+
*
|
|
2599
|
+
* @example
|
|
2600
|
+
* ```ts
|
|
2601
|
+
* const result = task.phase.tasks.update(task.id, { name: 'Renamed task' })
|
|
2602
|
+
* ```
|
|
2603
|
+
*/
|
|
2604
|
+
export declare interface TaskUpdate {
|
|
2605
|
+
readonly name?: string;
|
|
2606
|
+
readonly description?: string;
|
|
2607
|
+
}
|
|
2608
|
+
|
|
2609
|
+
/**
|
|
2610
|
+
* The shape of a {@link import('./types.js').TaskUpdate} — a partial edit to a
|
|
2611
|
+
* `pending` task's `name` / `description`, both optional.
|
|
2612
|
+
*
|
|
2613
|
+
* @remarks
|
|
2614
|
+
* Mirrors {@link taskShape}'s `name` / `description` constraints exactly (a provided
|
|
2615
|
+
* `name` still has `minLength: 1`); never `id` / `run` / `retries` / `timeout` (those
|
|
2616
|
+
* are not patchable fields, AGENTS §12).
|
|
2617
|
+
*/
|
|
2618
|
+
export declare const taskUpdateShape: ObjectShape<{
|
|
2619
|
+
name: OptionalShape<StringShape>;
|
|
2620
|
+
description: OptionalShape<StringShape>;
|
|
2621
|
+
}>;
|
|
2240
2622
|
|
|
2241
2623
|
/**
|
|
2242
2624
|
* The {@link TaskStatus} values that are TERMINAL — a task in one of these will
|
|
@@ -2295,6 +2677,21 @@ export declare type UnitOutcome<TResult> = {
|
|
|
2295
2677
|
* `start` / `complete` / `fail` / `stop` on a derived-status CHANGE; the emitter isolates a
|
|
2296
2678
|
* listener throw and routes it to its `error` handler (the `error` option); `fail` carries
|
|
2297
2679
|
* the failing task's {@link TaskResult}.
|
|
2680
|
+
* - **Structural API (AGENTS §7).** `add` / `remove` / `move` / `update` gate BEFORE
|
|
2681
|
+
* delegating to {@link phases} (the manager gates the target's own existence/status/id/
|
|
2682
|
+
* bounds), then emit the matching {@link WorkflowEventMap} event on success only. NATIVE,
|
|
2683
|
+
* bottom-up gating (no runner-installed hook): refused outright while this workflow's own
|
|
2684
|
+
* `status` is terminal; otherwise a target position must fall within the PENDING SUFFIX —
|
|
2685
|
+
* the contiguous trailing run of `pending` phases — whose boundary is
|
|
2686
|
+
* {@link import('./helpers.js').deriveBoundary} over the live phases' statuses. A `pending`
|
|
2687
|
+
* workflow's phases are all `pending`, so the boundary is `0` and every position is
|
|
2688
|
+
* naturally accepted.
|
|
2689
|
+
* - **Runtime lifecycle (AGENTS §10).** `pause` / `resume` / `wait` gate execution at the runner's
|
|
2690
|
+
* phase/task boundaries WITHOUT touching {@link status} — `paused` is runtime-only, never
|
|
2691
|
+
* persisted. `destroy` is a terminal teardown: it aborts {@link signal}, `stop`s every
|
|
2692
|
+
* non-terminal live phase (so an engine parked on a phase's own gate unparks and the tree
|
|
2693
|
+
* lands coherent), forces the `stop` override on THIS workflow when not already terminal,
|
|
2694
|
+
* releases any parked {@link wait} waiter, and marks {@link destroyed} — all four idempotent.
|
|
2298
2695
|
*/
|
|
2299
2696
|
export declare class Workflow implements WorkflowInterface {
|
|
2300
2697
|
#private;
|
|
@@ -2305,6 +2702,9 @@ export declare class Workflow implements WorkflowInterface {
|
|
|
2305
2702
|
get description(): string | undefined;
|
|
2306
2703
|
get context(): WorkflowContext;
|
|
2307
2704
|
get bail(): boolean;
|
|
2705
|
+
get paused(): boolean;
|
|
2706
|
+
get destroyed(): boolean;
|
|
2707
|
+
get signal(): AbortSignal;
|
|
2308
2708
|
get status(): WorkflowStatus;
|
|
2309
2709
|
get phases(): PhaseManagerInterface;
|
|
2310
2710
|
phase(id: string): PhaseInterface | undefined;
|
|
@@ -2312,92 +2712,20 @@ export declare class Workflow implements WorkflowInterface {
|
|
|
2312
2712
|
skip(): void;
|
|
2313
2713
|
stop(): void;
|
|
2314
2714
|
complete(): void;
|
|
2715
|
+
pause(): void;
|
|
2716
|
+
resume(): void;
|
|
2717
|
+
destroy(): void;
|
|
2718
|
+
wait(): Promise<void>;
|
|
2719
|
+
add(definition: PhaseDefinition, index?: number): Result<PhaseInterface, WorkflowError>;
|
|
2720
|
+
remove(id: string): Result<PhaseInterface, WorkflowError>;
|
|
2721
|
+
move(id: string, index: number): Result<PhaseInterface, WorkflowError>;
|
|
2722
|
+
update(id: string, patch: PhaseUpdate): Result<PhaseInterface, WorkflowError>;
|
|
2315
2723
|
snapshot(): WorkflowSnapshot;
|
|
2316
2724
|
}
|
|
2317
2725
|
|
|
2318
2726
|
/** Every {@link WorkflowStatus} value, frozen — the lifecycle vocabulary of a workflow. */
|
|
2319
2727
|
export declare const WORKFLOW_STATUSES: readonly WorkflowStatus[];
|
|
2320
2728
|
|
|
2321
|
-
/**
|
|
2322
|
-
* The DESCRIPTION {@link import('./factories.js').createWorkflowTool} advertises — a
|
|
2323
|
-
* multi-line guide that teaches a small model how to author a complete workflow tree.
|
|
2324
|
-
*
|
|
2325
|
-
* @remarks
|
|
2326
|
-
* Presents the SIMPLE flat shape (`{ name, steps: [{ name, via }] }`) as the PRIMARY way with
|
|
2327
|
-
* one complete worked example ({@link WORKFLOW_TOOL_FLAT_EXAMPLE}), names the three `via`
|
|
2328
|
-
* values + that a step's `name` is a REGISTERED name (not a human label), and documents the full nested
|
|
2329
|
-
* {@link WorkflowDefinition} as the ADVANCED form with a minimal example
|
|
2330
|
-
* ({@link WORKFLOW_TOOL_NESTED_EXAMPLE}). Both examples are interpolated VERBATIM from the
|
|
2331
|
-
* validated constants, so a parity test pins them — the description can never drift from a
|
|
2332
|
-
* real, contract-valid example. The `parameters` the tool advertises are the FLAT shape's
|
|
2333
|
-
* schema; the nested form is the documented escape-hatch (the tool accepts both).
|
|
2334
|
-
*/
|
|
2335
|
-
export declare const WORKFLOW_TOOL_DESCRIPTION: string;
|
|
2336
|
-
|
|
2337
|
-
/**
|
|
2338
|
-
* A complete FLAT authoring example — the PRIMARY way a small model authors a workflow
|
|
2339
|
-
* through {@link import('./factories.js').createWorkflowTool}: `{ name, steps: [{ name, via }] }`.
|
|
2340
|
-
*
|
|
2341
|
-
* @remarks
|
|
2342
|
-
* Each step becomes a one-task phase, in order; a step's `name` is a REGISTERED behavior name
|
|
2343
|
-
* (not a label) and `via` is the execution mechanism. The tool expands this
|
|
2344
|
-
* ({@link import('./helpers.js').expandSteps}) into a valid {@link WorkflowDefinition}. It
|
|
2345
|
-
* is embedded VERBATIM in {@link WORKFLOW_TOOL_DESCRIPTION} and guarded by a parity test
|
|
2346
|
-
* (it must expand to a tree the STRICT contract accepts), so the doc example can never drift.
|
|
2347
|
-
*/
|
|
2348
|
-
export declare const WORKFLOW_TOOL_FLAT_EXAMPLE: WorkflowSteps;
|
|
2349
|
-
|
|
2350
|
-
/**
|
|
2351
|
-
* The name under which the {@link import('./WorkflowRunner.js').WorkflowRunner} BINDS the
|
|
2352
|
-
* depth/cycle-aware workflow tool onto a dispatched `agent` task's
|
|
2353
|
-
* `AgentContextInterface` (the future `@orkestrel/agent` package, W-c2).
|
|
2354
|
-
*
|
|
2355
|
-
* @remarks
|
|
2356
|
-
* The propagation seam's well-known key: before running an `agent` task, the runner adds a
|
|
2357
|
-
* {@link import('./factories.js').createWorkflowTool}-built tool under this name to the
|
|
2358
|
-
* resolved agent's `context.tools`, so the subagent can author + run a NESTED workflow
|
|
2359
|
-
* (bounded by {@link MAX_WORKFLOW_DEPTH}). A subagent that wants to fan out into a workflow
|
|
2360
|
-
* calls this tool by this name; the bound handler runs the nested workflow at depth + 1.
|
|
2361
|
-
*/
|
|
2362
|
-
export declare const WORKFLOW_TOOL_NAME = "workflow";
|
|
2363
|
-
|
|
2364
|
-
/**
|
|
2365
|
-
* A minimal NESTED authoring example — the ADVANCED escape-hatch form a model may use
|
|
2366
|
-
* instead of the flat shape: a full {@link WorkflowDefinition}.
|
|
2367
|
-
*
|
|
2368
|
-
* @remarks
|
|
2369
|
-
* The full four-level form, documented in {@link WORKFLOW_TOOL_DESCRIPTION} as the advanced
|
|
2370
|
-
* alternative. It is embedded VERBATIM and guarded by a parity test (`createWorkflowContract().is`
|
|
2371
|
-
* must accept it), so the doc example can never drift from a valid definition.
|
|
2372
|
-
*/
|
|
2373
|
-
export declare const WORKFLOW_TOOL_NESTED_EXAMPLE: WorkflowDefinition;
|
|
2374
|
-
|
|
2375
|
-
/**
|
|
2376
|
-
* The `agent`-task behavior resolver (W-c2) — resolves a registered agent BY NAME to a
|
|
2377
|
-
* live {@link AgentInterface} the runner runs as a subagent.
|
|
2378
|
-
*
|
|
2379
|
-
* @remarks
|
|
2380
|
-
* The `agent` analogue of the {@link WorkflowFunctions} registry / the
|
|
2381
|
-
* {@link ToolManagerInterface} the other two forms dispatch through: the runner resolves
|
|
2382
|
-
* an `agent`-form {@link TaskForm}'s `name` here. A name absent from the resolver is the
|
|
2383
|
-
* no-handler case — the task AUTO-COMPLETES (the ROADMAP rule), exactly like an
|
|
2384
|
-
* unregistered `function` / `tool`.
|
|
2385
|
-
*
|
|
2386
|
-
* **Resolve a FRESH agent per call.** A phase's tasks run CONCURRENTLY, so two `agent`
|
|
2387
|
-
* tasks naming the same agent are resolved concurrently — and the runner BINDS a
|
|
2388
|
-
* depth/cycle-aware workflow tool onto each resolved agent's `context.tools` (the
|
|
2389
|
-
* propagation seam — see {@link WorkflowToolOptions}). An implementation that returns the
|
|
2390
|
-
* SAME instance for both would have them race on that mutation, so it must mint a fresh
|
|
2391
|
-
* agent each call (exactly as `AgentRegistry.build` does). A function resolver
|
|
2392
|
-
* (`(name) => …`) is the minimal shape; the agents module's `AgentRegistry` is not a
|
|
2393
|
-
* direct fit (its `build` rehydrates from a serializable `AgentJobInput`, not a bare
|
|
2394
|
-
* name), so a small adapter `(name) => registry.build({ provider, ... })` bridges it.
|
|
2395
|
-
*
|
|
2396
|
-
* @param name - The agent's registry key (the `agent`-form's `name`)
|
|
2397
|
-
* @returns The resolved live agent, or `undefined` when the name is unregistered
|
|
2398
|
-
*/
|
|
2399
|
-
export declare type WorkflowAgents = (name: string) => AgentInterface | undefined;
|
|
2400
|
-
|
|
2401
2729
|
/**
|
|
2402
2730
|
* The ambient context of a workflow — the identity every level inherits.
|
|
2403
2731
|
*
|
|
@@ -2433,68 +2761,6 @@ export declare interface WorkflowDefinition {
|
|
|
2433
2761
|
readonly bail?: boolean;
|
|
2434
2762
|
}
|
|
2435
2763
|
|
|
2436
|
-
/**
|
|
2437
|
-
* A draft workflow — a {@link WorkflowDefinition} with OPTIONAL `id` / `name` at all
|
|
2438
|
-
* three levels (workflow / phase / task).
|
|
2439
|
-
*
|
|
2440
|
-
* @remarks
|
|
2441
|
-
* The lenient authoring form `createWorkflowDraftContract` validates and
|
|
2442
|
-
* {@link import('./helpers.js').completeDraft} completes into a strict
|
|
2443
|
-
* {@link WorkflowDefinition}. `run` stays required; the `bail` policy carries over.
|
|
2444
|
-
*/
|
|
2445
|
-
export declare interface WorkflowDraft {
|
|
2446
|
-
readonly id?: string;
|
|
2447
|
-
readonly name?: string;
|
|
2448
|
-
readonly description?: string;
|
|
2449
|
-
readonly phases: readonly PhaseDraft[];
|
|
2450
|
-
/** Failure policy: `false` (default) continues gracefully, `true` halts on the first failure. */
|
|
2451
|
-
readonly bail?: boolean;
|
|
2452
|
-
}
|
|
2453
|
-
|
|
2454
|
-
/**
|
|
2455
|
-
* The shape of a DRAFT workflow — identical to {@link workflowShape} EXCEPT `id` and
|
|
2456
|
-
* `name` are OPTIONAL at all three levels (workflow / phase / task), so a small model
|
|
2457
|
-
* can omit the six identity strings and let the tool synthesize them positionally.
|
|
2458
|
-
*
|
|
2459
|
-
* @remarks
|
|
2460
|
-
* The lenient counterpart {@link import('./factories.js').createWorkflowDraftContract}
|
|
2461
|
-
* compiles. `run` stays required; a provided `id` / `name` still has `minLength: 1` (so an
|
|
2462
|
-
* explicitly-empty `id: ''` is REJECTED, not auto-filled). After
|
|
2463
|
-
* {@link import('./helpers.js').completeDraft} fills the missing ids/names, the result is
|
|
2464
|
-
* validated against the STRICT {@link import('./factories.js').createWorkflowContract} gate
|
|
2465
|
-
* before running.
|
|
2466
|
-
*/
|
|
2467
|
-
export declare const workflowDraftShape: ObjectShape<{
|
|
2468
|
-
id: OptionalShape<StringShape>;
|
|
2469
|
-
name: OptionalShape<StringShape>;
|
|
2470
|
-
description: OptionalShape<StringShape>;
|
|
2471
|
-
phases: ArrayShape<ObjectShape<{
|
|
2472
|
-
id: OptionalShape<StringShape>;
|
|
2473
|
-
name: OptionalShape<StringShape>;
|
|
2474
|
-
description: OptionalShape<StringShape>;
|
|
2475
|
-
tasks: ArrayShape<ObjectShape<{
|
|
2476
|
-
id: OptionalShape<StringShape>;
|
|
2477
|
-
name: OptionalShape<StringShape>;
|
|
2478
|
-
description: OptionalShape<StringShape>;
|
|
2479
|
-
run: UnionShape<[ ObjectShape<{
|
|
2480
|
-
via: LiteralShape<readonly ["function"]>;
|
|
2481
|
-
name: StringShape;
|
|
2482
|
-
}>, ObjectShape<{
|
|
2483
|
-
via: LiteralShape<readonly ["tool"]>;
|
|
2484
|
-
name: StringShape;
|
|
2485
|
-
}>, ObjectShape<{
|
|
2486
|
-
via: LiteralShape<readonly ["agent"]>;
|
|
2487
|
-
name: StringShape;
|
|
2488
|
-
}>]>;
|
|
2489
|
-
retries: OptionalShape<NumberShape>;
|
|
2490
|
-
timeout: OptionalShape<NumberShape>;
|
|
2491
|
-
}>>;
|
|
2492
|
-
concurrency: OptionalShape<NumberShape>;
|
|
2493
|
-
bail: OptionalShape<LiteralShape<readonly [true, false]>>;
|
|
2494
|
-
}>>;
|
|
2495
|
-
bail: OptionalShape<LiteralShape<readonly [true, false]>>;
|
|
2496
|
-
}>;
|
|
2497
|
-
|
|
2498
2764
|
/**
|
|
2499
2765
|
* An error thrown by the workflow entity + W-c2 recursion layer.
|
|
2500
2766
|
*
|
|
@@ -2503,11 +2769,11 @@ export declare const workflowDraftShape: ObjectShape<{
|
|
|
2503
2769
|
* offending node id / status. Thrown for an illegal lifecycle transition
|
|
2504
2770
|
* (`TRANSITION`), a structurally invalid {@link import('./types.js').WorkflowSnapshot}
|
|
2505
2771
|
* passed to {@link import('./factories.js').restoreWorkflow} (`RESTORE`), an over-deep /
|
|
2506
|
-
* cyclic nested-workflow dispatch (`DEPTH`), and a malformed
|
|
2507
|
-
*
|
|
2508
|
-
* workflow-tool
|
|
2509
|
-
*
|
|
2510
|
-
*
|
|
2772
|
+
* cyclic nested-workflow dispatch (`DEPTH`), and a malformed workflow-authoring-tool args
|
|
2773
|
+
* blob (`TOOL`). `DEPTH` and `TOOL` are public type surface constructed by the
|
|
2774
|
+
* `@orkestrel/tool` package's workflow-tool / agent-function adapters; on that seam the
|
|
2775
|
+
* throw is ISOLATED by its `ToolManager` into the tool result's top-level `error`
|
|
2776
|
+
* (AGENTS §14 — the universal tool-handler contract).
|
|
2511
2777
|
*/
|
|
2512
2778
|
export declare class WorkflowError extends Error {
|
|
2513
2779
|
readonly code: WorkflowErrorCode;
|
|
@@ -2525,23 +2791,35 @@ export declare class WorkflowError extends Error {
|
|
|
2525
2791
|
* the offending current status + requested transition in the error `context`.
|
|
2526
2792
|
* - `RESTORE` — a {@link import('./factories.js').restoreWorkflow} given a structurally
|
|
2527
2793
|
* invalid {@link WorkflowSnapshot} (a status outside the lifecycle vocabulary).
|
|
2528
|
-
* - `DEPTH` — a nested-workflow dispatch (W-c2) that
|
|
2529
|
-
*
|
|
2530
|
-
*
|
|
2531
|
-
*
|
|
2532
|
-
*
|
|
2533
|
-
* (
|
|
2534
|
-
*
|
|
2535
|
-
*
|
|
2536
|
-
*
|
|
2537
|
-
* -
|
|
2538
|
-
*
|
|
2539
|
-
*
|
|
2540
|
-
* returning a failure result)
|
|
2541
|
-
*
|
|
2542
|
-
*
|
|
2543
|
-
|
|
2544
|
-
|
|
2794
|
+
* - `DEPTH` — a nested-workflow dispatch (W-c2) that a depth / cycle guard rejected:
|
|
2795
|
+
* running it would push the nested-workflow chain past a bounded max depth, OR its
|
|
2796
|
+
* target agent (or a workflow it would author) is already an ancestor of the current
|
|
2797
|
+
* run (a re-entry cycle). Public type surface consumed by the `@orkestrel/tool`
|
|
2798
|
+
* package's workflow-tool / agent-function adapters, which construct
|
|
2799
|
+
* {@link import('./errors.js').WorkflowError}s with this code (thrown, then ISOLATED
|
|
2800
|
+
* by that package's `ToolManager` into the tool result's `error`). The error `context`
|
|
2801
|
+
* names the offending agent / workflow id + the depth.
|
|
2802
|
+
* - `TOOL` — a workflow-authoring tool handler (in `@orkestrel/tool`) was handed a
|
|
2803
|
+
* MALFORMED / over-constraint authored args blob (e.g. an empty `id`, `concurrency: 0`)
|
|
2804
|
+
* that {@link import('./factories.js').createWorkflowContract} rejected, so no workflow
|
|
2805
|
+
* ran. Public type surface: `@orkestrel/tool` constructs this code and THROWS it
|
|
2806
|
+
* (rather than returning a failure result); its `ToolManager` ISOLATES the throw into
|
|
2807
|
+
* the canonical tool result's top-level `error` (AGENTS §14 — the universal
|
|
2808
|
+
* tool-handler contract); the error `context` names the wrapped workflow id.
|
|
2809
|
+
* - `MUTATION` — a GATED structural or patch edit was refused: a duplicate id on
|
|
2810
|
+
* `append`/`add`, a target that does not exist or is not `pending`, an out-of-bounds
|
|
2811
|
+
* `index`, a patch that failed shaper validation, or a live structural edit refused by
|
|
2812
|
+
* the NATIVE bottom-up gate — a terminal container, an edit targeting (or destined for)
|
|
2813
|
+
* a position BEFORE the container's own pending-suffix boundary, or (a running phase)
|
|
2814
|
+
* anything other than a pure append. The manager /
|
|
2815
|
+
* entity structural API (AGENTS §12) returns it as a graceful `Result` `failure` —
|
|
2816
|
+
* it NEVER throws for this code except {@link TaskInterface.patch} /
|
|
2817
|
+
* {@link PhaseInterface.patch}'s defense-in-depth self-check and the build-time
|
|
2818
|
+
* {@link TaskManagerInterface.append} / {@link PhaseManagerInterface.append} duplicate-id
|
|
2819
|
+
* guard (both genuine programmer-error paths, AGENTS §12). The error `context` names
|
|
2820
|
+
* the offending id / index / status.
|
|
2821
|
+
*/
|
|
2822
|
+
export declare type WorkflowErrorCode = 'TRANSITION' | 'RESTORE' | 'DEPTH' | 'TOOL' | 'MUTATION';
|
|
2545
2823
|
|
|
2546
2824
|
/**
|
|
2547
2825
|
* The push observation surface (AGENTS §13) of the workflow entity (W-b) — the
|
|
@@ -2552,10 +2830,13 @@ export declare type WorkflowErrorCode = 'TRANSITION' | 'RESTORE' | 'DEPTH' | 'TO
|
|
|
2552
2830
|
* Present-tense events with arg tuples. `start` fires when the workflow begins;
|
|
2553
2831
|
* `complete` when every phase settled successfully; `fail` when a phase failed
|
|
2554
2832
|
* under `bail` (carrying the failing {@link TaskResult}); `stop` when the workflow
|
|
2555
|
-
* was permanently ended.
|
|
2556
|
-
*
|
|
2557
|
-
* AGENTS §
|
|
2558
|
-
*
|
|
2833
|
+
* was permanently ended. `add` / `remove` / `move` / `update` fire on a successful
|
|
2834
|
+
* structural or patch edit through {@link WorkflowInterface.add} / `remove` / `move` /
|
|
2835
|
+
* `update` (AGENTS §7) — never on a refused/gated one. A throwing listener never
|
|
2836
|
+
* reaches the domain surface — the emitter isolates it and routes it to its OWN
|
|
2837
|
+
* `error` handler (the `error` option, AGENTS §13). Declared as a `type` alias (not
|
|
2838
|
+
* `interface extends EventMap`, AGENTS §4.5) so the type-literal satisfies `EventMap`
|
|
2839
|
+
* structurally.
|
|
2559
2840
|
*/
|
|
2560
2841
|
export declare type WorkflowEventMap = {
|
|
2561
2842
|
/** The workflow began — its `id`. */
|
|
@@ -2566,6 +2847,14 @@ export declare type WorkflowEventMap = {
|
|
|
2566
2847
|
readonly fail: readonly [result: TaskResult];
|
|
2567
2848
|
/** The workflow was permanently stopped. */
|
|
2568
2849
|
readonly stop: readonly [];
|
|
2850
|
+
/** A phase was inserted — the inserted phase + its final index. */
|
|
2851
|
+
readonly add: readonly [phase: PhaseInterface, index: number];
|
|
2852
|
+
/** A phase was removed — the removed phase. */
|
|
2853
|
+
readonly remove: readonly [phase: PhaseInterface];
|
|
2854
|
+
/** A phase was repositioned — the moved phase + its new index. */
|
|
2855
|
+
readonly move: readonly [phase: PhaseInterface, index: number];
|
|
2856
|
+
/** A phase was patched — the patched phase. */
|
|
2857
|
+
readonly update: readonly [phase: PhaseInterface];
|
|
2569
2858
|
};
|
|
2570
2859
|
|
|
2571
2860
|
/**
|
|
@@ -2589,10 +2878,10 @@ export declare type WorkflowFunction = (controller: TaskControllerInterface) =>
|
|
|
2589
2878
|
* {@link WorkflowFunction} handlers.
|
|
2590
2879
|
*
|
|
2591
2880
|
* @remarks
|
|
2592
|
-
*
|
|
2593
|
-
*
|
|
2594
|
-
*
|
|
2595
|
-
* lookup, with no lifecycle of its own.
|
|
2881
|
+
* A live {@link TaskInterface} resolves its `run` name against this registry ONCE at
|
|
2882
|
+
* construction into its {@link TaskInterface.handler}. A name absent from the registry (or
|
|
2883
|
+
* an omitted `run`) is the no-handler case — the task AUTO-COMPLETES (the ROADMAP rule). A
|
|
2884
|
+
* plain record (not a manager) — the registry is a lookup, with no lifecycle of its own.
|
|
2596
2885
|
*/
|
|
2597
2886
|
export declare type WorkflowFunctions = Readonly<Record<string, WorkflowFunction>>;
|
|
2598
2887
|
|
|
@@ -2634,13 +2923,182 @@ export declare interface WorkflowInterface {
|
|
|
2634
2923
|
readonly bail: boolean;
|
|
2635
2924
|
readonly status: WorkflowStatus;
|
|
2636
2925
|
readonly phases: PhaseManagerInterface;
|
|
2926
|
+
/**
|
|
2927
|
+
* Whether the workflow is currently paused (AGENTS §10 — resumable); RUNTIME-ONLY —
|
|
2928
|
+
* never a {@link WorkflowStatus}, never persisted in a {@link WorkflowSnapshot} (a
|
|
2929
|
+
* paused workflow's `status` still reports its ordinary `pending` / `running` value).
|
|
2930
|
+
*/
|
|
2931
|
+
readonly paused: boolean;
|
|
2932
|
+
/** Whether {@link destroy} has torn this workflow down; RUNTIME-ONLY, never persisted. */
|
|
2933
|
+
readonly destroyed: boolean;
|
|
2934
|
+
/**
|
|
2935
|
+
* This workflow's own cancellation signal — fires on {@link destroy}. RUNTIME-ONLY
|
|
2936
|
+
* (implemented over `@orkestrel/abort`, AGENTS core precedent), never persisted.
|
|
2937
|
+
*/
|
|
2938
|
+
readonly signal: AbortSignal;
|
|
2637
2939
|
/** Look up one live phase by its `id`. */
|
|
2638
2940
|
phase(id: string): PhaseInterface | undefined;
|
|
2639
2941
|
/** Every settled task's result across all phases, in positional order — the workflow tier of the result tree. */
|
|
2640
2942
|
results(): readonly TaskResult[];
|
|
2943
|
+
/**
|
|
2944
|
+
* FORCE this workflow to `skipped` (AGENTS §10), overriding the derived value; idempotent.
|
|
2945
|
+
*
|
|
2946
|
+
* @remarks
|
|
2947
|
+
* A NO-OP once `status` is already terminal — a settled workflow cannot be re-forced.
|
|
2948
|
+
* Always releases a parked {@link wait} waiter regardless (a terminal workflow has nothing
|
|
2949
|
+
* left to pause for).
|
|
2950
|
+
*/
|
|
2641
2951
|
skip(): void;
|
|
2952
|
+
/**
|
|
2953
|
+
* FORCE this workflow to `stopped` (AGENTS §10), overriding the derived value; idempotent.
|
|
2954
|
+
*
|
|
2955
|
+
* @remarks
|
|
2956
|
+
* A NO-OP once `status` is already terminal — a settled workflow cannot be re-forced. Always
|
|
2957
|
+
* releases a parked {@link wait} waiter regardless (a terminal workflow has nothing left to
|
|
2958
|
+
* pause for).
|
|
2959
|
+
*/
|
|
2642
2960
|
stop(): void;
|
|
2961
|
+
/**
|
|
2962
|
+
* FORCE this workflow to `completed` (AGENTS §10), overriding the derived value.
|
|
2963
|
+
*
|
|
2964
|
+
* @remarks
|
|
2965
|
+
* A NO-OP unless `status` is `pending` — its ONLY legitimate use is settling a vacuously
|
|
2966
|
+
* DONE tree (no work happened), mirroring the runner's own gate. Never overrides a real
|
|
2967
|
+
* `completed` / a bail-true `failed` / a `stopped` / a derived `skipped`.
|
|
2968
|
+
*/
|
|
2643
2969
|
complete(): void;
|
|
2970
|
+
/**
|
|
2971
|
+
* Suspend the workflow (AGENTS §10 — resumable); idempotent.
|
|
2972
|
+
*
|
|
2973
|
+
* @remarks
|
|
2974
|
+
* A no-op when already `paused`, when `status` is terminal, or once {@link destroyed}.
|
|
2975
|
+
* RUNTIME-ONLY (AGENTS §10) — never a {@link WorkflowStatus}, never persisted in a
|
|
2976
|
+
* {@link WorkflowSnapshot}. A driving {@link WorkflowRunnerInterface.execute} gates at the
|
|
2977
|
+
* next phase boundary and before each task's own dispatch; an in-flight task body is
|
|
2978
|
+
* never suspended mid-flight. **Pausing does NOT suspend the run's timeout / budget /
|
|
2979
|
+
* abort clocks** — those bounds keep ticking while paused, so a run parked on
|
|
2980
|
+
* `pause()` can still be cancelled (and settle `stopped`) by its own deadline / budget /
|
|
2981
|
+
* abort while parked.
|
|
2982
|
+
*
|
|
2983
|
+
* @example
|
|
2984
|
+
* ```ts
|
|
2985
|
+
* workflow.pause()
|
|
2986
|
+
* workflow.paused // true
|
|
2987
|
+
* ```
|
|
2988
|
+
*/
|
|
2989
|
+
pause(): void;
|
|
2990
|
+
/**
|
|
2991
|
+
* Continue a paused workflow (AGENTS §10); idempotent — a no-op unless {@link paused}.
|
|
2992
|
+
*
|
|
2993
|
+
* @example
|
|
2994
|
+
* ```ts
|
|
2995
|
+
* workflow.resume()
|
|
2996
|
+
* workflow.paused // false
|
|
2997
|
+
* ```
|
|
2998
|
+
*/
|
|
2999
|
+
resume(): void;
|
|
3000
|
+
/**
|
|
3001
|
+
* Tear this workflow down (AGENTS §10) — a TERMINAL teardown: aborts {@link signal},
|
|
3002
|
+
* `stop`s every non-terminal live phase (so any engine parked on a phase's own gate
|
|
3003
|
+
* unparks and the tree lands coherent), forces the `stop` override on THIS workflow if
|
|
3004
|
+
* it is not already terminal, resolves any parked {@link wait} waiter, and marks
|
|
3005
|
+
* {@link destroyed}; idempotent.
|
|
3006
|
+
*
|
|
3007
|
+
* @remarks
|
|
3008
|
+
* After `destroy`, every structural mutator (`add` / `remove` / `move` / `update` /
|
|
3009
|
+
* `patch`) and `pause` / `resume` reject (a `Result` failure) or no-op — never throws
|
|
3010
|
+
* for calling `destroy` itself twice.
|
|
3011
|
+
*
|
|
3012
|
+
* @example
|
|
3013
|
+
* ```ts
|
|
3014
|
+
* workflow.destroy()
|
|
3015
|
+
* workflow.destroyed // true
|
|
3016
|
+
* ```
|
|
3017
|
+
*/
|
|
3018
|
+
destroy(): void;
|
|
3019
|
+
/**
|
|
3020
|
+
* Park until this workflow is not paused — **promise-parked**, never a timer or
|
|
3021
|
+
* busy-loop (AGENTS §21; mirrors {@link ControllerInterface.wait}'s doc style).
|
|
3022
|
+
*
|
|
3023
|
+
* @remarks
|
|
3024
|
+
* Resolves IMMEDIATELY when not {@link paused}. While paused, parks until `resume` /
|
|
3025
|
+
* `skip` / `stop` / `destroy` — each always releases a parked waiter (a permanently
|
|
3026
|
+
* ended workflow has nothing left to pause for). NEVER rejects.
|
|
3027
|
+
*
|
|
3028
|
+
* @returns A promise that resolves once the workflow is no longer paused
|
|
3029
|
+
*/
|
|
3030
|
+
wait(): Promise<void>;
|
|
3031
|
+
/**
|
|
3032
|
+
* MINT a live {@link PhaseInterface} (and its tasks) from `definition` and insert it
|
|
3033
|
+
* into this workflow (AGENTS §7 the entity structural API) — gated BEFORE delegating
|
|
3034
|
+
* to {@link phases}' manager.
|
|
3035
|
+
*
|
|
3036
|
+
* @remarks
|
|
3037
|
+
* Converts `definition` → {@link PhaseSnapshot} and constructs the live phase (wired to
|
|
3038
|
+
* THIS workflow, its recompute cascade, and its emitter hooks) plus each of its live
|
|
3039
|
+
* tasks — each task's `run` / `retries` / `timeout` carried from its {@link TaskDefinition}
|
|
3040
|
+
* and its {@link TaskInterface.handler} resolved against the workflow-level
|
|
3041
|
+
* {@link WorkflowOptions.functions} registry (mirrors
|
|
3042
|
+
* {@link import('./factories.js').createWorkflow}'s build-time resolution). The
|
|
3043
|
+
* phase's effective `bail` resolves exactly as the build path does
|
|
3044
|
+
* (`definition.bail ?? this.bail`). Requires `definition.id` to be UNIQUE among this
|
|
3045
|
+
* workflow's existing phase ids — a duplicate is a `MUTATION` failure (mirrors
|
|
3046
|
+
* {@link PhaseManagerInterface.add}'s own duplicate-id gate).
|
|
3047
|
+
*
|
|
3048
|
+
* NATIVE gating, purely from this workflow's own derived `status` and the phase list's
|
|
3049
|
+
* positions (AGENTS §12 — no runner-installed hook), UNCHANGED from the entity-taking
|
|
3050
|
+
* predecessor: refused outright while this workflow's own `status` is terminal or once
|
|
3051
|
+
* {@link destroyed}. Otherwise the effective target position (`index ?? phases.count`)
|
|
3052
|
+
* must fall within the PENDING SUFFIX — the contiguous trailing run of `pending` phases
|
|
3053
|
+
* (phases run sequentially, so every already-started phase forms a contiguous leading
|
|
3054
|
+
* prefix); its boundary is {@link import('./helpers.js').deriveBoundary}. A `pending`
|
|
3055
|
+
* workflow's phases are ALL `pending`, so the boundary is `0` and every index is
|
|
3056
|
+
* naturally accepted — no special case needed. Delegates the minted phase to
|
|
3057
|
+
* {@link PhaseManagerInterface.add} then emits `add` on success.
|
|
3058
|
+
*
|
|
3059
|
+
* @param definition - The {@link PhaseDefinition} to mint a live phase (and tasks) from
|
|
3060
|
+
* @param index - The insertion position; omitted inserts at the end
|
|
3061
|
+
* @returns A {@link Result} boxing the minted, inserted phase, or a `MUTATION` failure
|
|
3062
|
+
*/
|
|
3063
|
+
add(definition: PhaseDefinition, index?: number): Result<PhaseInterface, WorkflowError>;
|
|
3064
|
+
/**
|
|
3065
|
+
* Remove the `pending` phase `id` from this workflow.
|
|
3066
|
+
*
|
|
3067
|
+
* @remarks
|
|
3068
|
+
* NATIVE gating: refused while this workflow's own `status` is terminal. Otherwise the
|
|
3069
|
+
* target must exist at an index within the pending suffix (at or past
|
|
3070
|
+
* {@link import('./helpers.js').deriveBoundary}) — the manager separately gates the
|
|
3071
|
+
* target's own `pending` status (AGENTS §9).
|
|
3072
|
+
*
|
|
3073
|
+
* @param id - The phase id to remove
|
|
3074
|
+
* @returns A {@link Result} boxing the removed phase, or a `MUTATION` failure
|
|
3075
|
+
*/
|
|
3076
|
+
remove(id: string): Result<PhaseInterface, WorkflowError>;
|
|
3077
|
+
/**
|
|
3078
|
+
* Reposition the `pending` phase `id` to `index` within this workflow.
|
|
3079
|
+
*
|
|
3080
|
+
* @remarks
|
|
3081
|
+
* NATIVE gating: refused while this workflow's own `status` is terminal. Otherwise BOTH
|
|
3082
|
+
* the target's current index and the destination `index` must fall within the pending
|
|
3083
|
+
* suffix (see {@link remove}).
|
|
3084
|
+
*
|
|
3085
|
+
* @param id - The phase id to move
|
|
3086
|
+
* @param index - The destination position
|
|
3087
|
+
* @returns A {@link Result} boxing the moved phase, or a `MUTATION` failure
|
|
3088
|
+
*/
|
|
3089
|
+
move(id: string, index: number): Result<PhaseInterface, WorkflowError>;
|
|
3090
|
+
/**
|
|
3091
|
+
* Apply a validated {@link PhaseUpdate} patch to the `pending` phase `id` in this workflow.
|
|
3092
|
+
*
|
|
3093
|
+
* @remarks
|
|
3094
|
+
* NATIVE gating: refused while this workflow's own `status` is terminal. Otherwise the
|
|
3095
|
+
* target must exist at an index within the pending suffix (see {@link remove}).
|
|
3096
|
+
*
|
|
3097
|
+
* @param id - The phase id to patch
|
|
3098
|
+
* @param patch - The fields to update
|
|
3099
|
+
* @returns A {@link Result} boxing the patched phase, or a `MUTATION` failure
|
|
3100
|
+
*/
|
|
3101
|
+
update(id: string, patch: PhaseUpdate): Result<PhaseInterface, WorkflowError>;
|
|
2644
3102
|
snapshot(): WorkflowSnapshot;
|
|
2645
3103
|
}
|
|
2646
3104
|
|
|
@@ -2670,6 +3128,19 @@ export declare interface WorkflowOptions {
|
|
|
2670
3128
|
readonly error?: EmitterErrorHandler;
|
|
2671
3129
|
/** Per-phase {@link PhaseOptions}, keyed by the phase's `id`. */
|
|
2672
3130
|
readonly phases?: Readonly<Record<string, PhaseOptions>>;
|
|
3131
|
+
/**
|
|
3132
|
+
* The `function`-task behavior registry ({@link WorkflowFunctions}) each live task's
|
|
3133
|
+
* {@link TaskDefinition.run} / {@link TaskSnapshot.run} name resolves against ONCE at
|
|
3134
|
+
* construction into its runtime {@link TaskInterface.handler} — the SAME registry a
|
|
3135
|
+
* fresh build ({@link import('./factories.js').createWorkflow}) and a restore
|
|
3136
|
+
* ({@link import('./factories.js').restoreWorkflow}) both consume, and the same shape a
|
|
3137
|
+
* live {@link WorkflowInterface.add} / {@link PhaseInterface.add} mint resolves a newly
|
|
3138
|
+
* minted task against. A `run` name absent from `functions` (or omitted entirely)
|
|
3139
|
+
* resolves to no handler — that task AUTO-COMPLETES (the no-handler rule): its
|
|
3140
|
+
* phase/workflow still reaches a terminal status, just with no dispatched behavior.
|
|
3141
|
+
* Omitted ⇒ an empty registry (every task auto-completes).
|
|
3142
|
+
*/
|
|
3143
|
+
readonly functions?: WorkflowFunctions;
|
|
2673
3144
|
}
|
|
2674
3145
|
|
|
2675
3146
|
/**
|
|
@@ -2695,35 +3166,51 @@ export declare interface WorkflowResult {
|
|
|
2695
3166
|
|
|
2696
3167
|
/**
|
|
2697
3168
|
* The thin orchestrator that EXECUTES a live W-b workflow tree by COMPOSING the shipped
|
|
2698
|
-
* substrate — phases sequential, tasks concurrent — dispatching each task
|
|
2699
|
-
*
|
|
3169
|
+
* substrate — phases sequential, tasks concurrent — dispatching each task through its OWN
|
|
3170
|
+
* resolved handler under the `bail` policy.
|
|
2700
3171
|
*
|
|
2701
3172
|
* @remarks
|
|
2702
3173
|
* - **Composes, never re-implements.** Per-phase bounded concurrency is one
|
|
2703
3174
|
* {@link createRunner} per phase (the substrate {@link RunnerInterface} over the workers
|
|
2704
3175
|
* `Queue`); `bail` maps onto that Runner's fail-fast vs settle-all; the run-level abort /
|
|
2705
|
-
* timeout / budget fold through {@link createAbort} / {@link createTimeout} +
|
|
3176
|
+
* timeout / budget / entity `signal` fold through {@link createAbort} / {@link createTimeout} +
|
|
2706
3177
|
* `AbortSignal.any` (exactly as the agent runtime folds its bounds); pacing is the shipped
|
|
2707
3178
|
* {@link SchedulerInterface}. The runner writes ZERO concurrency / retry / abort logic of
|
|
2708
|
-
* its own — it only sequences phases, dispatches a task, and drives the live
|
|
2709
|
-
*
|
|
2710
|
-
*
|
|
2711
|
-
*
|
|
2712
|
-
*
|
|
2713
|
-
*
|
|
2714
|
-
*
|
|
2715
|
-
*
|
|
2716
|
-
*
|
|
2717
|
-
*
|
|
2718
|
-
*
|
|
2719
|
-
*
|
|
2720
|
-
*
|
|
2721
|
-
*
|
|
2722
|
-
*
|
|
2723
|
-
*
|
|
2724
|
-
*
|
|
2725
|
-
*
|
|
2726
|
-
*
|
|
3179
|
+
* its own — it only sequences phases, dispatches a task's own handler, and drives the live
|
|
3180
|
+
* entity.
|
|
3181
|
+
* - **Pure engine — no registries, no tool/agent knowledge.** The runner carries no
|
|
3182
|
+
* `functions` / `tools` / `agents` registry: each live {@link TaskInterface} already
|
|
3183
|
+
* resolved its own {@link import('./types.js').WorkflowFunction} into
|
|
3184
|
+
* {@link import('./types.js').TaskInterface.handler} ONCE at construction (build, restore,
|
|
3185
|
+
* or a live mint all resolve it identically, from {@link WorkflowOptions.functions}), so
|
|
3186
|
+
* dispatch is simply "invoke the task's own handler". Static tool / agent calling is an
|
|
3187
|
+
* OPT-IN concern of the `@orkestrel/tool` package's adapter factories — plain
|
|
3188
|
+
* {@link import('./types.js').WorkflowFunction}s a caller wires into
|
|
3189
|
+
* {@link WorkflowOptions.functions} like any other behavior. This module never imports
|
|
3190
|
+
* any tool/agent package.
|
|
3191
|
+
* - **Two `execute` forms, one engine.** `execute(definition, options)` BUILDS the live tree
|
|
3192
|
+
* from a {@link WorkflowDefinition} (single source of truth for the `run` / `concurrency`
|
|
3193
|
+
* metadata); `execute(workflow, options)` DRIVES a caller-owned, ALREADY-BUILT
|
|
3194
|
+
* {@link WorkflowInterface} instead — the entity-native control surface (AGENTS §10:
|
|
3195
|
+
* `pause` / `resume` / `add` / `stop` / `destroy` live on the entity itself). Both forms
|
|
3196
|
+
* converge on the SAME `#execute` engine: neither reads a `WorkflowDefinition` once the tree
|
|
3197
|
+
* exists — `#runTask` reads each task's OWN {@link import('./types.js').TaskInterface.handler}
|
|
3198
|
+
* / `retries` / `timeout`, and `#runPhase` reads each phase's OWN
|
|
3199
|
+
* {@link PhaseInterface.concurrency} / `bail`, so a live `add`-minted phase or task (V5)
|
|
3200
|
+
* runs under EXACTLY the same rules as one built from the original definition.
|
|
3201
|
+
* - **Phases sequential, tasks concurrent — LIVE continuity.** `#execute` drives the phases in
|
|
3202
|
+
* order, RE-READING `workflow.phases.phases()` every iteration (a cursor over the live
|
|
3203
|
+
* manager, not a one-time snapshot) so a caller's `workflow.add(phaseDefinition)` mid-run is
|
|
3204
|
+
* picked up. Within a phase, `#runPhase` subscribes to that phase's `add` event BEFORE
|
|
3205
|
+
* capturing its task list, then `spawn`s any task added mid-phase onto the SAME substrate
|
|
3206
|
+
* Runner (so it is actually dispatched, under the same `concurrency`); a task added too late
|
|
3207
|
+
* for `spawn` to accept (the runner already drained) is swept `skip`ped afterward so the
|
|
3208
|
+
* phase always reaches a coherent terminal state.
|
|
3209
|
+
* - **Dispatch by handler.** `#runTask` invokes the live task's own
|
|
3210
|
+
* {@link import('./types.js').TaskInterface.handler} directly: `undefined` (an omitted `run`,
|
|
3211
|
+
* or a `run` name absent from the {@link WorkflowOptions.functions} registry it was resolved
|
|
3212
|
+
* against) AUTO-COMPLETES — the ROADMAP no-handler rule; otherwise the handler runs with the
|
|
3213
|
+
* task's {@link import('./types.js').TaskControllerInterface} handle.
|
|
2727
3214
|
* - **`bail` → substrate.** Under `bail: true` (halt) a genuine task failure `fail`s the leaf
|
|
2728
3215
|
* THEN re-throws, so the substrate Runner fail-fasts — it aborts the in-flight siblings
|
|
2729
3216
|
* (their `controller.signal` fires; a mid-flight sibling `skip`s) and rejects the phase run;
|
|
@@ -2731,7 +3218,20 @@ export declare interface WorkflowResult {
|
|
|
2731
3218
|
* Under `bail: false` (graceful) a failure `fail`s the leaf and RESOLVES (never throws), so
|
|
2732
3219
|
* the Runner settles every unit (allSettled) and the run finishes (the workflow derives
|
|
2733
3220
|
* `completed`, the failure recorded in the result tree).
|
|
2734
|
-
* - **
|
|
3221
|
+
* - **Pause / stop / destroy gates.** `workflow.pause()` is honoured at exactly two points —
|
|
3222
|
+
* the next phase boundary (workflow-only) and each task's own pre-dispatch (before
|
|
3223
|
+
* `task.start()`, workflow gate FIRST then this task's own `phase.pause()`) — by parking on
|
|
3224
|
+
* {@link WorkflowInterface.wait} / {@link PhaseInterface.wait}; an in-flight task body is
|
|
3225
|
+
* NEVER suspended mid-flight. A GRACEFUL `workflow.stop()` (no signal involved) is caught at
|
|
3226
|
+
* those same gates: not-yet-started work is `skip`ped, in-flight work finishes naturally. A
|
|
3227
|
+
* HARD `workflow.destroy()` aborts {@link WorkflowInterface.signal}, which `#fold` has folded
|
|
3228
|
+
* into the run's composed signal — so it cancels the active phase Runner (and every
|
|
3229
|
+
* in-flight task) exactly like an external abort / timeout / budget fire. EVERY park on a
|
|
3230
|
+
* `wait()` gate is RACED against that same run signal (`#raceWait`, S2) — so a cancel firing
|
|
3231
|
+
* WHILE parked unparks the engine promptly instead of hanging until `resume`; the existing
|
|
3232
|
+
* halt / abort re-checks after the gate then decide the outcome.
|
|
3233
|
+
* - **Abort / Timeout / Budget / entity-signal fold.** `#execute` folds the live workflow's
|
|
3234
|
+
* own {@link WorkflowInterface.signal}, the run's external `signal`, a
|
|
2735
3235
|
* {@link TimeoutInterface}, and the `@orkestrel/budget` package's `BudgetInterface`'s
|
|
2736
3236
|
* `signal` into one `runSignal` (`AbortSignal.any`); a fire aborts the active phase's Runner
|
|
2737
3237
|
* (cancelling every in-flight task) and HALTS the run — the remaining tasks / phases `skip`
|
|
@@ -2739,19 +3239,77 @@ export declare interface WorkflowResult {
|
|
|
2739
3239
|
* {@link TaskController} signal `AbortSignal.any`-combines the substrate per-unit signal with
|
|
2740
3240
|
* `runSignal`, so a handler observes either cause directly.
|
|
2741
3241
|
* - **Re-entrant-safe.** No shared per-run mutable field: the active-Runner holder is LOCAL to
|
|
2742
|
-
* each `#execute`, so a nested `execute` (
|
|
2743
|
-
* while the outer run is suspended
|
|
3242
|
+
* each `#execute`, so a nested `execute` (a bound workflow-tool handler re-entering this
|
|
3243
|
+
* instance while the outer run is suspended awaiting it) cannot clobber the outer run's state.
|
|
2744
3244
|
*/
|
|
2745
3245
|
export declare class WorkflowRunner implements WorkflowRunnerInterface {
|
|
2746
3246
|
#private;
|
|
2747
|
-
constructor(
|
|
3247
|
+
constructor(scheduler: SchedulerInterface);
|
|
3248
|
+
/**
|
|
3249
|
+
* Execute a workflow definition to completion — BUILD its live tree, run the phases
|
|
3250
|
+
* sequentially with each phase's tasks concurrent — resolving its terminal
|
|
3251
|
+
* {@link WorkflowResult} (whose `workflow` is the freshly-built live tree).
|
|
3252
|
+
*
|
|
3253
|
+
* @remarks
|
|
3254
|
+
* One-shot. The runner BUILDS the live tree from `definition` internally (one source of
|
|
3255
|
+
* truth — the per-task `run` and per-phase `concurrency` come from the same definition
|
|
3256
|
+
* the tree is constructed from, so the executed tree can never drift from the metadata).
|
|
3257
|
+
* The {@link WorkflowOptions} part of `options` (initial `on` listeners, a `bail` override,
|
|
3258
|
+
* the per-node `phases` bag, the {@link WorkflowOptions.functions} registry each task's
|
|
3259
|
+
* `run` resolves against) is forwarded to the build. Under `bail: false` (graceful) every
|
|
3260
|
+
* task settles (a failure is recorded on its {@link TaskInterface}) and the workflow
|
|
3261
|
+
* reaches `completed`; under `bail: true` (halt) the first failure aborts the in-flight
|
|
3262
|
+
* sibling tasks AND `skip`s the remaining tasks / phases, settling the workflow `failed`. A
|
|
3263
|
+
* {@link WorkflowRunOptions} abort / timeout / budget fires every in-flight task's signal
|
|
3264
|
+
* and `stop`s the run. `execute` resolves (never rejects) on a cancel — the partial outcome
|
|
3265
|
+
* is read from the returned {@link WorkflowResult} (its `workflow` / `status` / `results`).
|
|
3266
|
+
*
|
|
3267
|
+
* @param definition - The {@link WorkflowDefinition} to build the live tree from and drive
|
|
3268
|
+
* @param options - The construction options ({@link WorkflowOptions}: `on` / `bail` /
|
|
3269
|
+
* `phases` / `functions`) PLUS the per-run bounds (`signal` / `timeout` / `budget`)
|
|
3270
|
+
* @returns The run's terminal {@link WorkflowResult} (its `workflow` is the built tree)
|
|
3271
|
+
* @example
|
|
3272
|
+
* ```ts
|
|
3273
|
+
* const result = await runner.execute(definition, { timeout: 5_000 })
|
|
3274
|
+
* result.status // 'completed' | 'failed' | 'stopped'
|
|
3275
|
+
* ```
|
|
3276
|
+
*/
|
|
2748
3277
|
execute(definition: WorkflowDefinition, options?: WorkflowRunOptions): Promise<WorkflowResult>;
|
|
3278
|
+
/**
|
|
3279
|
+
* Drive an ALREADY-BUILT, CALLER-OWNED live {@link WorkflowInterface} — the entity-native
|
|
3280
|
+
* counterpart to the definition-building {@link execute} overload.
|
|
3281
|
+
*
|
|
3282
|
+
* @remarks
|
|
3283
|
+
* `createWorkflow` mints the live tree, this overload drives it, and the caller controls
|
|
3284
|
+
* the SAME entity mid-run via its own `pause` / `resume` / `add` / `stop` / `destroy`
|
|
3285
|
+
* (AGENTS §10). Requires `workflow.status === 'pending'` and `!workflow.destroyed` —
|
|
3286
|
+
* otherwise this is a programmer-timing error and it THROWS a `TRANSITION`
|
|
3287
|
+
* {@link WorkflowError} (AGENTS §12) rather than silently no-opping or building a second
|
|
3288
|
+
* tree. Once accepted, observable semantics are byte-identical to the `definition` form —
|
|
3289
|
+
* except the phase loop RE-READS the live tree every iteration, so a caller's live `add`
|
|
3290
|
+
* mid-run is picked up and actually dispatched. `options` carries only the per-run bounds
|
|
3291
|
+
* (`signal` / `timeout` / `budget`) — the construction half of {@link WorkflowRunOptions}
|
|
3292
|
+
* does not apply, since the tree already exists.
|
|
3293
|
+
*
|
|
3294
|
+
* @param workflow - The live {@link WorkflowInterface} to drive
|
|
3295
|
+
* @param options - The per-run bounds (`signal` / `timeout` / `budget`)
|
|
3296
|
+
* @returns The run's terminal {@link WorkflowResult} (its `workflow` is the SAME entity passed in)
|
|
3297
|
+
* @example
|
|
3298
|
+
* ```ts
|
|
3299
|
+
* const workflow = createWorkflow(definition)
|
|
3300
|
+
* const run = runner.execute(workflow)
|
|
3301
|
+
* workflow.pause()
|
|
3302
|
+
* workflow.resume()
|
|
3303
|
+
* await run
|
|
3304
|
+
* ```
|
|
3305
|
+
*/
|
|
3306
|
+
execute(workflow: WorkflowInterface, options?: Omit<WorkflowRunOptions, keyof WorkflowOptions>): Promise<WorkflowResult>;
|
|
2749
3307
|
}
|
|
2750
3308
|
|
|
2751
3309
|
/**
|
|
2752
3310
|
* A thin orchestrator that EXECUTES a live {@link WorkflowInterface} tree by composing the
|
|
2753
|
-
* shipped substrate — phases sequential, tasks concurrent,
|
|
2754
|
-
* `bail` policy.
|
|
3311
|
+
* shipped substrate — phases sequential, tasks concurrent, each task dispatched through its
|
|
3312
|
+
* OWN resolved handler under the `bail` policy.
|
|
2755
3313
|
*
|
|
2756
3314
|
* @remarks
|
|
2757
3315
|
* `execute(definition, options?)` BUILDS the live W-b entity tree from the definition itself
|
|
@@ -2760,18 +3318,22 @@ export declare class WorkflowRunner implements WorkflowRunnerInterface {
|
|
|
2760
3318
|
* through ONE substrate {@link RunnerInterface} (concurrency =
|
|
2761
3319
|
* the phase's {@link PhaseDefinition.concurrency}). The definition is the SINGLE source of
|
|
2762
3320
|
* truth: the runner owns both the declarative state (the live tree it constructs) and the
|
|
2763
|
-
* EXECUTION-ONLY
|
|
2764
|
-
*
|
|
2765
|
-
*
|
|
2766
|
-
*
|
|
2767
|
-
* {@link
|
|
2768
|
-
*
|
|
2769
|
-
* → `complete` / `fail`), never
|
|
2770
|
-
* substrate's fail-fast (`bail: true`
|
|
2771
|
-
* the rest) vs settle-all (`bail:
|
|
2772
|
-
*
|
|
2773
|
-
* listeners, a `bail` override,
|
|
2774
|
-
* per
|
|
3321
|
+
* EXECUTION-ONLY field the snapshot deliberately dropped — each task's `run` (resolved into
|
|
3322
|
+
* its {@link TaskInterface.handler} once at construction, against
|
|
3323
|
+
* {@link WorkflowOptions.functions}) and each phase's `concurrency` (so there is no
|
|
3324
|
+
* separately-supplied workflow to drift from the definition). The freshly-built live tree is
|
|
3325
|
+
* returned in {@link WorkflowResult.workflow}. The runner carries NO registry of its own — it
|
|
3326
|
+
* simply invokes each task's OWN {@link TaskInterface.handler}; a task with no handler
|
|
3327
|
+
* AUTO-COMPLETES. The runner DRIVES the live entity (`start` → `complete` / `fail`), never
|
|
3328
|
+
* re-implementing status. The `bail` policy maps onto the substrate's fail-fast (`bail: true`
|
|
3329
|
+
* — the first failure aborts in-flight siblings and skips the rest) vs settle-all (`bail:
|
|
3330
|
+
* false` — failures are recorded and the run finishes). The {@link WorkflowOptions} half of
|
|
3331
|
+
* the options is forwarded to `createWorkflow` (initial listeners, a `bail` override,
|
|
3332
|
+
* per-node options, the `functions` registry); the Abort / Timeout / Budget bounds fold per
|
|
3333
|
+
* run via `AbortSignal.any`, halting the run and `stop`ping the workflow. A second
|
|
3334
|
+
* `execute(workflow, options?)` overload drives a CALLER-BUILT live tree instead — the
|
|
3335
|
+
* entity-native control surface (AGENTS §10: `pause` / `resume` / `add` / `stop` /
|
|
3336
|
+
* `destroy` live on {@link WorkflowInterface} itself); see its own doc for details.
|
|
2775
3337
|
*/
|
|
2776
3338
|
export declare interface WorkflowRunnerInterface {
|
|
2777
3339
|
/**
|
|
@@ -2781,10 +3343,11 @@ export declare interface WorkflowRunnerInterface {
|
|
|
2781
3343
|
*
|
|
2782
3344
|
* @remarks
|
|
2783
3345
|
* One-shot. The runner BUILDS the live tree from `definition` internally (one source of
|
|
2784
|
-
* truth — the per-task {@link
|
|
2785
|
-
* same definition the tree is constructed from, so the executed
|
|
2786
|
-
* the
|
|
2787
|
-
* listeners, a `bail` override, the per-node `phases` bag
|
|
3346
|
+
* truth — the per-task `run` (resolved into its {@link TaskInterface.handler}) and per-phase
|
|
3347
|
+
* `concurrency` come from the same definition the tree is constructed from, so the executed
|
|
3348
|
+
* tree can never drift from the metadata). The {@link WorkflowOptions} part of `options`
|
|
3349
|
+
* (initial `on` listeners, a `bail` override, the per-node `phases` bag, the `functions`
|
|
3350
|
+
* registry) is forwarded to the build.
|
|
2788
3351
|
* Under `bail: false` (graceful) every task settles (a failure is recorded on its
|
|
2789
3352
|
* {@link TaskInterface}) and the workflow reaches `completed`; under `bail: true` (halt)
|
|
2790
3353
|
* the first failure aborts the in-flight sibling tasks AND `skip`s the remaining tasks /
|
|
@@ -2796,33 +3359,73 @@ export declare interface WorkflowRunnerInterface {
|
|
|
2796
3359
|
* the run as `stopped` — the cancel supersedes the same-tick failure, and that task's error
|
|
2797
3360
|
* is not recorded.
|
|
2798
3361
|
*
|
|
3362
|
+
* **Programmer-error exception (AGENTS §12).** A PATHOLOGICAL `definition` (e.g. a
|
|
3363
|
+
* duplicate phase or task `id`) THROWS SYNCHRONOUSLY at construction — before any phase
|
|
3364
|
+
* runs, and before the returned `Promise` is even created — rather than resolving a
|
|
3365
|
+
* failed/partial {@link WorkflowResult}. This is the one exception to the "resolves,
|
|
3366
|
+
* never rejects" contract above: a malformed definition is a programmer-timing error, not
|
|
3367
|
+
* a runtime outcome to report through the result tree.
|
|
3368
|
+
*
|
|
2799
3369
|
* @param definition - The {@link WorkflowDefinition} to build the live tree from and drive
|
|
2800
3370
|
* @param options - The construction options ({@link WorkflowOptions}: `on` / `bail` /
|
|
2801
3371
|
* `phases`) PLUS the per-run bounds (`signal` / `timeout` / `budget`)
|
|
2802
3372
|
* @returns The run's terminal {@link WorkflowResult} (its `workflow` is the built tree)
|
|
2803
3373
|
*/
|
|
2804
3374
|
execute(definition: WorkflowDefinition, options?: WorkflowRunOptions): Promise<WorkflowResult>;
|
|
3375
|
+
/**
|
|
3376
|
+
* Drive an ALREADY-BUILT, CALLER-OWNED live {@link WorkflowInterface} — the
|
|
3377
|
+
* ENTITY-NATIVE counterpart to the definition-building {@link execute} overload.
|
|
3378
|
+
*
|
|
3379
|
+
* @remarks
|
|
3380
|
+
* The entity itself is now the single control surface (no separate run handle):
|
|
3381
|
+
* `createWorkflow` mints the live tree, this overload drives it, and the caller
|
|
3382
|
+
* controls the SAME entity mid-run via its own `pause` / `resume` / `add` / `stop` /
|
|
3383
|
+
* `destroy` (AGENTS §10). Requires `workflow.status === 'pending'` and
|
|
3384
|
+
* `!workflow.destroyed` — otherwise this is a programmer-timing error and it THROWS a
|
|
3385
|
+
* `TRANSITION` {@link import('./errors.js').WorkflowError} (AGENTS §12) rather than
|
|
3386
|
+
* silently no-opping or building a second tree. Once accepted, phases run
|
|
3387
|
+
* SEQUENTIALLY and, within each phase, tasks CONCURRENTLY — byte-identical observable
|
|
3388
|
+
* semantics to the `definition`-form `execute` — except the phase loop RE-READS the
|
|
3389
|
+
* live `workflow.phases` / each phase's live `tasks` every iteration (a cursor over
|
|
3390
|
+
* the live managers, not a one-time snapshot), so a caller's live `add` mid-run is
|
|
3391
|
+
* picked up and actually dispatched. `workflow.pause()` gates the run at the next
|
|
3392
|
+
* phase boundary AND before each task's dispatch (an in-flight task body is never
|
|
3393
|
+
* suspended); `workflow.stop()` skips not-yet-started work gracefully; `workflow.destroy()`
|
|
3394
|
+
* folds `workflow.signal` into the run's cancellation, aborting in-flight work
|
|
3395
|
+
* immediately. `options` carries only the per-run BOUNDS (`signal` / `timeout` /
|
|
3396
|
+
* `budget`) — the construction half of {@link WorkflowRunOptions}
|
|
3397
|
+
* does not apply, since the tree already exists.
|
|
3398
|
+
*
|
|
3399
|
+
* **Run round-trips through the snapshot.** Driving a tree rebuilt by
|
|
3400
|
+
* {@link import('./factories.js').restoreWorkflow} behaves according to whether a
|
|
3401
|
+
* {@link WorkflowFunctions} registry was supplied at that build: WITH a registry,
|
|
3402
|
+
* each task's `run` name is re-resolved against it, so a matched task carries a real
|
|
3403
|
+
* handler and this overload actually DISPATCHES it, resuming real work. WITHOUT a
|
|
3404
|
+
* registry (or when a task's `run` name has no match in it), the task's
|
|
3405
|
+
* {@link TaskInterface.run} is `undefined` — the no-handler rule then AUTO-COMPLETES
|
|
3406
|
+
* that task (no dispatch occurs). A PARTIALLY-run restored tree (any live phase/task
|
|
3407
|
+
* not `pending`) is rejected outright by the `workflow.status === 'pending'` guard
|
|
3408
|
+
* above — only a wholly `pending` restored tree is drivable.
|
|
3409
|
+
*
|
|
3410
|
+
* @param workflow - The live {@link WorkflowInterface} to drive (its own entity surface —
|
|
3411
|
+
* `pause` / `resume` / `add` / `stop` / `destroy` — is the caller's control seam)
|
|
3412
|
+
* @param options - The per-run bounds (`signal` / `timeout` / `budget`); the construction
|
|
3413
|
+
* half of {@link WorkflowRunOptions} does not apply (the tree already exists)
|
|
3414
|
+
* @returns The run's terminal {@link WorkflowResult} (its `workflow` is the SAME entity passed in)
|
|
3415
|
+
*/
|
|
3416
|
+
execute(workflow: WorkflowInterface, options?: Omit<WorkflowRunOptions, keyof WorkflowOptions>): Promise<WorkflowResult>;
|
|
2805
3417
|
}
|
|
2806
3418
|
|
|
2807
3419
|
/**
|
|
2808
|
-
* The options for `createWorkflowRunner` — the
|
|
2809
|
-
*
|
|
2810
|
-
*
|
|
2811
|
-
* @remarks
|
|
2812
|
-
*
|
|
2813
|
-
*
|
|
2814
|
-
*
|
|
2815
|
-
* -
|
|
2816
|
-
*
|
|
2817
|
-
* invokes it with the task's input. An unregistered tool name is the no-handler case
|
|
2818
|
-
* (auto-completes). Omitted ⇒ every `tool` task auto-completes.
|
|
2819
|
-
* - `agents` — the {@link WorkflowAgents} resolver (W-c2) an `agent`-form task is dispatched
|
|
2820
|
-
* through: the runner resolves `run.name` to a live
|
|
2821
|
-
* {@link AgentInterface}, BINDS a depth/cycle-aware workflow
|
|
2822
|
-
* tool onto its `context.tools` (the propagation seam), folds the task's cancellation into
|
|
2823
|
-
* the agent run, and drives it (success → `complete`, throw → `fail`), all behind the
|
|
2824
|
-
* depth + cycle guard. An unregistered agent name is the no-handler case (auto-completes).
|
|
2825
|
-
* Omitted ⇒ every `agent` task auto-completes.
|
|
3420
|
+
* The options for `createWorkflowRunner` — the optional pacing scheduler the runner
|
|
3421
|
+
* paces phase boundaries with.
|
|
3422
|
+
*
|
|
3423
|
+
* @remarks
|
|
3424
|
+
* The runner is a PURE engine — it carries no `functions` / `tools` / `agents` registry
|
|
3425
|
+
* (each live task already resolved its own handler at construction from
|
|
3426
|
+
* {@link WorkflowOptions.functions}); wiring a `function`-form task to a tool or an agent is
|
|
3427
|
+
* an OPT-IN concern of the `@orkestrel/tool` package's adapter factories, which a caller
|
|
3428
|
+
* composes into its OWN `functions` registry.
|
|
2826
3429
|
* - `scheduler` — the {@link SchedulerInterface} that paces the tree (a cooperative
|
|
2827
3430
|
* `yield` between phases). Omitted ⇒ the shipped cross-environment default
|
|
2828
3431
|
* ({@link createScheduler}).
|
|
@@ -2833,10 +3436,6 @@ export declare interface WorkflowRunnerInterface {
|
|
|
2833
3436
|
* wire. A future runner-level emitter would introduce its own `EmitterHooks` here.
|
|
2834
3437
|
*/
|
|
2835
3438
|
export declare interface WorkflowRunnerOptions {
|
|
2836
|
-
readonly functions?: WorkflowFunctions;
|
|
2837
|
-
readonly tools?: ToolManagerInterface;
|
|
2838
|
-
/** The {@link WorkflowAgents} resolver for `agent`-form tasks (W-c2); omitted ⇒ every `agent` task auto-completes. */
|
|
2839
|
-
readonly agents?: WorkflowAgents;
|
|
2840
3439
|
readonly scheduler?: SchedulerInterface;
|
|
2841
3440
|
}
|
|
2842
3441
|
|
|
@@ -2869,28 +3468,15 @@ export declare interface WorkflowRunnerOptions {
|
|
|
2869
3468
|
* `signal` and `start`s it. (A `max: 0` budget is exhausted from its first `start`, so it
|
|
2870
3469
|
* cancels the run at entry — a DIFFERENT primitive from the `timeout: 0` "no deadline" case.)
|
|
2871
3470
|
*
|
|
2872
|
-
* The
|
|
2873
|
-
*
|
|
2874
|
-
*
|
|
2875
|
-
*
|
|
2876
|
-
* runner-bound workflow tool ({@link import('./factories.js').createWorkflowTool}) supplies
|
|
2877
|
-
* them, incrementing the depth and extending the ancestry for each nested run.
|
|
2878
|
-
* - `depth` — the run's nesting depth (default `0`). An `agent` task is REJECTED (a typed
|
|
2879
|
-
* `DEPTH` `task.fail`) when running it would push the chain past
|
|
2880
|
-
* {@link import('./constants.js').MAX_WORKFLOW_DEPTH}.
|
|
2881
|
-
* - `ancestry` — the identifiers of the workflows + agents already in this run chain
|
|
2882
|
-
* (e.g. `workflow:<id>` / `agent:<name>`). An `agent` task whose target agent — or the
|
|
2883
|
-
* workflow it would author — is already present is a CYCLE and is likewise rejected.
|
|
2884
|
-
* Default empty.
|
|
3471
|
+
* The engine itself carries NO nesting bookkeeping — the depth / cycle guard for a nested
|
|
3472
|
+
* `agent` → workflow-tool → workflow chain lives entirely in the OPT-IN adapter factories
|
|
3473
|
+
* shipped by `@orkestrel/tool`, closed over their own `depth` / `ancestry`, never threaded
|
|
3474
|
+
* through `execute`'s options.
|
|
2885
3475
|
*/
|
|
2886
3476
|
export declare type WorkflowRunOptions = WorkflowOptions & {
|
|
2887
3477
|
readonly signal?: AbortSignal;
|
|
2888
3478
|
readonly timeout?: number;
|
|
2889
3479
|
readonly budget?: BudgetInterface<TokenUsage>;
|
|
2890
|
-
/** The run's nesting depth (W-c2); default `0`. Threaded by the bound workflow tool, never by a top-level caller. */
|
|
2891
|
-
readonly depth?: number;
|
|
2892
|
-
/** The workflow / agent identifiers already in this run chain (W-c2 cycle guard); default empty. */
|
|
2893
|
-
readonly ancestry?: readonly string[];
|
|
2894
3480
|
};
|
|
2895
3481
|
|
|
2896
3482
|
/**
|
|
@@ -2911,16 +3497,7 @@ export declare const workflowShape: ObjectShape<{
|
|
|
2911
3497
|
id: StringShape;
|
|
2912
3498
|
name: StringShape;
|
|
2913
3499
|
description: OptionalShape<StringShape>;
|
|
2914
|
-
run:
|
|
2915
|
-
via: LiteralShape<readonly ["function"]>;
|
|
2916
|
-
name: StringShape;
|
|
2917
|
-
}>, ObjectShape<{
|
|
2918
|
-
via: LiteralShape<readonly ["tool"]>;
|
|
2919
|
-
name: StringShape;
|
|
2920
|
-
}>, ObjectShape<{
|
|
2921
|
-
via: LiteralShape<readonly ["agent"]>;
|
|
2922
|
-
name: StringShape;
|
|
2923
|
-
}>]>;
|
|
3500
|
+
run: OptionalShape<StringShape>;
|
|
2924
3501
|
retries: OptionalShape<NumberShape>;
|
|
2925
3502
|
timeout: OptionalShape<NumberShape>;
|
|
2926
3503
|
}>>;
|
|
@@ -2993,57 +3570,6 @@ export declare interface WorkflowSnapshotRow {
|
|
|
2993
3570
|
*/
|
|
2994
3571
|
export declare type WorkflowStatus = LifecycleStatus;
|
|
2995
3572
|
|
|
2996
|
-
/**
|
|
2997
|
-
* One flat step — `{ name, via? }` — the building block of a {@link WorkflowSteps} blob.
|
|
2998
|
-
*
|
|
2999
|
-
* @remarks
|
|
3000
|
-
* `name` is the REGISTERED behavior name the step runs (it becomes the task's `run.name`,
|
|
3001
|
-
* NOT a human label). `via` is the optional execution mechanism — `'function'` (the
|
|
3002
|
-
* default when omitted), `'tool'`, or `'agent'`.
|
|
3003
|
-
*/
|
|
3004
|
-
export declare interface WorkflowStep {
|
|
3005
|
-
/** The registered behavior name this step runs (becomes the task's `run.name`). */
|
|
3006
|
-
readonly name: string;
|
|
3007
|
-
/** How to run it — `'function'` (default), `'tool'`, or `'agent'`. */
|
|
3008
|
-
readonly via?: TaskVia;
|
|
3009
|
-
}
|
|
3010
|
-
|
|
3011
|
-
/**
|
|
3012
|
-
* The FLAT authoring blob `createWorkflowTool` advertises — `{ name?, steps }` — the
|
|
3013
|
-
* simplest surface a small model can fill.
|
|
3014
|
-
*
|
|
3015
|
-
* @remarks
|
|
3016
|
-
* Each {@link WorkflowStep} becomes a one-task phase, in order
|
|
3017
|
-
* ({@link import('./helpers.js').expandSteps}); `name` is the optional workflow name
|
|
3018
|
-
* (defaulted when omitted). The expanded tree is validated against the STRICT
|
|
3019
|
-
* {@link import('./factories.js').createWorkflowContract} gate before running.
|
|
3020
|
-
*/
|
|
3021
|
-
export declare interface WorkflowSteps {
|
|
3022
|
-
readonly name?: string;
|
|
3023
|
-
readonly steps: readonly WorkflowStep[];
|
|
3024
|
-
}
|
|
3025
|
-
|
|
3026
|
-
/**
|
|
3027
|
-
* The FLAT authoring shape `createWorkflowTool` advertises as its `parameters` — the
|
|
3028
|
-
* simplest surface a small model can fill: `{ name?, steps: [{ name, via? }] }`.
|
|
3029
|
-
*
|
|
3030
|
-
* @remarks
|
|
3031
|
-
* The deliberately-reduced surface (AGENTS §21): a flat ordered list of steps, each a
|
|
3032
|
-
* `{ name, via? }`. The tool EXPANDS it ({@link import('./helpers.js').expandSteps}) into a
|
|
3033
|
-
* full {@link import('./types.js').WorkflowDefinition} — one one-task phase per step, in
|
|
3034
|
-
* order — then validates against the STRICT
|
|
3035
|
-
* {@link import('./factories.js').createWorkflowContract} gate. The full nested form is
|
|
3036
|
-
* STILL accepted by the tool (it branches on the args' shape) and is documented as the
|
|
3037
|
-
* advanced escape-hatch in the tool's description — but THIS is what `parameters` advertises.
|
|
3038
|
-
*/
|
|
3039
|
-
export declare const workflowStepsShape: ObjectShape<{
|
|
3040
|
-
name: OptionalShape<StringShape>;
|
|
3041
|
-
steps: ArrayShape<ObjectShape<{
|
|
3042
|
-
name: StringShape;
|
|
3043
|
-
via: OptionalShape<LiteralShape<readonly ["function", "tool", "agent"]>>;
|
|
3044
|
-
}>>;
|
|
3045
|
-
}>;
|
|
3046
|
-
|
|
3047
3573
|
/**
|
|
3048
3574
|
* The durable persistence seam for a {@link WorkflowSnapshot} — three async primitives
|
|
3049
3575
|
* (`get` / `set` / `delete`) keyed by a workflow id, the snapshot analogue of
|
|
@@ -3091,89 +3617,4 @@ export declare interface WorkflowStoreInterface {
|
|
|
3091
3617
|
delete(id: string): Promise<void>;
|
|
3092
3618
|
}
|
|
3093
3619
|
|
|
3094
|
-
/**
|
|
3095
|
-
* The ancestry identifier of a workflow run — `workflow:<id>`.
|
|
3096
|
-
*
|
|
3097
|
-
* @remarks
|
|
3098
|
-
* The {@link import('./WorkflowRunner.js').WorkflowRunner}'s cycle guard records one of
|
|
3099
|
-
* these per workflow in the current nested run chain (carried on
|
|
3100
|
-
* {@link import('./types.js').WorkflowRunOptions.ancestry}). Tagging the bare id keeps a
|
|
3101
|
-
* workflow id and an {@link agentTag} agent name in ONE namespaced set without collision,
|
|
3102
|
-
* so re-entering a workflow OR an agent already in the chain is a single `includes` check.
|
|
3103
|
-
*
|
|
3104
|
-
* @param id - The workflow definition's `id`
|
|
3105
|
-
* @returns The namespaced ancestry tag (`workflow:<id>`)
|
|
3106
|
-
*/
|
|
3107
|
-
export declare function workflowTag(id: string): string;
|
|
3108
|
-
|
|
3109
|
-
/**
|
|
3110
|
-
* The workflow-tool binder — the signature of {@link import('./factories.js').createWorkflowTool},
|
|
3111
|
-
* threaded into the {@link WorkflowRunnerInterface} at construction (W-c2) so the runner can BIND a
|
|
3112
|
-
* depth/cycle-aware workflow tool onto a dispatched subagent.
|
|
3113
|
-
*
|
|
3114
|
-
* @remarks
|
|
3115
|
-
* The runner receives a REFERENCE to `createWorkflowTool` rather than importing it, because
|
|
3116
|
-
* `createWorkflowTool` lives in `factories.ts` which imports the runner CLASS (the
|
|
3117
|
-
* factories→classes direction); importing the factory back into the class would be a cycle. The
|
|
3118
|
-
* factory (which legitimately owns `createWorkflowContract`) is passed as a value at construction,
|
|
3119
|
-
* and the runner invokes it with `this` as the `runner` argument — keeping the cycle-free seam an
|
|
3120
|
-
* explicit, typed contract rather than a hidden dependency.
|
|
3121
|
-
*
|
|
3122
|
-
* @param definition - The workflow the bound tool runs when called with no authored args
|
|
3123
|
-
* @param runner - The runner that executes the (nested) workflow (the runner passes `this`)
|
|
3124
|
-
* @param options - The depth + ancestry the nested workflow runs under (see {@link WorkflowToolOptions})
|
|
3125
|
-
* @returns The bound {@link ToolInterface}
|
|
3126
|
-
*/
|
|
3127
|
-
export declare type WorkflowToolBinder = (definition: WorkflowDefinition, runner: WorkflowRunnerInterface, options?: WorkflowToolOptions) => ToolInterface;
|
|
3128
|
-
|
|
3129
|
-
/**
|
|
3130
|
-
* Options for {@link import('./factories.js').createWorkflowTool} — the depth + ancestry the
|
|
3131
|
-
* wrapped {@link WorkflowDefinition} runs the NESTED workflow at when an LLM invokes the tool.
|
|
3132
|
-
*
|
|
3133
|
-
* @remarks
|
|
3134
|
-
* This is the PROPAGATION carrier across the agent/tool boundary. A `Tool`'s handler receives
|
|
3135
|
-
* ONLY the model-supplied `args` (no ambient context, no signal — see
|
|
3136
|
-
* the `@orkestrel/agent` package's `ToolOptions`), so the run's position in the
|
|
3137
|
-
* workflow→agent→workflow chain CANNOT be threaded through a tool call at runtime. Instead the
|
|
3138
|
-
* runner CLOSES it over the tool at BIND time: when it dispatches an `agent` task at depth `D`
|
|
3139
|
-
* with ancestry `A`, it builds the agent's workflow tool with `{ depth: D, ancestry: A }`, so
|
|
3140
|
-
* the handler's closure carries them. On invocation the handler runs the nested workflow at
|
|
3141
|
-
* `depth: D + 1` with `ancestry: A ∪ { workflow:<id> }` — bounded by
|
|
3142
|
-
* {@link import('./constants.js').MAX_WORKFLOW_DEPTH} (an over-deep / cyclic nested run THROWS a
|
|
3143
|
-
* typed `DEPTH` {@link import('./errors.js').WorkflowError}, which the `ToolManager` isolates into
|
|
3144
|
-
* the tool result's top-level `error`, AGENTS §14).
|
|
3145
|
-
*
|
|
3146
|
-
* Both fields are OPTIONAL: a workflow tool built for a TOP-LEVEL caller (not by the runner's
|
|
3147
|
-
* agent-task binding) omits them — its nested run starts the chain at depth `1` with the bare
|
|
3148
|
-
* `workflow:<id>` ancestry.
|
|
3149
|
-
*/
|
|
3150
|
-
export declare interface WorkflowToolOptions {
|
|
3151
|
-
/** The depth the INVOKING agent runs at; the nested workflow runs at `depth + 1`. Default `0`. */
|
|
3152
|
-
readonly depth?: number;
|
|
3153
|
-
/** The ancestry of the invoking run; the nested run extends it with its own `workflow:<id>`. Default empty. */
|
|
3154
|
-
readonly ancestry?: readonly string[];
|
|
3155
|
-
}
|
|
3156
|
-
|
|
3157
|
-
/**
|
|
3158
|
-
* Summarize a terminal {@link WorkflowResult} into the PLAIN value a
|
|
3159
|
-
* {@link import('./factories.js').createWorkflowTool} handler returns on success.
|
|
3160
|
-
*
|
|
3161
|
-
* @remarks
|
|
3162
|
-
* This is the run summary the handler returns DIRECTLY — NOT a `ToolResult` (the future `@orkestrel/agent` package).
|
|
3163
|
-
* The handler conforms to the universal tool-handler contract (AGENTS §14): it returns the plain value
|
|
3164
|
-
* (and throws on failure), so the `@orkestrel/agent` package's `ToolManager` performs
|
|
3165
|
-
* the ONE canonical wrap (`{ id, name, value }`) and the model reads exactly this summary — once,
|
|
3166
|
-
* identically — over BOTH the agent loop and MCP. The summary is LEAN: the workflow's terminal `status`
|
|
3167
|
-
* and the COUNT of settled task results — enough for a caller / model to react without serializing the
|
|
3168
|
-
* whole live tree. (It carries no synthetic `id` / `name`: a tool handler has no call id; the manager
|
|
3169
|
-
* supplies the canonical envelope's identity.)
|
|
3170
|
-
*
|
|
3171
|
-
* @param result - The terminal {@link WorkflowResult} the run produced
|
|
3172
|
-
* @returns The plain success summary — `{ status, count }`
|
|
3173
|
-
*/
|
|
3174
|
-
export declare function workflowToolSummary(result: WorkflowResult): Readonly<{
|
|
3175
|
-
status: WorkflowStatus;
|
|
3176
|
-
count: number;
|
|
3177
|
-
}>;
|
|
3178
|
-
|
|
3179
3620
|
export { }
|