@uipath/maestro-builder-sdk 5.2.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 (238) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +322 -0
  3. package/dist/bindings-v2.d.ts +37 -0
  4. package/dist/bindings-v2.js +155 -0
  5. package/dist/bindings.d.ts +6 -0
  6. package/dist/bindings.js +6 -0
  7. package/dist/bpmn/bpmn-expr-check.d.ts +41 -0
  8. package/dist/bpmn/bpmn-expr-check.js +218 -0
  9. package/dist/bpmn/bpmn-sdk.d.ts +2257 -0
  10. package/dist/bpmn/bpmn-sdk.js +1476 -0
  11. package/dist/bpmn/check-cli.d.ts +3 -0
  12. package/dist/bpmn/check-cli.js +32 -0
  13. package/dist/bpmn/check.d.ts +25 -0
  14. package/dist/bpmn/check.js +430 -0
  15. package/dist/bpmn/compile-cli.d.ts +3 -0
  16. package/dist/bpmn/compile-cli.js +60 -0
  17. package/dist/bpmn/connector.d.ts +56 -0
  18. package/dist/bpmn/connector.js +199 -0
  19. package/dist/bpmn/decompile-cli.d.ts +8 -0
  20. package/dist/bpmn/decompile-cli.js +54 -0
  21. package/dist/bpmn/decompile.d.ts +6 -0
  22. package/dist/bpmn/decompile.js +1108 -0
  23. package/dist/bpmn/format-profile.d.ts +27 -0
  24. package/dist/bpmn/format-profile.js +11 -0
  25. package/dist/bpmn/intsvc.d.ts +77 -0
  26. package/dist/bpmn/intsvc.js +155 -0
  27. package/dist/bpmn/load.d.ts +4 -0
  28. package/dist/bpmn/load.js +22 -0
  29. package/dist/bpmn/merge-cli.d.ts +3 -0
  30. package/dist/bpmn/merge-cli.js +45 -0
  31. package/dist/bpmn/merge.d.ts +19 -0
  32. package/dist/bpmn/merge.js +293 -0
  33. package/dist/bpmn/registry-types.json +1869 -0
  34. package/dist/bpmn/serialize.d.ts +28 -0
  35. package/dist/bpmn/serialize.js +757 -0
  36. package/dist/bpmn/tidy-cli.d.ts +2 -0
  37. package/dist/bpmn/tidy-cli.js +39 -0
  38. package/dist/bpmn/typed-node.d.ts +382 -0
  39. package/dist/bpmn/typed-node.js +551 -0
  40. package/dist/bpmn/uipath-moddle.v1.json +823 -0
  41. package/dist/bpmn/xml-ranges.d.ts +45 -0
  42. package/dist/bpmn/xml-ranges.js +151 -0
  43. package/dist/case/case-expr-check.d.ts +35 -0
  44. package/dist/case/case-expr-check.js +85 -0
  45. package/dist/case/case-sdk.d.ts +1282 -0
  46. package/dist/case/case-sdk.js +923 -0
  47. package/dist/case/check-cli.d.ts +3 -0
  48. package/dist/case/check-cli.js +31 -0
  49. package/dist/case/check.d.ts +18 -0
  50. package/dist/case/check.js +456 -0
  51. package/dist/case/compile-cli.d.ts +3 -0
  52. package/dist/case/compile-cli.js +291 -0
  53. package/dist/case/decompile-cli.d.ts +9 -0
  54. package/dist/case/decompile-cli.js +117 -0
  55. package/dist/case/decompile.d.ts +187 -0
  56. package/dist/case/decompile.js +1170 -0
  57. package/dist/case/entry-points.d.ts +79 -0
  58. package/dist/case/entry-points.js +118 -0
  59. package/dist/case/format-profile.d.ts +60 -0
  60. package/dist/case/format-profile.js +79 -0
  61. package/dist/case/ids.d.ts +24 -0
  62. package/dist/case/ids.js +76 -0
  63. package/dist/case/load.d.ts +12 -0
  64. package/dist/case/load.js +32 -0
  65. package/dist/case/preserve.d.ts +133 -0
  66. package/dist/case/preserve.js +105 -0
  67. package/dist/case/serialize.d.ts +10 -0
  68. package/dist/case/serialize.js +1414 -0
  69. package/dist/check-cli.d.ts +3 -0
  70. package/dist/check-cli.js +118 -0
  71. package/dist/check.d.ts +146 -0
  72. package/dist/check.js +4898 -0
  73. package/dist/cli/commands/bpmn.d.ts +2 -0
  74. package/dist/cli/commands/bpmn.js +73 -0
  75. package/dist/cli/commands/case.d.ts +2 -0
  76. package/dist/cli/commands/case.js +60 -0
  77. package/dist/cli/commands/flow.d.ts +2 -0
  78. package/dist/cli/commands/flow.js +99 -0
  79. package/dist/cli/commands/registry.d.ts +10 -0
  80. package/dist/cli/commands/registry.js +170 -0
  81. package/dist/cli/common.d.ts +30 -0
  82. package/dist/cli/common.js +92 -0
  83. package/dist/cli/index.d.ts +2 -0
  84. package/dist/cli/index.js +18 -0
  85. package/dist/cli-run.d.ts +2 -0
  86. package/dist/cli-run.js +42 -0
  87. package/dist/compile-cli.d.ts +3 -0
  88. package/dist/compile-cli.js +160 -0
  89. package/dist/config.d.ts +47 -0
  90. package/dist/config.js +201 -0
  91. package/dist/core/actions.d.ts +3244 -0
  92. package/dist/core/actions.js +1062 -0
  93. package/dist/core/binding-messages.d.ts +1 -0
  94. package/dist/core/binding-messages.js +16 -0
  95. package/dist/core/bindings.d.ts +12 -0
  96. package/dist/core/bindings.js +67 -0
  97. package/dist/core/ceql.d.ts +73 -0
  98. package/dist/core/ceql.js +272 -0
  99. package/dist/core/cli-spelling.d.ts +39 -0
  100. package/dist/core/cli-spelling.js +62 -0
  101. package/dist/core/connector-raw-node.d.ts +21 -0
  102. package/dist/core/connector-raw-node.js +47 -0
  103. package/dist/core/connectors.d.ts +184 -0
  104. package/dist/core/connectors.js +128 -0
  105. package/dist/core/expr-check.d.ts +93 -0
  106. package/dist/core/expr-check.js +186 -0
  107. package/dist/core/expr.d.ts +323 -0
  108. package/dist/core/expr.js +400 -0
  109. package/dist/core/index.d.ts +10 -0
  110. package/dist/core/index.js +10 -0
  111. package/dist/core/library.d.ts +440 -0
  112. package/dist/core/library.js +1183 -0
  113. package/dist/core/list-envelope.d.ts +45 -0
  114. package/dist/core/list-envelope.js +97 -0
  115. package/dist/core/lookup-store.d.ts +22 -0
  116. package/dist/core/lookup-store.js +85 -0
  117. package/dist/core/lookups.d.ts +227 -0
  118. package/dist/core/lookups.js +231 -0
  119. package/dist/core/node-classes.d.ts +234 -0
  120. package/dist/core/node-classes.js +158 -0
  121. package/dist/core/script-return.d.ts +68 -0
  122. package/dist/core/script-return.js +197 -0
  123. package/dist/core/stable-id.d.ts +28 -0
  124. package/dist/core/stable-id.js +37 -0
  125. package/dist/core-definitions.json +16249 -0
  126. package/dist/decompile-cli.d.ts +3 -0
  127. package/dist/decompile-cli.js +131 -0
  128. package/dist/decompile.d.ts +138 -0
  129. package/dist/decompile.js +2482 -0
  130. package/dist/emit.d.ts +10 -0
  131. package/dist/emit.js +60 -0
  132. package/dist/event-filters.d.ts +130 -0
  133. package/dist/event-filters.js +137 -0
  134. package/dist/flow-expr-check.d.ts +17 -0
  135. package/dist/flow-expr-check.js +193 -0
  136. package/dist/flow-sdk.d.ts +1341 -0
  137. package/dist/flow-sdk.js +1164 -0
  138. package/dist/flow-variables.d.ts +13 -0
  139. package/dist/flow-variables.js +42 -0
  140. package/dist/format-profile.d.ts +72 -0
  141. package/dist/format-profile.js +97 -0
  142. package/dist/generators/_connections.py +287 -0
  143. package/dist/generators/_events.py +355 -0
  144. package/dist/generators/_lookups.py +114 -0
  145. package/dist/generators/_naming.py +185 -0
  146. package/dist/generators/_objects.py +299 -0
  147. package/dist/generators/_resolve.py +273 -0
  148. package/dist/generators/convert_library_to_md.py +1441 -0
  149. package/dist/generators/extract_library.py +125 -0
  150. package/dist/generators/generate_connectors_ts.py +936 -0
  151. package/dist/generators/generate_library_json.py +2527 -0
  152. package/dist/generators/generate_triggers_ts.py +110 -0
  153. package/dist/generators/materialize_registry.py +155 -0
  154. package/dist/generators/prepare_connector.py +1688 -0
  155. package/dist/index.d.ts +35 -0
  156. package/dist/index.js +35 -0
  157. package/dist/ixp-definition.json +1982 -0
  158. package/dist/library.d.ts +6 -0
  159. package/dist/library.js +6 -0
  160. package/dist/load.d.ts +16 -0
  161. package/dist/load.js +95 -0
  162. package/dist/merge-cli.d.ts +3 -0
  163. package/dist/merge-cli.js +47 -0
  164. package/dist/merge.d.ts +125 -0
  165. package/dist/merge.js +0 -0
  166. package/dist/migrate.d.ts +15 -0
  167. package/dist/migrate.js +245 -0
  168. package/dist/node-runtime.d.ts +3 -0
  169. package/dist/node-runtime.js +22 -0
  170. package/dist/package-name.d.ts +17 -0
  171. package/dist/package-name.js +17 -0
  172. package/dist/ref-resolve.d.ts +77 -0
  173. package/dist/ref-resolve.js +170 -0
  174. package/dist/registry/cache.d.ts +55 -0
  175. package/dist/registry/cache.js +134 -0
  176. package/dist/registry/curated-overlay.d.ts +16 -0
  177. package/dist/registry/curated-overlay.js +62 -0
  178. package/dist/registry/extractor.d.ts +22 -0
  179. package/dist/registry/extractor.js +18 -0
  180. package/dist/registry/materialize-bin.d.ts +2 -0
  181. package/dist/registry/materialize-bin.js +7 -0
  182. package/dist/registry/materialize-cli.d.ts +1 -0
  183. package/dist/registry/materialize-cli.js +46 -0
  184. package/dist/registry/materializer.d.ts +23 -0
  185. package/dist/registry/materializer.js +34 -0
  186. package/dist/registry/path-cli.d.ts +1 -0
  187. package/dist/registry/path-cli.js +56 -0
  188. package/dist/registry/prepare-cli.d.ts +62 -0
  189. package/dist/registry/prepare-cli.js +185 -0
  190. package/dist/registry/pull-cli.d.ts +1 -0
  191. package/dist/registry/pull-cli.js +274 -0
  192. package/dist/registry/python.d.ts +26 -0
  193. package/dist/registry/python.js +46 -0
  194. package/dist/registry/search-cli.d.ts +52 -0
  195. package/dist/registry/search-cli.js +159 -0
  196. package/dist/schema-version.d.ts +165 -0
  197. package/dist/schema-version.js +148 -0
  198. package/dist/serialize.d.ts +64 -0
  199. package/dist/serialize.js +6398 -0
  200. package/lib/README.md +112 -0
  201. package/lib/library-json.samples/index.json +158 -0
  202. package/lib/library-json.samples/invariant-collections.json +83 -0
  203. package/lib/library-json.samples/list-envelopes.json +123 -0
  204. package/lib/library-json.samples/uipath-atlassian-jira/create-issue@1.0.0.json +131 -0
  205. package/lib/library-json.samples/uipath-atlassian-jira/create-issue@1.0.0.v1def.json +306 -0
  206. package/lib/library-json.samples/uipath-atlassian-jira/generic/create_issue/create@1.0.0.json +86 -0
  207. package/lib/library-json.samples/uipath-atlassian-jira/generic/create_issue/create@1.0.0.v1def.json +208 -0
  208. package/lib/library-json.samples/uipath-atlassian-jira/get-issue@1.0.0.json +2040 -0
  209. package/lib/library-json.samples/uipath-atlassian-jira/get-issue@1.0.0.v1def.json +195 -0
  210. package/lib/library-json.samples/uipath-google-vertex/execute-google-vertex-agent@1.0.0.json +169 -0
  211. package/lib/library-json.samples/uipath-google-vertex/execute-google-vertex-agent@1.0.0.v1def.json +209 -0
  212. package/lib/library-json.samples/uipath-http-webhook/event-http-webhook@1.0.0.json +63 -0
  213. package/lib/library-json.samples/uipath-http-webhook/event-http-webhook@1.0.0.v1def.json +262 -0
  214. package/lib/library-json.samples/uipath-http-webhook/trigger-http-webhook@1.0.0.json +63 -0
  215. package/lib/library-json.samples/uipath-http-webhook/trigger-http-webhook@1.0.0.v1def.json +213 -0
  216. package/lib/library-json.samples/uipath-microsoft-azureactivedirectory/list-groups@1.0.0.json +227 -0
  217. package/lib/library-json.samples/uipath-microsoft-azureactivedirectory/list-groups@1.0.0.v1def.json +373 -0
  218. package/lib/library-json.samples/uipath-microsoft-onedrive/event-file-created@1.0.0.json +116 -0
  219. package/lib/library-json.samples/uipath-microsoft-onedrive/event-file-created@1.0.0.v1def.json +369 -0
  220. package/lib/library-json.samples/uipath-microsoft-onedrive/event-list-item-added@1.0.0.json +56 -0
  221. package/lib/library-json.samples/uipath-microsoft-onedrive/event-list-item-added@1.0.0.v1def.json +256 -0
  222. package/lib/library-json.samples/uipath-microsoft-onedrive/trigger-file-created@1.0.0.json +116 -0
  223. package/lib/library-json.samples/uipath-microsoft-onedrive/trigger-file-created@1.0.0.v1def.json +320 -0
  224. package/lib/library-json.samples/uipath-microsoft-onedrive/trigger-list-item-added@1.0.0.json +56 -0
  225. package/lib/library-json.samples/uipath-microsoft-onedrive/trigger-list-item-added@1.0.0.v1def.json +207 -0
  226. package/lib/library-json.samples/uipath-microsoft-outlook365/event-email-received@1.0.0.json +107 -0
  227. package/lib/library-json.samples/uipath-microsoft-outlook365/event-email-received@1.0.0.v1def.json +264 -0
  228. package/lib/library-json.samples/uipath-microsoft-outlook365/send-email@1.0.0.json +142 -0
  229. package/lib/library-json.samples/uipath-microsoft-outlook365/send-email@1.0.0.v1def.json +306 -0
  230. package/lib/library-json.samples/uipath-microsoft-outlook365/trigger-email-received@1.0.0.json +107 -0
  231. package/lib/library-json.samples/uipath-microsoft-outlook365/trigger-email-received@1.0.0.v1def.json +217 -0
  232. package/lib/library-json.samples/uipath-microsoft-powerautomate/invoke-a-microsoft-power-automate-flow@1.0.0.json +85 -0
  233. package/lib/library-json.samples/uipath-microsoft-powerautomate/invoke-a-microsoft-power-automate-flow@1.0.0.v1def.json +209 -0
  234. package/lib/library-json.samples/uipath-salesforce-slack/send-message-to-user@1.0.0.json +755 -0
  235. package/lib/library-json.samples/uipath-salesforce-slack/send-message-to-user@1.0.0.v1def.json +513 -0
  236. package/lib/library-json.samples/uipath-uipath-dataservice/query-entity-records@1.0.0.json +122 -0
  237. package/lib/library-json.samples/uipath-uipath-dataservice/query-entity-records@1.0.0.v1def.json +227 -0
  238. package/package.json +85 -0
@@ -0,0 +1,1062 @@
1
+ import { splitConnectorNodeType, isTriggerDescriptor, } from './connectors.js';
2
+ import { FlowAction, FlowTrigger } from './node-classes.js';
3
+ /**
4
+ * The operation `type` each variant node must carry — one of, and only.
5
+ *
6
+ * @internal Serializer plumbing; an author states the variant, not the mapping.
7
+ */
8
+ export const VARIANT_OPERATION = {
9
+ map: 'map',
10
+ filter: 'filter',
11
+ 'group-by': 'groupBy',
12
+ };
13
+ // ─── Document extraction (uipath.ixp.*) ──────────────────────────────────────
14
+ //
15
+ // The platform's *Extract* node (that is its `display.canvasLabel`): it hands a
16
+ // document to a published IxP — Intelligent eXtraction Platform — project and
17
+ // reads the trained model's fields back. Every extractor on a tenant is its own
18
+ // node type, `uipath.ixp.<projectSlug>.<projectVersionId>-<folderKey>`, so the
19
+ // four identity fields below come from the tenant and are named exactly as the
20
+ // node names them.
21
+ //
22
+ // The type is RESOLVED, never constructed: three different spellings of that
23
+ // tail exist in the deployed corpus (the sanitized folder path, the literal
24
+ // string `undefined`, and today's version-id + folder-key pair), so copy the
25
+ // one `registry search` prints.
26
+ /**
27
+ * Split an extractor's node type into the two GUIDs its tail packs.
28
+ *
29
+ * `uipath.ixp.<projectSlug>.<projectVersionId>-<folderKey>` — the version id is
30
+ * the `ixpDeployment` binding's `resourceKey` and the node's `model.id`; the
31
+ * folder key is `inputs.folderKey`. Returns `undefined` for a tail that is not
32
+ * exactly two uuids joined by `-`, which is how the two older spellings (a
33
+ * sanitized folder path, and the literal string `undefined`) are refused rather
34
+ * than mis-split.
35
+ *
36
+ * @internal Public for compatibility; not an authoring factory.
37
+ */
38
+ export function parseIxpProjectType(nodeType) {
39
+ const rest = nodeType.startsWith('uipath.ixp.') ? nodeType.slice('uipath.ixp.'.length) : undefined;
40
+ if (!rest)
41
+ return undefined;
42
+ const dot = rest.lastIndexOf('.');
43
+ if (dot <= 0)
44
+ return undefined;
45
+ const slug = rest.slice(0, dot);
46
+ const tail = rest.slice(dot + 1);
47
+ const m = /^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i.exec(tail);
48
+ if (!m)
49
+ return undefined;
50
+ return { slug, versionId: m[1], folderKey: m[2] };
51
+ }
52
+ // ─── Delay (core.logic.delay) ────────────────────────────────────────────────
53
+ /**
54
+ * The twelve durations the designer's dropdown offers. Purely an ENCODING
55
+ * detail: a duration in this list ships as `timerPreset: '<duration>'` and any
56
+ * other ships as `timerPreset: 'custom'` + `timerValue: '<duration>'`. Both
57
+ * deploy and both wait the same length of time — the author never picks.
58
+ * `core-definitions.test.ts` pins this list against the definition's own form.
59
+ */
60
+ export const DELAY_PRESETS = [
61
+ 'PT5S', 'PT15S', 'PT30S', 'PT1M', 'PT5M', 'PT15M', 'PT30M',
62
+ 'PT1H', 'PT6H', 'PT12H', 'P1D', 'P1W',
63
+ ];
64
+ // ── Built-in spec adapters ──────────────────────────────────────────────────
65
+ // Every factory result IS a FlowAction/FlowTrigger instance (design §4.4 pass
66
+ // 1), so `instanceof` can tell an SDK-owned construct from a raw literal. The
67
+ // serializer still lowers built-ins through its kind-switch — these adapters
68
+ // exist for identity, not lowering — and `Object.assign` keeps every spec
69
+ // field an own enumerable property, so the wire-visible shape (JSON, toEqual,
70
+ // spread) is exactly what the plain object was.
71
+ class BuiltinAction extends FlowAction {
72
+ constructor(spec) {
73
+ super();
74
+ Object.assign(this, spec);
75
+ }
76
+ contribute() {
77
+ throw new Error('built-in action specs are lowered by the serializer directly; contribute() is only called on custom FlowAction subclasses');
78
+ }
79
+ }
80
+ class BuiltinTrigger extends FlowTrigger {
81
+ constructor(spec) {
82
+ super();
83
+ Object.assign(this, spec);
84
+ }
85
+ contribute() {
86
+ throw new Error('built-in trigger specs are lowered by the serializer directly; contribute() is only called on custom FlowTrigger subclasses');
87
+ }
88
+ }
89
+ /**
90
+ * Wrap a built-in action spec literal in its adapter class without changing
91
+ * its declared type. SDK-internal — factories call it so their results are
92
+ * `instanceof FlowAction`; authors never need it.
93
+ *
94
+ * @internal
95
+ * @param spec - The spec literal a factory built.
96
+ * @returns The same spec, as a `FlowAction` instance.
97
+ */
98
+ export function builtinActionSpec(spec) {
99
+ return new BuiltinAction(spec);
100
+ }
101
+ /**
102
+ * Wrap a built-in trigger spec literal in its adapter class without changing
103
+ * its declared type. SDK-internal — factories call it so their results are
104
+ * `instanceof FlowTrigger`; authors never need it.
105
+ *
106
+ * @internal
107
+ * @param spec - The spec literal a factory built.
108
+ * @returns The same spec, as a `FlowTrigger` instance.
109
+ */
110
+ export function builtinTriggerSpec(spec) {
111
+ return new BuiltinTrigger(spec);
112
+ }
113
+ /**
114
+ * Declare an HTTP request action, explicitly choosing standalone or managed.
115
+ *
116
+ * @param inputs - The request: `url`, `method`, `body`, the response fields you
117
+ * read back via `returns`, and the `managed` node choice.
118
+ * @returns An action spec to pass to `.step(name, …)`.
119
+ */
120
+ export function http(inputs) {
121
+ if (typeof inputs.managed !== 'boolean') {
122
+ throw new Error('http() requires managed: true or managed: false because they emit different platform nodes. '
123
+ + 'Use true for Managed HTTP Request/core.action.http.v2 or when non-2xx statuses must reach .onError(); '
124
+ + 'use false for the standalone core.action.http node.');
125
+ }
126
+ return builtinActionSpec({ kind: 'http', inputs });
127
+ }
128
+ /**
129
+ * Declare an inline script action.
130
+ *
131
+ * @param inputs - The JavaScript body (`code`, which must `return`) and what it
132
+ * returns (`returns`).
133
+ * @returns An action spec to pass to `.step(name, …)`.
134
+ */
135
+ export function script(inputs) {
136
+ return builtinActionSpec({ kind: 'script', inputs });
137
+ }
138
+ /**
139
+ * Declare a Transform action — a chain of declarative operations over a
140
+ * collection. Read the result downstream with `out('<step>')`.
141
+ *
142
+ * @remarks
143
+ * For a node that does ONE thing, name the variant — the emitted `.flow` then
144
+ * carries `core.action.transform.filter` and reads as `Filter` in the designer
145
+ * instead of a generic `Transform`:
146
+ *
147
+ * ```ts
148
+ * .step('bigOrders', transform({
149
+ * variant: 'filter',
150
+ * collection: v('orders'),
151
+ * operations: [
152
+ * { type: 'filter', filters: [{ field: 'amount', condition: 'greater_equal', value: 100 }] },
153
+ * ],
154
+ * }))
155
+ * ```
156
+ *
157
+ * @example
158
+ * **Filter a collection, then reshape what survives**
159
+ * ```ts
160
+ * .var('catalog', types.array, [
161
+ * { title: 'Deep Learning', author: 'Goodfellow', difficulty: 9, pages: 800 },
162
+ * { title: 'Information Theory', author: 'MacKay', difficulty: 7, pages: 540 },
163
+ * ])
164
+ * .step('curate', transform({
165
+ * collection: v('catalog'),
166
+ * operations: [
167
+ * { type: 'filter', operation: 'and', filters: [
168
+ * { field: 'difficulty', condition: 'greater_than', value: 5 },
169
+ * { field: 'pages', condition: 'less_than', value: 600 },
170
+ * ] },
171
+ * { type: 'map', keepOriginalFields: false, mappings: [
172
+ * { field: 'title', transformation: 'uppercase' },
173
+ * { field: 'author' },
174
+ * ] },
175
+ * ],
176
+ * }))
177
+ * ```
178
+ *
179
+ * @param inputs - The `collection` to transform and the chain of `operations` to
180
+ * run over it.
181
+ * @returns An action spec to pass to `.step(name, …)`.
182
+ */
183
+ export function transform(inputs) {
184
+ return builtinActionSpec({ kind: 'transform', inputs });
185
+ }
186
+ /**
187
+ * Declare a human task — a step that pauses for a person to read some values,
188
+ * fill others in, and press one of the outcome buttons.
189
+ *
190
+ * @remarks
191
+ * Read an answer with `out('review', '<fieldId>')`, and which button they pressed
192
+ * with `out('review', 'Action')` — branch on that for per-outcome routing.
193
+ *
194
+ * ### Picking a node type with `variant`
195
+ *
196
+ * The example above emits `uipath.human-in-the-loop`, the original node, and
197
+ * that stays the default. Two other spellings of the same human task exist
198
+ * ({@link HitlVariant}), and `variant` is how you say which:
199
+ *
200
+ * ```ts
201
+ * // Same inline form, the newer node type — no `inputs.type` is written.
202
+ * hitl({ variant: 'quick-form', fields: […], outcomes: ['Approve', 'Reject'] })
203
+ *
204
+ * // The form lives in a DEPLOYED APP: no `fields`, but still your outcomes.
205
+ * hitl({
206
+ * variant: 'action-app',
207
+ * app: { name: 'Expense Review', key: '<guid>', folderPath: 'Shared',
208
+ * inputs: { 'Expense Amount': out('fetchExpense', 'total') } },
209
+ * outcomes: ['Approve', 'Reject'],
210
+ * })
211
+ * ```
212
+ *
213
+ * What every variant shares: one `completed` port, and the same two outputs
214
+ * (`output`, carrying the answers, and `status`, carrying the outcome name) —
215
+ * all three definitions declare them identically, so downstream reads do not
216
+ * change when you switch.
217
+ *
218
+ * @example
219
+ * **Pause for a person to approve, then read their decision**
220
+ * ```ts
221
+ * .step('review', hitl({
222
+ * title: 'Review Expense',
223
+ * fields: [
224
+ * { id: 'amount', type: 'number', direction: 'input', value: input('amount') },
225
+ * { id: 'approved', type: 'boolean', direction: 'output' },
226
+ * { id: 'comments', type: 'text', direction: 'output' },
227
+ * ],
228
+ * outcomes: ['Approve', 'Reject'],
229
+ * }))
230
+ * .step('log', script({ code: 'return "Decision: " + $vars.review.output.approved;' }))
231
+ * ```
232
+ *
233
+ * @param inputs - The form's fields, outcomes and recipient.
234
+ * @returns An action spec for `.step(...)`.
235
+ * @example example-eval/GallerySubmission.flow.ts
236
+ */
237
+ export function hitl(inputs) {
238
+ return builtinActionSpec({ kind: 'hitl', inputs });
239
+ }
240
+ /**
241
+ * Summarize a document with citations — the platform's **Summarize** node.
242
+ *
243
+ * @remarks
244
+ * **The node type is `uipath.pattern.deep-rag`.** The canvas calls it
245
+ * *Summarize*, its properties panel is titled *Summarize Configuration*, and
246
+ * the wire type stays `deep-rag` — it is the same node, under the name the
247
+ * backend service contract uses (`ECS.DeepRag`). There is no
248
+ * `uipath.pattern.summarize`. (A same-named inline-agent TOOL,
249
+ * `uipath.agent.resource.tool.builtin.summarize`, is a different family.)
250
+ *
251
+ * The answer's fields are **PascalCase** — `content.Text`,
252
+ * `content.Citations[].{Ordinal, PageNumber, Source, Reference}`. Lowercase
253
+ * `content.text` resolves to nothing at run time.
254
+ *
255
+ * A local run cannot reach the service: it returns the baked
256
+ * fixture shape, and only a real platform run (`uip maestro flow debug
257
+ * --attachment <var>=<file>`) calls the model.
258
+ *
259
+ * @example
260
+ * **Summarize an attached contract, with citations**
261
+ * ```ts
262
+ * flow('SummarizeDemo')
263
+ * .input({ documentFile: types.file })
264
+ * .output({ summary: types.string, citations: types.array })
265
+ * .step('summarizeContract', summarize({
266
+ * attachment: out('start', 'documentFile'),
267
+ * prompt: 'Write a 5-bullet executive summary covering scope, term and SLAs.',
268
+ * returnCitations: true,
269
+ * }))
270
+ * .return({
271
+ * summary: out('summarizeContract', 'content.Text'),
272
+ * citations: out('summarizeContract', 'content.Citations'),
273
+ * })
274
+ * ```
275
+ *
276
+ * @param inputs - The document (`attachment`), the question to answer (`prompt`),
277
+ * and whether to return citations.
278
+ * @returns An action spec to pass to `.step(name, …)`.
279
+ */
280
+ export function summarize(inputs) {
281
+ return builtinActionSpec({ kind: 'summarize', inputs });
282
+ }
283
+ /**
284
+ * Add AI-generated columns to a CSV — the platform's **Batch transform** node,
285
+ * `uipath.pattern.batch-transform` (service contract `ECS.BatchTransform`).
286
+ *
287
+ * @remarks
288
+ * The output is a **file handle for the enriched CSV**, not the rows:
289
+ * `{ ID, FullName, MimeType }` — the service writes a new
290
+ * `batch-transform-<uuid>.csv` and hands back its attachment. Note `ID`, two
291
+ * capitals: that is what the platform returns.
292
+ *
293
+ * Same dispatch story as {@link summarize} — dry-run fixture locally, a real
294
+ * model call only on a platform run.
295
+ *
296
+ * @example
297
+ * **Categorize each CSV row with two generated columns**
298
+ * ```ts
299
+ * flow('BatchTransformDemo')
300
+ * .input({ csvFile: types.file })
301
+ * .output({ result: types.file })
302
+ * .step('categorizeRows', batchTransform({
303
+ * attachment: out('start', 'csvFile'),
304
+ * prompt: 'Classify each row by category and write a one-line summary.',
305
+ * outputColumns: [
306
+ * { name: 'Category', description: 'One of: Utility, Software, Travel, Other' },
307
+ * { name: 'Summary', description: 'Plain-English one-line summary of the row' },
308
+ * ],
309
+ * }))
310
+ * .return({ result: out('categorizeRows') })
311
+ * ```
312
+ *
313
+ * @param inputs - The CSV (`attachment`), the instruction (`prompt`), and the
314
+ * `outputColumns` to add to each row.
315
+ * @returns An action spec to pass to `.step(name, …)`.
316
+ */
317
+ export function batchTransform(inputs) {
318
+ return builtinActionSpec({ kind: 'batchTransform', inputs });
319
+ }
320
+ /**
321
+ * Extract fields from a document with a published IxP project — the platform's
322
+ * **Extract** node (`uipath.ixp.*`, service contract `IXP.Extraction`).
323
+ *
324
+ * @remarks
325
+ * **The result's shape is three levels deep and PascalCase.** A field lands at
326
+ * `out('<step>', 'ExtractionResult.ResultsDocument.Fields')` — an array of
327
+ * `{ FieldId, FieldName, FieldType, IsMissing, Values[], Confidence }`, looked
328
+ * up by `FieldName`. `Fields[]` is under `ResultsDocument`, not directly under
329
+ * `ExtractionResult`, and there is no `result` wrapper: the platform's
330
+ * serializer strips it before the value reaches the variable.
331
+ *
332
+ * **A local run cannot extract anything** — extraction needs a real document on
333
+ * the IxP service. An offline run returns the baked
334
+ * fixture shape, and only a platform run reaches the model. So a green local
335
+ * rung proves the wiring and the definition, never that a document was read.
336
+ *
337
+ * **`fileRef` is emitted as a PLAIN `=js:` string, not the expression envelope
338
+ * the rest of the file uses** — the one place this family diverges from the
339
+ * format's general spelling, and the contract this node owes the platform. The
340
+ * product's own `ixp-node` validator tests `typeof fileRef !== 'string'` and
341
+ * refuses the object form (*"inputs.fileRef must be a `=js:$vars.…`
342
+ * expression"*), the node's registry manifest declares
343
+ * `{type:'string', minLength:1}`, and so do all 150 v1-authored instances in the
344
+ * deployed corpus that carry the field — at file versions 1.6, 1.8 and 1.9 alike,
345
+ * with zero envelopes among them. The RUNTIME
346
+ * accepts both, so only `uip maestro flow validate` sees a wrong one; the
347
+ * emitter's exemption lives in `migrate.ts` (`UNWRAPPED_INPUTS`).
348
+ * See `skill/references/ixp.md` §3.
349
+ *
350
+ * @example
351
+ * **Extract an invoice total and read it out of the nested result**
352
+ * ```ts
353
+ * flow('InvoiceIntake')
354
+ * .input({ invoiceFile: types.file })
355
+ * .output({ total: types.string })
356
+ * .step('extract', ixpExtract({
357
+ * project: 'uipath.ixp.invoiceixp-cef0d447-ixp.ff973488-5d89-8035-86ac-f980b4be6deb-c4359cde-55f0-4f0e-9322-c6cdce74ab4c',
358
+ * modelName: 'invoiceixp-cef0d447-ixp',
359
+ * name: 'InvoiceIXP',
360
+ * folderName: 'Shared',
361
+ * fileRef: out('start', 'invoiceFile'),
362
+ * }))
363
+ * .step('readTotal', script({ code: `
364
+ * const fields = $vars.extract.output.ExtractionResult.ResultsDocument.Fields || [];
365
+ * return { total: fields.find(f => f.FieldName === 'invoiceTotal')?.Values?.[0] };
366
+ * ` }))
367
+ * .return({ total: out('readTotal', 'total') })
368
+ * ```
369
+ *
370
+ * @param inputs - The published IxP `project` and `modelName`, and the document
371
+ * to read (`fileRef`).
372
+ * @returns An action spec to pass to `.step(name, …)`.
373
+ */
374
+ export function ixpExtract(inputs) {
375
+ return builtinActionSpec({ kind: 'ixpExtract', inputs });
376
+ }
377
+ /**
378
+ * Declare a delay — a step that pauses the flow for a fixed length of time and
379
+ * then carries on.
380
+ *
381
+ * @remarks
382
+ * A delay produces nothing: there is no `out('settle')` to read. It is a wait,
383
+ * not a value.
384
+ *
385
+ * The node itself splits that one duration across two fields (`timerPreset`
386
+ * holds it directly, or the literal `"custom"` with the real value in
387
+ * `timerValue`); the serializer picks the encoding, so you state the wait once.
388
+ *
389
+ * @example
390
+ * **Wait thirty seconds before carrying on**
391
+ * ```ts
392
+ * .step('settle', delay({ duration: 'PT30S' }))
393
+ * ```
394
+ *
395
+ * @param inputs - How long to wait (`duration`), as an ISO-8601 duration.
396
+ * @returns An action spec to pass to `.step(name, …)`.
397
+ */
398
+ export function delay(inputs) {
399
+ // Key presence, not value shape: `{ duration: undefined }` picks the
400
+ // duration arm and flows to check()'s DELAY_NO_DURATION diagnostic — the
401
+ // factory only rejects picking BOTH arms or NEITHER.
402
+ const hasDuration = 'duration' in inputs;
403
+ const hasUntil = 'until' in inputs;
404
+ if (hasDuration === hasUntil) {
405
+ throw new Error("delay() takes exactly ONE of { duration } (an ISO-8601 duration, e.g. 'PT15M') or "
406
+ + "{ until } (an ISO-8601 date-time, e.g. '2026-09-01T09:00:00Z').");
407
+ }
408
+ return builtinActionSpec({ kind: 'delay', inputs });
409
+ }
410
+ /**
411
+ * Declare a PLACEHOLDER step — "a real node goes here later".
412
+ *
413
+ * @remarks
414
+ * A mock takes **no inputs and publishes nothing**. It is a marker on the canvas
415
+ * that keeps the graph wired and the flow deployable while one step is still
416
+ * missing — not a stub that returns test data. `out('extractInvoice')` is
417
+ * refused at compile time (`MOCK_HAS_NO_OUTPUT`) because it would read `null` at
418
+ * run time, always.
419
+ *
420
+ * Say what belongs there in the step's own name and in the label the canvas
421
+ * shows; the corpus's placeholders read like
422
+ * `"Extract Invoice Fields (mock — IxP model not yet published)"`.
423
+ *
424
+ * ### Why there are no arguments (convention #191 — the family contract)
425
+ *
426
+ * The platform's `core.logic.mock@1.0.0` declares **no `inputDefinition`** and one
427
+ * output whose `source` is the literal `"null"`. Measured over the 4,033 distinct
428
+ * archived `.flow` artifacts: **74 mock instances in 62 flows, and 0 carrying a
429
+ * fixture anywhere in the node** — 71 of them with `inputs: {}` or no `inputs`
430
+ * key. The 3 exceptions carry free-text `placeholder` / `_placeholder` keys the
431
+ * definition never declares, invented by agents on runs that scored 0.9 and 0.4.
432
+ *
433
+ * **This is NOT a local runner's `kind: 'mock'` test construct**, which returns a
434
+ * baked fixture. They are different things that share
435
+ * a name, and a `mock({ fixture })` surface would emit a node whose local
436
+ * behaviour and deployed behaviour disagree silently — see
437
+ * [#125](https://github.com/UiPath/flow-builder-sdk/issues/125). Nothing this SDK
438
+ * emits opens that channel: an SDK-authored mock publishes `null` locally,
439
+ * exactly as the platform does.
440
+ *
441
+ * @example
442
+ * **Hold a step's place until the real node exists**
443
+ * ```ts
444
+ * .step('extractInvoice', mock()) // ← swap for the IxP node once the project exists
445
+ * ```
446
+ *
447
+ * @returns An action spec to pass to `.step(name, …)`.
448
+ */
449
+ export function mock() {
450
+ return builtinActionSpec({ kind: 'mock' });
451
+ }
452
+ /**
453
+ * Invoke a deployed RPA (robotic process automation) workflow — a classic
454
+ * UI-automation process, published to Orchestrator, run by a robot.
455
+ *
456
+ * @remarks
457
+ * Three fields identify the process and they all come from the tenant, which is
458
+ * why they are named exactly as the platform names them:
459
+ *
460
+ * key the published process's release key (a GUID). It becomes part of
461
+ * the node's TYPE — `uipath.core.rpa-workflow.<key>` — so the
462
+ * platform can tell one process's node from another's.
463
+ * name the process's name in Orchestrator.
464
+ * folderPath the Orchestrator folder it lives in.
465
+ *
466
+ * `name` + `folderPath` are what the robot is actually started by (the runtime
467
+ * re-resolves the release from them), and together they are also the process's
468
+ * `resourceKey`: `"<folderPath>.<name>"`. The serializer emits the two of them
469
+ * as the flow's process bindings and points the node at them, because a
470
+ * bindings entry the node does not reference is not a bound process.
471
+ *
472
+ * `inputs` are the PROCESS's own input arguments — whatever it declares, by its
473
+ * own argument names. They are not a fixed schema.
474
+ *
475
+ * The step publishes whatever the process returns, under `output`: read a field
476
+ * with `out('<step>', '<field>')`. Nothing local can check that an argument name
477
+ * or a returned field name matches the deployed process — only the robot knows —
478
+ * so a wrong name shows up as a faulted job on a live run, not at compile time.
479
+ *
480
+ * @example
481
+ * **Start a deployed process and read what it returns**
482
+ * ```ts
483
+ * .step('getTitle', rpaWorkflow({
484
+ * key: '486edc26-0658-4ac1-92c9-1ef953927151',
485
+ * name: 'RPA Workflow',
486
+ * folderPath: 'Shared/uipath-maestro-flow/ProjectEuler RPA',
487
+ * inputs: { problemId: 123 },
488
+ * }))
489
+ * .return({ title: out('getTitle', 'title') })
490
+ * ```
491
+ *
492
+ * @param inputs - The published process to start (`key`, `name`, `folderPath`),
493
+ * its `inputs`, and the output fields you read back via `returns`.
494
+ * @returns An action spec to pass to `.step(name, …)`.
495
+ */
496
+ export function rpaWorkflow(inputs) {
497
+ return builtinActionSpec({ kind: 'rpaWorkflow', inputs });
498
+ }
499
+ /**
500
+ * Invoke a deployed API workflow — a coded workflow published to Orchestrator,
501
+ * run as a serverless job rather than by a robot.
502
+ *
503
+ * @remarks
504
+ * The same three identifiers as `rpaWorkflow`, for the same reason: `key` is
505
+ * the key the node's TYPE carries (`uipath.core.api-workflow.<key>`), while
506
+ * `name` + `folderPath` are what the runtime resolves the job by — and together
507
+ * they are the workflow's `resourceKey`, `"<folderPath>.<name>"`. The serializer
508
+ * emits those two as the flow's process bindings and points the node at them.
509
+ *
510
+ * The step publishes the job's output arguments under `output`, so
511
+ * `out('<step>', '<field>')` reads one of the fields `returns` declares. Whether
512
+ * an argument name or a returned field actually matches the deployed workflow is
513
+ * something only the tenant knows — a wrong one is a faulted job on a live run,
514
+ * not a compile error.
515
+ *
516
+ * @example
517
+ * **Start an API workflow and read a declared output argument**
518
+ * ```ts
519
+ * .step('getAge', apiWorkflow({
520
+ * key: 'ce857908-ee1d-4392-b552-38bcea0be29c',
521
+ * name: 'NameToAgeFixed',
522
+ * folderPath: 'Shared',
523
+ * inputs: { name: 'tomasz' },
524
+ * returns: { EstimatedAge: 'integer' },
525
+ * }))
526
+ * .return({ age: out('getAge', 'EstimatedAge') })
527
+ * ```
528
+ *
529
+ * @param inputs - The published API workflow to start (`key`, `name`,
530
+ * `folderPath`), its `inputs`, and the fields you read back via `returns`.
531
+ * @returns An action spec to pass to `.step(name, …)`.
532
+ */
533
+ export function apiWorkflow(inputs) {
534
+ return builtinActionSpec({ kind: 'apiWorkflow', inputs });
535
+ }
536
+ /**
537
+ * Invoke a published Orchestrator **Function** — a deployed unit of code run as
538
+ * one step (`uipath.core.function.<key>`, dispatched as
539
+ * `Orchestrator.ExecuteFunctionAsync`).
540
+ *
541
+ * ```ts
542
+ * .step('echo', publishedFunction({
543
+ * key: '7059bdb5-fdd7-4e13-9d7b-1748aaeb129d',
544
+ * name: 'acme-echo',
545
+ * folderPath: 'Shared/acme-echo',
546
+ * inputs: { message: 'hello' },
547
+ * returns: { echoed: 'string' },
548
+ * }))
549
+ * ```
550
+ *
551
+ * The node type carries the key, so the function must already exist on the
552
+ * tenant — read `key`, `name` and `folderPath` from the registry rather than
553
+ * constructing them. Like the other published families, the resource identity
554
+ * is CLOSED by a binding pair (`<folderPath>.<name>`), and two steps on the
555
+ * same function share one pair.
556
+ *
557
+ * @param inputs - The function's identity, its arguments, and what it returns.
558
+ * @returns An action spec to pass to `.step(...)`.
559
+ */
560
+ export function publishedFunction(inputs) {
561
+ return builtinActionSpec({ kind: 'publishedFunction', inputs });
562
+ }
563
+ /**
564
+ * Post an assistant message into a live conversation
565
+ * (`uipath.conversational.send-message`).
566
+ *
567
+ * ```ts
568
+ * .step('answer', sendMessage({
569
+ * conversationId: out('start', 'conversationId'),
570
+ * exchangeId: out('listen', 'conversationContext.latestExchangeId'),
571
+ * content: 'Your order ships tomorrow.',
572
+ * }))
573
+ * ```
574
+ *
575
+ * The message is Markdown (`text/markdown` is the node's only supported type)
576
+ * and the role is always `assistant` — a flow speaks as the assistant.
577
+ *
578
+ * @param inputs - The conversation, the exchange, and what to say.
579
+ * @returns An action spec to pass to `.step(...)`.
580
+ */
581
+ export function sendMessage(inputs) {
582
+ return builtinActionSpec({ kind: 'sendMessage', inputs });
583
+ }
584
+ /**
585
+ * PAUSE until the person sends their next message
586
+ * (`uipath.conversational.wait-for-message`) — a catch event, like
587
+ * `waitForEvent`, so the flow suspends rather than polling.
588
+ *
589
+ * ```ts
590
+ * .step('listen', waitForMessage({ conversationId: out('start', 'conversationId') }))
591
+ * ```
592
+ *
593
+ * It resumes with the conversation context:
594
+ * `out('listen', 'conversationContext.messages')` is the transcript and
595
+ * `…conversationContext.latestExchangeId` is the turn to answer.
596
+ *
597
+ * @param inputs - The conversation to wait on, and how much history to return.
598
+ * @returns An action spec to pass to `.step(...)`.
599
+ */
600
+ export function waitForMessage(inputs) {
601
+ return builtinActionSpec({ kind: 'waitForMessage', inputs });
602
+ }
603
+ /**
604
+ * READ a conversation's transcript so far without waiting
605
+ * (`uipath.conversational.get-conversation-context`) — the shape a
606
+ * conversational agent takes as its turn context.
607
+ *
608
+ * ```ts
609
+ * .step('history', conversationContext({
610
+ * conversationId: out('start', 'conversationId'), exchangeLimit: 10,
611
+ * }))
612
+ * ```
613
+ *
614
+ * @param inputs - The conversation to read, and how many exchanges to return.
615
+ * @returns An action spec to pass to `.step(...)`.
616
+ */
617
+ export function conversationContext(inputs) {
618
+ return builtinActionSpec({ kind: 'conversationContext', inputs });
619
+ }
620
+ /**
621
+ * Place an outgoing phone call
622
+ * (`uipath.conversational.voice.create-outgoing-call`) and get back the
623
+ * `callContext` every other voice step is keyed by.
624
+ *
625
+ * ```ts
626
+ * .step('dial', createOutgoingCall({ from: '+15550001111', to: input('customerPhone') }))
627
+ * .step('talk', voiceAgent({
628
+ * systemPrompt: 'Confirm the delivery window, then thank them.',
629
+ * callContext: out('dial', 'callContext'),
630
+ * }))
631
+ * ```
632
+ *
633
+ * @param inputs - The provisioned `from` number and the `to` number to dial.
634
+ * @returns An action spec to pass to `.step(...)`.
635
+ */
636
+ export function createOutgoingCall(inputs) {
637
+ return builtinActionSpec({ kind: 'createOutgoingCall', inputs });
638
+ }
639
+ /**
640
+ * Hang up (`uipath.conversational.voice.end-call`). Reads
641
+ * `out('<step>', 'ended')`.
642
+ *
643
+ * @param inputs - The `callContext` of the call to end.
644
+ * @returns An action spec to pass to `.step(...)`.
645
+ */
646
+ export function endCall(inputs) {
647
+ return builtinActionSpec({ kind: 'endCall', inputs });
648
+ }
649
+ /**
650
+ * Put a VOICE agent on a live call (`uipath.agent.voice`) — it speaks and
651
+ * listens for one turn, then the flow continues.
652
+ *
653
+ * ```ts
654
+ * .trigger(voiceTrigger())
655
+ * .step('greet', voiceAgent({
656
+ * systemPrompt: 'Greet {{input.customerName}} and find out why they called.',
657
+ * inputs: { customerName: input('customerName') },
658
+ * callContext: out('start', 'callContext'),
659
+ * voice: { model: 'gemini-3.1-flash-live-preview', persona: 'Kore' },
660
+ * }))
661
+ * ```
662
+ *
663
+ * Like `inlineAgent`, compile emits the node PLUS a stable
664
+ * `<source>/agent.json` sidecar. Unlike it, the turn's content comes from the
665
+ * call rather than from a user-prompt argument. Flow context can still be
666
+ * supplied through `inputs` and referenced from the system prompt. There are no
667
+ * declared `returns`: read the turn back as
668
+ * `out('<step>', 'uipath__agent_response_messages')`.
669
+ *
670
+ * @param inputs - The instructions, the call to join, and how the agent sounds.
671
+ * @returns An action spec to pass to `.step(...)`.
672
+ */
673
+ export function voiceAgent(inputs) {
674
+ return builtinActionSpec({ kind: 'voiceAgent', inputs });
675
+ }
676
+ /**
677
+ * A CONVERSATIONAL agent (`uipath.agent.conversational`) — it answers one turn
678
+ * of a live chat, reading the transcript rather than flow arguments.
679
+ *
680
+ * ```ts
681
+ * .trigger(conversationTrigger())
682
+ * .step('listen', waitForMessage({ conversationId: out('start', 'conversationId') }))
683
+ * .step('reply', conversationalAgent({
684
+ * model: 'gpt-5.4',
685
+ * systemPrompt: 'You are a support agent. Be brief.',
686
+ * settings: { context: out('listen', 'conversationContext') },
687
+ * }))
688
+ * ```
689
+ *
690
+ * The reply is `out('<step>', 'uipath__agent_response_messages')` — the
691
+ * platform's own field name. Like `inlineAgent`, compile emits the node plus a
692
+ * stable `<source>/agent.json` sidecar.
693
+ *
694
+ * `sendMessage` is the alternative when the flow (not a model) decides what to
695
+ * say; this factory is for when the model does.
696
+ *
697
+ * @param inputs - The model, the instructions, and how the turn is bound.
698
+ * @returns An action spec to pass to `.step(...)`.
699
+ */
700
+ export function conversationalAgent(inputs) {
701
+ return builtinActionSpec({ kind: 'conversationalAgent', inputs });
702
+ }
703
+ /**
704
+ * Invoke a deployed AGENTIC PROCESS — a Maestro process orchestration published to
705
+ * Orchestrator: a BPMN process that coordinates agents, robots and people, started
706
+ * as a job the same way an RPA or API workflow is.
707
+ *
708
+ * @remarks
709
+ * The same three identifiers as `rpaWorkflow` and `apiWorkflow`, for the same
710
+ * reason: `key` is the key the node's TYPE carries
711
+ * (`uipath.core.agentic-process.<key>`), while `name` + `folderPath` are what
712
+ * the runtime resolves the job by — and together they are the process's
713
+ * `resourceKey`, `"<folderPath>.<name>"`. The serializer emits those two as the
714
+ * flow's process bindings and points the node at them.
715
+ *
716
+ * By default the step WAITS for the process and publishes its output arguments
717
+ * under `output`, so `out('<step>', '<field>')` reads one of the fields
718
+ * `returns` declares.
719
+ *
720
+ * `completion: 'fire-and-forget'` selects the designer's own async switch
721
+ * instead: the node's service type becomes `Orchestrator.Start…ProcessAsync`
722
+ * and it publishes no output but `error`. The type is a discriminated union, so
723
+ * `returns` is impossible in that form and nothing downstream can read one; a
724
+ * local run dispatches without waiting and yields `{ jobKey, started: true }`.
725
+ *
726
+ * `form` picks which published Agentic Process this is — `'bpmn'` (the default,
727
+ * a Maestro process orchestration), `'flow'` (a published Maestro Flow), or
728
+ * `'case'` (a Case Management process). They share one public concept and
729
+ * differ only in wire identity.
730
+ *
731
+ * @example
732
+ * **Start a Maestro process and wait for its result**
733
+ * ```ts
734
+ * .step('runIntake', agenticProcess({
735
+ * key: '4fc450ab-89be-4462-8fc8-21ac4c1d6fb9',
736
+ * name: 'ProcurementProcess',
737
+ * folderPath: 'Shared/uipath-agents/ProcurementProcess',
738
+ * inputs: { productId: 1 },
739
+ * returns: { status: 'boolean' },
740
+ * }))
741
+ * .return({ ok: out('runIntake', 'status') })
742
+ * ```
743
+ *
744
+ * @param inputs - The published Maestro process to start (`key`, `name`,
745
+ * `folderPath`), its `inputs`, and the fields you read back via `returns`.
746
+ * @returns An action spec to pass to `.step(name, …)`.
747
+ */
748
+ export function agenticProcess(inputs) {
749
+ // Types are erased at run time, so the discriminated union alone cannot stop
750
+ // `{ completion: 'fire-and-forget', returns: {...} }` arriving from untyped
751
+ // code — and silently dropping the returns would validate a read that can
752
+ // never be satisfied.
753
+ if (inputs.completion === 'fire-and-forget' && inputs.returns !== undefined) {
754
+ throw new Error("agenticProcess(): completion 'fire-and-forget' publishes no output — remove `returns`, "
755
+ + "or use completion: 'wait' to read the process result.");
756
+ }
757
+ return builtinActionSpec({ kind: 'agenticProcess', inputs });
758
+ }
759
+ /**
760
+ * Invoke an AGENT resource — either one published to Orchestrator or a sibling
761
+ * agent project registered in the same solution. Both start through
762
+ * `Orchestrator.StartAgentJob`.
763
+ *
764
+ * @remarks
765
+ * **Coded and low-code agents are the same node.** This one factory authors both.
766
+ * `registry get` on a coded agent and on a low-code one returns the same node type,
767
+ * the same service type, the same `sortOrder: 505` and the same bindings shape; the
768
+ * only difference is the icon, which is what `flavour` sets. Which kind a resource
769
+ * is a property of what somebody published, not of the flow — so if a task asks for
770
+ * "a coded agent", what it is asking you to get right is the RESOURCE you point at.
771
+ *
772
+ * **What this factory cannot do, said plainly:** it does not create an agent. A
773
+ * published resource must already be deployed. An in-solution resource must first
774
+ * be scaffolded and registered with `uip solution projects add`; this factory then
775
+ * authors the local reference from the registered resource key and project id.
776
+ *
777
+ * The three identifiers are separate for `rpaWorkflow`'s reason: `agent` is the key
778
+ * the node's TYPE carries (`uipath.core.agent.<agent>`), while `name` +
779
+ * `folderPath` are what the runtime resolves the job by and together are the
780
+ * `resourceKey`, `"<folderPath>.<name>"`. `folderPath` earns its keep twice here —
781
+ * see {@link AgentInputs.folderPath} for the two-agents-called-CountLetters case.
782
+ *
783
+ * The step WAITS for the job and publishes its output arguments under `output`, so
784
+ * `out('<step>', '<field>')` reads a field `returns` declares — using the names the
785
+ * agent's own definition declares, case included.
786
+ *
787
+ * ── the live bar, stated ─────────────────────────────────────────────────────────
788
+ * A green live rung here means **a model responded with the declared output shape**,
789
+ * not that the answer was right. A real Orchestrator job runs, the flow's input
790
+ * reaches it, and its answer reaches the flow's output — all four independently
791
+ * checkable (`ladder.sh job`). Whether the number it returned is the correct number
792
+ * is the model's business, and no rung asserts it. What CAN be asserted is that the
793
+ * flow did not fake it: the offline seeds assert the exact UNFIXTURED value, which a
794
+ * hardcoded answer cannot produce.
795
+ *
796
+ * @example
797
+ * **Start a published agent and read one declared output**
798
+ * ```ts
799
+ * .step('countLetters', agent({
800
+ * key: '6a47dc5b-5fd4-461f-b97d-6c1817abcaaa',
801
+ * name: 'CountLetters LowCode Agent',
802
+ * folderPath: 'Shared/uipath-maestro-flow/CountLetters LowCode',
803
+ * inputs: { inputString: input('word') },
804
+ * returns: { count: 'integer', inputString: 'string' },
805
+ * }))
806
+ * .return({ rs: out('countLetters', 'count') })
807
+ * ```
808
+ *
809
+ * @param inputs - The agent to start (`name`, `folderPath`, and `key` or
810
+ * `projectId`), its `inputs`, and the fields you read back via `returns`.
811
+ * @returns An action spec to pass to `.step(name, …)`.
812
+ */
813
+ export function agent(inputs) {
814
+ return builtinActionSpec({ kind: 'agent', inputs });
815
+ }
816
+ /**
817
+ * Declare an INLINE AUTONOMOUS AGENT — an agent defined inside this flow's own
818
+ * project rather than published to Orchestrator (`uipath.agent.autonomous`,
819
+ * `Orchestrator.StartInlineAgentJob`).
820
+ *
821
+ * @remarks
822
+ * **Two artifacts, not one.** The node carries the prompts and the variable
823
+ * descriptors, and it points at a directory — `source` — where the platform expects
824
+ * the agent's own configuration (flow-v1 emits `entryPoint: <source>/agent.json`).
825
+ * So `compile` writes `<source>/agent.json` beside the `.flow`, built from the same
826
+ * fields. Nothing to assemble by hand; `source` defaults to a uuid derived from the
827
+ * flow id and step name so a recompile is not a diff.
828
+ *
829
+ * **How this differs from `agent()`.** That one references something already
830
+ * published and started as an Orchestrator job; this one IS the definition, and the
831
+ * platform runs it inside the flow's own debug/publish context. The practical
832
+ * consequences: there is no folder, no release key and no binding pair here — and
833
+ * no `uip` verb that starts one headlessly either.
834
+ *
835
+ * ── the live bar, stated ─────────────────────────────────────────────────────────
836
+ * Weaker than `agent()`'s, and in a specific way. `Orchestrator.StartInlineAgentJob`
837
+ * is Studio-Web-debug-only, so there is no Orchestrator job to point at and no
838
+ * headless verb that starts one. No local runner currently calls a model for this
839
+ * node either — an offline run asserts the WIRING and the declared `returns` shape,
840
+ * never that a model answered. Two differences would remain for any runner that did
841
+ * call one: knowledge grounding (a context handle) is a cloud-side index an offline
842
+ * path does not have, so the call would be ungrounded; and the node's `model` would
843
+ * have to be substituted for one reachable headlessly. Answer quality stays on the
844
+ * offline `expect` seeds; real behaviour needs a Studio Web debug run.
845
+ *
846
+ * @example
847
+ * **Classify an email with an agent defined inline**
848
+ * ```ts
849
+ * .step('triage', inlineAgent({
850
+ * model: 'gpt-5.4',
851
+ * systemPrompt:
852
+ * 'You are a support triage assistant. Classify the email into exactly one ' +
853
+ * 'category (billing | technical | account) and one priority (low | normal | ' +
854
+ * 'high). Return ONLY a JSON object with keys "category" and "priority".',
855
+ * userPrompt: 'Classify this email:\n{{input.body}}',
856
+ * inputs: { body: input('body') },
857
+ * returns: { category: 'string', priority: 'string' },
858
+ * }))
859
+ * .return({ category: out('triage', 'category') })
860
+ * ```
861
+ *
862
+ * @param inputs - The agent defined in this project: its `model`,
863
+ * `systemPrompt`, `userPrompt`, and the `returns` fields it must produce.
864
+ * @returns An action spec to pass to `.step(name, …)`.
865
+ */
866
+ export function inlineAgent(inputs) {
867
+ return builtinActionSpec({ kind: 'inlineAgent', inputs });
868
+ }
869
+ /**
870
+ * Classify a document into a document type (`uipath.document.classify`). The
871
+ * result publishes `ClassificationResult` — an array of typed classifications
872
+ * with page ranges and confidences.
873
+ *
874
+ * @param inputs - The file reference and optional page range / split / model settings.
875
+ * @returns An action spec to pass to `.step(name, …)`.
876
+ */
877
+ export function documentClassify(inputs) {
878
+ return builtinActionSpec({ kind: 'documentClassify', inputs });
879
+ }
880
+ /**
881
+ * Extract fields from a document with an INLINE schema — Dynamic Extract
882
+ * (`uipath.ixp.extract-document-builder`), the newer of the two extraction
883
+ * shapes. No deployed IXP project is referenced: the extraction schema rides
884
+ * the node. The result publishes `ExtractionResult` (and `Taxonomy`).
885
+ *
886
+ * @param inputs - The file reference, the inline extraction schema, and
887
+ * optional page range / model settings.
888
+ * @returns An action spec to pass to `.step(name, …)`.
889
+ */
890
+ export function dynamicExtract(inputs) {
891
+ return builtinActionSpec({ kind: 'dynamicExtract', inputs });
892
+ }
893
+ /**
894
+ * Read ONE entity record from Data Fabric (`core.datafabric.read`). The record
895
+ * publishes to the step's `output`; downstream references re-fetch fresh data
896
+ * at activation time (the engine re-runs the query rather than caching).
897
+ *
898
+ * @remarks
899
+ * **Prefer the connector for Data Fabric work during the transition.**
900
+ * `core.datafabric.*` has exactly two verbs — this one and
901
+ * {@link dataFabricUpdate} — and neither declares an output schema. Create,
902
+ * delete, get-by-id, a multi-record query with a row limit, file record fields
903
+ * and entity events are NOT in this family: they are operations on the SAME
904
+ * product reached through its Integration Service connector,
905
+ * `uipath-uipath-dataservice` (the tenant displays it as **UiPath Data
906
+ * Fabric**), which covers every verb including the two here.
907
+ *
908
+ * Taking this node for the one verb that has a native form leaves the rest of
909
+ * the same entity on the connector — two connection bindings and two payload
910
+ * shapes in one flow. So route entity work through the connector unless the
911
+ * scenario names these nodes; native forms for the remaining verbs are the
912
+ * direction of travel, and this guidance changes when they land. `check` does
913
+ * not reject a native node — this is a routing default, not a rule:
914
+ *
915
+ * ```ts
916
+ * .step('create', connector('uipath-uipath-dataservice', 'create-entity-record',
917
+ * { entityName: 'Contracts', contractTitle: 'Q3 renewal' }, { connection: 'df' }))
918
+ * ```
919
+ *
920
+ * That operation's body fields come from the entity, so the library cannot
921
+ * carry them: run `npx flow-sdk registry prepare uipath-uipath-dataservice
922
+ * create-entity-record -f entityName=<Entity>` first (`uip maestro registry
923
+ * prepare …` is the same command when you are driving through the UiPath CLI). The routing table is in
924
+ * the `data-fabric.md` reference and the parent-field loop in
925
+ * `connector-params.md` — cited by name rather than linked, because this
926
+ * comment renders both into the flat corpus, where those files sit alongside
927
+ * it, and onto the site, where each symbol is its own page and a relative
928
+ * `./data-fabric` resolves to nothing.
929
+ *
930
+ * @param inputs - The entity, optional filter rows, and folder scope.
931
+ * @returns An action spec to pass to `.step(name, …)`.
932
+ */
933
+ export function dataFabricRead(inputs) {
934
+ return builtinActionSpec({ kind: 'dataFabricRead', inputs });
935
+ }
936
+ /**
937
+ * Update an entity record in Data Fabric (`core.datafabric.update`). Target the
938
+ * record by id or through an earlier {@link dataFabricRead} step; downstream
939
+ * reads of this step observe the record AFTER the write.
940
+ *
941
+ * @remarks
942
+ * The second and last verb of the native family — see {@link dataFabricRead}
943
+ * for what the family does NOT cover, which connector operation covers it
944
+ * instead, and why entity work routes through the connector during the
945
+ * transition. For an update whose flow also creates, gets or deletes on the
946
+ * same entity, use `connector(…, 'update-entity-record', …)` so the flow keeps
947
+ * one surface.
948
+ *
949
+ * @param inputs - The entity, the record selector, and the columns to write.
950
+ * @returns An action spec to pass to `.step(name, …)`.
951
+ */
952
+ export function dataFabricUpdate(inputs) {
953
+ const byId = inputs.record?.byId !== undefined;
954
+ const fromRead = typeof inputs.record?.fromRead === 'string';
955
+ if (byId === fromRead) {
956
+ throw new Error("dataFabricUpdate() targets exactly ONE of record: { byId } or record: { fromRead: '<step>' }.");
957
+ }
958
+ return builtinActionSpec({ kind: 'dataFabricUpdate', inputs });
959
+ }
960
+ /**
961
+ * Declare an Orchestrator QUEUE ITEM step.
962
+ *
963
+ * @remarks
964
+ * A queue is Orchestrator's work list: something puts items on it, and an
965
+ * automation bound to the queue takes them off one at a time. This step is the
966
+ * putting-on half.
967
+ *
968
+ * `queue` + `folderPath` are what the runtime resolves the queue by, and `key` is
969
+ * the queue's own Orchestrator key: it joins this node to the flow's queue
970
+ * bindings, which the serializer emits and points the node at. All three, for the
971
+ * same reason `rpaWorkflow` takes three — the key is the AUTHORING identity, the
972
+ * two bindings are the RUNTIME one.
973
+ *
974
+ * `item` is the work item's data. It becomes the item's `SpecificContent`, and it
975
+ * must be FLAT: Orchestrator rejects a nested object or array outright.
976
+ *
977
+ * **`wait`** picks between the family's two node types, which are one construct
978
+ * with two data paths. Default `false` enqueues and moves on, publishing the queue
979
+ * item's own Orchestrator record — read a field with `out('<step>', 'Key')`, and
980
+ * nothing extra has to be declared because that record's shape is the same for
981
+ * every queue. `wait: true` PARKS the flow until the item has been processed and
982
+ * publishes the consumer's result instead, which is per-automation — so a read of
983
+ * it needs `returns`, exactly as an rpa process's output does.
984
+ *
985
+ * What no rung can tell you: whether anything actually drains this queue. A
986
+ * `wait: true` step on a queue with no consumer waits until it times out.
987
+ *
988
+ * @example
989
+ * **Enqueue a work item and read its Orchestrator key**
990
+ * ```ts
991
+ * .step('enqueue', queueItem({
992
+ * queue: 'SupplierInvoices',
993
+ * folderPath: 'Shared',
994
+ * key: 'fa1a7328-cd17-4525-b5ab-29d86e399312',
995
+ * item: { InvoiceId: input('invoiceRef'), Amount: input('amount') },
996
+ * reference: 'INV-2031',
997
+ * }))
998
+ * .return({ itemKey: out('enqueue', 'Key') })
999
+ * ```
1000
+ *
1001
+ * @param inputs - The `queue` and `folderPath`, the `item` to add, and whether
1002
+ * to `wait` for it to be processed.
1003
+ * @returns An action spec to pass to `.step(name, …)`.
1004
+ */
1005
+ export function queueItem(inputs) {
1006
+ return builtinActionSpec({ kind: 'queueItem', inputs });
1007
+ }
1008
+ export function connector(a, b, c, d) {
1009
+ if (typeof a === 'string') {
1010
+ const opts = (d ?? {});
1011
+ return builtinActionSpec({
1012
+ kind: 'connector',
1013
+ key: a,
1014
+ action: b,
1015
+ version: opts.version,
1016
+ connection: opts.connection,
1017
+ folder: opts.folder,
1018
+ object: opts.object,
1019
+ inputs: c ?? {},
1020
+ });
1021
+ }
1022
+ // Descriptor form: (descriptor, inputs, opts) — derive key/action from the nodeType.
1023
+ const { key, action } = splitConnectorNodeType(a.nodeType);
1024
+ const opts = (c ?? {});
1025
+ return builtinActionSpec({
1026
+ kind: 'connector',
1027
+ key,
1028
+ action,
1029
+ version: opts.version ?? a.version,
1030
+ connection: opts.connection,
1031
+ folder: opts.folder,
1032
+ object: opts.object ?? a.objectName,
1033
+ inputs: b ?? {},
1034
+ });
1035
+ }
1036
+ /**
1037
+ * Fold a typed `(descriptor, opts)` call into the same {@link EventSubscription}
1038
+ * the stringly form produces, or pass a stringly subscription through unchanged.
1039
+ * Shared by `onEvent` (flow-sdk) and `waitForEvent` so both surfaces stay in
1040
+ * lock-step — the descriptor only supplies `connector`/`event`/`version`.
1041
+ *
1042
+ * @internal Public for compatibility; not an authoring factory.
1043
+ */
1044
+ export function subscriptionFrom(a, opts) {
1045
+ if (!isTriggerDescriptor(a))
1046
+ return a;
1047
+ // No options at all is legal: an operation with no event parameters (HTTP
1048
+ // Webhook) has nothing to put in them, and the descriptor carries the version.
1049
+ return {
1050
+ connector: a.connector,
1051
+ event: a.event,
1052
+ ...(opts?.where ? { where: opts.where } : {}),
1053
+ ...(opts?.object ? { object: opts.object } : {}),
1054
+ ...(opts?.filters ? { filters: opts.filters } : {}),
1055
+ ...(opts?.connection ? { connection: opts.connection } : {}),
1056
+ ...(opts?.folder ? { folder: opts.folder } : {}),
1057
+ version: opts?.version ?? a.version,
1058
+ };
1059
+ }
1060
+ export function waitForEvent(a, opts) {
1061
+ return builtinActionSpec({ kind: 'waitEvent', subscription: subscriptionFrom(a, opts) });
1062
+ }