@uipath/maestro-builder-sdk 6.42.0 → 6.43.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 (52) hide show
  1. package/dist/api-index.md +99 -99
  2. package/dist/api-members.md +307 -307
  3. package/dist/check.d.ts +0 -19
  4. package/dist/check.js +40 -1036
  5. package/dist/compile-cli.js +2 -1
  6. package/dist/core/actions.d.ts +1 -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/node-id-placeholder.d.ts +8 -0
  14. package/dist/core/node-id-placeholder.js +10 -0
  15. package/dist/core/ts-literal.d.ts +6 -0
  16. package/dist/core/ts-literal.js +15 -0
  17. package/dist/core/typed-raw-node.js +0 -5
  18. package/dist/decompile.js +34 -822
  19. package/dist/flow-node-registry.js +2 -1
  20. package/dist/flow-node-type.d.ts +130 -6
  21. package/dist/flow-sdk.d.ts +1 -0
  22. package/dist/flow-sdk.js +1 -0
  23. package/dist/nodes/agent/flow/check.d.ts +88 -0
  24. package/dist/nodes/agent/flow/check.js +873 -0
  25. package/dist/nodes/agent/flow/factories.d.ts +134 -0
  26. package/dist/nodes/agent/flow/factories.js +143 -0
  27. package/dist/nodes/agent/flow/family.d.ts +3 -0
  28. package/dist/nodes/agent/flow/family.js +8 -0
  29. package/dist/nodes/agent/flow/index.d.ts +3 -0
  30. package/dist/nodes/agent/flow/index.js +3 -0
  31. package/dist/nodes/agent/flow/inline-agent-lift.d.ts +44 -0
  32. package/dist/nodes/agent/flow/inline-agent-lift.js +572 -0
  33. package/dist/nodes/agent/flow/inline-agent.d.ts +15 -0
  34. package/dist/nodes/agent/flow/inline-agent.js +526 -0
  35. package/dist/nodes/agent/flow/node-type.d.ts +20 -0
  36. package/dist/nodes/agent/flow/node-type.js +422 -0
  37. package/dist/nodes/agent/flow/resources.d.ts +502 -0
  38. package/dist/nodes/agent/flow/resources.js +1409 -0
  39. package/dist/nodes/agent/flow/spec.d.ts +448 -0
  40. package/dist/nodes/agent/flow/spec.js +1 -0
  41. package/dist/nodes/process/flow/check.d.ts +40 -2
  42. package/dist/nodes/process/flow/check.js +156 -0
  43. package/dist/nodes/process/flow/factories.d.ts +58 -3
  44. package/dist/nodes/process/flow/factories.js +59 -2
  45. package/dist/nodes/process/flow/node-type.d.ts +4 -1
  46. package/dist/nodes/process/flow/node-type.js +181 -10
  47. package/dist/nodes/process/flow/spec.d.ts +112 -5
  48. package/dist/serialize.d.ts +9 -54
  49. package/dist/serialize.js +47 -2763
  50. package/package.json +2 -2
  51. /package/dist/{config.d.ts → core/connector-configuration.d.ts} +0 -0
  52. /package/dist/{ixp-definition.json → core/ixp-definition.json} +0 -0
@@ -0,0 +1,572 @@
1
+ /**
2
+ * The inline agent's lift and printer: the agent node, its `<source>/agent.json`
3
+ * and the resource nodes on its artifact handles, read back as one
4
+ * `inlineAgent({ … context, tools, escalation, memory })` call. Moved from
5
+ * decompile.ts in Phase 4 of docs/NODE_TYPE_ARCHITECTURE_DESIGN.md; the printed
6
+ * source, warnings and `--strict` refusals are unchanged.
7
+ *
8
+ * Every value the lift recovers from a resource is literal data — a name, an
9
+ * id, a setting, a form row; an expression query is printed as the text compile
10
+ * reads it from — so the lift writes each resource's options as source once,
11
+ * through the core literal writers, while the warnings and refusals that
12
+ * reading them raises still go through the context. The agent's own inputs are
13
+ * the only expressions, kept as `Expr`s for the printer.
14
+ */
15
+ import { agentSidecarInputs } from '../../../core/agent-sidecar.js';
16
+ import { derivedContextSource, derivedEscalationSource, derivedResourceNodeId, derivedToolSource, } from '../../../core/agent-resource-identity.js';
17
+ import { CONTEXT_INDEX_DEFAULTS, CONTEXT_INDEX_DEFAULT_FILE_EXTENSION, contextIndexSlug, parseContextIndexType, } from '../../../core/context-index.js';
18
+ import { Expr } from '../../../core/expr.js';
19
+ import { formFieldRowLoss, formFieldRowLossMessage, formFieldSettingsSource, liftFormFieldSettings, sourceFormFieldType, } from '../../../core/form-field-type.js';
20
+ import { ownEntry } from '../../../core/own-entry.js';
21
+ import { tsKey as key, tsLiteral, tsNumber, tsObject as objLit, tsOptions as opts, tsText } from '../../../core/ts-literal.js';
22
+ import { wireExprBody } from '../../../core/wire-expr.js';
23
+ /** Where the agent's own `inputs` go in the option list: the printer writes them, as expressions. */
24
+ const INPUT_ROWS = Symbol('inputs');
25
+ /** Plain JSON data as source, in the `{ k: v }` / `[a, b]` spelling (a form field's `options`, `rules`, `defaultValue`). */
26
+ function dataSource(v) {
27
+ if (Array.isArray(v))
28
+ return `[${v.map(dataSource).join(', ')}]`;
29
+ if (v !== null && typeof v === 'object') {
30
+ const parts = Object.entries(v).filter(([, x]) => x !== undefined).map(([k, x]) => `${key(k)}: ${dataSource(x)}`);
31
+ return parts.length ? `{ ${parts.join(', ')} }` : '{}';
32
+ }
33
+ return tsLiteral(v);
34
+ }
35
+ /**
36
+ * Where a context-index resource node keeps its identity, read in the order
37
+ * that holds for every writer.
38
+ *
39
+ * SDK compile writes `indexId` / `indexName` / `folderPath` onto the node. The
40
+ * canvas and the CLI do not: their node carries only `inputs.source`, and the
41
+ * identity lives in two other places.
42
+ *
43
+ * - The node TYPE, `…context.index.<slug>.<uuid>`: the uuid is the index id
44
+ * (the `ContextIndexRef.id` JSDoc says to read it there).
45
+ * - The resource sidecar `<agent source>/resources/<inputs.source>/resource.json`,
46
+ * whose `name` is the index's real name (the one the slug is made from) and
47
+ * whose `folderPath` is its folder. `display.label` is only what the canvas
48
+ * shows, and a canvas rename changes it.
49
+ *
50
+ * So the id comes from the type (then `inputs.indexId`). The name is the first
51
+ * of `inputs.indexName`, sidecar `name`, sidecar `indexName`, label that slugs to
52
+ * the type's slug, else the first one present in that order. Compile derives
53
+ * the type from `slug(name)` + id, so when the chosen name does not slug back to
54
+ * the type's slug the recompiled node gets a different type, and that is warned.
55
+ */
56
+ function contextIndexIdentity(agent, c, rPlain, ctx) {
57
+ const fromType = parseContextIndexType(c.type);
58
+ const sidecar = contextResourceSidecar(agent, c, ctx);
59
+ const sidecarText = (k) => typeof sidecar?.[k] === 'string' && sidecar[k] !== '' ? sidecar[k] : undefined;
60
+ const label = typeof c.display?.label === 'string' && c.display.label !== '' ? c.display.label : undefined;
61
+ // The canvas can set both sidecar `name` and `indexName`, and they can differ.
62
+ // The one that slugs to the type's slug is the one the type was built from, so
63
+ // it wins; the fixed order is the fallback when none matches.
64
+ const candidates = [rPlain(c, 'indexName'), sidecarText('name'), sidecarText('indexName'), label]
65
+ .filter((n) => n !== undefined);
66
+ const name = (fromType?.slug ? candidates.find((n) => contextIndexSlug(n) === fromType.slug) : undefined)
67
+ ?? candidates[0] ?? '';
68
+ const id = (fromType?.id || undefined) ?? rPlain(c, 'indexId') ?? '';
69
+ if (fromType !== undefined && fromType.slug !== '' && contextIndexSlug(name) !== fromType.slug) {
70
+ ctx.warn(`context index "${c.id}" on agent "${agent.id}": its node type names the index "${fromType.slug}", `
71
+ + `but the name decompile recovered, ${JSON.stringify(name)}, slugs to "${contextIndexSlug(name)}", so compile `
72
+ + `will write a different node type. Set \`name\` to the index's real name`
73
+ + (sidecar === undefined ? ', or keep the resources/ folder beside the .flow so decompile can read it.' : '.'));
74
+ }
75
+ return { name, id, folderPath: rPlain(c, 'folderPath') ?? sidecarText('folderPath'), sidecar };
76
+ }
77
+ /** The retrieval modes `ContextIndexRef.retrievalMode` can hold. */
78
+ const CONTEXT_RETRIEVAL_MODES = new Set(['semantic', 'structured', 'deeprag', 'batchtransform']);
79
+ /** The `settings` keys of a context `resource.json` that {@link contextIndexSettings} reads or checks. */
80
+ const CONTEXT_SETTINGS_KEYS = new Set([
81
+ 'retrievalMode', 'query', 'folderPathPrefix', 'threshold', 'resultCount', 'fileExtension',
82
+ 'citationMode', 'webSearchGrounding', 'outputColumns',
83
+ ]);
84
+ /**
85
+ * A context index's retrieval settings, as the `context: [...]` entry's option
86
+ * rows (`retrievalMode`, `query`, `threshold`, `resultCount`, `fileExtension`),
87
+ * each left out when it is what compile writes anyway.
88
+ *
89
+ * The inverse of `contextResourceJson` (serialize.ts). Read from the sidecar's
90
+ * `settings` first: a node the canvas or the CLI placed keeps its inputs minimal
91
+ * (`inputs.source`), so `resource.json` is the only copy, and it is what the
92
+ * runtime reads. The node's own inputs (the SDK writes both) answer when there
93
+ * is no sidecar. Before #1183 neither was read, so a no-edit round trip reset
94
+ * every setting to the SDK default without a word.
95
+ *
96
+ * The query is variant-tagged in the sidecar and mode-tagged on the node:
97
+ *
98
+ * - `dynamic` / `prompt` → a plain string (the guidance the model reads);
99
+ * - `static` / `text-builder` whose text is a `=js:` expression → that
100
+ * expression, which compile writes back as `text-builder` / `static`;
101
+ * - `static` with `''` is the canvas's spelling of "no query", as the SDK's
102
+ * `dynamic` with `''` is: left out.
103
+ *
104
+ * A setting the SDK cannot express (a `static` query of plain text, an
105
+ * `argument` query, deeprag citations off, batchtransform web grounding off or
106
+ * output columns, a folder-path prefix, an unknown mode or key) is reported:
107
+ * a warning, or an error under `--strict`. Compile would write the SDK's
108
+ * value instead, so it is never dropped silently.
109
+ */
110
+ function contextIndexSettings(agent, c, sidecar, ctx) {
111
+ const settings = sidecar?.settings && typeof sidecar.settings === 'object' && !Array.isArray(sidecar.settings)
112
+ ? sidecar.settings : undefined;
113
+ const ni = (c.inputs ?? {});
114
+ const where = `context index "${c.id}" on agent "${agent.id}"`;
115
+ const lossy = (what) => {
116
+ const message = `${where}: ${what}, which \`context: [...]\` cannot express, so compile writes the SDK's `
117
+ + `value instead. Edit that setting in the canvas after merging, or keep the original resource.json.`;
118
+ ctx.lossy(message);
119
+ };
120
+ const textOf = (v) => (typeof v === 'string' ? v : undefined);
121
+ const numOf = (v) => {
122
+ const raw = ctx.plainValue(v);
123
+ return typeof raw === 'number' && Number.isFinite(raw) ? raw : undefined;
124
+ };
125
+ const valueOf = (v) => (v && typeof v === 'object' ? v.value : undefined);
126
+ // Retrieval mode.
127
+ const rawMode = textOf(settings?.retrievalMode) ?? textOf(ctx.sourceText(ni.retrievalMode));
128
+ let mode = CONTEXT_INDEX_DEFAULTS.retrievalMode;
129
+ if (rawMode !== undefined && rawMode !== '') {
130
+ if (CONTEXT_RETRIEVAL_MODES.has(rawMode))
131
+ mode = rawMode;
132
+ else
133
+ lossy(`its retrieval mode is ${JSON.stringify(rawMode)}`);
134
+ }
135
+ const sidecarQuery = (() => {
136
+ const q = settings?.query;
137
+ if (!q || typeof q !== 'object')
138
+ return undefined;
139
+ if (q.variant === 'dynamic')
140
+ return { kind: 'prompt', text: textOf(q.description) ?? '' };
141
+ if (q.variant === 'static')
142
+ return { kind: 'text', text: textOf(q.value) ?? '' };
143
+ if (q.variant === 'argument')
144
+ return { kind: 'argument', text: textOf(q.value) ?? '' };
145
+ lossy(`its query has variant ${JSON.stringify(q.variant)}`);
146
+ return undefined;
147
+ })();
148
+ const nodeQuery = (() => {
149
+ const q = ni.query;
150
+ if (typeof q === 'string')
151
+ return q === '' ? undefined : { kind: q.startsWith('=js:') ? 'text' : 'prompt', text: q };
152
+ if (!q || typeof q !== 'object')
153
+ return undefined;
154
+ const t = q;
155
+ if (t.mode === 'text-builder')
156
+ return { kind: 'text', text: textOf(t.textValue) ?? '' };
157
+ if (t.mode === 'variable')
158
+ return { kind: 'argument', text: textOf(t.argumentPath) ?? '' };
159
+ return { kind: 'prompt', text: textOf(t.promptValue) ?? '' };
160
+ })();
161
+ const query = sidecarQuery ?? nodeQuery;
162
+ let querySrc;
163
+ if (query?.kind === 'prompt' && query.text !== '')
164
+ querySrc = tsLiteral(query.text);
165
+ else if (query?.kind === 'text' && query.text.startsWith('=js:'))
166
+ querySrc = tsLiteral(query.text);
167
+ else if (query?.kind === 'text' && query.text !== '')
168
+ lossy(`its query is static text (${JSON.stringify(query.text)})`);
169
+ else if (query?.kind === 'argument')
170
+ lossy(`its query is the agent argument ${JSON.stringify(query.text)}`);
171
+ // Numbers and the file extension.
172
+ const threshold = numOf(settings?.threshold) ?? numOf(ni.threshold);
173
+ const resultCount = numOf(settings?.resultCount) ?? numOf(ni.resultCount);
174
+ const fileExtension = textOf(valueOf(settings?.fileExtension)) ?? textOf(ctx.sourceText(ni.fileExtension));
175
+ // The node's flat `All` is the platform's node default for every mode; only
176
+ // the resource's per-mode default is what compile would write anyway.
177
+ const defaultExtension = ownEntry(CONTEXT_INDEX_DEFAULT_FILE_EXTENSION, mode) ?? 'All';
178
+ const extensionSrc = fileExtension === undefined || fileExtension === '' || fileExtension === defaultExtension
179
+ || (settings?.fileExtension === undefined && fileExtension === 'All')
180
+ ? undefined : tsLiteral(fileExtension);
181
+ // What compile writes as constants; anything else has no field.
182
+ if (mode === 'deeprag') {
183
+ const citation = textOf(valueOf(settings?.citationMode)) ?? textOf(ctx.sourceText(ni.citations));
184
+ if (citation !== undefined && !['Inline', 'enabled'].includes(citation))
185
+ lossy(`its citation mode is ${JSON.stringify(citation)}`);
186
+ }
187
+ if (mode === 'batchtransform') {
188
+ const grounding = textOf(valueOf(settings?.webSearchGrounding)) ?? textOf(valueOf(ni.webSearchGrounding));
189
+ if (grounding !== undefined && !['Enabled', 'enabled'].includes(grounding))
190
+ lossy(`its web search grounding is ${JSON.stringify(grounding)}`);
191
+ const columns = settings?.outputColumns ?? ni.outputColumns;
192
+ if (Array.isArray(columns) && columns.length > 0)
193
+ lossy(`it has ${columns.length} output column(s)`);
194
+ }
195
+ // The folder-path prefix: variant-tagged in the sidecar, mode-tagged on the node.
196
+ const field = (v, k) => (v && typeof v === 'object' ? textOf(v[k]) : undefined);
197
+ const prefixText = settings?.folderPathPrefix !== undefined
198
+ ? field(settings.folderPathPrefix, 'value') ?? field(settings.folderPathPrefix, 'description') ?? ''
199
+ : field(ni.folderPathPrefix, 'textValue') ?? field(ni.folderPathPrefix, 'promptValue') ?? '';
200
+ if (prefixText !== '')
201
+ lossy(`its folder-path prefix is ${JSON.stringify(prefixText)}`);
202
+ for (const k of Object.keys(settings ?? {})) {
203
+ if (!CONTEXT_SETTINGS_KEYS.has(k))
204
+ lossy(`its resource.json settings carry ${JSON.stringify(k)}`);
205
+ }
206
+ return [
207
+ ['query', querySrc],
208
+ ['retrievalMode', mode !== CONTEXT_INDEX_DEFAULTS.retrievalMode ? tsLiteral(mode) : undefined],
209
+ ['threshold', threshold !== undefined && threshold !== CONTEXT_INDEX_DEFAULTS.threshold ? tsNumber(threshold) : undefined],
210
+ ['resultCount', resultCount !== undefined && resultCount !== CONTEXT_INDEX_DEFAULTS.resultCount ? tsNumber(resultCount) : undefined],
211
+ ['fileExtension', extensionSrc],
212
+ ];
213
+ }
214
+ /**
215
+ * A context resource's `resource.json` sidecar, parsed; `undefined` when it is
216
+ * not beside the `.flow`, or (with a warning) when it is not a JSON object.
217
+ */
218
+ function contextResourceSidecar(agent, c, ctx) {
219
+ const agentSource = ctx.sourceText(agent.inputs?.source);
220
+ const resourceSource = ctx.sourceText(c.inputs?.source);
221
+ if (!agentSource || !resourceSource)
222
+ return undefined;
223
+ const path = `${agentSource}/resources/${resourceSource}/resource.json`;
224
+ const raw = ctx.sidecar(path);
225
+ if (raw === undefined)
226
+ return undefined;
227
+ try {
228
+ const json = JSON.parse(raw);
229
+ if (json && typeof json === 'object' && !Array.isArray(json))
230
+ return json;
231
+ }
232
+ catch {
233
+ // Reported below with the non-object case.
234
+ }
235
+ ctx.warn(`context index "${c.id}": ${path} is not valid JSON, so its name and folder decompile from the node.`);
236
+ return undefined;
237
+ }
238
+ /**
239
+ * An AGENT and its attached resources — the inline autonomous agent, the
240
+ * conversational agent, and the voice agent.
241
+ *
242
+ * The cluster is a node plus artifact nodes on its `tool` / `context` /
243
+ * `escalation` / `memory` handles, so this walks those edges and recovers each
244
+ * resource as an argument rather than as a step (see {@link ARTIFACT_PORTS}).
245
+ *
246
+ * **The author's input NAMES are not recoverable, and that is by design.** The
247
+ * platform does not send an agent the names you declared: it keys each argument
248
+ * by the reference PATH, `__`-joined (`$vars.prep.output` → `prep__output`), and
249
+ * only those flat names survive in the emitted file. Recovery therefore uses
250
+ * them for both the `inputs` keys and the `{{input.…}}` placeholders — the same
251
+ * arguments reach the model, spelled the platform's way. (Node ids are
252
+ * preserved exactly; only these logical names change.)
253
+ */
254
+ export function liftInlineAgent(node, ctx) {
255
+ // A key on the node wins over the sidecar's copy of it.
256
+ const own = (node.inputs ?? {});
257
+ const i = {
258
+ ...agentSidecarInputs({
259
+ nodeId: node.id, inputs: own, source: ctx.sourceText(own.source), dialect: 'inline',
260
+ read: (path) => ctx.sidecar(path), warn: (m) => ctx.warn(m),
261
+ }),
262
+ ...own,
263
+ };
264
+ const plain = (v) => {
265
+ const raw = ctx.sourceText(v);
266
+ return raw === undefined || raw === '' ? undefined : raw;
267
+ };
268
+ const num = (v) => {
269
+ const raw = ctx.plainValue(v);
270
+ return typeof raw === 'number' ? String(raw) : undefined;
271
+ };
272
+ // Prompts. A sidecar prompt already speaks `{{input.<flatName>}}`, so this
273
+ // leaves it alone. An EMBEDDED node's prompt (Studio Web with the
274
+ // self-contained flag on, or an SDK before #927) carries each input as its
275
+ // rendered binding instead; the bindings in `agentInputVariables` are exactly
276
+ // what to put back — longest first, so a shorter binding cannot eat a longer
277
+ // one's prefix.
278
+ const vars = (Array.isArray(i.agentInputVariables) ? i.agentInputVariables : []);
279
+ const refs = vars
280
+ .filter((v) => typeof v.id === 'string' && typeof v.binding === 'string')
281
+ .map((v) => ({ flatName: v.id, binding: v.binding }))
282
+ .sort((a, b) => b.binding.length - a.binding.length);
283
+ const unrender = (text) => {
284
+ let out = text;
285
+ for (const r of refs)
286
+ out = out.split(r.binding).join(`{{input.${r.flatName}}}`);
287
+ return out;
288
+ };
289
+ const promptSrc = (v) => {
290
+ const raw = plain(v);
291
+ return raw === undefined ? undefined : tsLiteral(unrender(raw));
292
+ };
293
+ const inputRows = refs
294
+ // Emit in the file's own order, not the length-sorted one.
295
+ .slice()
296
+ .sort((a, b) => vars.findIndex((v) => v.id === a.flatName) - vars.findIndex((v) => v.id === b.flatName))
297
+ .map((r) => {
298
+ return [r.flatName, new Expr(wireExprBody(r.binding))];
299
+ });
300
+ const outVars = (Array.isArray(i.agentOutputVariables) ? i.agentOutputVariables : []);
301
+ const returns = outVars.length
302
+ ? objLit(outVars.map((v) => [String(v.id ?? ''), tsLiteral(String(v.type ?? 'string'))]))
303
+ : undefined;
304
+ // The resources, from the agent's own artifact edges. Each edge read here is
305
+ // carried by the agent spec (edge accounting, #1125); `limit` is for a port
306
+ // the spec carries only one resource on.
307
+ const resource = (port, limit = Infinity) => ctx.attached(port, limit);
308
+ // Record what compile will call each folded resource node. Serialize mints
309
+ // `uid(scope, \`${step.name}<Kind>\`)` per resource, in spec order, and the
310
+ // spec order is this edge order: the first is `<agent><Kind>`, the n-th
311
+ // `<agent><Kind><n>` (claimId's dedupe). Only the first memory is recovered,
312
+ // so every further memory maps to `undefined`.
313
+ //
314
+ // When a port's nodes do not ALL carry those ids (the canvas or the CLI named
315
+ // them), every resource on the port is written with its own `nodeId`, and
316
+ // compile keeps the file's ids. All of them, not only the odd one: compile
317
+ // numbers the derived ids in order, so a derived id after an explicit one
318
+ // would come out one lower than the file's.
319
+ // This reads the edges directly, not through `resource()`: it must see EVERY
320
+ // artifact edge, including ones the spec does not carry, and it must not
321
+ // account for any edge.
322
+ const keepIds = new Set();
323
+ for (const [port, kind, emittedCount] of [
324
+ ['context', 'Context', Infinity], ['tool', 'Tool', Infinity],
325
+ ['escalation', 'Escalation', Infinity], ['memory', 'Memory', 1],
326
+ ]) {
327
+ const targets = ctx.attachedIds(port);
328
+ const keep = port !== 'memory'
329
+ && targets.some((id, k) => id !== derivedResourceNodeId(node.id, kind, k));
330
+ targets.forEach((id, k) => {
331
+ if (keep)
332
+ keepIds.add(id);
333
+ ctx.absorb(id, keep ? id : k >= emittedCount ? undefined : derivedResourceNodeId(node.id, kind, k));
334
+ });
335
+ }
336
+ /**
337
+ * The `nodeId` / `source` entries for resource node `r`: each only when it
338
+ * differs from what compile derives (`derivedSource`), so a flow compile
339
+ * wrote decompiles without them.
340
+ */
341
+ const placement = (r, derivedSource) => {
342
+ const source = ctx.sourceText((r.inputs ?? {}).source);
343
+ return [
344
+ ['nodeId', keepIds.has(r.id) ? tsLiteral(r.id) : undefined],
345
+ ['source', source !== undefined && source !== '' && source !== derivedSource ? tsLiteral(source) : undefined],
346
+ ];
347
+ };
348
+ /** A tool's options plus its placement; `seed` is the ref compile derives the tool's directory from. */
349
+ const toolOpts = (t, seed, entries) => opts([...entries, ...placement(t, derivedToolSource(ctx.flowId, node.id, seed))]);
350
+ const rInputs = (n) => (n.inputs ?? {});
351
+ const rPlain = (n, k) => {
352
+ const raw = ctx.sourceText(rInputs(n)[k]);
353
+ return raw === undefined || raw === '' ? undefined : raw;
354
+ };
355
+ const toolSrc = resource('tool').map((t) => {
356
+ const ti = rInputs(t);
357
+ const type = t.type;
358
+ if (type === 'uipath.agent.resource.tool.clientside') {
359
+ const schemaTypes = (v) => {
360
+ const props = v?.properties;
361
+ if (!props || Object.keys(props).length === 0)
362
+ return undefined;
363
+ return objLit(Object.entries(props).map(([k, x]) => [k, tsLiteral(String(x?.type ?? 'string'))]));
364
+ };
365
+ return toolOpts(t, { kind: 'clientside', name: rPlain(t, 'name') ?? '' }, [
366
+ ['kind', tsLiteral('clientside')],
367
+ ['name', tsLiteral(rPlain(t, 'name') ?? '')],
368
+ ['description', rPlain(t, 'description') !== undefined ? tsLiteral(rPlain(t, 'description')) : undefined],
369
+ ['inputs', schemaTypes(ti.inputSchema)],
370
+ ['returns', schemaTypes(ti.outputSchema)],
371
+ ]);
372
+ }
373
+ if (type === 'uipath.agent.resource.tool.builtin.httprequest') {
374
+ // A field is authored only when it left prompt mode (text-builder).
375
+ const fixed = (k) => {
376
+ const row = ti[k];
377
+ if (!row || row.mode !== 'text-builder')
378
+ return undefined;
379
+ const v = row.textValue;
380
+ return typeof v === 'number' ? String(v) : typeof v === 'string' ? tsLiteral(v) : JSON.stringify(v);
381
+ };
382
+ // `name` is not recovered, so compile derives the directory from the default.
383
+ return toolOpts(t, { kind: 'httpRequest' }, [
384
+ ['kind', tsLiteral('httpRequest')],
385
+ ['url', fixed('url')], ['method', fixed('method')],
386
+ ['headers', fixed('headers')], ['params', fixed('params')],
387
+ ['body', fixed('body')], ['timeout', fixed('timeout')],
388
+ ]);
389
+ }
390
+ if (type.startsWith('uipath.agent.resource.tool.mcp.')) {
391
+ return toolOpts(t, { kind: 'mcp', name: '', key: rPlain(t, 'referenceKey') ?? '' }, [
392
+ ['kind', tsLiteral('mcp')],
393
+ ['name', tsLiteral(rPlain(t, 'name') ?? '')],
394
+ ['key', tsLiteral(rPlain(t, 'referenceKey') ?? '')],
395
+ // The mapper's field name for the canonical server slug.
396
+ ['slug', rPlain(t, 'serverUrl') !== undefined ? tsLiteral(rPlain(t, 'serverUrl')) : undefined],
397
+ ['folderPath', rPlain(t, 'folderPath') !== undefined ? tsLiteral(rPlain(t, 'folderPath')) : undefined],
398
+ ['mcpType', rPlain(t, 'mcpType') !== undefined ? tsLiteral(rPlain(t, 'mcpType')) : undefined],
399
+ ]);
400
+ }
401
+ if (type.startsWith('uipath.agent.resource.tool.a2a.')) {
402
+ return toolOpts(t, { kind: 'a2a', name: '', slug: '', key: rPlain(t, 'referenceKey') ?? '' }, [
403
+ ['kind', tsLiteral('a2a')],
404
+ ['name', tsLiteral(rPlain(t, 'name') ?? '')],
405
+ ['key', tsLiteral(rPlain(t, 'referenceKey') ?? '')],
406
+ ['slug', tsLiteral(rPlain(t, 'slug') ?? '')],
407
+ ['folderPath', rPlain(t, 'folderPath') !== undefined ? tsLiteral(rPlain(t, 'folderPath')) : undefined],
408
+ ]);
409
+ }
410
+ if (type.startsWith('uipath.agent.resource.tool.builtin.')) {
411
+ const tool = type.slice('uipath.agent.resource.tool.builtin.'.length);
412
+ return toolOpts(t, { kind: 'builtin', tool }, [
413
+ ['kind', tsLiteral('builtin')],
414
+ ['tool', tsLiteral(tool)],
415
+ ['description', rPlain(t, 'description') !== undefined ? tsLiteral(rPlain(t, 'description')) : undefined],
416
+ ]);
417
+ }
418
+ if (type.startsWith('uipath.agent.resource.tool.ixp.')) {
419
+ const tail = type.slice('uipath.agent.resource.tool.ixp.'.length);
420
+ const projectId = tail.slice(tail.indexOf('.') + 1);
421
+ return toolOpts(t, { kind: 'ixp', name: '', projectId }, [
422
+ ['kind', tsLiteral('ixp')],
423
+ ['projectId', tsLiteral(projectId)],
424
+ ['name', tsLiteral(rPlain(t, 'name') ?? '')],
425
+ ]);
426
+ }
427
+ // The per-instance resource kinds (process / api / flow / maestro / agent /
428
+ // function): the key is the node type's tail, the rest is a binding pair.
429
+ const PROCESS_NS = [
430
+ ['uipath.agent.resource.tool.processorchestration.', 'maestro'],
431
+ ['uipath.agent.resource.tool.process.', 'process'],
432
+ ['uipath.agent.resource.tool.function.', 'function'],
433
+ ['uipath.agent.resource.tool.api.', 'api'],
434
+ ['uipath.agent.resource.tool.flow.', 'flow'],
435
+ ['uipath.agent.resource.tool.agent.', 'agent'],
436
+ ];
437
+ const ns = PROCESS_NS.find(([prefix]) => type.startsWith(prefix));
438
+ if (ns) {
439
+ const def = ctx.definitionOf(t);
440
+ const values = (def?.model?.bindings?.values ?? []);
441
+ const bound = (n) => {
442
+ const row = values.find((v) => v.name === n);
443
+ return typeof row?.default === 'string' ? row.default : undefined;
444
+ };
445
+ const key = type.slice(ns[0].length);
446
+ return toolOpts(t, { kind: 'process', name: '', folderPath: '', key }, [
447
+ ['kind', tsLiteral(ns[1])],
448
+ ['key', tsLiteral(key)],
449
+ ['name', tsLiteral(bound('name') ?? rPlain(t, 'name') ?? '')],
450
+ ['folderPath', tsLiteral(bound('folderPath') ?? '')],
451
+ ]);
452
+ }
453
+ return opts([['kind', tsLiteral('builtin')], ['tool', tsLiteral('summarize')]]); // unreachable in practice
454
+ });
455
+ const contextSrc = resource('context').map((c) => {
456
+ const { name, id, folderPath, sidecar } = contextIndexIdentity(node, c, rPlain, ctx);
457
+ // Compile labels the node with `name`; a canvas rename is kept as `label`.
458
+ const label = typeof c.display?.label === 'string' && c.display.label !== '' && c.display.label !== name
459
+ ? c.display.label : undefined;
460
+ return opts([
461
+ ['name', tsLiteral(name)],
462
+ ['id', tsLiteral(id)],
463
+ ['folderPath', folderPath !== undefined ? tsLiteral(folderPath) : undefined],
464
+ ['folderKey', rPlain(c, 'folderKey') !== undefined ? tsLiteral(rPlain(c, 'folderKey')) : undefined],
465
+ // `query` and the retrieval settings, from resource.json or the node (#1183).
466
+ ...contextIndexSettings(node, c, sidecar, ctx),
467
+ ['label', label !== undefined ? tsLiteral(label) : undefined],
468
+ ...placement(c, derivedContextSource(ctx.flowId, node.id, id)),
469
+ ]);
470
+ });
471
+ const escalationSrc = resource('escalation').map((e) => {
472
+ const ei = rInputs(e);
473
+ const recipients = Array.isArray(ei.recipients)
474
+ ? ei.recipients.map((r) => tsText(r.value))
475
+ : [];
476
+ const outcomeNames = Object.keys((ei.outcomeMapping ?? {}));
477
+ const isQuickForm = e.type === 'uipath.agent.resource.escalation.quick-form';
478
+ const rows = isQuickForm
479
+ ? (ei.schema?.fields ?? [])
480
+ : [];
481
+ const app = ei.app;
482
+ const extra = (ei._additionalProps ?? {});
483
+ return opts([
484
+ ['variant', isQuickForm ? tsLiteral('quick-form') : undefined],
485
+ ['name', tsLiteral(rPlain(e, 'name') ?? '')],
486
+ ['description', rPlain(e, 'description') !== undefined ? tsLiteral(rPlain(e, 'description')) : undefined],
487
+ ['fields', rows.length ? `[${rows.map((f) => {
488
+ const id = String(f.id ?? '');
489
+ const direction = String(f.direction ?? 'output');
490
+ // Every row key the source cannot carry is reported, never dropped
491
+ // silently: a warning, an error under --strict (#1250).
492
+ const loss = formFieldRowLoss(f, 'escalation');
493
+ if (loss.length > 0) {
494
+ const message = formFieldRowLossMessage(`quick-form escalation ${JSON.stringify(rPlain(e, 'name') ?? e.id)} on agent ${JSON.stringify(node.id)}`, id, loss);
495
+ ctx.lossy(message);
496
+ }
497
+ return opts([
498
+ ['id', tsText(f.id)],
499
+ // serialize defaults a row's label to its id.
500
+ ['label', typeof f.label === 'string' && f.label !== id ? tsLiteral(f.label) : undefined],
501
+ ['type', tsLiteral(sourceFormFieldType(f.type ?? 'string'))],
502
+ ['direction', tsLiteral(direction)],
503
+ ['required', typeof f.required === 'boolean' && direction !== 'input' ? String(f.required) : undefined],
504
+ ...formFieldSettingsSource(liftFormFieldSettings(f), dataSource),
505
+ ]);
506
+ }).join(', ')}]` : undefined],
507
+ ['app', app === undefined ? undefined : opts([
508
+ ['key', tsText(app.key)],
509
+ ['name', tsText(app.name)],
510
+ ['folderPath', typeof app.folderPath === 'string' && app.folderPath !== '' ? tsLiteral(app.folderPath) : undefined],
511
+ ])],
512
+ ['recipients', recipients.length ? `[${recipients.join(', ')}]` : undefined],
513
+ ['outcomes', outcomeNames.length ? `[${outcomeNames.map((o) => tsLiteral(o)).join(', ')}]` : undefined],
514
+ ['taskTitle', typeof extra.taskTitle === 'string' && extra.taskTitle !== '' ? tsLiteral(extra.taskTitle) : undefined],
515
+ // 'medium' is the platform default.
516
+ ['priority', typeof extra.priority === 'string' && extra.priority !== 'medium' ? tsLiteral(extra.priority) : undefined],
517
+ ...placement(e, derivedEscalationSource(ctx.flowId, node.id, rPlain(e, 'name') ?? '')),
518
+ ]);
519
+ });
520
+ const mem = resource('memory', 1)[0];
521
+ const memorySrc = mem === undefined ? undefined : (() => {
522
+ // The memory's id is the node type's tail; the def carries it too.
523
+ const tail = mem.type.slice('uipath.agent.resource.memory.'.length);
524
+ const id = tail.slice(tail.indexOf('.') + 1);
525
+ const mi = rInputs(mem);
526
+ return opts([
527
+ ['name', tsLiteral(rPlain(mem, 'name') ?? '')],
528
+ ['id', tsLiteral(id)],
529
+ ['description', rPlain(mem, 'description') !== undefined ? tsLiteral(rPlain(mem, 'description')) : undefined],
530
+ // The platform defaults: few-shot on, similarity 0, k 3, hybrid search.
531
+ ['dynamicFewShotLearning', ctx.plainValue(mi.dynamicFewShotLearning) === false ? 'false' : undefined],
532
+ ['semanticSimilarity', num(mi.semanticSimilarity) !== undefined && num(mi.semanticSimilarity) !== '0' ? num(mi.semanticSimilarity) : undefined],
533
+ ['kValue', num(mi.kValue) !== undefined && num(mi.kValue) !== '3' ? num(mi.kValue) : undefined],
534
+ ['searchMode', rPlain(mem, 'searchMode') !== undefined && rPlain(mem, 'searchMode') !== 'hybrid'
535
+ ? tsLiteral(rPlain(mem, 'searchMode')) : undefined],
536
+ ]);
537
+ })();
538
+ const guardrails = Array.isArray(i.guardrails) && i.guardrails.length > 0
539
+ ? JSON.stringify(i.guardrails)
540
+ : undefined;
541
+ const list = (items) => (items.length ? `[${items.join(', ')}]` : undefined);
542
+ return { kind: 'inlineAgent', inputs: { inputRows, options: [
543
+ ['model', tsLiteral(plain(i.model) ?? '')],
544
+ ['systemPrompt', promptSrc(i.systemPrompt) ?? tsLiteral('')],
545
+ ['userPrompt', promptSrc(i.userPrompt) ?? tsLiteral('')],
546
+ ['inputs', INPUT_ROWS],
547
+ ['returns', returns],
548
+ ['temperature', num(i.temperature)],
549
+ ['maxTokenPerResponse', num(i.maxTokenPerResponse)],
550
+ ['maxIterations', num(i.maxIterations)],
551
+ ['mode', plain(i.mode) !== undefined ? tsLiteral(plain(i.mode)) : undefined],
552
+ ['guardrails', guardrails],
553
+ ['context', list(contextSrc)],
554
+ ['tools', list(toolSrc)],
555
+ ['escalation', list(escalationSrc)],
556
+ ['memory', memorySrc],
557
+ // The agent's directory uuid is derived from the flow and step ids, but a
558
+ // decompiled flow must keep the ORIGINAL — the sidecar lives at
559
+ // `<source>/agent.json`, so a re-derived one would point at nothing.
560
+ ['source', tsLiteral(plain(i.source) ?? '')],
561
+ ] } };
562
+ }
563
+ export function printInlineAgent(spec, ctx) {
564
+ const { inputRows, options } = spec.inputs;
565
+ const rows = inputRows.length
566
+ ? `{ ${inputRows.map(([k, e]) => `${ctx.key(k)}: ${ctx.value(e)}`).join(', ')} }`
567
+ : undefined;
568
+ return {
569
+ factory: 'inlineAgent',
570
+ options: options.map(([k, v]) => [k, v === INPUT_ROWS ? rows : v]),
571
+ };
572
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The inline (autonomous) agent's serialize: the agent node, its
3
+ * `<source>/agent.json`, and every resource it attaches — a node per context
4
+ * index, tool, escalation and memory on the agent's artifact handles, with the
5
+ * `resources/<id>/resource.json` each one resolves from. Moved from serialize.ts
6
+ * in Phase 4 of docs/NODE_TYPE_ARCHITECTURE_DESIGN.md; nodes, edges,
7
+ * definitions, bindings and files unchanged.
8
+ */
9
+ import type { InlineAgentInputs } from './spec.js';
10
+ import type { FlowNodeContribution, FlowSerializeContext } from '../../../flow-node-type.js';
11
+ /** Every bundled version of the inline agent, oldest first; the newest is the default (#956). */
12
+ export declare const INLINE_AGENT_VERSIONS: readonly string[];
13
+ export declare const INLINE_AGENT_DEFAULT_VERSION: string;
14
+ /** The inline agent's node, sidecar and resources. */
15
+ export declare function serializeInlineAgent(s: InlineAgentInputs, ctx: FlowSerializeContext): FlowNodeContribution;