footprintjs 5.0.0 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +51 -8
- package/README.md +1 -0
- package/dist/advanced.js +2 -3
- package/dist/esm/advanced.js +2 -2
- package/dist/esm/index.js +2 -2
- package/dist/esm/lib/builder/FlowChartBuilder.js +552 -103
- package/dist/esm/lib/builder/index.js +2 -2
- package/dist/esm/lib/builder/structure/StructureRecorder.js +158 -0
- package/dist/esm/lib/builder/structure/StructureRecorderDispatcher.js +171 -0
- package/dist/esm/lib/builder/types.js +1 -1
- package/dist/esm/lib/engine/errors/errorInfo.js +4 -3
- package/dist/esm/lib/engine/handlers/ChildrenExecutor.js +14 -3
- package/dist/esm/lib/engine/handlers/DeciderHandler.js +5 -7
- package/dist/esm/lib/engine/handlers/RuntimeStructureManager.js +2 -2
- package/dist/esm/lib/engine/handlers/SelectorHandler.js +13 -7
- package/dist/esm/lib/engine/handlers/SubflowExecutor.js +7 -1
- package/dist/esm/lib/engine/handlers/index.js +1 -3
- package/dist/esm/lib/engine/handlers/types.js +2 -2
- package/dist/esm/lib/engine/index.js +1 -1
- package/dist/esm/lib/engine/narrative/CombinedNarrativeRecorder.js +12 -2
- package/dist/esm/lib/engine/narrative/FlowRecorderDispatcher.js +17 -3
- package/dist/esm/lib/engine/narrative/NarrativeFlowRecorder.js +8 -1
- package/dist/esm/lib/engine/narrative/NullControlFlowNarrativeGenerator.js +2 -1
- package/dist/esm/lib/engine/narrative/index.js +1 -1
- package/dist/esm/lib/engine/narrative/types.js +1 -1
- package/dist/esm/lib/engine/runtimeStageId.js +64 -2
- package/dist/esm/lib/engine/traversal/FlowchartTraverser.js +35 -57
- package/dist/esm/lib/engine/types.js +1 -1
- package/dist/esm/lib/engine/walkSubflowSpec.js +168 -0
- package/dist/esm/lib/recorder/CombinedRecorder.js +8 -1
- package/dist/esm/lib/runner/FlowChartExecutor.js +23 -17
- package/dist/esm/lib/runner/getSubtreeSnapshot.js +3 -2
- package/dist/esm/trace.js +3 -2
- package/dist/index.js +3 -2
- package/dist/lib/builder/FlowChartBuilder.js +554 -104
- package/dist/lib/builder/index.js +3 -2
- package/dist/lib/builder/structure/StructureRecorder.js +159 -0
- package/dist/lib/builder/structure/StructureRecorderDispatcher.js +175 -0
- package/dist/lib/builder/types.js +1 -1
- package/dist/lib/engine/errors/errorInfo.js +4 -3
- package/dist/lib/engine/handlers/ChildrenExecutor.js +14 -3
- package/dist/lib/engine/handlers/DeciderHandler.js +5 -7
- package/dist/lib/engine/handlers/RuntimeStructureManager.js +2 -2
- package/dist/lib/engine/handlers/SelectorHandler.js +13 -7
- package/dist/lib/engine/handlers/SubflowExecutor.js +7 -1
- package/dist/lib/engine/handlers/index.js +2 -5
- package/dist/lib/engine/handlers/types.js +2 -2
- package/dist/lib/engine/index.js +1 -1
- package/dist/lib/engine/narrative/CombinedNarrativeRecorder.js +12 -2
- package/dist/lib/engine/narrative/FlowRecorderDispatcher.js +17 -3
- package/dist/lib/engine/narrative/NarrativeFlowRecorder.js +8 -1
- package/dist/lib/engine/narrative/NullControlFlowNarrativeGenerator.js +2 -1
- package/dist/lib/engine/narrative/index.js +1 -1
- package/dist/lib/engine/narrative/types.js +1 -1
- package/dist/lib/engine/runtimeStageId.js +66 -3
- package/dist/lib/engine/traversal/FlowchartTraverser.js +35 -57
- package/dist/lib/engine/types.js +1 -1
- package/dist/lib/engine/walkSubflowSpec.js +172 -0
- package/dist/lib/recorder/CombinedRecorder.js +8 -1
- package/dist/lib/runner/FlowChartExecutor.js +23 -17
- package/dist/lib/runner/getSubtreeSnapshot.js +3 -2
- package/dist/trace.js +5 -2
- package/dist/types/advanced.d.ts +4 -4
- package/dist/types/index.d.ts +4 -2
- package/dist/types/lib/builder/FlowChartBuilder.d.ts +202 -17
- package/dist/types/lib/builder/index.d.ts +3 -2
- package/dist/types/lib/builder/structure/StructureRecorder.d.ts +349 -0
- package/dist/types/lib/builder/structure/StructureRecorderDispatcher.d.ts +77 -0
- package/dist/types/lib/builder/types.d.ts +39 -6
- package/dist/types/lib/engine/errors/errorInfo.d.ts +3 -2
- package/dist/types/lib/engine/handlers/ChildrenExecutor.d.ts +1 -1
- package/dist/types/lib/engine/handlers/DeciderHandler.d.ts +3 -3
- package/dist/types/lib/engine/handlers/RuntimeStructureManager.d.ts +1 -1
- package/dist/types/lib/engine/handlers/SelectorHandler.d.ts +2 -2
- package/dist/types/lib/engine/handlers/index.d.ts +1 -2
- package/dist/types/lib/engine/handlers/types.d.ts +2 -9
- package/dist/types/lib/engine/index.d.ts +1 -1
- package/dist/types/lib/engine/narrative/FlowRecorderDispatcher.d.ts +4 -2
- package/dist/types/lib/engine/narrative/NullControlFlowNarrativeGenerator.d.ts +1 -0
- package/dist/types/lib/engine/narrative/index.d.ts +1 -1
- package/dist/types/lib/engine/narrative/types.d.ts +59 -2
- package/dist/types/lib/engine/runtimeStageId.d.ts +57 -1
- package/dist/types/lib/engine/traversal/FlowchartTraverser.d.ts +1 -6
- package/dist/types/lib/engine/types.d.ts +19 -26
- package/dist/types/lib/engine/walkSubflowSpec.d.ts +95 -0
- package/dist/types/lib/runner/FlowChartExecutor.d.ts +4 -16
- package/dist/types/trace.d.ts +3 -1
- package/package.json +6 -4
- package/dist/esm/lib/engine/handlers/ExtractorRunner.js +0 -122
- package/dist/lib/engine/handlers/ExtractorRunner.js +0 -126
- package/dist/types/lib/engine/handlers/ExtractorRunner.d.ts +0 -41
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StructureRecorder — passive observer of BUILD-TIME chart construction events.
|
|
3
|
+
*
|
|
4
|
+
* The build-time twin of `FlowRecorder`. Where `FlowRecorder` observes
|
|
5
|
+
* RUNTIME control-flow transitions (per-execution `runtimeStageId`,
|
|
6
|
+
* iteration counts, errors, pauses), `StructureRecorder` observes
|
|
7
|
+
* STATIC chart shape as it's assembled by the builder — every spec
|
|
8
|
+
* node added, every outgoing edge wired, every decider closed.
|
|
9
|
+
*
|
|
10
|
+
* Why two interfaces, not one
|
|
11
|
+
* ───────────────────────────
|
|
12
|
+
* Build and runtime events have different INVARIANTS, not just
|
|
13
|
+
* different timing:
|
|
14
|
+
*
|
|
15
|
+
* - Runtime events carry `runtimeStageId` (`[subflowPath/]stageId#N`),
|
|
16
|
+
* `iteration`, `traversalContext` — load-bearing for time-travel
|
|
17
|
+
* UIs, commit-log indices, and `SequenceRecorder<T>` consumers.
|
|
18
|
+
* NONE of these exist at build time.
|
|
19
|
+
*
|
|
20
|
+
* - Build events carry only `stageId` + structural fields. No
|
|
21
|
+
* execution index, no iteration, no snapshot.
|
|
22
|
+
*
|
|
23
|
+
* - Some events have no analog across phases: `onPause` /
|
|
24
|
+
* `onResume` / `onError` / `onRunStart` are runtime-only;
|
|
25
|
+
* `onDeciderComplete` / `onStageAdded` are build-only.
|
|
26
|
+
*
|
|
27
|
+
* A single `FlowRecorder` with `phase: 'static' | 'dynamic'`
|
|
28
|
+
* discriminator would force every consumer to write
|
|
29
|
+
* `if (e.phase === 'static') ...` branches and would erase the
|
|
30
|
+
* least-privilege boundary (a static-only consumer should NOT
|
|
31
|
+
* accidentally observe runtime data — e.g., a public docs site
|
|
32
|
+
* rendering chart topology must not see scope values).
|
|
33
|
+
*
|
|
34
|
+
* Two interfaces, same mental model, clean separation. Two
|
|
35
|
+
* registration sites ship today (pick whichever fits your call
|
|
36
|
+
* site):
|
|
37
|
+
*
|
|
38
|
+
* 1. **Options-bag** (preferred when the recorder set is known
|
|
39
|
+
* at construction time — registers BEFORE `start()` so even
|
|
40
|
+
* the seed event fires through the normal dispatcher fan-out):
|
|
41
|
+
* ```ts
|
|
42
|
+
* flowChart('seed', fn, 'seed', { structureRecorders: [rec] })
|
|
43
|
+
* .addFunction('a', fnA, 'a').build();
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* 2. **Fluent** (preferred when attach is conditional, late, or
|
|
47
|
+
* in a chain builder — the just-attached recorder gets a
|
|
48
|
+
* one-time seed replay so it observes the root stage):
|
|
49
|
+
* ```ts
|
|
50
|
+
* flowChart('seed', fn, 'seed')
|
|
51
|
+
* .attachStructureRecorder(rec)
|
|
52
|
+
* .addFunction('a', fnA, 'a').build();
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* Both deliver the same event stream to the same recorder. See the
|
|
56
|
+
* `@example` block below for a fully-fleshed-out implementation.
|
|
57
|
+
*
|
|
58
|
+
* Lifecycle + ordering invariants
|
|
59
|
+
* ───────────────────────────────
|
|
60
|
+
* - Fires SYNCHRONOUSLY during builder chain calls (and during
|
|
61
|
+
* `.build()` for the terminal node) at the natural moment each
|
|
62
|
+
* spec mutation completes.
|
|
63
|
+
* - `onStageAdded(A)` and `onStageAdded(B)` fire BEFORE any
|
|
64
|
+
* `onEdgeAdded({from: A, to: B})` — endpoint registration
|
|
65
|
+
* happens before edge wiring.
|
|
66
|
+
* - `onDeciderComplete(D)` fires at sub-builder `.end()` time, AFTER
|
|
67
|
+
* every child's `onStageAdded` and every `onEdgeAdded({from: D,
|
|
68
|
+
* to: child})`. Marks the decider as no-further-mutation.
|
|
69
|
+
* - `onSubflowMounted({subflowId})` fires once per mount.
|
|
70
|
+
* **MOUNT-ONLY**: parent recorders do NOT receive a replay of
|
|
71
|
+
* the subflow's own internal structure events (those fired
|
|
72
|
+
* during the subflow's own `.build()`). Matches the runtime
|
|
73
|
+
* `onSubflowEntry` semantics — composition over replay.
|
|
74
|
+
*
|
|
75
|
+
* Error isolation (matches FlowRecorder contract)
|
|
76
|
+
* ───────────────────────────────────────────────
|
|
77
|
+
* - A throwing handler is caught, logged via `isDevMode()` warning,
|
|
78
|
+
* and accumulated on `builder.getStructureBuildErrors()` for
|
|
79
|
+
* post-hoc inspection.
|
|
80
|
+
* - Subsequent recorders + subsequent events fire normally; one
|
|
81
|
+
* misbehaving recorder cannot THROW its way into blocking
|
|
82
|
+
* construction.
|
|
83
|
+
* - The errors[] accumulator is soft-capped (~100 entries) with a
|
|
84
|
+
* `__truncated__` sentinel record once the cap is hit, to prevent
|
|
85
|
+
* unbounded growth on chatty broken recorders.
|
|
86
|
+
* - Note: throw isolation does NOT defend against a handler that
|
|
87
|
+
* succeeds at runtime but mutates `event.spec` to corrupt the
|
|
88
|
+
* chart. See "Spec mutation" below.
|
|
89
|
+
*
|
|
90
|
+
* Spec mutation — readonly-by-contract (NOT runtime-enforced)
|
|
91
|
+
* ────────────────────────────────────────────────────────────
|
|
92
|
+
* - Event payloads pass spec references where useful (e.g., `spec`
|
|
93
|
+
* on `onStageAdded`). Every field on every event payload is
|
|
94
|
+
* marked `readonly` in TypeScript — the type system signals
|
|
95
|
+
* consumer intent at author time.
|
|
96
|
+
* - There is NO runtime freeze. The builder fires `onStageAdded`
|
|
97
|
+
* IMMEDIATELY when a spec node is added, BEFORE the builder
|
|
98
|
+
* wires that node's `.next`/`.children`/`.loopTarget` in the
|
|
99
|
+
* subsequent `addX` call. Freezing here would break the
|
|
100
|
+
* builder's own subsequent mutation.
|
|
101
|
+
* - Handler mutation of `event.spec` is DOCUMENTED UNDEFINED
|
|
102
|
+
* BEHAVIOR — it will succeed at runtime, but is not supported
|
|
103
|
+
* and downstream consumers may break. Specifically, mutating
|
|
104
|
+
* `event.spec.fn`, `event.spec.id`, or `event.spec.children`
|
|
105
|
+
* can corrupt subsequent runtime behavior of the chart.
|
|
106
|
+
* - **Trust model**: attach ONLY recorders from trusted code paths.
|
|
107
|
+
* A hostile or buggy recorder can effectively substitute stage
|
|
108
|
+
* functions or rewire the chart structure. The `readonly`
|
|
109
|
+
* markers cannot defend against intentional mutation.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* class TraceStructureRecorder implements StructureRecorder {
|
|
114
|
+
* readonly id = 'trace-static';
|
|
115
|
+
* nodes: XyflowNode[] = [];
|
|
116
|
+
* edges: XyflowEdge[] = [];
|
|
117
|
+
*
|
|
118
|
+
* onStageAdded(e) {
|
|
119
|
+
* // Node role: 'stage' is the initial type. If outgoing edges
|
|
120
|
+
* // arrive with kind 'fork-branch' / 'decision-branch' the node
|
|
121
|
+
* // is functioning as a fork/decider — derive the visual style
|
|
122
|
+
* // from those edges, not from `e.type` alone.
|
|
123
|
+
* this.nodes.push({ id: e.stageId, type: 'lensStage', data: { label: e.name } });
|
|
124
|
+
* }
|
|
125
|
+
* onEdgeAdded(e) {
|
|
126
|
+
* this.edges.push({ id: `${e.from}->${e.to}`, source: e.from, target: e.to });
|
|
127
|
+
* }
|
|
128
|
+
* onSubflowMounted(e) {
|
|
129
|
+
* this.nodes.push({ id: e.subflowId, type: 'subflow', data: { label: e.subflowName } });
|
|
130
|
+
* }
|
|
131
|
+
* onDeciderComplete(e) {
|
|
132
|
+
* // Optional: finalize node styling now that branch list is sealed.
|
|
133
|
+
* }
|
|
134
|
+
* }
|
|
135
|
+
*
|
|
136
|
+
* // Registration option A — options-bag (preferred when recorders
|
|
137
|
+
* // are known up front; attaches BEFORE the seed event fires):
|
|
138
|
+
* const rec = new TraceStructureRecorder();
|
|
139
|
+
* const builder = flowChart('seed', fn, 'seed', {
|
|
140
|
+
* structureRecorders: [rec],
|
|
141
|
+
* }).addFunction('a', fnA, 'a');
|
|
142
|
+
* const chart = builder.build();
|
|
143
|
+
*
|
|
144
|
+
* // Registration option B — fluent chain (preferred for conditional
|
|
145
|
+
* // or late attach; the just-attached recorder gets a seed replay):
|
|
146
|
+
* const rec2 = new TraceStructureRecorder();
|
|
147
|
+
* const builder2 = flowChart('seed', fn, 'seed')
|
|
148
|
+
* .attachStructureRecorder(rec2)
|
|
149
|
+
* .addFunction('a', fnA, 'a');
|
|
150
|
+
*
|
|
151
|
+
* // Inspect any recorder errors (call on the BUILDER, not the chart):
|
|
152
|
+
* const errors = builder.getStructureBuildErrors();
|
|
153
|
+
*
|
|
154
|
+
* <ReactFlow nodes={rec.nodes} edges={rec.edges} />
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
import type { FlowChartSpec, SerializedPipelineStructure } from '../types.js';
|
|
158
|
+
/**
|
|
159
|
+
* Event payload for `StructureRecorder.onStageAdded`. Fires for every
|
|
160
|
+
* spec node added to the chart, including the seed (added via
|
|
161
|
+
* `flowChart()` factory) and subflow mount nodes. Excludes synthetic
|
|
162
|
+
* loop-reference nodes (those carry `isLoopReference: true` on the
|
|
163
|
+
* spec; consumers see them via the separate `onLoopEdgeAdded` event
|
|
164
|
+
* instead of as fresh stages).
|
|
165
|
+
*/
|
|
166
|
+
export interface StructureStageAddedEvent {
|
|
167
|
+
/**
|
|
168
|
+
* Stable identifier for this node. AT EVENT FIRE TIME this is the
|
|
169
|
+
* builder's LOCAL form (no subflow prefix — the prefix is applied
|
|
170
|
+
* later by `_prefixNodeTree` when this builder is mounted as a
|
|
171
|
+
* subflow into a parent).
|
|
172
|
+
*
|
|
173
|
+
* Note: `spec.id` is a LIVE reference. If you read it AFTER this
|
|
174
|
+
* chart has been mounted as a subflow, it may have been rewritten
|
|
175
|
+
* to the FULL prefixed form. Use `splitStageId(spec.id)` from
|
|
176
|
+
* `footprintjs/trace` to decompose it back into local + subflowPath.
|
|
177
|
+
*
|
|
178
|
+
* Correlating with runtime events:
|
|
179
|
+
* - Same builder (no mount) →
|
|
180
|
+
* `event.stageId === parseRuntimeStageId(runtime).stageId`
|
|
181
|
+
* - This builder mounted as subflow → use `splitStageId` on the
|
|
182
|
+
* prefixed form (or `parseRuntimeStageId` on the full
|
|
183
|
+
* runtimeStageId) before comparing.
|
|
184
|
+
*/
|
|
185
|
+
readonly stageId: string;
|
|
186
|
+
/** Human-readable label for the node. */
|
|
187
|
+
readonly name: string;
|
|
188
|
+
/** Spec node `type`. Lets recorders branch on stage vs decider vs
|
|
189
|
+
* fork vs subflow without re-deriving from other fields. */
|
|
190
|
+
readonly type: NonNullable<FlowChartSpec['type']>;
|
|
191
|
+
/** True for nodes added via `addPausableFunction()` — useful for
|
|
192
|
+
* visualisers that want to mark stages that can pause execution. */
|
|
193
|
+
readonly isPausable?: boolean;
|
|
194
|
+
/** Live reference to the full spec node, for handlers that want
|
|
195
|
+
* details beyond the discriminator fields above. MUST NOT be
|
|
196
|
+
* mutated by the handler — readonly is type-level intent; no
|
|
197
|
+
* runtime freeze. See "Spec mutation" in the file header for the
|
|
198
|
+
* trust-model caveats. */
|
|
199
|
+
readonly spec: FlowChartSpec;
|
|
200
|
+
}
|
|
201
|
+
/** Edge kinds the builder produces at structural time. Matches the
|
|
202
|
+
* footprintjs control-flow vocabulary used at runtime.
|
|
203
|
+
*
|
|
204
|
+
* Why no `subflow-entry` here: subflow mounts use the lifecycle
|
|
205
|
+
* event `onSubflowMounted` (not an edge event). If a future use case
|
|
206
|
+
* needs the parent→subflow-root edge as a distinct kind, it'll be
|
|
207
|
+
* added then — YAGNI now (Panel 3, L7.2 review). */
|
|
208
|
+
export type StructureEdgeKind = 'next' | 'fork-branch' | 'decision-branch';
|
|
209
|
+
/**
|
|
210
|
+
* Event payload for `StructureRecorder.onEdgeAdded`. Fires whenever
|
|
211
|
+
* the builder wires an outgoing edge from one node to another. Both
|
|
212
|
+
* endpoints have already been announced via `onStageAdded` by the
|
|
213
|
+
* time this fires.
|
|
214
|
+
*
|
|
215
|
+
* Loop back-edges have their OWN event (`onLoopEdgeAdded`) so
|
|
216
|
+
* consumers can theme them distinctly and so build-time events stay
|
|
217
|
+
* free of the runtime-only `iteration` field.
|
|
218
|
+
*/
|
|
219
|
+
export interface StructureEdgeAddedEvent {
|
|
220
|
+
readonly from: string;
|
|
221
|
+
readonly to: string;
|
|
222
|
+
readonly kind: StructureEdgeKind;
|
|
223
|
+
/** Optional human-readable label — used today for decider branch
|
|
224
|
+
* keys (e.g., `'low'`, `'high'`, `'high (default)'`) and parallel
|
|
225
|
+
* branch ids. */
|
|
226
|
+
readonly label?: string;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Event payload for `StructureRecorder.onLoopEdgeAdded`. Fires when
|
|
230
|
+
* `.loopTo(target)` installs a back-edge. Distinct from
|
|
231
|
+
* `onEdgeAdded` so consumers can theme back-edges differently and
|
|
232
|
+
* because runtime `onLoop` carries `iteration: number` which has no
|
|
233
|
+
* build-time meaning — keeping the events separated avoids forcing
|
|
234
|
+
* an `iteration?: number` lie into the structural shape.
|
|
235
|
+
*/
|
|
236
|
+
export interface StructureLoopEdgeAddedEvent {
|
|
237
|
+
readonly from: string;
|
|
238
|
+
readonly to: string;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Event payload for `StructureRecorder.onDeciderComplete`. Fires
|
|
242
|
+
* when a decider / selector sub-builder closes via `.end()`. By the
|
|
243
|
+
* time this fires every branch has been announced and the
|
|
244
|
+
* `defaultBranch` (if set via `.setDefault()`) is final. Lets
|
|
245
|
+
* recorders treat the decider as no-further-mutation and snapshot
|
|
246
|
+
* its branch list as final.
|
|
247
|
+
*/
|
|
248
|
+
export interface StructureDeciderCompleteEvent {
|
|
249
|
+
/** Decider / selector stage id. */
|
|
250
|
+
readonly decider: string;
|
|
251
|
+
/** Spec type (`'decider'` vs `'selector'`) — exposed so consumers
|
|
252
|
+
* don't need to look up the original `onStageAdded` event. */
|
|
253
|
+
readonly type: 'decider' | 'selector';
|
|
254
|
+
/** Branch member ids in declaration order. */
|
|
255
|
+
readonly branchIds: readonly string[];
|
|
256
|
+
/** Default branch id when set via `.setDefault()`; undefined when
|
|
257
|
+
* no default is configured (e.g., selectors). */
|
|
258
|
+
readonly defaultBranch?: string;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Event payload for `StructureRecorder.onSubflowMounted`. Fires once
|
|
262
|
+
* per subflow mount (`addSubFlowChart` / `addSubFlowChartNext` and
|
|
263
|
+
* their lazy variants).
|
|
264
|
+
*
|
|
265
|
+
* **MOUNT-ONLY semantics** — the subflow's OWN structure events
|
|
266
|
+
* (every `onStageAdded` / `onEdgeAdded` inside the subflow) fired
|
|
267
|
+
* during the subflow's own `.build()`, before the mount. Parent
|
|
268
|
+
* recorders do NOT receive a replay. Instead, this event delivers
|
|
269
|
+
* the subflow's full structure via `subflowSpec`, and consumers can
|
|
270
|
+
* walk it via `walkSubflowSpec` from `footprintjs/trace`.
|
|
271
|
+
*
|
|
272
|
+
* This matches `FlowRecorder.onSubflowEntry` semantics at runtime
|
|
273
|
+
* (parents see the boundary, not a replay of internals) and
|
|
274
|
+
* preserves the "one purpose per recorder" convention.
|
|
275
|
+
*/
|
|
276
|
+
export interface StructureSubflowMountedEvent {
|
|
277
|
+
/** Subflow identifier the parent assigned at mount. */
|
|
278
|
+
readonly subflowId: string;
|
|
279
|
+
/** Human-readable subflow name. */
|
|
280
|
+
readonly subflowName: string;
|
|
281
|
+
/** Mount node id in the parent's chart. */
|
|
282
|
+
readonly rootStageId: string;
|
|
283
|
+
/** True when the mount uses lazy resolution (deferred subflow
|
|
284
|
+
* resolution until execution). */
|
|
285
|
+
readonly isLazy?: boolean;
|
|
286
|
+
/**
|
|
287
|
+
* The mounted subflow's complete spec — the SAME OBJECT
|
|
288
|
+
* (=== reference equality) reachable via `subflow.buildTimeStructure`
|
|
289
|
+
* for the FlowChart the consumer passed to `addSubFlowChartBranch` /
|
|
290
|
+
* `addSubFlowChart` / `addSubFlowChartNext`.
|
|
291
|
+
*
|
|
292
|
+
* UNDEFINED for lazy mounts at build time (`isLazy: true`) — the
|
|
293
|
+
* subflow's structure hasn't been resolved yet. Consumers waiting on
|
|
294
|
+
* lazy subflows handle the runtime `onSubflowEntry` event instead.
|
|
295
|
+
*
|
|
296
|
+
* Immutable post-build; consumers MUST NOT mutate.
|
|
297
|
+
*
|
|
298
|
+
* @internal `SerializedPipelineStructure` is library-internal.
|
|
299
|
+
* Use `walkSubflowSpec` from `footprintjs/trace` for the
|
|
300
|
+
* stable public contract.
|
|
301
|
+
*/
|
|
302
|
+
readonly subflowSpec?: SerializedPipelineStructure;
|
|
303
|
+
/**
|
|
304
|
+
* Local mount id of this subflow within its parent — equal to
|
|
305
|
+
* `subflowId` for top-level mounts (e.g. `'auth'`), composed
|
|
306
|
+
* (`'auth/verify'`) for nested mounts whose recorder is attached
|
|
307
|
+
* to the grandparent. Matches runtime `traversalContext.subflowPath`
|
|
308
|
+
* semantics — NEVER prefixed with `__root__/`.
|
|
309
|
+
*/
|
|
310
|
+
readonly subflowPath: string;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Pluggable observer for BUILD-TIME chart construction events.
|
|
314
|
+
*
|
|
315
|
+
* All methods are optional — implement only the hooks you need.
|
|
316
|
+
* Handlers fire SYNCHRONOUSLY during builder operations and `.build()`.
|
|
317
|
+
* A throwing handler is caught (see "Error isolation" in the file
|
|
318
|
+
* header); subsequent dispatch continues.
|
|
319
|
+
*
|
|
320
|
+
* Lifecycle: each `StructureRecorder` instance is registered via
|
|
321
|
+
* EITHER the `flowChart()` options bag (`{ structureRecorders: [rec] }`)
|
|
322
|
+
* OR the fluent `.attachStructureRecorder(rec)` chain — see the file
|
|
323
|
+
* header for the trade-offs. Registration after `.build()` is
|
|
324
|
+
* rejected (chart is sealed).
|
|
325
|
+
*/
|
|
326
|
+
export interface StructureRecorder {
|
|
327
|
+
/**
|
|
328
|
+
* Stable identifier — used by the dispatcher to scope error
|
|
329
|
+
* messages and to support `detach(id)` lookup.
|
|
330
|
+
*
|
|
331
|
+
* Convention (matches `FlowRecorder.id` from CLAUDE.md):
|
|
332
|
+
* - domain-prefixed kebab-case (`'lens-structure'`,
|
|
333
|
+
* `'agentfootprint-composition'`, `'trace-explainable'`)
|
|
334
|
+
* - same id → multiple recorders coexist (NOT deduplicated by
|
|
335
|
+
* id; the dispatcher fires every attached recorder regardless)
|
|
336
|
+
* - `detach(id)` removes EVERY recorder with that id — be
|
|
337
|
+
* intentional about reuse if you rely on selective detach
|
|
338
|
+
*
|
|
339
|
+
* Choose a stable id at module load and don't randomise it across
|
|
340
|
+
* runs — it lands in `StructureBuildError.recorderId` so debug
|
|
341
|
+
* output is greppable.
|
|
342
|
+
*/
|
|
343
|
+
readonly id: string;
|
|
344
|
+
onStageAdded?(event: StructureStageAddedEvent): void;
|
|
345
|
+
onEdgeAdded?(event: StructureEdgeAddedEvent): void;
|
|
346
|
+
onLoopEdgeAdded?(event: StructureLoopEdgeAddedEvent): void;
|
|
347
|
+
onDeciderComplete?(event: StructureDeciderCompleteEvent): void;
|
|
348
|
+
onSubflowMounted?(event: StructureSubflowMountedEvent): void;
|
|
349
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StructureRecorderDispatcher — Fans build-time structure events out to N
|
|
3
|
+
* attached `StructureRecorder` instances.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors `FlowRecorderDispatcher` (engine/narrative/) exactly:
|
|
6
|
+
*
|
|
7
|
+
* - `recorders: StructureRecorder[]` — attach order preserved
|
|
8
|
+
* - per-event fire methods early-return when no recorders attached
|
|
9
|
+
* (zero-allocation fast path)
|
|
10
|
+
* - per-recorder try/catch isolates errors; one bad recorder cannot
|
|
11
|
+
* cascade into the chain build or sibling recorders
|
|
12
|
+
* - errors route to BOTH the dev-mode console warning (matches
|
|
13
|
+
* FlowRecorderDispatcher) AND a structured `buildErrors`
|
|
14
|
+
* accumulator so consumers can inspect failures post-build
|
|
15
|
+
* - spec payloads are NOT frozen at dispatch time — handlers must
|
|
16
|
+
* respect the `readonly` markers on event payload types (the
|
|
17
|
+
* builder still needs to mutate `spec.next` after the immediate
|
|
18
|
+
* `onStageAdded` fires; see `fireStageAdded` for the full note,
|
|
19
|
+
* and `StructureRecorder.ts` header "Spec mutation" for the
|
|
20
|
+
* trust-model implications)
|
|
21
|
+
*
|
|
22
|
+
* The dispatcher itself owns NO chart state. The builder owns the
|
|
23
|
+
* dispatcher; events fire from the natural mutation points in
|
|
24
|
+
* FlowChartBuilder (L7.3).
|
|
25
|
+
*/
|
|
26
|
+
import type { FlowChartSpec } from '../types.js';
|
|
27
|
+
import type { StructureDeciderCompleteEvent, StructureEdgeAddedEvent, StructureLoopEdgeAddedEvent, StructureRecorder, StructureStageAddedEvent, StructureSubflowMountedEvent } from './StructureRecorder.js';
|
|
28
|
+
/** Structured error captured when a recorder throws. Read post-build
|
|
29
|
+
* via `builder.getStructureBuildErrors()` — call on the BUILDER
|
|
30
|
+
* reference (NOT the chart returned by `.build()`). Capture the
|
|
31
|
+
* builder reference before `.build()` if you need post-build access. */
|
|
32
|
+
export interface StructureBuildError {
|
|
33
|
+
/** Which recorder's handler threw. */
|
|
34
|
+
readonly recorderId: string;
|
|
35
|
+
/** Which event method (`'onStageAdded'`, `'onEdgeAdded'`, ...). */
|
|
36
|
+
readonly method: string;
|
|
37
|
+
/** Error message extracted from the thrown value. */
|
|
38
|
+
readonly message: string;
|
|
39
|
+
/** The original thrown value — `Error` instance or whatever the
|
|
40
|
+
* recorder threw. Useful when diagnosis needs a stack trace. */
|
|
41
|
+
readonly error: unknown;
|
|
42
|
+
}
|
|
43
|
+
export declare class StructureRecorderDispatcher {
|
|
44
|
+
private recorders;
|
|
45
|
+
private readonly errors;
|
|
46
|
+
private _truncated;
|
|
47
|
+
/** Attach a `StructureRecorder`. Multiple recorders with the same
|
|
48
|
+
* id are allowed; the convention is one id per logical concern. */
|
|
49
|
+
attach(recorder: StructureRecorder): void;
|
|
50
|
+
/** Detach every recorder with the given id. */
|
|
51
|
+
detach(id: string): void;
|
|
52
|
+
/** Defensive copy of the attached recorders — used in tests + by
|
|
53
|
+
* tooling that wants to inspect what's registered. */
|
|
54
|
+
getRecorders(): StructureRecorder[];
|
|
55
|
+
/** Find one recorder by id. */
|
|
56
|
+
getRecorderById<T extends StructureRecorder = StructureRecorder>(id: string): T | undefined;
|
|
57
|
+
/** Read accumulated errors from this build. Returns a defensive copy. */
|
|
58
|
+
getErrors(): StructureBuildError[];
|
|
59
|
+
fireStageAdded(event: StructureStageAddedEvent): void;
|
|
60
|
+
fireEdgeAdded(event: StructureEdgeAddedEvent): void;
|
|
61
|
+
fireLoopEdgeAdded(event: StructureLoopEdgeAddedEvent): void;
|
|
62
|
+
fireDeciderComplete(event: StructureDeciderCompleteEvent): void;
|
|
63
|
+
fireSubflowMounted(event: StructureSubflowMountedEvent): void;
|
|
64
|
+
/**
|
|
65
|
+
* Externally-callable error capture for events the builder fires
|
|
66
|
+
* OUTSIDE the normal fire* fan-out path — specifically the seed
|
|
67
|
+
* replay in `FlowChartBuilder.attachStructureRecorder()`, which
|
|
68
|
+
* targets one specific recorder rather than every attached recorder.
|
|
69
|
+
*
|
|
70
|
+
* Same observability contract as the internal `recordError`:
|
|
71
|
+
* accumulates on `getErrors()` AND logs in dev mode.
|
|
72
|
+
*/
|
|
73
|
+
recordErrorForReplay(recorderId: string, method: string, err: unknown): void;
|
|
74
|
+
private recordError;
|
|
75
|
+
}
|
|
76
|
+
/** Re-export the FlowChartSpec type for downstream type completeness. */
|
|
77
|
+
export type { FlowChartSpec };
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* The builder remains standalone at runtime.
|
|
10
10
|
*/
|
|
11
11
|
import type { StageNode } from '../engine/graph/StageNode.js';
|
|
12
|
-
import type { ILogger, ScopeFactory, StageFunction
|
|
12
|
+
import type { ILogger, ScopeFactory, StageFunction } from '../engine/types.js';
|
|
13
13
|
import type { ScopeProtectionMode } from '../scope/protection/types.js';
|
|
14
|
+
import type { StructureRecorder } from './structure/StructureRecorder.js';
|
|
14
15
|
export type { ResumeFn, StageNode } from '../engine/graph/StageNode.js';
|
|
15
16
|
export type { ILogger, StageFunction, StreamCallback, StreamHandlers, StreamLifecycleHandler, StreamTokenHandler, SubflowMountOptions, } from '../engine/types.js';
|
|
16
17
|
export { ArrayMergeMode } from '../engine/types.js';
|
|
@@ -52,6 +53,15 @@ export interface SerializedPipelineStructure {
|
|
|
52
53
|
isLoopReference?: boolean;
|
|
53
54
|
/** When true, this stage can pause execution (PausableHandler pattern). */
|
|
54
55
|
isPausable?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* STRUCTURE-ONLY: for a fork/selector/decider branch, the downstream stage
|
|
58
|
+
* id its convergence `next` edge points to, instead of the shared next-stage
|
|
59
|
+
* its siblings converge at. Set from `SubflowMountOptions.convergeAt`; read by
|
|
60
|
+
* `_fireNextEdgeFromParent` to express an unequal-depth merge (e.g. tools →
|
|
61
|
+
* call-llm, bypassing message-api). Visualization-only — runtime convergence
|
|
62
|
+
* is unchanged.
|
|
63
|
+
*/
|
|
64
|
+
convergeAt?: string;
|
|
55
65
|
}
|
|
56
66
|
export interface FlowChartSpec {
|
|
57
67
|
name: string;
|
|
@@ -77,14 +87,37 @@ export interface FlowChartSpec {
|
|
|
77
87
|
/** True when this node is a back-edge reference created by loopTo() — not an executable stage. */
|
|
78
88
|
isLoopReference?: boolean;
|
|
79
89
|
}
|
|
80
|
-
/**
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
export
|
|
90
|
+
/**
|
|
91
|
+
* Options-bag argument shape for the `flowChart()` factory.
|
|
92
|
+
*/
|
|
93
|
+
export interface FlowChartOptions {
|
|
94
|
+
/**
|
|
95
|
+
* Build-time recorders to attach BEFORE `start()` fires. Equivalent
|
|
96
|
+
* to chaining `.attachStructureRecorder(rec)` immediately after the
|
|
97
|
+
* factory returns — but registered EARLIER, so even the seed event
|
|
98
|
+
* fires through the dispatcher without needing the seed-replay path.
|
|
99
|
+
*
|
|
100
|
+
* Multiple recorders attach in array order (same as
|
|
101
|
+
* `.attachStructureRecorder` repeated). See `StructureRecorder` JSDoc
|
|
102
|
+
* for event semantics, ordering invariants, and the trust model.
|
|
103
|
+
*/
|
|
104
|
+
structureRecorders?: StructureRecorder[];
|
|
105
|
+
/** Free-form description shown on the root spec node. */
|
|
106
|
+
description?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Only meaningful for `flowChartSelector` (a root selector). When the
|
|
109
|
+
* selector picks ≥2 branches they fan out in parallel: `failFast: true`
|
|
110
|
+
* uses `Promise.all` (first branch error rejects + aborts), the default
|
|
111
|
+
* uses `Promise.allSettled` (best-effort — all branches run even if some
|
|
112
|
+
* fail). Use fail-fast when all selected branches are REQUIRED. Ignored for
|
|
113
|
+
* non-selector charts. Same flag `addSelectorFunction` / `addListOfFunction`
|
|
114
|
+
* expose.
|
|
115
|
+
*/
|
|
116
|
+
failFast?: boolean;
|
|
117
|
+
}
|
|
84
118
|
export type FlowChart<TOut = any, TScope = any> = {
|
|
85
119
|
root: StageNode<TOut, TScope>;
|
|
86
120
|
stageMap: Map<string, StageFunction<TOut, TScope>>;
|
|
87
|
-
extractor?: TraversalExtractor;
|
|
88
121
|
subflows?: Record<string, {
|
|
89
122
|
root: StageNode<TOut, TScope>;
|
|
90
123
|
}>;
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* a single extraction point that preserves structured details while still
|
|
7
7
|
* producing a human-readable message.
|
|
8
8
|
*
|
|
9
|
-
* Consumers (narrative recorders,
|
|
10
|
-
* StructuredErrorInfo instead of a flat string, and can
|
|
9
|
+
* Consumers (narrative recorders, FlowRecorder.onError handlers, diagnostic
|
|
10
|
+
* collectors) receive StructuredErrorInfo instead of a flat string, and can
|
|
11
|
+
* decide how to render it.
|
|
11
12
|
* String-ification happens only at the final rendering boundary.
|
|
12
13
|
*/
|
|
13
14
|
import type { ValidationIssue } from '../../schema/errors.js';
|
|
@@ -28,5 +28,5 @@ export declare class ChildrenExecutor<TOut = any, TScope = any> {
|
|
|
28
28
|
* Execute selected children based on selector result.
|
|
29
29
|
* Validates IDs, records selection info, then delegates to executeNodeChildren.
|
|
30
30
|
*/
|
|
31
|
-
executeSelectedChildren(selector: Selector, children: StageNode<TOut, TScope>[], input: any, context: StageContext, branchPath: string, traversalContext?: TraversalContext): Promise<Record<string, NodeResultType>>;
|
|
31
|
+
executeSelectedChildren(selector: Selector, children: StageNode<TOut, TScope>[], input: any, context: StageContext, branchPath: string, traversalContext?: TraversalContext, failFast?: boolean): Promise<Record<string, NodeResultType>>;
|
|
32
32
|
}
|
|
@@ -8,8 +8,8 @@ import type { StageContext } from '../../memory/StageContext.js';
|
|
|
8
8
|
import type { StageNode } from '../graph/StageNode.js';
|
|
9
9
|
import type { TraversalContext } from '../narrative/types.js';
|
|
10
10
|
import type { HandlerDeps, StageFunction } from '../types.js';
|
|
11
|
-
import type {
|
|
12
|
-
export type {
|
|
11
|
+
import type { ExecuteNodeFn, RunStageFn } from './types.js';
|
|
12
|
+
export type { ExecuteNodeFn, RunStageFn };
|
|
13
13
|
export declare class DeciderHandler<TOut = any, TScope = any> {
|
|
14
14
|
private readonly deps;
|
|
15
15
|
constructor(deps: HandlerDeps<TOut, TScope>);
|
|
@@ -20,5 +20,5 @@ export declare class DeciderHandler<TOut = any, TScope = any> {
|
|
|
20
20
|
*/
|
|
21
21
|
handleScopeBased(node: StageNode<TOut, TScope>, stageFunc: StageFunction<TOut, TScope>, context: StageContext, breakFlag: {
|
|
22
22
|
shouldBreak: boolean;
|
|
23
|
-
}, branchPath: string | undefined, runStage: RunStageFn<TOut, TScope>, executeNode: ExecuteNodeFn<TOut, TScope>,
|
|
23
|
+
}, branchPath: string | undefined, runStage: RunStageFn<TOut, TScope>, executeNode: ExecuteNodeFn<TOut, TScope>, traversalContext?: TraversalContext): Promise<any>;
|
|
24
24
|
}
|
|
@@ -11,7 +11,7 @@ import type { StageNode } from '../graph/StageNode.js';
|
|
|
11
11
|
import type { SerializedPipelineStructure } from '../types.js';
|
|
12
12
|
/**
|
|
13
13
|
* Compute the node type from node properties.
|
|
14
|
-
*
|
|
14
|
+
* Used by RuntimeStructureManager for serialization.
|
|
15
15
|
*/
|
|
16
16
|
export declare function computeNodeType(node: StageNode): 'stage' | 'decider' | 'selector' | 'fork' | 'streaming' | 'subflow' | 'loop';
|
|
17
17
|
export declare class RuntimeStructureManager {
|
|
@@ -11,7 +11,7 @@ import type { StageNode } from '../graph/StageNode.js';
|
|
|
11
11
|
import type { TraversalContext } from '../narrative/types.js';
|
|
12
12
|
import type { HandlerDeps, NodeResultType, StageFunction } from '../types.js';
|
|
13
13
|
import type { ChildrenExecutor } from './ChildrenExecutor.js';
|
|
14
|
-
import type {
|
|
14
|
+
import type { ExecuteNodeFn, RunStageFn } from './types.js';
|
|
15
15
|
export declare class SelectorHandler<TOut = any, TScope = any> {
|
|
16
16
|
private readonly deps;
|
|
17
17
|
private readonly childrenExecutor;
|
|
@@ -23,5 +23,5 @@ export declare class SelectorHandler<TOut = any, TScope = any> {
|
|
|
23
23
|
*/
|
|
24
24
|
handleScopeBased(node: StageNode<TOut, TScope>, stageFunc: StageFunction<TOut, TScope>, context: StageContext, breakFlag: {
|
|
25
25
|
shouldBreak: boolean;
|
|
26
|
-
}, branchPath: string | undefined, runStage: RunStageFn<TOut, TScope>, executeNode: ExecuteNodeFn<TOut, TScope>,
|
|
26
|
+
}, branchPath: string | undefined, runStage: RunStageFn<TOut, TScope>, executeNode: ExecuteNodeFn<TOut, TScope>, traversalContext?: TraversalContext): Promise<Record<string, NodeResultType>>;
|
|
27
27
|
}
|
|
@@ -3,12 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export { StageRunner } from './StageRunner.js';
|
|
5
5
|
export { NodeResolver } from './NodeResolver.js';
|
|
6
|
-
export type {
|
|
6
|
+
export type { ExecuteNodeFn, RunStageFn } from './types.js';
|
|
7
7
|
export { ChildrenExecutor } from './ChildrenExecutor.js';
|
|
8
8
|
export { DeciderHandler } from './DeciderHandler.js';
|
|
9
9
|
export { SelectorHandler } from './SelectorHandler.js';
|
|
10
10
|
export { ContinuationResolver, DEFAULT_MAX_ITERATIONS } from './ContinuationResolver.js';
|
|
11
11
|
export { SubflowExecutor } from './SubflowExecutor.js';
|
|
12
12
|
export { applyOutputMapping, createSubflowHandlerDeps, extractParentScopeValues, getInitialScopeValues, seedSubflowGlobalStore, } from './SubflowInputMapper.js';
|
|
13
|
-
export { ExtractorRunner } from './ExtractorRunner.js';
|
|
14
13
|
export { computeNodeType, RuntimeStructureManager } from './RuntimeStructureManager.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* handlers/types.ts — Shared callback types for all handler modules.
|
|
3
3
|
*
|
|
4
|
-
* Avoids duplicate definitions of ExecuteNodeFn /
|
|
4
|
+
* Avoids duplicate definitions of ExecuteNodeFn / RunStageFn / etc.
|
|
5
5
|
* across ChildrenExecutor, DeciderHandler, ContinuationResolver, SubflowExecutor.
|
|
6
6
|
* All types are callbacks that break circular dependencies with FlowchartTraverser.
|
|
7
7
|
*/
|
|
@@ -28,12 +28,5 @@ export interface BreakFlag {
|
|
|
28
28
|
}
|
|
29
29
|
/** Recursive node execution — avoids circular dep with FlowchartTraverser. */
|
|
30
30
|
export type ExecuteNodeFn<TOut = any, TScope = any> = (node: StageNode<TOut, TScope>, context: StageContext, breakFlag: BreakFlag, branchPath?: string) => Promise<any>;
|
|
31
|
-
/** Run a stage function with commit
|
|
31
|
+
/** Run a stage function with commit. */
|
|
32
32
|
export type RunStageFn<TOut = any, TScope = any> = (node: StageNode<TOut, TScope>, stageFunc: StageFunction<TOut, TScope>, context: StageContext, breakFn: () => void) => Promise<TOut>;
|
|
33
|
-
/** Call the traversal extractor after stage execution. */
|
|
34
|
-
export type CallExtractorFn<TOut = any, TScope = any> = (node: StageNode<TOut, TScope>, context: StageContext, stagePath: string, stageOutput?: unknown, errorInfo?: {
|
|
35
|
-
type: string;
|
|
36
|
-
message: string;
|
|
37
|
-
}) => void;
|
|
38
|
-
/** Compute the stage path string for extractor and narrative. */
|
|
39
|
-
export type GetStagePathFn<TOut = any, TScope = any> = (node: StageNode<TOut, TScope>, branchPath?: string, contextStageName?: string) => string;
|
|
@@ -14,7 +14,7 @@ export { NullControlFlowNarrativeGenerator } from './narrative/NullControlFlowNa
|
|
|
14
14
|
export type { IControlFlowNarrative } from './narrative/types.js';
|
|
15
15
|
export { FlowRecorderDispatcher } from './narrative/FlowRecorderDispatcher.js';
|
|
16
16
|
export { NarrativeFlowRecorder } from './narrative/NarrativeFlowRecorder.js';
|
|
17
|
-
export type { FlowBreakEvent, FlowDecisionEvent, FlowErrorEvent, FlowForkEvent, FlowLoopEvent, FlowNextEvent, FlowRecorder, FlowSelectedEvent, FlowStageEvent, FlowSubflowEvent, FlowSubflowRegisteredEvent, TraversalContext, } from './narrative/types.js';
|
|
17
|
+
export type { FlowBreakEvent, FlowDecisionEvent, FlowErrorEvent, FlowForkEvent, FlowLoopEvent, FlowNextEvent, FlowRecorder, FlowRunEvent, FlowRunFailedEvent, FlowSelectedEvent, FlowStageEvent, FlowSubflowEvent, FlowSubflowRegisteredEvent, TraversalContext, } from './narrative/types.js';
|
|
18
18
|
export type { StructuredErrorInfo } from './errors/errorInfo.js';
|
|
19
19
|
export { extractErrorInfo, formatErrorInfo } from './errors/errorInfo.js';
|
|
20
20
|
export { AdaptiveNarrativeFlowRecorder } from './narrative/recorders/AdaptiveNarrativeFlowRecorder.js';
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
* When no recorders are attached, every method is a fast no-op (empty array check).
|
|
11
11
|
*/
|
|
12
12
|
import type { DecisionEvidence, SelectionEvidence } from '../../decide/types.js';
|
|
13
|
-
import type {
|
|
13
|
+
import type { StructuredErrorInfo } from '../errors/errorInfo.js';
|
|
14
|
+
import type { FlowRecorder, IControlFlowNarrative, StageType, TraversalContext } from './types.js';
|
|
14
15
|
export declare class FlowRecorderDispatcher implements IControlFlowNarrative {
|
|
15
16
|
private recorders;
|
|
16
17
|
/** Attach a FlowRecorder. Duplicate IDs are allowed (same as scope ScopeRecorder). */
|
|
@@ -21,7 +22,7 @@ export declare class FlowRecorderDispatcher implements IControlFlowNarrative {
|
|
|
21
22
|
getScopeRecorders(): FlowRecorder[];
|
|
22
23
|
/** Find a recorder by ID. Useful for retrieving built-in recorders like NarrativeFlowRecorder. */
|
|
23
24
|
getRecorderById<T extends FlowRecorder = FlowRecorder>(id: string): T | undefined;
|
|
24
|
-
onStageExecuted(stageName: string, description
|
|
25
|
+
onStageExecuted(stageName: string, description: string | undefined, traversalContext: TraversalContext | undefined, stageType: StageType): void;
|
|
25
26
|
onNext(fromStage: string, toStage: string, description?: string, traversalContext?: TraversalContext): void;
|
|
26
27
|
onDecision(deciderName: string, chosenBranch: string, rationale?: string, deciderDescription?: string, traversalContext?: TraversalContext, evidence?: DecisionEvidence): void;
|
|
27
28
|
onFork(parentStage: string, childNames: string[], traversalContext?: TraversalContext): void;
|
|
@@ -36,6 +37,7 @@ export declare class FlowRecorderDispatcher implements IControlFlowNarrative {
|
|
|
36
37
|
onResume(stageName: string, stageId: string, hasInput: boolean, traversalContext?: TraversalContext): void;
|
|
37
38
|
onRunStart(input: unknown, traversalContext?: TraversalContext): void;
|
|
38
39
|
onRunEnd(output: unknown, traversalContext?: TraversalContext): void;
|
|
40
|
+
onRunFailed(error: StructuredErrorInfo, traversalContext?: TraversalContext): void;
|
|
39
41
|
/**
|
|
40
42
|
* Returns sentences from an attached NarrativeFlowRecorder (looked up by ID).
|
|
41
43
|
* Callers that need sentences should attach a NarrativeFlowRecorder with id 'narrative'
|