@voltro/plugin-ai-flows 0.33.0 → 0.35.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/CHANGELOG.md +1968 -0
- package/dist/index.d.ts +415 -58
- package/dist/index.js +523 -291
- package/dist/ir-BOv5uwYI.js +142 -0
- package/dist/ir.d.ts +142 -7
- package/dist/ir.js +2 -102
- package/dist/web.d.ts +306 -7
- package/dist/web.js +96 -1
- package/dist/workflow.d.ts +42 -3
- package/dist/workflow.js +4 -3
- package/package.json +11 -10
package/dist/index.d.ts
CHANGED
|
@@ -42,20 +42,18 @@ export declare const aiFlowRunsTable: Table<"_voltro_ai_flow_runs", FieldDefinit
|
|
|
42
42
|
readonly currentStep: ColumnBuilder<number, "integer", true>;
|
|
43
43
|
readonly totalSteps: ColumnBuilder<number, "integer", true>;
|
|
44
44
|
/** The HITL answer, written by `respond`. */
|
|
45
|
-
readonly humanResponse: ColumnBuilder<
|
|
46
|
-
readonly value?: string | undefined;
|
|
47
|
-
readonly text?: string | undefined;
|
|
48
|
-
readonly decision?: "approve" | "reject" | undefined;
|
|
49
|
-
readonly respondedAt?: string | undefined;
|
|
50
|
-
} | null, "json", boolean>;
|
|
45
|
+
readonly humanResponse: ColumnBuilder<HumanResponse | null, "json", boolean>;
|
|
51
46
|
/** Staged follow-up when the chain requires confirmation. */
|
|
52
|
-
readonly chainPending: ColumnBuilder<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
47
|
+
readonly chainPending: ColumnBuilder<ChainPending | null, "json", boolean>;
|
|
48
|
+
/**
|
|
49
|
+
* Why a declared `chainTo` did NOT start — a cycle, or the depth ceiling.
|
|
50
|
+
*
|
|
51
|
+
* A column rather than a log line, because the run row is what a user looks
|
|
52
|
+
* at: a chain that silently does not fire is indistinguishable from a chain
|
|
53
|
+
* that was never declared, and "the second flow never ran" is precisely the
|
|
54
|
+
* report this would otherwise generate.
|
|
55
|
+
*/
|
|
56
|
+
readonly chainRefusal: ColumnBuilder<string | null, "text", boolean>;
|
|
59
57
|
/** Accumulated cost in micro-USD (app view projects to €/cents). */
|
|
60
58
|
readonly costMicroUsd: ColumnBuilder<number, "integer", true>;
|
|
61
59
|
readonly durationMs: ColumnBuilder<number | null, "integer", boolean>;
|
|
@@ -79,6 +77,15 @@ export declare const aiFlowRunsTable: Table<"_voltro_ai_flow_runs", FieldDefinit
|
|
|
79
77
|
readonly updatedBy: ColumnDefinition<string | null, "reference", boolean>;
|
|
80
78
|
}, true, never>;
|
|
81
79
|
|
|
80
|
+
/** Tunables an `aiFlowsPlugin({...})` call can set from `app.config.ts`. */
|
|
81
|
+
export declare interface AiFlowsDefaults {
|
|
82
|
+
/** Park bound for a `human` step, in ms. `0` = wait forever. */
|
|
83
|
+
readonly humanReviewTimeoutMs?: number;
|
|
84
|
+
/** How many flows one `chainTo` chain may traverse. See
|
|
85
|
+
* {@link MAX_CHAIN_DEPTH_DEFAULT}. */
|
|
86
|
+
readonly maxChainDepth?: number;
|
|
87
|
+
}
|
|
88
|
+
|
|
82
89
|
/**
|
|
83
90
|
* The AI-Flows plugin. Install it in `app.config.ts` `plugins: [...]`. It
|
|
84
91
|
* contributes the canonical `ai_flows` + `ai_flow_runs` tables plus the
|
|
@@ -94,6 +101,59 @@ export declare const aiFlowsPlugin: (options?: AiFlowsPluginOptions) => VoltroPl
|
|
|
94
101
|
export declare interface AiFlowsPluginOptions {
|
|
95
102
|
/** Namespace for this plugin's routes / inspect endpoints. Default `aiFlows`. */
|
|
96
103
|
readonly alias?: string;
|
|
104
|
+
/**
|
|
105
|
+
* Contribute this plugin's tables via `extendSchema.tables`. Default `true`.
|
|
106
|
+
*
|
|
107
|
+
* Set `false` when your app ALREADY declares equivalent tables and you want to
|
|
108
|
+
* keep them — the seam this exists for. The plugin then contributes no DDL and
|
|
109
|
+
* the declarative differ never proposes its tables; everything else (routes,
|
|
110
|
+
* inspect, interceptors) is unchanged.
|
|
111
|
+
*
|
|
112
|
+
* **What you take over, exactly:** `_voltro_ai_flows` (definitions) and
|
|
113
|
+
* `_voltro_ai_flow_runs` (runs). The retention sweep registered below still
|
|
114
|
+
* targets `_voltro_ai_flow_runs` by name, so your table inherits the same TTL
|
|
115
|
+
* — which is the intent, but say so to whoever owns that table.
|
|
116
|
+
*
|
|
117
|
+
* It is not offered on every plugin, and the omissions are deliberate rather
|
|
118
|
+
* than unfinished: a `tables: false` that quietly disables a table carrying an
|
|
119
|
+
* AUTHORIZATION or SAFETY decision — the SAML replay cache, SCIM provisioning
|
|
120
|
+
* state, billing's usage counters, cdc-out's outbox — is a security regression
|
|
121
|
+
* shipped as an ergonomics feature. Those plugins need a named store seam
|
|
122
|
+
* first, not a boolean.
|
|
123
|
+
*/
|
|
124
|
+
readonly tables?: boolean;
|
|
125
|
+
/**
|
|
126
|
+
* How long a `human` step parks awaiting its review before the run fails, in
|
|
127
|
+
* ms. Default 7 days (`VOLTRO_AI_FLOW_HUMAN_REVIEW_TIMEOUT_HOURS` overrides at
|
|
128
|
+
* deploy time); `0` = wait forever. A flow's `humanTimeoutMs` and a step's own
|
|
129
|
+
* `timeoutMs` both outrank this.
|
|
130
|
+
*/
|
|
131
|
+
readonly humanReviewTimeoutMs?: number;
|
|
132
|
+
/**
|
|
133
|
+
* How long a FINISHED flow run is kept, in ms. Default 90 days
|
|
134
|
+
* (`VOLTRO_AI_FLOW_RUNS_TTL_HOURS`).
|
|
135
|
+
*
|
|
136
|
+
* `_voltro_ai_flow_runs` stores every step's full output plus review payloads
|
|
137
|
+
* and grows with traffic, so it is registered with the framework retention
|
|
138
|
+
* sweep like every other run-family table. Two properties of that policy are
|
|
139
|
+
* deliberate:
|
|
140
|
+
*
|
|
141
|
+
* - **Only TERMINAL runs are swept.** The predicate is status-aware
|
|
142
|
+
* (`succeeded | failed | cancelled`), so a run parked on a human review
|
|
143
|
+
* survives regardless of age — a plain time-TTL would delete the pending
|
|
144
|
+
* approvals this plugin exists to support.
|
|
145
|
+
* - **Media artifacts are NOT swept with the row.** A run's steps carry hosted
|
|
146
|
+
* URLs whose blobs belong to the storage plugin; deleting the row orphans
|
|
147
|
+
* them. Keep this TTL at or above the app's own media-purge window, or purge
|
|
148
|
+
* by run id before the row ages out.
|
|
149
|
+
*/
|
|
150
|
+
readonly runsTtlMs?: number;
|
|
151
|
+
/**
|
|
152
|
+
* Ceiling on rows ONE inspect call may return (`/flows`, `/runs`). Default
|
|
153
|
+
* 200. A run row carries every step's full output, so the page size is a real
|
|
154
|
+
* response-size knob, not a formality.
|
|
155
|
+
*/
|
|
156
|
+
readonly inspectPageMax?: number;
|
|
97
157
|
}
|
|
98
158
|
|
|
99
159
|
/** `ai_flows` — a reusable flow DEFINITION (the data front door persists these;
|
|
@@ -115,33 +175,12 @@ export declare const aiFlowsTable: Table<"_voltro_ai_flows", FieldDefinitions<{
|
|
|
115
175
|
/** The ordered plan (`FlowStep[]`); null ≡ empty. */
|
|
116
176
|
readonly steps: ColumnBuilder<readonly FlowStep[] | null, "json", boolean>;
|
|
117
177
|
/** The launch-form brief (`BriefField[]`). */
|
|
118
|
-
readonly inputSchema: ColumnBuilder<readonly
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}[] | null, "json", boolean>;
|
|
125
|
-
readonly chainTo: ColumnBuilder<{
|
|
126
|
-
readonly flowRef: string;
|
|
127
|
-
readonly mappings: readonly {
|
|
128
|
-
readonly sourceKey: string;
|
|
129
|
-
readonly targetKey: string;
|
|
130
|
-
}[];
|
|
131
|
-
readonly requireConfirmation?: boolean | undefined;
|
|
132
|
-
} | null, "json", boolean>;
|
|
133
|
-
readonly cadence: ColumnBuilder<{
|
|
134
|
-
readonly frequency?: "weekly" | "monthly" | undefined;
|
|
135
|
-
readonly repeats: readonly number[];
|
|
136
|
-
readonly intervalWeeks?: number | undefined;
|
|
137
|
-
readonly anchorDate?: string | undefined;
|
|
138
|
-
readonly weekOfMonth?: 1 | 2 | 3 | 4 | "last" | undefined;
|
|
139
|
-
readonly hour?: number | undefined;
|
|
140
|
-
readonly minute?: 0 | 15 | 30 | 45 | undefined;
|
|
141
|
-
readonly defaultInput?: {
|
|
142
|
-
readonly [x: string]: unknown;
|
|
143
|
-
} | undefined;
|
|
144
|
-
} | null, "json", boolean>;
|
|
178
|
+
readonly inputSchema: ColumnBuilder<readonly BriefField[] | null, "json", boolean>;
|
|
179
|
+
readonly chainTo: ColumnBuilder<FlowChain | null, "json", boolean>;
|
|
180
|
+
readonly cadence: ColumnBuilder<FlowCadence | null, "json", boolean>;
|
|
181
|
+
/** Flow-wide park bound for `human` steps, in ms (a step's own `timeoutMs`
|
|
182
|
+
* wins). Null → the plugin default. `0` = wait forever. */
|
|
183
|
+
readonly humanTimeoutMs: ColumnBuilder<number | null, "integer", boolean>;
|
|
145
184
|
/** Master on/off — gates scheduling. */
|
|
146
185
|
readonly isEnabled: ColumnBuilder<boolean, "boolean", true>;
|
|
147
186
|
readonly metadata: ColumnBuilder<Record<string, unknown> | null, "json", boolean>;
|
|
@@ -177,7 +216,17 @@ export declare const BriefField: Schema.Struct<{
|
|
|
177
216
|
placeholder: Schema.optional<typeof Schema.String>;
|
|
178
217
|
}>;
|
|
179
218
|
|
|
180
|
-
|
|
219
|
+
/** An INTERFACE for the same reason as {@link FlowStep} — it is reached from an
|
|
220
|
+
* exported table (`aiFlows.inputSchema`), so an alias to a mapped type gets
|
|
221
|
+
* expanded structurally into the api report, in an order that is not stable
|
|
222
|
+
* across build scopes. The `Equals` pin below fails to compile on any drift. */
|
|
223
|
+
export declare interface BriefField {
|
|
224
|
+
readonly key: string;
|
|
225
|
+
readonly label: string;
|
|
226
|
+
readonly type: 'text' | 'textarea' | 'number' | 'boolean';
|
|
227
|
+
readonly required?: boolean | undefined;
|
|
228
|
+
readonly placeholder?: string | undefined;
|
|
229
|
+
}
|
|
181
230
|
|
|
182
231
|
/**
|
|
183
232
|
* Build the `flow.run` executor over a live `AppContext` + injected capabilities.
|
|
@@ -221,7 +270,12 @@ export declare const ChainPending: Schema.Struct<{
|
|
|
221
270
|
status: Schema.Literal<["pending", "confirmed", "dismissed"]>;
|
|
222
271
|
}>;
|
|
223
272
|
|
|
224
|
-
|
|
273
|
+
/** An INTERFACE — reached from `aiFlowRuns.chainPending`; see {@link BriefField}. */
|
|
274
|
+
export declare interface ChainPending {
|
|
275
|
+
readonly flowRef: string;
|
|
276
|
+
readonly input: Json;
|
|
277
|
+
readonly status: 'pending' | 'confirmed' | 'dismissed';
|
|
278
|
+
}
|
|
225
279
|
|
|
226
280
|
export declare const clampMaxSteps: (n: number | null | undefined) => number;
|
|
227
281
|
|
|
@@ -231,6 +285,11 @@ export declare const clearRegistry: () => void;
|
|
|
231
285
|
/** Every `{{ref}}` name referenced in `text` (order-preserving, may repeat). */
|
|
232
286
|
export declare const collectRefs: (text: string) => ReadonlyArray<string>;
|
|
233
287
|
|
|
288
|
+
/** The comparison a `when:` performs. */
|
|
289
|
+
export declare const ConditionOp: Schema.Literal<["truthy", "falsy", "eq", "neq", "contains"]>;
|
|
290
|
+
|
|
291
|
+
export declare type ConditionOp = typeof ConditionOp.Type;
|
|
292
|
+
|
|
234
293
|
/** Create a flow row. Generates an id when absent; tenant/audit columns are
|
|
235
294
|
* auto-stamped by the runtime. */
|
|
236
295
|
export declare const createFlow: (ctx: AppContext, fields: Record<string, unknown>) => Effect.Effect<Readonly<Record<string, unknown>>, never, never>;
|
|
@@ -257,6 +316,9 @@ export declare interface DefineFlowInput {
|
|
|
257
316
|
};
|
|
258
317
|
readonly chain?: FlowChain;
|
|
259
318
|
readonly cadence?: FlowCadence;
|
|
319
|
+
/** Flow-wide park bound for every `human` step that sets no `timeoutMs` of its
|
|
320
|
+
* own, in ms. `0` = wait forever. */
|
|
321
|
+
readonly humanTimeoutMs?: number;
|
|
260
322
|
}
|
|
261
323
|
|
|
262
324
|
/** Hard-delete a flow row by id. Returns whether a row was removed. */
|
|
@@ -264,11 +326,16 @@ export declare const deleteFlow: (ctx: AppContext, args: {
|
|
|
264
326
|
id: string;
|
|
265
327
|
}) => Effect.Effect<boolean, never, never>;
|
|
266
328
|
|
|
329
|
+
/** A one-line rendering for the run timeline and the editor preview. Exported
|
|
330
|
+
* so the reason a step was skipped is the SAME sentence in both places. */
|
|
331
|
+
export declare const describeCondition: (condition: StepCondition) => string;
|
|
332
|
+
|
|
267
333
|
export declare interface EngineDeps {
|
|
268
334
|
/** Resolve an `agent` step's `agentRef` → system prompt + model. Absent →
|
|
269
335
|
* agent steps with an `agentRef` fail with FlowCapabilityMissing. */
|
|
270
336
|
readonly resolveAgent?: (agentRef: string) => Effect.Effect<AgentResolution, FlowNotFound, unknown>;
|
|
271
|
-
/** Media generator for image/video/audio steps (
|
|
337
|
+
/** Media generator for image/video/audio steps (`makeMediaGenerator` in
|
|
338
|
+
* `mediaAdapter.ts` is the @voltro/ai-backed implementation). */
|
|
272
339
|
readonly generateMedia?: MediaGenerator;
|
|
273
340
|
/** Fallback model per modality when a step omits `model`. */
|
|
274
341
|
readonly defaultModels?: {
|
|
@@ -288,11 +355,39 @@ export declare interface EngineDeps {
|
|
|
288
355
|
/** Long-term-memory prefix prepended to the orchestrator system prompt (wire
|
|
289
356
|
* to the app's ai_user_memories). Best-effort. */
|
|
290
357
|
readonly memoryPrefix?: (ownerId: string | null) => Effect.Effect<string, never, unknown>;
|
|
358
|
+
/** Default park bound for `human` steps in ms, for flows that set none. Sits
|
|
359
|
+
* between the flow's own `humanTimeoutMs` and the `aiFlowsPlugin({...})`
|
|
360
|
+
* option / `VOLTRO_AI_FLOW_HUMAN_REVIEW_TIMEOUT_HOURS` (see `defaults.ts`).
|
|
361
|
+
* `0` = wait forever. */
|
|
362
|
+
readonly humanReviewTimeoutMs?: number;
|
|
363
|
+
/** How many flows one `chainTo` chain may traverse, INCLUDING the flow that
|
|
364
|
+
* started it. Sits between nothing and the `aiFlowsPlugin({...})` option /
|
|
365
|
+
* `VOLTRO_AI_FLOW_MAX_CHAIN_DEPTH` (see `defaults.ts`). A cycle is refused
|
|
366
|
+
* separately and cannot be raised by this number. */
|
|
367
|
+
readonly maxChainDepth?: number;
|
|
291
368
|
}
|
|
292
369
|
|
|
370
|
+
/**
|
|
371
|
+
* Evaluate `condition` against a run context.
|
|
372
|
+
*
|
|
373
|
+
* A condition on a ref the context does not carry evaluates as ABSENT — false
|
|
374
|
+
* for `truthy`/`eq`/`contains`, true for `falsy`/`neq`. That asymmetry is the
|
|
375
|
+
* honest reading of "the producing step did not run", and it is why
|
|
376
|
+
* `validateFlow` refuses a dangling ref at registration: at run time, a typo and
|
|
377
|
+
* a genuinely-skipped producer are indistinguishable here.
|
|
378
|
+
*/
|
|
379
|
+
export declare const evaluateCondition: (condition: StepCondition, context: Readonly<Record<string, unknown>>) => boolean;
|
|
380
|
+
|
|
293
381
|
/** The canonical name the launch action starts + the app re-export registers. */
|
|
294
382
|
export declare const FLOW_RUN_WORKFLOW = "flow.run";
|
|
295
383
|
|
|
384
|
+
/** Deploy-time override for {@link FLOW_RUNS_TTL_HOURS_DEFAULT}, in hours. */
|
|
385
|
+
export declare const FLOW_RUNS_TTL_ENV = "VOLTRO_AI_FLOW_RUNS_TTL_HOURS";
|
|
386
|
+
|
|
387
|
+
/** Framework default retention for `_voltro_ai_flow_runs`: 90 days of finished
|
|
388
|
+
* runs. Only TERMINAL runs are swept — see `index.ts`. */
|
|
389
|
+
export declare const FLOW_RUNS_TTL_HOURS_DEFAULT: number;
|
|
390
|
+
|
|
296
391
|
/** A required brief field was blank at launch. */
|
|
297
392
|
declare class FlowBriefIncomplete extends FlowBriefIncomplete_base {
|
|
298
393
|
}
|
|
@@ -322,7 +417,25 @@ export declare const FlowCadence: Schema.Struct<{
|
|
|
322
417
|
defaultInput: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
|
|
323
418
|
}>;
|
|
324
419
|
|
|
325
|
-
|
|
420
|
+
/**
|
|
421
|
+
* An INTERFACE — reached from `aiFlows.cadence`; see {@link BriefField}.
|
|
422
|
+
*
|
|
423
|
+
* This one is not hypothetical: a single-package `api:report` and a
|
|
424
|
+
* full-monorepo build emitted `hour`/`minute` in DIFFERENT positions inside the
|
|
425
|
+
* structurally-expanded alias, so the api-surface gate rejected a file nobody
|
|
426
|
+
* had touched, showing the same members moving. That is the exact failure
|
|
427
|
+
* {@link FlowStep}'s comment describes.
|
|
428
|
+
*/
|
|
429
|
+
export declare interface FlowCadence {
|
|
430
|
+
readonly frequency?: 'weekly' | 'monthly' | undefined;
|
|
431
|
+
readonly repeats: ReadonlyArray<number>;
|
|
432
|
+
readonly intervalWeeks?: number | undefined;
|
|
433
|
+
readonly anchorDate?: string | undefined;
|
|
434
|
+
readonly weekOfMonth?: 1 | 2 | 3 | 4 | 'last' | undefined;
|
|
435
|
+
readonly hour?: number | undefined;
|
|
436
|
+
readonly minute?: 0 | 15 | 30 | 45 | undefined;
|
|
437
|
+
readonly defaultInput?: Json | undefined;
|
|
438
|
+
}
|
|
326
439
|
|
|
327
440
|
/** A generation step required a capability the host did not provide (e.g. a
|
|
328
441
|
* media modality with no configured generator, or storage for the artifact). */
|
|
@@ -347,7 +460,15 @@ export declare const FlowChain: Schema.Struct<{
|
|
|
347
460
|
requireConfirmation: Schema.optional<typeof Schema.Boolean>;
|
|
348
461
|
}>;
|
|
349
462
|
|
|
350
|
-
|
|
463
|
+
/** An INTERFACE — reached from `aiFlows.chainTo`; see {@link BriefField}. */
|
|
464
|
+
export declare interface FlowChain {
|
|
465
|
+
readonly flowRef: string;
|
|
466
|
+
readonly mappings: ReadonlyArray<{
|
|
467
|
+
readonly targetKey: string;
|
|
468
|
+
readonly sourceKey: string;
|
|
469
|
+
}>;
|
|
470
|
+
readonly requireConfirmation?: boolean | undefined;
|
|
471
|
+
}
|
|
351
472
|
|
|
352
473
|
/** The raw flow definition either front door supplies before normalization.
|
|
353
474
|
* Optional fields tolerate explicit `undefined` (row reads produce it). */
|
|
@@ -361,6 +482,7 @@ export declare interface FlowDefinitionInput {
|
|
|
361
482
|
readonly orchestratorInstructions?: string | null | undefined;
|
|
362
483
|
readonly chain?: FlowChain | null | undefined;
|
|
363
484
|
readonly cadence?: FlowCadence | null | undefined;
|
|
485
|
+
readonly humanTimeoutMs?: number | null | undefined;
|
|
364
486
|
}
|
|
365
487
|
|
|
366
488
|
/** The single representation the engine interprets, from either front door. */
|
|
@@ -376,6 +498,10 @@ export declare interface FlowIR {
|
|
|
376
498
|
};
|
|
377
499
|
readonly chain?: FlowChain;
|
|
378
500
|
readonly cadence?: FlowCadence;
|
|
501
|
+
/** Flow-wide default for a `human` step's park bound, in ms. A step's own
|
|
502
|
+
* `timeoutMs` wins; absent here too → the engine/plugin default. `0` = wait
|
|
503
|
+
* forever. */
|
|
504
|
+
readonly humanTimeoutMs?: number;
|
|
379
505
|
}
|
|
380
506
|
|
|
381
507
|
/** A lifecycle event the host can turn into a notification (best-effort). */
|
|
@@ -436,8 +562,34 @@ export declare interface FlowRunPayload {
|
|
|
436
562
|
readonly input: Record<string, unknown>;
|
|
437
563
|
readonly source: 'manual' | 'cron';
|
|
438
564
|
readonly requestId: string;
|
|
565
|
+
readonly chainPath?: ReadonlyArray<string> | undefined;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/** One unit of execution: a single step, or a set that runs concurrently. */
|
|
569
|
+
export declare interface FlowSegment {
|
|
570
|
+
/** `undefined` for an ungrouped single step. */
|
|
571
|
+
readonly group?: string | undefined;
|
|
572
|
+
/** The steps in this segment, with their ORIGINAL indices — the durable step
|
|
573
|
+
* name and the timeline slot both key off the index, so it travels. */
|
|
574
|
+
readonly steps: ReadonlyArray<{
|
|
575
|
+
readonly index: number;
|
|
576
|
+
readonly step: FlowStep;
|
|
577
|
+
}>;
|
|
439
578
|
}
|
|
440
579
|
|
|
580
|
+
/**
|
|
581
|
+
* Split a step list into execution segments.
|
|
582
|
+
*
|
|
583
|
+
* Only CONSECUTIVE steps sharing a group name form a segment. A group that
|
|
584
|
+
* reappears after an interruption forms a SECOND segment — which is almost
|
|
585
|
+
* certainly not what the author meant, so `validateFlow` refuses it rather than
|
|
586
|
+
* letting this function silently produce two sequential fan-outs from what reads
|
|
587
|
+
* like one. This function stays permissive on purpose: it is used by the
|
|
588
|
+
* validator, and a validator whose input has already been sanitised cannot
|
|
589
|
+
* report on it.
|
|
590
|
+
*/
|
|
591
|
+
export declare const flowSegments: (steps: ReadonlyArray<FlowStep>) => ReadonlyArray<FlowSegment>;
|
|
592
|
+
|
|
441
593
|
/** Flow-definition lifecycle. */
|
|
442
594
|
export declare const FlowStatus: Schema.Literal<["draft", "active", "archived"]>;
|
|
443
595
|
|
|
@@ -479,6 +631,29 @@ export declare const FlowStep: Schema.Struct<{
|
|
|
479
631
|
value: typeof Schema.String;
|
|
480
632
|
label: typeof Schema.String;
|
|
481
633
|
}>>>;
|
|
634
|
+
/** Gate this step on a prior value. Absent → the step always runs. A step
|
|
635
|
+
* whose condition is false is SKIPPED, not failed: it produces no output, so
|
|
636
|
+
* anything referencing its `outputKey` sees an absent value. */
|
|
637
|
+
when: Schema.optional<Schema.Struct<{
|
|
638
|
+
ref: typeof Schema.String;
|
|
639
|
+
op: Schema.Literal<["truthy", "falsy", "eq", "neq", "contains"]>;
|
|
640
|
+
value: Schema.optional<typeof Schema.Unknown>;
|
|
641
|
+
}>>;
|
|
642
|
+
/**
|
|
643
|
+
* Fan-out group. CONSECUTIVE steps sharing a group name run CONCURRENTLY,
|
|
644
|
+
* each still journaled as its own durable step.
|
|
645
|
+
*
|
|
646
|
+
* Steps in one group may not reference each other's outputs — they have no
|
|
647
|
+
* order between them — and `validateFlow` refuses a flow that tries. A `human`
|
|
648
|
+
* step may not join a group either: it suspends the whole workflow, which is
|
|
649
|
+
* not a thing one branch of a fan-out can do.
|
|
650
|
+
*/
|
|
651
|
+
group: Schema.optional<typeof Schema.String>;
|
|
652
|
+
/** `human` step only — how long the run parks awaiting this review before it
|
|
653
|
+
* fails, in milliseconds. Omitted → the flow's `humanTimeoutMs`, then the
|
|
654
|
+
* engine/plugin default (see `resolveHumanReviewTimeoutMs`). `0` means WAIT
|
|
655
|
+
* FOREVER (the park is slot-free, so an unbounded wait costs no worker). */
|
|
656
|
+
timeoutMs: Schema.optional<typeof Schema.Number>;
|
|
482
657
|
}>;
|
|
483
658
|
|
|
484
659
|
/**
|
|
@@ -519,6 +694,9 @@ export declare interface FlowStep {
|
|
|
519
694
|
readonly schema?: Json | undefined;
|
|
520
695
|
readonly reviewMode?: ReviewMode | undefined;
|
|
521
696
|
readonly options?: ReadonlyArray<ReviewOption> | undefined;
|
|
697
|
+
readonly when?: StepCondition | undefined;
|
|
698
|
+
readonly group?: string | undefined;
|
|
699
|
+
readonly timeoutMs?: number | undefined;
|
|
522
700
|
}
|
|
523
701
|
|
|
524
702
|
/** Typed builders for each step kind — terser + safer than hand-writing the
|
|
@@ -531,7 +709,7 @@ export declare const flowStep: {
|
|
|
531
709
|
prompt: string;
|
|
532
710
|
model?: string;
|
|
533
711
|
outputKey?: string;
|
|
534
|
-
}) => FlowStepDraft;
|
|
712
|
+
} & StepControls) => FlowStepDraft;
|
|
535
713
|
/** An image/video/audio generation. */
|
|
536
714
|
media: (modality: Modality, o: {
|
|
537
715
|
title?: string;
|
|
@@ -540,7 +718,7 @@ export declare const flowStep: {
|
|
|
540
718
|
model?: string;
|
|
541
719
|
params?: Record<string, unknown>;
|
|
542
720
|
outputKey?: string;
|
|
543
|
-
}) => FlowStepDraft;
|
|
721
|
+
} & StepControls) => FlowStepDraft;
|
|
544
722
|
/** Delegate to an allowed sub-agent (text-only). */
|
|
545
723
|
agent: (o: {
|
|
546
724
|
title?: string;
|
|
@@ -549,7 +727,7 @@ export declare const flowStep: {
|
|
|
549
727
|
prompt: string;
|
|
550
728
|
model?: string;
|
|
551
729
|
outputKey?: string;
|
|
552
|
-
}) => FlowStepDraft;
|
|
730
|
+
} & StepControls) => FlowStepDraft;
|
|
553
731
|
/** Return a JSON object validated against a JSON Schema. */
|
|
554
732
|
structured: (o: {
|
|
555
733
|
title?: string;
|
|
@@ -558,15 +736,16 @@ export declare const flowStep: {
|
|
|
558
736
|
schema: Record<string, unknown>;
|
|
559
737
|
model?: string;
|
|
560
738
|
outputKey?: string;
|
|
561
|
-
}) => FlowStepDraft;
|
|
739
|
+
} & StepControls) => FlowStepDraft;
|
|
562
740
|
/** Free-text guidance — the interpolated prompt itself is the output. */
|
|
563
741
|
note: (o: {
|
|
564
742
|
title?: string;
|
|
565
743
|
description?: string;
|
|
566
744
|
prompt: string;
|
|
567
745
|
outputKey?: string;
|
|
568
|
-
}) => FlowStepDraft;
|
|
569
|
-
/** Pause for human review.
|
|
746
|
+
} & StepControls) => FlowStepDraft;
|
|
747
|
+
/** Pause for human review. `timeoutMs` bounds the park (default: the flow's
|
|
748
|
+
* `humanTimeoutMs`, then the plugin default — 7 days; `0` = wait forever). */
|
|
570
749
|
human: (o: {
|
|
571
750
|
title?: string;
|
|
572
751
|
description?: string;
|
|
@@ -574,12 +753,16 @@ export declare const flowStep: {
|
|
|
574
753
|
options?: ReadonlyArray<ReviewOption>;
|
|
575
754
|
prompt?: string;
|
|
576
755
|
outputKey?: string;
|
|
577
|
-
|
|
756
|
+
timeoutMs?: number;
|
|
757
|
+
} & Pick<StepControls, "when">) => FlowStepDraft;
|
|
578
758
|
};
|
|
579
759
|
|
|
580
760
|
/** A step without its `id` — `defineFlow` assigns stable index-based ids. */
|
|
581
761
|
export declare type FlowStepDraft = Omit<FlowStep, 'id'>;
|
|
582
762
|
|
|
763
|
+
/** The recorded `app.config.ts` tunables. */
|
|
764
|
+
export declare const getAiFlowsDefaults: () => AiFlowsDefaults;
|
|
765
|
+
|
|
583
766
|
/** One stored flow by id, or undefined (tenant-scoped by the runtime). */
|
|
584
767
|
export declare const getFlow: (ctx: AppContext, args: {
|
|
585
768
|
id: string;
|
|
@@ -588,8 +771,18 @@ export declare const getFlow: (ctx: AppContext, args: {
|
|
|
588
771
|
/** Resolve a code-registered flow by name, or `undefined` for a data flow. */
|
|
589
772
|
export declare const getRegisteredFlow: (name: string) => FlowIR | undefined;
|
|
590
773
|
|
|
591
|
-
/**
|
|
592
|
-
|
|
774
|
+
/** Namespace of the signal a `human` step parks on. Never used on its own —
|
|
775
|
+
* the signal a step actually awaits is {@link humanResponseSignalName}. */
|
|
776
|
+
export declare const HUMAN_RESPONSE_SIGNAL_PREFIX = "flow-human-response";
|
|
777
|
+
|
|
778
|
+
/** Deploy-time override for {@link HUMAN_REVIEW_TIMEOUT_HOURS_DEFAULT}, in
|
|
779
|
+
* hours. `0` (or a negative value) means WAIT FOREVER. */
|
|
780
|
+
export declare const HUMAN_REVIEW_TIMEOUT_ENV = "VOLTRO_AI_FLOW_HUMAN_REVIEW_TIMEOUT_HOURS";
|
|
781
|
+
|
|
782
|
+
/** Framework default park bound for a human review: 7 days. Long enough to
|
|
783
|
+
* survive a weekend + a holiday Monday, short enough that an abandoned review
|
|
784
|
+
* eventually settles instead of pinning a run forever. */
|
|
785
|
+
export declare const HUMAN_REVIEW_TIMEOUT_HOURS_DEFAULT: number;
|
|
593
786
|
|
|
594
787
|
/** The HITL answer, written by `respond`. */
|
|
595
788
|
export declare const HumanResponse: Schema.Struct<{
|
|
@@ -599,17 +792,81 @@ export declare const HumanResponse: Schema.Struct<{
|
|
|
599
792
|
respondedAt: Schema.optional<typeof Schema.String>;
|
|
600
793
|
}>;
|
|
601
794
|
|
|
602
|
-
|
|
795
|
+
/** An INTERFACE — reached from `aiFlowRuns.humanResponse`; see {@link BriefField}. */
|
|
796
|
+
export declare interface HumanResponse {
|
|
797
|
+
readonly decision?: 'approve' | 'reject' | undefined;
|
|
798
|
+
readonly value?: string | undefined;
|
|
799
|
+
readonly text?: string | undefined;
|
|
800
|
+
readonly respondedAt?: string | undefined;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
/**
|
|
804
|
+
* The signal name ONE human step parks on, derived from that step's position in
|
|
805
|
+
* the (journal-pinned) plan.
|
|
806
|
+
*
|
|
807
|
+
* **Why this is per-step and not one constant.** `awaitSignalSuspending` derives
|
|
808
|
+
* its `DurableDeferred` from workflow-name + signal-name per execution, so a
|
|
809
|
+
* single `'flow-human-response'` for every human step in a flow meant the SECOND
|
|
810
|
+
* review awaited the deferred the FIRST answer had already completed — it
|
|
811
|
+
* resolved instantly, with the first reviewer's payload, and the run finished
|
|
812
|
+
* carrying an approval nobody gave. Measured before the fix: a two-review flow,
|
|
813
|
+
* one answer, `status: 'succeeded'`, `output: { first: 'answer-one', second:
|
|
814
|
+
* 'answer-one' }`. The same collision aliased the wait's durable timeout clock
|
|
815
|
+
* (`await-signal-timeout/<name>`), so the second park inherited the first's
|
|
816
|
+
* expiry too.
|
|
817
|
+
*
|
|
818
|
+
* **Why the INDEX is the identity.** It must be identical on every replay and
|
|
819
|
+
* derivable by the responder without re-resolving the flow definition (which may
|
|
820
|
+
* have been edited mid-run). The step list is pinned in the run's journal at
|
|
821
|
+
* step 0, so a step's index is fixed for the life of the run; the responder
|
|
822
|
+
* reads it back off the run row's live timeline. A counter, a clock, or a
|
|
823
|
+
* `randomUUID` would all break replay; the authored step `id` would break the
|
|
824
|
+
* moment a definition is re-ordered under a live run.
|
|
825
|
+
*/
|
|
826
|
+
export declare const humanResponseSignalName: (stepIndex: number) => string;
|
|
603
827
|
|
|
604
828
|
/** Replace `{{key}}` with `context[key]` (objects/arrays JSON-stringified; an
|
|
605
829
|
* absent/null value renders empty). */
|
|
606
830
|
export declare const interpolate: (text: string, context: Record<string, unknown>) => string;
|
|
607
831
|
|
|
832
|
+
/**
|
|
833
|
+
* Truthiness, defined once so the engine and the editor cannot disagree.
|
|
834
|
+
*
|
|
835
|
+
* Deliberately NOT JavaScript's: `0` and `''` are falsy in JS, and a step gated
|
|
836
|
+
* on a count or a generated string would then be skipped for a legitimate value.
|
|
837
|
+
* A flow author writing `when: { ref: 'count', op: 'truthy' }` means "there is a
|
|
838
|
+
* count", not "the count is non-zero" — the second is `{ op: 'neq', value: 0 }`,
|
|
839
|
+
* which they can say if they mean it.
|
|
840
|
+
*
|
|
841
|
+
* Absent, null and the empty ARRAY are the falsy set: those are the three
|
|
842
|
+
* shapes a step that produced nothing actually leaves behind.
|
|
843
|
+
*/
|
|
844
|
+
export declare const isTruthy: (v: unknown) => boolean;
|
|
845
|
+
|
|
608
846
|
/** A JSON value (for `params` / `input` / a `structured` step's JSON Schema). */
|
|
609
847
|
export declare const Json: Schema.Record$<typeof Schema.String, typeof Schema.Unknown>;
|
|
610
848
|
|
|
611
849
|
export declare type Json = typeof Json.Type;
|
|
612
850
|
|
|
851
|
+
/** A JSON-Schema node as stored on a `structured` step. */
|
|
852
|
+
export declare type JsonSchemaNode = Record<string, unknown>;
|
|
853
|
+
|
|
854
|
+
/**
|
|
855
|
+
* Adapt a `structured` step's JSON Schema to the Effect `Schema` the engine
|
|
856
|
+
* hands `generateObject`. An absent / unusable schema falls back to the open
|
|
857
|
+
* record, so a step authored without one behaves exactly as before.
|
|
858
|
+
*
|
|
859
|
+
* ```ts
|
|
860
|
+
* jsonSchemaToEffectSchema({
|
|
861
|
+
* type: 'object',
|
|
862
|
+
* properties: { title: { type: 'string' }, tags: { type: 'array', items: { type: 'string' } } },
|
|
863
|
+
* required: ['title'],
|
|
864
|
+
* })
|
|
865
|
+
* // ≡ Schema.Struct({ title: Schema.String, tags: Schema.optional(Schema.Array(Schema.String)) })
|
|
866
|
+
* ```
|
|
867
|
+
*/
|
|
868
|
+
export declare const jsonSchemaToEffectSchema: (jsonSchema: JsonSchemaNode | undefined) => Schema.Schema<unknown, unknown>;
|
|
869
|
+
|
|
613
870
|
/** Launch a fresh run of a flow (by code name or row id). Validates the brief,
|
|
614
871
|
* creates the run row, and starts the durable `flow.run` workflow. */
|
|
615
872
|
export declare const launchFlow: (ctx: AppContext, args: {
|
|
@@ -638,6 +895,20 @@ export declare const makeMediaGenerator: (persist: MediaPersist, opts?: {
|
|
|
638
895
|
readonly resolveModel?: (model: string) => ProviderConfig;
|
|
639
896
|
}) => MediaGenerator;
|
|
640
897
|
|
|
898
|
+
/**
|
|
899
|
+
* How many flows one chain may traverse, including the flow that started it.
|
|
900
|
+
*
|
|
901
|
+
* Five, because a chain is a hand-authored pipeline and nobody writes six on
|
|
902
|
+
* purpose — but the number is a FIELD rather than a constant precisely because
|
|
903
|
+
* "nobody does that" is an assumption about other people's apps. A cycle is
|
|
904
|
+
* refused separately and unconditionally; this bounds the acyclic case, where
|
|
905
|
+
* every hop is a real LLM run somebody pays for.
|
|
906
|
+
*/
|
|
907
|
+
export declare const MAX_CHAIN_DEPTH_DEFAULT = 5;
|
|
908
|
+
|
|
909
|
+
/** Deploy-time override for {@link MAX_CHAIN_DEPTH_DEFAULT}. */
|
|
910
|
+
export declare const MAX_CHAIN_DEPTH_ENV = "VOLTRO_AI_FLOW_MAX_CHAIN_DEPTH";
|
|
911
|
+
|
|
641
912
|
/** Legacy default was 30, clamped to [1,100]. (Distinct from `@voltro/ai`'s
|
|
642
913
|
* own `maxSteps` default of 8 for a single tool loop.) */
|
|
643
914
|
export declare const MAX_STEPS_DEFAULT = 30;
|
|
@@ -734,6 +1005,9 @@ export declare type Modality = typeof Modality.Type;
|
|
|
734
1005
|
*/
|
|
735
1006
|
export declare const nextRuns: (cadence: FlowCadence, from: Date, count?: number) => ReadonlyArray<Date>;
|
|
736
1007
|
|
|
1008
|
+
/** Group names that appear in more than one segment — a non-contiguous group. */
|
|
1009
|
+
export declare const nonContiguousGroups: (segments: ReadonlyArray<FlowSegment>) => ReadonlyArray<string>;
|
|
1010
|
+
|
|
737
1011
|
/**
|
|
738
1012
|
* Lower a raw flow definition (from code or a row) to the normalized IR:
|
|
739
1013
|
* default the mode, clamp maxSteps, sanitize outputKeys, drop empties. Pure +
|
|
@@ -745,16 +1019,52 @@ export declare const normalizeFlow: (def: FlowDefinitionInput) => FlowIR;
|
|
|
745
1019
|
* `defineFlow` when the module is loaded. */
|
|
746
1020
|
export declare const registerFlow: (ir: FlowIR) => void;
|
|
747
1021
|
|
|
1022
|
+
/** Test seam — forget the recorded tunables. */
|
|
1023
|
+
export declare const resetAiFlowsDefaults: () => void;
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* Resolve a human step's park bound down the precedence ladder. Pure — the env
|
|
1027
|
+
* read is passed in so a test can drive it without touching `process.env`.
|
|
1028
|
+
*/
|
|
1029
|
+
export declare const resolveHumanReviewTimeoutMs: (input: {
|
|
1030
|
+
readonly step?: {
|
|
1031
|
+
readonly timeoutMs?: number | undefined;
|
|
1032
|
+
};
|
|
1033
|
+
readonly flow?: {
|
|
1034
|
+
readonly humanTimeoutMs?: number | undefined;
|
|
1035
|
+
};
|
|
1036
|
+
readonly deps?: {
|
|
1037
|
+
readonly humanReviewTimeoutMs?: number | undefined;
|
|
1038
|
+
};
|
|
1039
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
1040
|
+
}) => number;
|
|
1041
|
+
|
|
748
1042
|
/** Resolve the IR: code registry by name first, else the stored `ai_flows` row. */
|
|
749
1043
|
export declare const resolveIr: (ctx: AppContext, flowRef: string) => Effect.Effect<FlowIR, FlowNotFound>;
|
|
750
1044
|
|
|
1045
|
+
/**
|
|
1046
|
+
* Resolve the chain-depth ceiling down the same ladder as every other tunable:
|
|
1047
|
+
* engine deps → plugin option (`app.config.ts`) → env → framework default.
|
|
1048
|
+
*
|
|
1049
|
+
* A value below 1 is IGNORED rather than honoured. `0` would mean "no flow may
|
|
1050
|
+
* chain at all", which is expressible by not declaring a chain, and reading it
|
|
1051
|
+
* literally would turn a typo into a silently disabled feature — the same
|
|
1052
|
+
* reasoning `msFromHoursEnv` applies to a negative timeout.
|
|
1053
|
+
*/
|
|
1054
|
+
export declare const resolveMaxChainDepth: (deps?: {
|
|
1055
|
+
readonly maxChainDepth?: number | undefined;
|
|
1056
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
1057
|
+
}) => number;
|
|
1058
|
+
|
|
751
1059
|
/** Record a human's answer to a `waiting` run + signal the parked workflow to
|
|
752
|
-
* resume.
|
|
1060
|
+
* resume. The signal is addressed to THAT STEP's own durable deferred — one
|
|
1061
|
+
* shared name meant a later review resolved with an earlier answer. */
|
|
753
1062
|
export declare const respondToFlow: (ctx: AppContext, args: {
|
|
754
1063
|
runId: string;
|
|
755
1064
|
response: HumanResponse;
|
|
756
1065
|
}) => Effect.Effect<{
|
|
757
1066
|
runId: string;
|
|
1067
|
+
stepIndex: number;
|
|
758
1068
|
}, FlowRunNotFound | FlowNotAwaitingResponse, never>;
|
|
759
1069
|
|
|
760
1070
|
/** Re-run a run from its first unfinished step. Reuses the SAME requestId so the
|
|
@@ -819,7 +1129,7 @@ export declare const RunStep: Schema.Struct<{
|
|
|
819
1129
|
title: typeof Schema.String;
|
|
820
1130
|
description: Schema.optional<typeof Schema.String>;
|
|
821
1131
|
type: Schema.Literal<["agent", "generate", "structured", "note", "human"]>;
|
|
822
|
-
status: Schema.Literal<["pending", "running", "waiting", "succeeded", "failed"]>;
|
|
1132
|
+
status: Schema.Literal<["pending", "running", "waiting", "succeeded", "failed", "skipped"]>;
|
|
823
1133
|
startedAt: Schema.optional<typeof Schema.String>;
|
|
824
1134
|
completedAt: Schema.optional<typeof Schema.String>;
|
|
825
1135
|
/** Per-step cost in micro-USD (the app view projects to €/cents). */
|
|
@@ -833,6 +1143,9 @@ export declare const RunStep: Schema.Struct<{
|
|
|
833
1143
|
text: typeof Schema.String;
|
|
834
1144
|
}>>;
|
|
835
1145
|
errorMessage: Schema.optional<typeof Schema.String>;
|
|
1146
|
+
/** Why a `skipped` step was skipped — the rendered condition, so the timeline
|
|
1147
|
+
* says "{{approved}} is not set" instead of leaving a silent gap. */
|
|
1148
|
+
skipReason: Schema.optional<typeof Schema.String>;
|
|
836
1149
|
review: Schema.optional<Schema.Struct<{
|
|
837
1150
|
mode: Schema.Literal<["approve", "choice", "text"]>;
|
|
838
1151
|
options: Schema.optional<Schema.Array$<Schema.Struct<{
|
|
@@ -861,16 +1174,48 @@ export declare interface RunStep {
|
|
|
861
1174
|
readonly text: string;
|
|
862
1175
|
} | undefined;
|
|
863
1176
|
readonly errorMessage?: string | undefined;
|
|
1177
|
+
readonly skipReason?: string | undefined;
|
|
864
1178
|
readonly review?: RunReview | undefined;
|
|
865
1179
|
}
|
|
866
1180
|
|
|
867
|
-
export declare const RunStepStatus: Schema.Literal<["pending", "running", "waiting", "succeeded", "failed"]>;
|
|
1181
|
+
export declare const RunStepStatus: Schema.Literal<["pending", "running", "waiting", "succeeded", "failed", "skipped"]>;
|
|
868
1182
|
|
|
869
1183
|
export declare type RunStepStatus = typeof RunStepStatus.Type;
|
|
870
1184
|
|
|
871
1185
|
/** Sanitize an outputKey to the `{{ref}}`-safe charset. */
|
|
872
1186
|
export declare const sanitizeOutputKey: (key: string) => string;
|
|
873
1187
|
|
|
1188
|
+
/** Record the `app.config.ts` tunables (called by the plugin factory). */
|
|
1189
|
+
export declare const setAiFlowsDefaults: (defaults: AiFlowsDefaults) => void;
|
|
1190
|
+
|
|
1191
|
+
declare const StepCondition: Schema.Struct<{
|
|
1192
|
+
/** A brief-field key or an EARLIER step's `outputKey`. */
|
|
1193
|
+
ref: typeof Schema.String;
|
|
1194
|
+
op: Schema.Literal<["truthy", "falsy", "eq", "neq", "contains"]>;
|
|
1195
|
+
/** The right-hand side for `eq` / `neq` / `contains`. Ignored by the unary ops. */
|
|
1196
|
+
value: Schema.optional<typeof Schema.Unknown>;
|
|
1197
|
+
}>;
|
|
1198
|
+
|
|
1199
|
+
/** An INTERFACE, for the same api-report reason as `FlowStep` — it is reached
|
|
1200
|
+
* from an exported table column, and an alias to a mapped type gets expanded
|
|
1201
|
+
* structurally in an order that is not stable across build scopes. */
|
|
1202
|
+
declare interface StepCondition {
|
|
1203
|
+
readonly ref: string;
|
|
1204
|
+
readonly op: ConditionOp;
|
|
1205
|
+
readonly value?: unknown;
|
|
1206
|
+
}
|
|
1207
|
+
export { StepCondition }
|
|
1208
|
+
export { StepCondition as StepConditionType }
|
|
1209
|
+
|
|
1210
|
+
/** Gating + fan-out, accepted by every builder. Kept as one type so a new
|
|
1211
|
+
* builder cannot quietly omit them — the six builders below spread it. */
|
|
1212
|
+
declare interface StepControls {
|
|
1213
|
+
/** Run this step only when the condition holds; otherwise SKIP it. */
|
|
1214
|
+
readonly when?: StepCondition;
|
|
1215
|
+
/** Consecutive steps sharing a group run CONCURRENTLY. */
|
|
1216
|
+
readonly group?: string;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
874
1219
|
/** The five step types. `generate` fans out to four modalities. */
|
|
875
1220
|
export declare const StepType: Schema.Literal<["agent", "generate", "structured", "note", "human"]>;
|
|
876
1221
|
|
|
@@ -905,4 +1250,16 @@ export declare const Visibility: Schema.Literal<["private", "organization", "sha
|
|
|
905
1250
|
|
|
906
1251
|
export declare type Visibility = typeof Visibility.Type;
|
|
907
1252
|
|
|
1253
|
+
/**
|
|
1254
|
+
* Which human step a `waiting` run is parked on — the index the engine used to
|
|
1255
|
+
* derive the step's signal name.
|
|
1256
|
+
*
|
|
1257
|
+
* Read from the LIVE TIMELINE the engine wrote when it parked (`steps[i].status
|
|
1258
|
+
* === 'waiting'`), with `currentStep` as the fallback for a row whose timeline
|
|
1259
|
+
* hasn't been written yet. Deliberately NOT re-resolved from the flow definition:
|
|
1260
|
+
* a definition edited mid-run would hand back a different plan than the one the
|
|
1261
|
+
* run's journal pinned, and the answer would be delivered to the wrong step.
|
|
1262
|
+
*/
|
|
1263
|
+
export declare const waitingStepIndex: (row: Record<string, unknown>) => number;
|
|
1264
|
+
|
|
908
1265
|
export { }
|