@uipath/maestro-builder-sdk 6.42.0 → 6.44.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.
Files changed (61) hide show
  1. package/dist/api-index.md +104 -103
  2. package/dist/api-members.md +319 -317
  3. package/dist/check.d.ts +0 -19
  4. package/dist/check.js +140 -1042
  5. package/dist/compile-cli.js +2 -1
  6. package/dist/core/actions.d.ts +10 -713
  7. package/dist/core/actions.js +0 -193
  8. package/dist/core/agent-sidecar.d.ts +186 -0
  9. package/dist/core/agent-sidecar.js +409 -0
  10. package/dist/core/agent-tool-resources.d.ts +62 -0
  11. package/dist/core/agent-tool-resources.js +81 -0
  12. package/dist/{config.js → core/connector-configuration.js} +2 -2
  13. package/dist/core/form-field-type.d.ts +7 -0
  14. package/dist/core/form-field-type.js +12 -2
  15. package/dist/core/node-id-placeholder.d.ts +8 -0
  16. package/dist/core/node-id-placeholder.js +10 -0
  17. package/dist/core/ts-literal.d.ts +6 -0
  18. package/dist/core/ts-literal.js +15 -0
  19. package/dist/core/typed-raw-node.js +0 -5
  20. package/dist/decompile.js +239 -857
  21. package/dist/flow-expr-check.js +5 -0
  22. package/dist/flow-node-registry.js +2 -1
  23. package/dist/flow-node-type.d.ts +139 -6
  24. package/dist/flow-sdk.d.ts +41 -5
  25. package/dist/flow-sdk.js +15 -1
  26. package/dist/flow-step-variables.d.ts +4 -0
  27. package/dist/flow-step-variables.js +22 -0
  28. package/dist/loop-version.d.ts +23 -6
  29. package/dist/loop-version.js +37 -15
  30. package/dist/nodes/agent/flow/check.d.ts +88 -0
  31. package/dist/nodes/agent/flow/check.js +873 -0
  32. package/dist/nodes/agent/flow/factories.d.ts +134 -0
  33. package/dist/nodes/agent/flow/factories.js +143 -0
  34. package/dist/nodes/agent/flow/family.d.ts +3 -0
  35. package/dist/nodes/agent/flow/family.js +8 -0
  36. package/dist/nodes/agent/flow/index.d.ts +3 -0
  37. package/dist/nodes/agent/flow/index.js +3 -0
  38. package/dist/nodes/agent/flow/inline-agent-lift.d.ts +44 -0
  39. package/dist/nodes/agent/flow/inline-agent-lift.js +572 -0
  40. package/dist/nodes/agent/flow/inline-agent.d.ts +15 -0
  41. package/dist/nodes/agent/flow/inline-agent.js +526 -0
  42. package/dist/nodes/agent/flow/node-type.d.ts +20 -0
  43. package/dist/nodes/agent/flow/node-type.js +422 -0
  44. package/dist/nodes/agent/flow/resources.d.ts +502 -0
  45. package/dist/nodes/agent/flow/resources.js +1409 -0
  46. package/dist/nodes/agent/flow/spec.d.ts +448 -0
  47. package/dist/nodes/agent/flow/spec.js +1 -0
  48. package/dist/nodes/hitl/flow/check.js +15 -0
  49. package/dist/nodes/hitl/flow/node-type.js +18 -3
  50. package/dist/nodes/process/flow/check.d.ts +40 -2
  51. package/dist/nodes/process/flow/check.js +156 -0
  52. package/dist/nodes/process/flow/factories.d.ts +58 -3
  53. package/dist/nodes/process/flow/factories.js +59 -2
  54. package/dist/nodes/process/flow/node-type.d.ts +4 -1
  55. package/dist/nodes/process/flow/node-type.js +198 -12
  56. package/dist/nodes/process/flow/spec.d.ts +112 -5
  57. package/dist/serialize.d.ts +9 -54
  58. package/dist/serialize.js +102 -2777
  59. package/package.json +2 -2
  60. /package/dist/{config.d.ts → core/connector-configuration.d.ts} +0 -0
  61. /package/dist/{ixp-definition.json → core/ixp-definition.json} +0 -0
@@ -29,6 +29,7 @@
29
29
  */
30
30
  import { Expr, cookedEscapesOf } from './core/expr.js';
31
31
  import { checkExpression, cookedEscapeDiagnostics } from './core/expr-check.js';
32
+ import { stepDeclaredVariables } from './flow-step-variables.js';
32
33
  const NOUN = 'input, variable, or step';
33
34
  /**
34
35
  * Every `$vars` root a reference may legitimately resolve to, across the WHOLE
@@ -77,6 +78,10 @@ function addStepNames(steps, roots) {
77
78
  // they are edges, not nodes, so there is nothing to reference them by.
78
79
  if (s.kind !== 'return' && s.kind !== 'stepToRef' && s.kind !== 'stepToList' && s.kind !== 'break' && s.kind !== 'continue')
79
80
  roots.add(s.name);
81
+ // A step declares the variables its fields land in too (`check.ts` mirrors this, #1309).
82
+ if (s.kind === 'action' || s.kind === 'stepSwitch')
83
+ for (const v of stepDeclaredVariables(s.spec, s.options?.version))
84
+ roots.add(v);
80
85
  switch (s.kind) {
81
86
  case 'stepToList':
82
87
  addStepNames(s.body, roots);
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import { NodeTypeRegistry } from './core/nodes/registry.js';
10
10
  import { hasBundledDefinition } from './flow-definitions.js';
11
+ import { agentFlowFamily } from './nodes/agent/flow/family.js';
11
12
  import { aiPatternsFlowFamily } from './nodes/ai-patterns/flow/family.js';
12
13
  import { conversationFlowFamily } from './nodes/conversation/flow/family.js';
13
14
  import { dataFabricFlowFamily } from './nodes/data-fabric/flow/family.js';
@@ -21,5 +22,5 @@ import { queueFlowFamily } from './nodes/queue/flow/family.js';
21
22
  import { scriptFlowFamily } from './nodes/script/flow/family.js';
22
23
  import { transformFlowFamily } from './nodes/transform/flow/family.js';
23
24
  /** The families, in no significant order. Adding one is the whole of registering it. */
24
- export const FLOW_NODE_FAMILIES = [aiPatternsFlowFamily, conversationFlowFamily, dataFabricFlowFamily, delayFlowFamily, documentFlowFamily, hitlFlowFamily, httpFlowFamily, mockFlowFamily, processFlowFamily, queueFlowFamily, scriptFlowFamily, transformFlowFamily];
25
+ export const FLOW_NODE_FAMILIES = [agentFlowFamily, aiPatternsFlowFamily, conversationFlowFamily, dataFabricFlowFamily, delayFlowFamily, documentFlowFamily, hitlFlowFamily, httpFlowFamily, mockFlowFamily, processFlowFamily, queueFlowFamily, scriptFlowFamily, transformFlowFamily];
25
26
  export const FLOW_NODE_TYPES = new NodeTypeRegistry('flow', FLOW_NODE_FAMILIES, { hasBundledDefinition });
@@ -14,6 +14,7 @@ import type { VersionedNodeType } from './core/nodes/versioned.js';
14
14
  import type { NodeFamily, Placement } from './core/nodes/family.js';
15
15
  import type { DefinitionReference, NodeContribution } from './core/node-classes.js';
16
16
  import type { CheckOpts } from './check.js';
17
+ import type { SerializeOpts } from './serialize.js';
17
18
  import type { DeclaredExit, NoExits } from './core/step-ports.js';
18
19
  /**
19
20
  * What a Flow node type's `serialize` returns: the node's type-owned fields.
@@ -65,6 +66,27 @@ export interface FlowNodeContribution extends Omit<NodeContribution, 'definition
65
66
  * `{nodeId}` substitution, which a merged contribution's outputs get.
66
67
  */
67
68
  replaceOutputs?: boolean;
69
+ /**
70
+ * Resource nodes this node carries on its artifact handles — an agent's
71
+ * contexts, tools, escalations and memory. Each is placed after this node and
72
+ * before the edges into it, drawn as a circle, with no node-level `model`, and
73
+ * joined by an edge from this node's `port` to the resource's `input`. Its
74
+ * inputs are written as given (render them first), and its definition is
75
+ * emitted into `definitions[]` like a per-tenant node's. A resource is not a
76
+ * step: it takes no control flow and never reaches an End.
77
+ */
78
+ attach?: ReadonlyArray<{
79
+ /** Its node id, from {@link FlowSerializeContext.resourceNodeId}. */
80
+ readonly id: string;
81
+ /** Its definition (the manifest). */
82
+ readonly definition: unknown;
83
+ readonly label: string;
84
+ readonly inputs: Readonly<Record<string, unknown>>;
85
+ /** The artifact handle on THIS node the edge leaves from (`context`, `tool`, `escalation`, `memory`). */
86
+ readonly port: string;
87
+ /** Display fields set over the definition's, after `shape: 'circle'` (a tool's `description`). */
88
+ readonly display?: Readonly<Record<string, unknown>>;
89
+ }>;
68
90
  }
69
91
  /** What `serialize` may ask of the serializer, for one placement. */
70
92
  export interface FlowSerializeContext {
@@ -95,10 +117,12 @@ export interface FlowSerializeContext {
95
117
  /** A deterministic id for `seed`, unique to this flow and node. */
96
118
  mint(seed: string): string;
97
119
  /**
98
- * Hoist a binding entry into the flow's `bindings`, deduplicated by `id`. With
99
- * the contribution's own `bindings`, these must close every `<bindings.NAME>`
100
- * the node's definition references: serialize refuses a name left open
101
- * (`CONTRIBUTION_BINDING_UNRESOLVED`), and `check` does not see bindings.
120
+ * Hoist a binding entry into the flow's `bindings`, deduplicated by `id`. It is
121
+ * in {@link bindings} at once, so a second resource of this step sees the
122
+ * first one's pair. With the contribution's own `bindings`, these must close
123
+ * every `<bindings.NAME>` the node's definition references: serialize refuses
124
+ * a name left open (`CONTRIBUTION_BINDING_UNRESOLVED`), and `check` does not
125
+ * see bindings.
102
126
  */
103
127
  bind(entry: {
104
128
  readonly id: string;
@@ -122,7 +146,15 @@ export interface FlowSerializeContext {
122
146
  * refusal check reports, and a value that cannot be a tenant id is warned about
123
147
  * (`CONNECTION_STUB`). `where` names the site in both, e.g. `managed http "fetch"`.
124
148
  */
125
- resolveBinding(name: string, attribute: 'connection' | 'folder', where: string): string;
149
+ resolveBinding(name: string, attribute: 'connection' | 'folder', where: string, target?: {
150
+ key: string;
151
+ action?: string;
152
+ }): string;
153
+ /** An unset label resolves to nothing. */
154
+ resolveBinding(name: string | undefined, attribute: 'connection' | 'folder', where: string, target?: {
155
+ key: string;
156
+ action?: string;
157
+ }): string | undefined;
126
158
  /**
127
159
  * Hoist the Integration Service connection pair a definition's `model`
128
160
  * references (`<bindings.NAME>` for its connection id and folder key), deduped
@@ -133,11 +165,54 @@ export interface FlowSerializeContext {
133
165
  bindConnection(o: {
134
166
  model: unknown;
135
167
  connectorKey: string;
136
- connectionId: string;
168
+ /** Undefined for an unresolved connection: the entries still close the references, with no `default`. */
169
+ connectionId: string | undefined;
137
170
  folderKey?: string;
138
171
  /** The entries' `resourceKey`; defaults to `connectionId`. */
139
172
  resourceKey?: string;
140
173
  }): void;
174
+ /**
175
+ * The folder an agent step's files live in (`<source>/agent.json`), a uuid:
176
+ * `carried` when the author or the file gave one, else one derived from the
177
+ * flow id and step name, so a recompile is byte-identical — then moved by the
178
+ * compile's `agentSource` option when it owns the folders (#1184).
179
+ */
180
+ agentSource(carried: string | undefined): string;
181
+ /**
182
+ * Write a file beside the `.flow` (an agent's `agent.json`), at a path relative
183
+ * to it. The same file twice is not a clash (a subflow body emitted for two
184
+ * callers); two different contents at a path an explicit `source` chose are
185
+ * refused (`INLINE_AGENT_RESOURCE_SOURCE_DUP`). The `json` object is kept, not
186
+ * copied, so `typeAgentInputs` can still fill it in.
187
+ */
188
+ sidecar(file: {
189
+ path: string;
190
+ json: unknown;
191
+ }, explicitSource?: boolean): void;
192
+ /**
193
+ * Type an agent sidecar's `inputSchema` once this scope's variables are known:
194
+ * each ref's `flatName` property gets the JSON Schema of the variable its
195
+ * `binding` reads, which no step can know while it is serialized (a later step
196
+ * may declare it).
197
+ */
198
+ typeAgentInputs(schema: {
199
+ properties: Record<string, unknown>;
200
+ definitions?: Record<string, unknown>;
201
+ }, refs: ReadonlyArray<{
202
+ flatName: string;
203
+ binding: string;
204
+ }>): void;
205
+ /**
206
+ * Claim the node id of a resource this step attaches: `explicit` exactly as
207
+ * written (decompile writes the file's id), refused when blank or already
208
+ * another node's (`INLINE_AGENT_RESOURCE_NODE_ID`); else `<seed>`, deduped
209
+ * file-wide (`<seed>2`, …).
210
+ */
211
+ resourceNodeId(explicit: string | undefined, seed: string, where: string): string;
212
+ /** The definition this flow has already emitted for `type@version`, if any (definitions[] holds one per pair). */
213
+ emitted(typeName: string, version: string): unknown;
214
+ /** The connector library serialize was given, for a type that resolves a connector operation. */
215
+ readonly library: SerializeOpts['library'];
141
216
  }
142
217
  /** What `deserialize` may ask of the decompiler, for one serialized node. */
143
218
  export interface FlowDeserializeContext {
@@ -168,6 +243,33 @@ export interface FlowDeserializeContext {
168
243
  * decompile.
169
244
  */
170
245
  lossy(message: string): void;
246
+ /**
247
+ * A file beside the `.flow` (an agent's `<source>/agent.json`) as text, by its
248
+ * path relative to it; undefined when decompile was given no reader or the
249
+ * file is not there.
250
+ */
251
+ sidecar(path: string): string | undefined;
252
+ /** The id of the flow being decompiled, as the source will name it: compile derives a resource's folder from it. */
253
+ readonly flowId: string;
254
+ /** Another node's definition: the file's own `definitions[]` entry for its type and version. */
255
+ definitionOf(node: {
256
+ type: string;
257
+ typeVersion?: string;
258
+ }): unknown;
259
+ /**
260
+ * The nodes attached to this one on an artifact handle (`tool`, `context`,
261
+ * `escalation`, `memory`), in edge order, at most `limit` of them. Their edges
262
+ * are carried by this node's spec, so they are not reported as dropped.
263
+ */
264
+ attached(port: string, limit?: number): readonly unknown[];
265
+ /** The ids of every node attached on that handle, without claiming their edges. */
266
+ attachedIds(port: string): readonly string[];
267
+ /**
268
+ * Record that an attached node folds into this node's spec, and the id
269
+ * compile will give it (undefined: compile will not emit it again), so what
270
+ * decompile writes about it — a layout entry — names the recompiled node.
271
+ */
272
+ absorb(nodeId: string, compiledId: string | undefined): void;
171
273
  /** The source ports this node's out-edges leave from, in edge order (an empty list outside a graph). */
172
274
  outPorts(): readonly string[];
173
275
  /**
@@ -233,7 +335,29 @@ export interface FlowCheckContext {
233
335
  }, use?: {
234
336
  id: string;
235
337
  connector: string | undefined;
338
+ },
339
+ /** The connector operation the labels are for, so a refusal names the `prepare` command for it. */
340
+ target?: {
341
+ key: string;
342
+ action?: string;
236
343
  }): void;
344
+ /**
345
+ * The node ids and folders this step's attached resources take, recorded
346
+ * file-wide — across the root flow and every subflow, as compile claims them.
347
+ * An explicit id equal to one another node gets is reported once the whole
348
+ * file is checked (`INLINE_AGENT_RESOURCE_NODE_ID`).
349
+ */
350
+ readonly resources: {
351
+ /** An id compile derives for one of this step's resources, and what it is, for that report. */
352
+ derivedNodeId(id: string, what: string): void;
353
+ /** Claim an explicit node id: the earlier claimant when one already has it (and nothing is recorded), else undefined. */
354
+ claimNodeId(id: string, what: string): {
355
+ step: string;
356
+ what: string;
357
+ } | undefined;
358
+ /** Claim an agent's folder (its `source`, compared lower-cased): the other step that has it, else undefined. */
359
+ claimFolder(source: string): string | undefined;
360
+ };
237
361
  }
238
362
  /** What a family-level `check` may ask of the checker. */
239
363
  export interface FlowFamilyCheckContext {
@@ -317,6 +441,15 @@ export interface FlowNodeType<Spec> extends NodeType<Spec, FlowNodeContribution,
317
441
  * one of these (`.onError()` routes it).
318
442
  */
319
443
  exits?(spec: Spec, pinnedVersion?: string): DeclaredExit[] | NoExits;
444
+ /**
445
+ * The flow variables a step of this type DECLARES by running: names a later
446
+ * `$vars.<name>` read resolves to that are neither a `.var()` nor a step
447
+ * name. A quick form's asked field lands its answer in its `variable`
448
+ * (`vars.<Step>_<field>`, as the designer names it), so the task declares
449
+ * that variable. `check` adds them to its declared set (#1309). Omitted: the
450
+ * type declares none.
451
+ */
452
+ declares?(spec: Spec, pinnedVersion?: string): string[];
320
453
  /**
321
454
  * Whether `port` is a forward handle the PRODUCT derives for this spec, which
322
455
  * the definition does not list — a human task's `outcome-<id>` handles, drawn
@@ -18,6 +18,7 @@
18
18
  */
19
19
  export * from './core/expr.js';
20
20
  export * from './core/actions.js';
21
+ export * from './nodes/agent/flow/index.js';
21
22
  export * from './nodes/ai-patterns/flow/index.js';
22
23
  export * from './nodes/conversation/flow/index.js';
23
24
  export * from './nodes/data-fabric/flow/index.js';
@@ -443,6 +444,39 @@ export interface NodeOptions {
443
444
  */
444
445
  label?: string;
445
446
  }
447
+ /**
448
+ * The options of `.parallel()`: the join's {@link NodeOptions}, plus the fork
449
+ * node when the flow has one.
450
+ */
451
+ export interface ParallelOptions extends NodeOptions {
452
+ /**
453
+ * A FORK node the arms leave from: a `core.logic.merge` with one incoming
454
+ * edge and one edge per arm, which is how Studio Web draws a parallel split
455
+ * (its "Parallel" gateway). Without it the arms leave from the previous
456
+ * step's own port, one edge per arm, which the platform runs the same way.
457
+ * Name it to round-trip a flow the canvas drew with a fork node; `label` is
458
+ * the canvas text, defaulting to the name, and `version` the fork node's
459
+ * exact `core.logic.merge` version when it differs from the join's.
460
+ *
461
+ * ```ts
462
+ * .parallel('join', [(a) => a.step('t1', …), (b) => b.step('t2', …)], { fork: 'split' })
463
+ * ```
464
+ */
465
+ fork?: string | {
466
+ name: string;
467
+ label?: string;
468
+ version?: string;
469
+ };
470
+ }
471
+ /**
472
+ * The fork node a `.parallel()` asks for, normalized, or `undefined`.
473
+ * @internal
474
+ */
475
+ export declare function parallelFork(options: ParallelOptions | undefined): {
476
+ name: string;
477
+ label?: string;
478
+ version?: string;
479
+ } | undefined;
446
480
  /**
447
481
  * `.return(...)`-specific options.
448
482
  *
@@ -587,15 +621,16 @@ export type Step = {
587
621
  /**
588
622
  * A fan-out and its join. `arms` is one step list per arm — an ARRAY, because
589
623
  * arms are positional and carry no author-supplied keys — and `name` names the
590
- * Merge node the arms converge on (the only node this step creates; the fork
591
- * itself is just N edges out of one port).
624
+ * Merge node the arms converge on (the only node this step creates unless
625
+ * `options.fork` names a fork node too; otherwise the fork is just N edges
626
+ * out of one port).
592
627
  */
593
628
  | {
594
629
  kind: 'parallel';
595
630
  name: string;
596
631
  label?: string;
597
632
  arms: Step[][];
598
- options?: NodeOptions;
633
+ options?: ParallelOptions;
599
634
  }
600
635
  /**
601
636
  * A hard stop: `core.logic.terminate`, a BPMN End event carrying a
@@ -1136,11 +1171,12 @@ declare class StepList {
1136
1171
  * @param arms - One callback per parallel arm, each receiving its own
1137
1172
  * sub-builder. Two or more.
1138
1173
  * @param options - Node options; `version` selects the exact definition
1139
- * version (see {@link NodeOptions}).
1174
+ * version (see {@link NodeOptions}), and `fork` names a fork node the arms
1175
+ * leave from (see {@link ParallelOptions}).
1140
1176
  * @returns This builder, positioned after the Merge — so what you chain next
1141
1177
  * runs once, when every arm has finished.
1142
1178
  */
1143
- parallel(name: string, arms: ((b: StepList) => void)[], options?: NodeOptions): this;
1179
+ parallel(name: string, arms: ((b: StepList) => void)[], options?: ParallelOptions): this;
1144
1180
  /**
1145
1181
  * Iterate `collection`; `bodyFn` receives a sub-builder for the loop body.
1146
1182
  *
package/dist/flow-sdk.js CHANGED
@@ -22,6 +22,7 @@
22
22
  export * from './core/expr.js';
23
23
  export * from './core/actions.js';
24
24
  // Node families' public surfaces (docs/NODE_TYPE_ARCHITECTURE_DESIGN.md §8).
25
+ export * from './nodes/agent/flow/index.js';
25
26
  export * from './nodes/ai-patterns/flow/index.js';
26
27
  export * from './nodes/conversation/flow/index.js';
27
28
  export * from './nodes/data-fabric/flow/index.js';
@@ -263,6 +264,18 @@ export function conversationTrigger() {
263
264
  export function voiceTrigger() {
264
265
  return builtinTriggerSpec({ kind: 'voice' });
265
266
  }
267
+ /**
268
+ * The fork node a `.parallel()` asks for, normalized, or `undefined`.
269
+ * @internal
270
+ */
271
+ export function parallelFork(options) {
272
+ const fork = options?.fork;
273
+ if (fork === undefined)
274
+ return undefined;
275
+ return typeof fork === 'string'
276
+ ? { name: fork }
277
+ : { name: fork.name, ...(fork.label !== undefined ? { label: fork.label } : {}), ...(fork.version !== undefined ? { version: fork.version } : {}) };
278
+ }
266
279
  /**
267
280
  * A node's layout at a canvas position — the short form of a {@link NodeLayout}
268
281
  * for the `nodes` map of {@link FlowBuilder.layout}.
@@ -763,7 +776,8 @@ class StepList {
763
776
  * @param arms - One callback per parallel arm, each receiving its own
764
777
  * sub-builder. Two or more.
765
778
  * @param options - Node options; `version` selects the exact definition
766
- * version (see {@link NodeOptions}).
779
+ * version (see {@link NodeOptions}), and `fork` names a fork node the arms
780
+ * leave from (see {@link ParallelOptions}).
767
781
  * @returns This builder, positioned after the Merge — so what you chain next
768
782
  * runs once, when every arm has finished.
769
783
  */
@@ -0,0 +1,4 @@
1
+ export declare function stepDeclaredVariables(spec: {
2
+ kind?: unknown;
3
+ inputs?: unknown;
4
+ } | undefined, pinnedVersion?: string): string[];
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The flow variables a step DECLARES by running (`FlowNodeType.declares`): a
3
+ * quick form's asked fields land in their `variable` (`vars.<Step>_<field>` as
4
+ * the designer names it), and later steps read `$vars.<name>`. Resolved at the
5
+ * version the step resolves to, the way `stepExits` does, so `check` and
6
+ * `flow-expr-check` agree on what a step publishes (#1309).
7
+ */
8
+ import { resolveVersion } from './core/nodes/versioned.js';
9
+ import { FLOW_NODE_TYPES } from './flow-node-registry.js';
10
+ export function stepDeclaredVariables(spec, pinnedVersion) {
11
+ const entry = typeof spec?.kind === 'string' ? FLOW_NODE_TYPES.byKind(spec.kind, spec) : undefined;
12
+ if (!entry)
13
+ return [];
14
+ let impl;
15
+ try {
16
+ impl = resolveVersion(entry.type, spec, pinnedVersion, 'declares');
17
+ }
18
+ catch {
19
+ impl = resolveVersion(entry.type, spec, undefined, 'declares');
20
+ }
21
+ return impl.declares?.(spec, pinnedVersion) ?? [];
22
+ }
@@ -3,28 +3,45 @@ import type { LoopOptions, Step } from './flow-sdk.js';
3
3
  export declare const LOOP_NODE_TYPE = "core.logic.loop";
4
4
  /** The `core.logic.loop` version `.loop()` emits unless `{ version }` pins another. */
5
5
  export declare const LOOP_DEFAULT_VERSION = "2.4";
6
+ /**
7
+ * The definition a loop at `version` compiles against: the bundled one, else
8
+ * the one the flow carries (`carried`, a `.definitions()` lookup), else
9
+ * `undefined`. `serialize` and `check` both resolve through this, so they agree
10
+ * on a carried `core.logic.loop@1.0`'s handles and inputs (#1311).
11
+ */
12
+ export declare function resolveLoopDefinition(version: string, carried?: (type: string, version: string) => unknown): unknown;
6
13
  /** The version `.loop()` emits for these options. */
7
14
  export declare function loopVersion(options: LoopOptions | undefined): string;
8
15
  /**
9
16
  * True when this loop version's body runs from the inner `start` handle and goes
10
17
  * back through `continue` (2.x); false for the legacy `output`/`loopBack` shape.
11
- * A version with no bundled definition counts as 2.x; its lookup fails later.
18
+ *
19
+ * The answer is read off the definition's target handles. `definition` is the
20
+ * one the loop compiles against: the bundled one for `version` by default, or
21
+ * the one the flow carries (`.definitions([...])`) when the SDK bundles none —
22
+ * a designer-saved `core.logic.loop@1.0` keeps its `output`/`loopBack` handles
23
+ * only because its carried definition says so (#1311). A version with no
24
+ * definition at all counts as 2.x; its lookup fails later.
12
25
  */
13
- export declare function loopHasInnerHandles(version: string): boolean;
26
+ export declare function loopHasInnerHandles(version: string, definition?: unknown): boolean;
14
27
  /**
15
28
  * The features this loop uses that its version's definition cannot express, in
16
29
  * a fixed order (`parallel`, `completionCondition`, `breakEnabled`, `break()`).
17
30
  * Empty when all are supported, or when no definition is bundled for the version
18
31
  * (an unknown version is reported elsewhere, by the definition lookup).
19
32
  */
20
- export declare function unsupportedLoopFeatures(options: LoopOptions | undefined, usesBreak: boolean): string[];
33
+ export declare function unsupportedLoopFeatures(options: LoopOptions | undefined, usesBreak: boolean, definition?: unknown): string[];
34
+ /** The inputs a loop definition declares (`collection`, `parallel`, `completionCondition`, `breakEnabled`, …). */
35
+ export declare function loopDeclaredInputs(definition: unknown): Record<string, unknown>;
21
36
  /**
22
37
  * The refusal for a loop whose options or body need a definition the requested
23
38
  * version does not have, or `undefined` when there is nothing to refuse.
24
39
  * `serialize` throws it; `check` reports it as `LOOP_VERSION_UNSUPPORTED` with
25
- * the same text, so the author reads one message in both places.
40
+ * the same text, so the author reads one message in both places. `definition`
41
+ * is the one the loop compiles against (bundled, else carried), as for
42
+ * `loopHasInnerHandles`.
26
43
  */
27
- export declare function loopVersionRefusal(name: string, options: LoopOptions | undefined, usesBreak: boolean): string | undefined;
44
+ export declare function loopVersionRefusal(name: string, options: LoopOptions | undefined, usesBreak: boolean, definition?: unknown): string | undefined;
28
45
  /**
29
46
  * The warning for `parallel: true` on a 1.0.0 loop, or `undefined`. The 1.0.0
30
47
  * definition declares the input, so the loop compiles and a canvas 1.0.0 loop
@@ -32,7 +49,7 @@ export declare function loopVersionRefusal(name: string, options: LoopOptions |
32
49
  * confirmed, so a new loop that needs that should use the default version.
33
50
  * `check` reports it as `LOOP_PARALLEL_LEGACY`.
34
51
  */
35
- export declare function loopParallelWarning(name: string, options: LoopOptions | undefined): string | undefined;
52
+ export declare function loopParallelWarning(name: string, options: LoopOptions | undefined, definition?: unknown): string | undefined;
36
53
  /**
37
54
  * True when a container body (or an arm/handler inside it, but not a NESTED
38
55
  * container's body) breaks: a nested `.loop()`/`.doWhile()` owns its own
@@ -11,6 +11,15 @@ import { BUNDLED_DEFINITIONS } from './flow-definitions.js';
11
11
  export const LOOP_NODE_TYPE = 'core.logic.loop';
12
12
  /** The `core.logic.loop` version `.loop()` emits unless `{ version }` pins another. */
13
13
  export const LOOP_DEFAULT_VERSION = '2.4';
14
+ /**
15
+ * The definition a loop at `version` compiles against: the bundled one, else
16
+ * the one the flow carries (`carried`, a `.definitions()` lookup), else
17
+ * `undefined`. `serialize` and `check` both resolve through this, so they agree
18
+ * on a carried `core.logic.loop@1.0`'s handles and inputs (#1311).
19
+ */
20
+ export function resolveLoopDefinition(version, carried) {
21
+ return loopDefinition(version) ?? carried?.(LOOP_NODE_TYPE, version);
22
+ }
14
23
  /** The version `.loop()` emits for these options. */
15
24
  export function loopVersion(options) {
16
25
  return options?.version ?? LOOP_DEFAULT_VERSION;
@@ -18,10 +27,16 @@ export function loopVersion(options) {
18
27
  /**
19
28
  * True when this loop version's body runs from the inner `start` handle and goes
20
29
  * back through `continue` (2.x); false for the legacy `output`/`loopBack` shape.
21
- * A version with no bundled definition counts as 2.x; its lookup fails later.
30
+ *
31
+ * The answer is read off the definition's target handles. `definition` is the
32
+ * one the loop compiles against: the bundled one for `version` by default, or
33
+ * the one the flow carries (`.definitions([...])`) when the SDK bundles none —
34
+ * a designer-saved `core.logic.loop@1.0` keeps its `output`/`loopBack` handles
35
+ * only because its carried definition says so (#1311). A version with no
36
+ * definition at all counts as 2.x; its lookup fails later.
22
37
  */
23
- export function loopHasInnerHandles(version) {
24
- return loopDefinition(version) ? targetHandleIds(version).has('continue') : true;
38
+ export function loopHasInnerHandles(version, definition = loopDefinition(version)) {
39
+ return definition ? targetHandleIdsOf(definition).has('continue') : true;
25
40
  }
26
41
  /** The loop options whose support depends on the version, in message order. */
27
42
  const VERSIONED_OPTIONS = ['parallel', 'completionCondition', 'breakEnabled'];
@@ -31,24 +46,29 @@ const VERSIONED_OPTIONS = ['parallel', 'completionCondition', 'breakEnabled'];
31
46
  * Empty when all are supported, or when no definition is bundled for the version
32
47
  * (an unknown version is reported elsewhere, by the definition lookup).
33
48
  */
34
- export function unsupportedLoopFeatures(options, usesBreak) {
35
- const def = loopDefinition(loopVersion(options));
36
- if (!def)
49
+ export function unsupportedLoopFeatures(options, usesBreak, definition = loopDefinition(loopVersion(options))) {
50
+ if (!definition)
37
51
  return [];
38
- const inputs = def.inputDefinition?.properties ?? {};
52
+ const inputs = loopDeclaredInputs(definition);
39
53
  const out = VERSIONED_OPTIONS.filter((k) => options?.[k] !== undefined && !(k in inputs));
40
- if (usesBreak && !targetHandleIds(loopVersion(options)).has('break'))
54
+ if (usesBreak && !targetHandleIdsOf(definition).has('break'))
41
55
  out.push('break()');
42
56
  return out;
43
57
  }
58
+ /** The inputs a loop definition declares (`collection`, `parallel`, `completionCondition`, `breakEnabled`, …). */
59
+ export function loopDeclaredInputs(definition) {
60
+ return definition?.inputDefinition?.properties ?? {};
61
+ }
44
62
  /**
45
63
  * The refusal for a loop whose options or body need a definition the requested
46
64
  * version does not have, or `undefined` when there is nothing to refuse.
47
65
  * `serialize` throws it; `check` reports it as `LOOP_VERSION_UNSUPPORTED` with
48
- * the same text, so the author reads one message in both places.
66
+ * the same text, so the author reads one message in both places. `definition`
67
+ * is the one the loop compiles against (bundled, else carried), as for
68
+ * `loopHasInnerHandles`.
49
69
  */
50
- export function loopVersionRefusal(name, options, usesBreak) {
51
- const missing = unsupportedLoopFeatures(options, usesBreak);
70
+ export function loopVersionRefusal(name, options, usesBreak, definition = loopDefinition(loopVersion(options))) {
71
+ const missing = unsupportedLoopFeatures(options, usesBreak, definition);
52
72
  if (missing.length === 0)
53
73
  return undefined;
54
74
  const version = loopVersion(options);
@@ -63,8 +83,8 @@ export function loopVersionRefusal(name, options, usesBreak) {
63
83
  * confirmed, so a new loop that needs that should use the default version.
64
84
  * `check` reports it as `LOOP_PARALLEL_LEGACY`.
65
85
  */
66
- export function loopParallelWarning(name, options) {
67
- if (options?.parallel !== true || loopHasInnerHandles(loopVersion(options)))
86
+ export function loopParallelWarning(name, options, definition = loopDefinition(loopVersion(options))) {
87
+ if (options?.parallel !== true || loopHasInnerHandles(loopVersion(options), definition))
68
88
  return undefined;
69
89
  return `loop "${name}": parallel: true on { version: '${loopVersion(options)}' } is written to the node, but `
70
90
  + `that version is not confirmed to run iterations in parallel, so the loop may run them one by one. `
@@ -86,9 +106,11 @@ export function bodyUsesBreak(steps) {
86
106
  function loopDefinition(version) {
87
107
  return BUNDLED_DEFINITIONS[`${LOOP_NODE_TYPE}@${version}`];
88
108
  }
89
- function targetHandleIds(version) {
109
+ /** The ids of a definition's target handles (`input`, `loopBack`, `continue`, `break`, …). */
110
+ function targetHandleIdsOf(definition) {
90
111
  const ids = new Set();
91
- for (const group of loopDefinition(version)?.handleConfiguration ?? []) {
112
+ const groups = definition?.handleConfiguration ?? [];
113
+ for (const group of groups) {
92
114
  for (const h of group.handles ?? [])
93
115
  if (h.type === 'target')
94
116
  ids.add(h.id);
@@ -0,0 +1,88 @@
1
+ /**
2
+ * The agents family's rules: what is decidable from a call to
3
+ * `conversationalAgent()`, `voiceAgent()`, `createOutgoingCall()`, `endCall()`
4
+ * or `inlineAgent()` — the turn wiring, the call's numbers, the `callContext`
5
+ * the voice steps share, and an inline agent's prompts, inputs, guardrails and
6
+ * resources. Moved from check.ts in Phase 4 of
7
+ * docs/NODE_TYPE_ARCHITECTURE_DESIGN.md; codes and messages unchanged.
8
+ */
9
+ import type { DiagnosticCatalog } from '../../../core/nodes/family.js';
10
+ import type { OutputPathRead } from '../../../core/nodes/node-type.js';
11
+ import type { FlowCheckContext } from '../../../flow-node-type.js';
12
+ import type { InlineAgentInputs } from './spec.js';
13
+ export declare const AGENT_DIAGNOSTICS: DiagnosticCatalog;
14
+ /**
15
+ * A conversational AGENT step (Phase 5).
16
+ *
17
+ * The turn wiring is the whole risk: `'simple'` mode reads everything out of
18
+ * ONE conversation-context binding, so a flow that names neither the context
19
+ * nor the individual fields deploys an agent with no transcript to answer.
20
+ */
21
+ export declare function checkConversationalAgent(inputs: Record<string, unknown> | undefined, ctx: FlowCheckContext): void;
22
+ /**
23
+ * A VOICE step (Phase 5D): create-outgoing-call, end-call, or the voice agent.
24
+ *
25
+ * Two things are decidable offline and expensive later: a call needs both
26
+ * numbers in a form the telephony provider accepts, and every voice step needs
27
+ * the `callContext` OBJECT — binding a bare conversation id instead is the
28
+ * classic mistake, because the field is typed `object` and a string passes the
29
+ * file's schema while failing at dispatch.
30
+ */
31
+ export declare function checkVoice(kind: 'createOutgoingCall' | 'endCall' | 'voiceAgent', inputs: Record<string, unknown> | undefined, ctx: FlowCheckContext): void;
32
+ /**
33
+ * The phrase in `text` that tells a model to answer in JSON TEXT, or `undefined`.
34
+ *
35
+ * `check` uses it for `INLINE_AGENT_PROMPT_JSON_TEXT`, passing the step's `returns`
36
+ * keys so the brace form only counts a brace that spells one of them. Without
37
+ * `returnKeys` (the example and doc sweeps) any quoted identifier key counts.
38
+ * `{{input.*}}` placeholders are removed first, so an input named `json` never
39
+ * matches.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * jsonTextDirective('Return ONLY a JSON object with keys "subject" and "body".'); // 'Return ONLY a JSON'
44
+ * jsonTextDirective('Return ONLY {"category","priority"}.', ['category']); // '{"category",'
45
+ * jsonTextDirective('Return a result conforming to the output schema.'); // undefined
46
+ * jsonTextDirective('Do not return JSON.'); // undefined
47
+ * jsonTextDirective('Answer the question using the JSON data below.'); // undefined
48
+ * ```
49
+ */
50
+ export declare function jsonTextDirective(text: string, returnKeys?: readonly string[]): string | undefined;
51
+ /**
52
+ * Check an `inlineAgent(...)` call.
53
+ *
54
+ * The interesting difference from every other node this SDK authors: **nothing here
55
+ * lives on a tenant.** An inline agent's whole contract is in the call, so these
56
+ * rules can be certain rather than best-effort — the definition's own `required`
57
+ * list is checkable, and so is whether the prompts and the declared variables agree.
58
+ *
59
+ * Three rules exist because the PLATFORM does something with what you wrote:
60
+ *
61
+ * - `INLINE_AGENT_SCAFFOLD_MODEL` — the model the platform's own scaffold ships is
62
+ * stale, and v1's smoke check for this node type fails a flow that keeps it. A
63
+ * warning, not an error: it is a real model id, it just should not be a default
64
+ * nobody chose.
65
+ * - `INLINE_AGENT_UNREFERENCED_INPUT` — flow-v1 derives the deployed input list by
66
+ * scanning the PROMPTS for `$vars.*` references and only falls back to the
67
+ * authored `agentInputVariables` when that pre-pass did not run. So a declared
68
+ * input the prompts never mention is pruned deployed while arriving locally: a
69
+ * disagreement between rungs and the platform, which is the one class that has to
70
+ * be said out loud rather than left to a run.
71
+ * - `INLINE_AGENT_PROMPT_JSON_TEXT` — the platform returns `returns` as a typed
72
+ * object: it becomes the `agent.json` `outputSchema`, and the agent runtime ends
73
+ * a run with a structured call that fills exactly those fields. A prompt that
74
+ * ALSO asks for JSON text makes the model pack its whole answer, serialized, into
75
+ * one string field. See {@link jsonTextDirective}.
76
+ */
77
+ export declare function checkInlineAgent(inputs: InlineAgentInputs | undefined, ctx: FlowCheckContext): void;
78
+ /**
79
+ * A read of an inline agent's output: `out('<step>', '<field>')`.
80
+ *
81
+ * Stricter than the published families' equivalent, and it can afford to be: the
82
+ * declared `returns` IS the contract (there is no tenant to disagree with), and it
83
+ * is what any runner has to coerce the model's completion to: build
84
+ * `{ <declared keys> }` and put the raw completion in the first one if the model
85
+ * ignored the shape. So a read outside the set is undefined by construction, not
86
+ * merely probably.
87
+ */
88
+ export declare function checkInlineAgentRead({ node: name, field, rest, reader: step }: OutputPathRead, spec: InlineAgentInputs, report: (code: string, message: string, suggestion?: string) => void): void;