@uipath/maestro-builder-sdk 6.41.2 → 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 (73) 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/cli/commands/registry.js +15 -0
  6. package/dist/compile-cli.js +2 -1
  7. package/dist/core/actions.d.ts +1 -713
  8. package/dist/core/actions.js +0 -193
  9. package/dist/core/agent-sidecar.d.ts +186 -0
  10. package/dist/core/agent-sidecar.js +409 -0
  11. package/dist/core/agent-tool-resources.d.ts +62 -0
  12. package/dist/core/agent-tool-resources.js +81 -0
  13. package/dist/core/cli-spelling.d.ts +9 -0
  14. package/dist/core/cli-spelling.js +9 -0
  15. package/dist/{config.js → core/connector-configuration.js} +2 -2
  16. package/dist/core/library-cache.d.ts +0 -9
  17. package/dist/core/library-cache.js +0 -9
  18. package/dist/core/library.d.ts +47 -0
  19. package/dist/core/library.js +135 -34
  20. package/dist/core/list-envelope.d.ts +36 -1
  21. package/dist/core/list-envelope.js +24 -19
  22. package/dist/core/lookup-store.d.ts +4 -3
  23. package/dist/core/lookup-store.js +46 -38
  24. package/dist/core/node-id-placeholder.d.ts +8 -0
  25. package/dist/core/node-id-placeholder.js +10 -0
  26. package/dist/core/read-text.d.ts +26 -0
  27. package/dist/core/read-text.js +43 -0
  28. package/dist/core/ts-literal.d.ts +6 -0
  29. package/dist/core/ts-literal.js +15 -0
  30. package/dist/core/typed-raw-node.js +0 -5
  31. package/dist/decompile.js +34 -822
  32. package/dist/flow-node-registry.js +2 -1
  33. package/dist/flow-node-type.d.ts +130 -6
  34. package/dist/flow-sdk.d.ts +1 -0
  35. package/dist/flow-sdk.js +1 -0
  36. package/dist/nodes/agent/flow/check.d.ts +88 -0
  37. package/dist/nodes/agent/flow/check.js +873 -0
  38. package/dist/nodes/agent/flow/factories.d.ts +134 -0
  39. package/dist/nodes/agent/flow/factories.js +143 -0
  40. package/dist/nodes/agent/flow/family.d.ts +3 -0
  41. package/dist/nodes/agent/flow/family.js +8 -0
  42. package/dist/nodes/agent/flow/index.d.ts +3 -0
  43. package/dist/nodes/agent/flow/index.js +3 -0
  44. package/dist/nodes/agent/flow/inline-agent-lift.d.ts +44 -0
  45. package/dist/nodes/agent/flow/inline-agent-lift.js +572 -0
  46. package/dist/nodes/agent/flow/inline-agent.d.ts +15 -0
  47. package/dist/nodes/agent/flow/inline-agent.js +526 -0
  48. package/dist/nodes/agent/flow/node-type.d.ts +20 -0
  49. package/dist/nodes/agent/flow/node-type.js +422 -0
  50. package/dist/nodes/agent/flow/resources.d.ts +502 -0
  51. package/dist/nodes/agent/flow/resources.js +1409 -0
  52. package/dist/nodes/agent/flow/spec.d.ts +448 -0
  53. package/dist/nodes/agent/flow/spec.js +1 -0
  54. package/dist/nodes/process/flow/check.d.ts +40 -2
  55. package/dist/nodes/process/flow/check.js +156 -0
  56. package/dist/nodes/process/flow/factories.d.ts +58 -3
  57. package/dist/nodes/process/flow/factories.js +59 -2
  58. package/dist/nodes/process/flow/node-type.d.ts +4 -1
  59. package/dist/nodes/process/flow/node-type.js +181 -10
  60. package/dist/nodes/process/flow/spec.d.ts +112 -5
  61. package/dist/registry/describe-cli.d.ts +10 -0
  62. package/dist/registry/describe-cli.js +41 -0
  63. package/dist/registry/library-reader.d.ts +12 -2
  64. package/dist/registry/library-reader.js +17 -16
  65. package/dist/registry/lookup-specs.d.ts +17 -1
  66. package/dist/registry/lookup-specs.js +3 -7
  67. package/dist/registry/path-cli.js +2 -1
  68. package/dist/registry/search-cli.js +2 -1
  69. package/dist/serialize.d.ts +9 -54
  70. package/dist/serialize.js +47 -2763
  71. package/package.json +2 -2
  72. /package/dist/{config.d.ts → core/connector-configuration.d.ts} +0 -0
  73. /package/dist/{ixp-definition.json → core/ixp-definition.json} +0 -0
@@ -0,0 +1,526 @@
1
+ import { agentInputPlan, inlineAgentJson } from '../../../core/agent-sidecar.js';
2
+ import { derivedContextSource, derivedEscalationSource, derivedToolSource } from '../../../core/agent-resource-identity.js';
3
+ import { GUID_RE } from '../../../core/binding-messages.js';
4
+ import { formFieldSettingsWire, wireFormFieldType } from '../../../core/form-field-type.js';
5
+ import { outcomeSlug } from '../../../core/hitl-routing.js';
6
+ import { jsonClone } from '../../../core/json-clone.js';
7
+ import { subNodeId } from '../../../core/node-id-placeholder.js';
8
+ import { ownEntry } from '../../../core/own-entry.js';
9
+ import { processResourceBindings } from '../../../core/process-resource.js';
10
+ import { fnv1aX4Uuid, schemaId } from '../../../core/stable-id.js';
11
+ import { synthesizedDefinitionRefusal } from '../../../core/synthesized-definition.js';
12
+ import { BUILTIN_TOOL_DEFS, INLINE_AGENT, PROCESS_TOOL_META, a2aToolDef, builtinToolResourceJson, connectorToolDef, connectorToolDescription, connectorToolDetail, connectorToolResourceJson, contextIndexDef, contextResourceJson, declaresMemoryHandle, escalationAppFolder, escalationDef, escalationResourceJson, fieldSchema, httpRequestToolResourceJson, inlineAgentDef, ixpToolDef, mcpToolDef, memoryResourceDef, processToolDef, renderContextQuery, toolResourceJson, } from './resources.js';
13
+ /** Every bundled version of the inline agent, oldest first; the newest is the default (#956). */
14
+ export const INLINE_AGENT_VERSIONS = ['1.2', '1.3', '1.4'];
15
+ export const INLINE_AGENT_DEFAULT_VERSION = INLINE_AGENT_VERSIONS[INLINE_AGENT_VERSIONS.length - 1];
16
+ /** The inline agent's node, sidecar and resources. */
17
+ export function serializeInlineAgent(s, ctx) {
18
+ const step = ctx.step;
19
+ const render = (v) => ctx.render(v);
20
+ const returns = s.returns && Object.keys(s.returns).length
21
+ ? s.returns
22
+ // The definition's own default. Deliberately kept rather than made
23
+ // required: it is what the platform scaffolds, so a flow that reads
24
+ // `content` is a real (if toy) flow. `check` says so.
25
+ : { content: 'string' };
26
+ // ONE default version for every call shape — the newest bundled pair (see
27
+ // `inlineAgentDef`). `mode` and `memory` used to pick the version too (1.3
28
+ // and 1.4), so a plain agent got a superseded 1.2 and each option moved the
29
+ // node to another version as a side effect (#956). Both now live in the
30
+ // sidecar and on edges; neither selects a definition. An explicit
31
+ // `{ version }` (what decompile writes back) resolves exactly.
32
+ const version = ctx.version;
33
+ // `definitions[]` holds one entry per type@version, so a flow where any
34
+ // agent attaches memory keeps the handle for all of them.
35
+ const withMemory = s.memory !== undefined || declaresMemoryHandle(ctx.emitted(INLINE_AGENT, version));
36
+ const def = inlineAgentDef(version, withMemory, (t, v) => ctx.definition(t, v));
37
+ // The registry refuses a version it neither registers nor finds carried
38
+ // before serialize runs, so a definition always resolves here.
39
+ if (!def)
40
+ throw new Error(`internal SDK error: step "${step}": no definition resolves for ${INLINE_AGENT}@${version}.`);
41
+ if (s.memory !== undefined && !declaresMemoryHandle(def)) {
42
+ throw new Error(`"${step}" attaches \`memory\`, but ${INLINE_AGENT}@${version} declares no \`memory\` handle. `
43
+ + (version === INLINE_AGENT_DEFAULT_VERSION
44
+ ? `Pin a version that has it with inlineAgent({ ..., version: '<x.y>' }) `
45
+ + `(bundled with memory: ${INLINE_AGENT_VERSIONS.filter((v) => declaresMemoryHandle(ctx.definition(INLINE_AGENT, v))).join(', ') || 'none'}), or drop \`memory\`.`
46
+ : `Drop { version: '${version}' } to use ${INLINE_AGENT_DEFAULT_VERSION}, or drop \`memory\`.`));
47
+ }
48
+ // `source` is the agent's directory name; see `ctx.agentSource`.
49
+ const source = ctx.agentSource(s.source);
50
+ // The per-instance CONTRACT lands on the node, because the definition is
51
+ // shared by every inline agent in the flow and cannot hold it (see
52
+ // `inlineAgentDef`): the declared keys over a copy of the definition's
53
+ // generic `output` descriptor, which is the shape an instance-refining reader
54
+ // picks up. The definition's slots get their `{nodeId}` placeholders filled,
55
+ // as every node's do; the author's keys are written as given, so the schema
56
+ // names exactly what `agentOutputVariables` and agent.json declare. Hence the
57
+ // whole map, `error` included, replaces the definition's rather than merging
58
+ // over it (a merge would fill placeholders in the author's keys too).
59
+ const outputs = def.outputDefinition === undefined ? undefined
60
+ : subNodeId(def.outputDefinition, ctx.nodeId);
61
+ if (outputs?.output && Object.keys(returns).length) {
62
+ outputs.output.schema = {
63
+ type: 'object',
64
+ properties: Object.fromEntries(Object.entries(returns).map(([k, t]) => [k, { type: t }])),
65
+ };
66
+ }
67
+ // What the PLATFORM will call each of these — computed once and shared by the
68
+ // descriptor array below and the sidecar. See `agentInputPlan`.
69
+ const plan = agentInputPlan(s.inputs ?? {}, render);
70
+ // A SHELL node (#927): the prompts and the model live only in the
71
+ // `<source>/agent.json` sidecar written below, never on the node. Studio Web
72
+ // decides which copy wins by `hasEmbeddedAgentContent` (@uipath/flow-schema):
73
+ // any `systemPrompt`/`userPrompt` string on the node makes the `.flow`
74
+ // authoritative and the sidecar is skipped, so a node copy shadowed the
75
+ // sidecar and lost the input tokens and the tool configuration on the first
76
+ // save. With no prompt strings the converter also keeps the
77
+ // `agentInputVariables` below as written (`canPruneAgentInputs` is false), and
78
+ // `uip maestro flow debug` reconciles them against the sidecar's `inputSchema`.
79
+ //
80
+ // The run settings (`mode`, `temperature`, `maxTokenPerResponse`,
81
+ // `maxIterations`, `guardrails`) live in the sidecar too. The node keeps
82
+ // exactly the keys Studio Web's own strip keeps (`toAgentShellInputs`,
83
+ // @uipath/flow-schema): anything else is discarded on hydrate, and while
84
+ // present it makes Studio Web "trust the .flow" when the sidecar folder is
85
+ // missing (`flowNodeHasRealInputs`), flushing a prompt-less agent.json.
86
+ // `modelMaxTokens` is written nowhere: the designer derives it from the
87
+ // selected model.
88
+ const inputs = {
89
+ source,
90
+ // The two DESCRIPTOR ARRAYS. `agentInputVariables` entries carry the binding
91
+ // expression; `agentOutputVariables` entries are name + type only, and the
92
+ // runtime's structured final call fills exactly these keys.
93
+ //
94
+ // `id` is the FLAT NAME, not the author's — the name the runtime's
95
+ // JobArguments are keyed by, and the key the CLI reconciles against the
96
+ // sidecar's `inputSchema`. One entry per flatName, so two logical names bound
97
+ // to the same reference claim one argument rather than two.
98
+ agentInputVariables: plan.refs.map((r) => ({ id: r.flatName, type: 'string', binding: r.binding })),
99
+ agentOutputVariables: Object.entries(returns).map(([k, t]) => ({ id: k, type: t })),
100
+ };
101
+ // The other half of the artifact: the agent's own configuration, which the
102
+ // platform resolves at `<source>/agent.json`, written by compile-cli beside
103
+ // the `.flow`. The AGENT's dialect: `{{input.x}}` placeholders, rewritten from
104
+ // the author's logical names to the FLAT NAMES the runtime's JobArguments are
105
+ // keyed by (board G-20).
106
+ const agentJson = inlineAgentJson({
107
+ model: s.model,
108
+ systemPrompt: s.systemPrompt,
109
+ userPrompt: s.userPrompt,
110
+ plan,
111
+ returns,
112
+ temperature: s.temperature,
113
+ maxTokenPerResponse: s.maxTokenPerResponse,
114
+ maxIterations: s.maxIterations,
115
+ mode: s.mode,
116
+ guardrails: s.guardrails,
117
+ source,
118
+ name: step,
119
+ });
120
+ ctx.sidecar({ path: `${source}/agent.json`, json: agentJson });
121
+ // The schema's property TYPES need this scope's finished variables, which do
122
+ // not exist yet: the `properties` object is filled in place when the scope
123
+ // closes.
124
+ ctx.typeAgentInputs(agentJson.inputSchema, plan.refs);
125
+ const attach = [];
126
+ // GROUNDING — one resource node per context index, joined to the agent's own
127
+ // `context` handle. An ARTIFACT, not a step: it takes no incoming control
128
+ // flow, produces no output, and never reaches the End node. The edge runs OUT
129
+ // of the agent (source port `context`) INTO the resource's `input` port, which
130
+ // is the direction both definitions declare.
131
+ const contexts = s.context === undefined ? [] : Array.isArray(s.context) ? s.context : [s.context];
132
+ for (const cx of contexts) {
133
+ // `check`'s AGENT_CONTEXT_NO_ID, again for `--no-check`: a blank id builds
134
+ // the type `…context.index.<slug>.`, which no tenant serves, and nothing
135
+ // after this point would say so.
136
+ if (typeof cx?.id !== 'string' || !GUID_RE.test(cx.id)) {
137
+ throw Object.assign(new Error(`inline agent "${step}": context index "${cx?.name ?? ''}" needs its index id (a GUID) as \`id\`; `
138
+ + `got ${JSON.stringify(cx?.id)}. \`uip solution resources list --kind Index --source remote --search "<name>"\` returns it as \`Key\`.`), { code: 'AGENT_CONTEXT_NO_ID' });
139
+ }
140
+ const cdef = contextIndexDef({ name: cx.name, id: cx.id });
141
+ // `<step>Context`, deduped for a second index on the same agent, unless the
142
+ // author placed it (`nodeId`, which decompile writes for a node the canvas
143
+ // named). Not slugged from the index NAME: an id is the author's handle on
144
+ // the node and a 40-character one helps nobody.
145
+ const cid = ctx.resourceNodeId(cx.nodeId, `${step}Context`, `inline agent "${step}": context index "${cx.name}"`);
146
+ // ONE identity, spent twice: the node's `inputs.source` and the sidecar
147
+ // resource's `id` are the same uuid, because that is what joins them. The
148
+ // platform validator says so in its own refusal text — *"the resource id
149
+ // from the parent inline agent's `resources[]`"*.
150
+ const contextResourceId = cx.source ?? derivedContextSource(ctx.flowId, step, cx.id);
151
+ const contextQuery = renderContextQuery(cx.query, render);
152
+ // The index's own configuration; the platform's `inputDefaults` are the
153
+ // shape a designer-placed node has, so an omitted option emits the
154
+ // designer's value rather than nothing.
155
+ attach.push({
156
+ id: cid, definition: cdef, label: cx.label ?? cx.name, port: 'context',
157
+ inputs: {
158
+ // REQUIRED, and the platform's validator is what says so — measured
159
+ // 2026-07-31, omitting it: *"Node type
160
+ // uipath.agent.resource.context.index.… requires a stable UUID at
161
+ // inputs.source … Set \"inputs\": { \"source\": \"<uuid>\" } on the
162
+ // node"* (MST-9265). It is the resource's own identity inside the
163
+ // project, so it is derived from flow + step + index rather than random,
164
+ // exactly like the agent's `source`: a recompile must not be a diff. An
165
+ // author's `source` (a canvas directory decompile carried) wins.
166
+ source: contextResourceId,
167
+ indexId: cx.id,
168
+ indexName: cx.name,
169
+ ...(cx.folderKey === undefined ? {} : { folderKey: cx.folderKey }),
170
+ ...(cx.folderPath === undefined ? {} : { folderPath: cx.folderPath }),
171
+ retrievalMode: cx.retrievalMode ?? 'semantic',
172
+ // The platform's `query` is a MODE-TAGGED object, not a bare string:
173
+ // `{mode, textValue, promptValue, argumentPath}`, with the mode saying
174
+ // which field is live. A plain string is the `prompt` mode; a flow
175
+ // expression is `text-builder`, whose `textValue` the runtime templates.
176
+ query: contextQuery,
177
+ threshold: cx.threshold ?? 0,
178
+ resultCount: cx.resultCount ?? 3,
179
+ fileExtension: cx.fileExtension ?? 'All',
180
+ folderPathPrefix: { mode: 'text-builder', textValue: '', promptValue: '', argumentPath: '' },
181
+ citations: 'enabled',
182
+ outputColumns: [],
183
+ webSearchGrounding: { value: 'enabled' },
184
+ },
185
+ });
186
+ // The other half — without it the node is inert: see `contextResourceJson`.
187
+ ctx.sidecar({
188
+ path: `${source}/resources/${contextResourceId}/resource.json`,
189
+ json: contextResourceJson(cx, { id: contextResourceId, query: contextQuery }),
190
+ }, cx.source !== undefined);
191
+ }
192
+ // TOOLS — one resource node per tool, joined to the agent's `tool` handle; the
193
+ // same artifact shape as context (no incoming control flow, no output, never
194
+ // reaches End — a graph walk drops it).
195
+ //
196
+ // Every tool node carries `inputs.source` — the platform's validator requires
197
+ // "a stable UUID at inputs.source … the resource id from the parent inline
198
+ // agent's resources[] for agent-tool resource nodes" (MST-9265's own wording)
199
+ // — derived, so a recompile is not a diff.
200
+ const toolRefs = s.tools === undefined ? [] : Array.isArray(s.tools) ? s.tools : [s.tools];
201
+ for (const tr of toolRefs) {
202
+ let tdef;
203
+ let label;
204
+ let extraInputs = {};
205
+ let connectorTool;
206
+ if (tr.kind === 'builtin') {
207
+ const bdef = ownEntry(BUILTIN_TOOL_DEFS, tr.tool);
208
+ tdef = bdef === undefined ? undefined : jsonClone(bdef);
209
+ if (!tdef)
210
+ throw new Error(`inline agent "${step}": unknown builtin tool "${tr.tool}" (analyzefiles | summarize | batchtransform).`);
211
+ label = tdef.display.label;
212
+ // The designer-placed node carries the def's `inputDefaults` with the
213
+ // author's values over them — the context rule, kept per builtin (each def
214
+ // declares different fields, so overrides apply only where the def has the
215
+ // field).
216
+ extraInputs = jsonClone(tdef.inputDefaults);
217
+ // summarize/batchtransform declare `source` among their defaults (as an
218
+ // empty string); the derived uuid below must win, not be clobbered.
219
+ delete extraInputs.source;
220
+ if (tr.description !== undefined)
221
+ extraInputs.description = tr.description;
222
+ if ('query' in extraInputs && tr.query !== undefined) {
223
+ extraInputs.query = renderContextQuery(tr.query, render);
224
+ }
225
+ if ('fileExtension' in extraInputs && tr.fileExtension !== undefined) {
226
+ extraInputs.fileExtension = { value: tr.fileExtension };
227
+ }
228
+ if ('citationMode' in extraInputs && tr.citationMode !== undefined) {
229
+ extraInputs.citationMode = { value: tr.citationMode };
230
+ }
231
+ }
232
+ else if (tr.kind === 'ixp') {
233
+ tdef = ixpToolDef(tr);
234
+ label = tr.name;
235
+ // The node carries the def's own `inputDefaults` (name / description /
236
+ // project identity / attachment config) with the derived `source` over
237
+ // them — the builtin-tool rule, not the process-tool one, because this
238
+ // family's configuration lives on the NODE rather than in a binding: its
239
+ // def declares no `model` at all, so there is no resource identity to bind
240
+ // and nothing to add to `bindings[]`.
241
+ extraInputs = jsonClone(tdef.inputDefaults);
242
+ }
243
+ else if (tr.kind === 'connector') {
244
+ if (!ctx.library)
245
+ throw new Error(`inline agent "${step}"'s connector tool needs a library (pass --library / set $FLOW_SDK_LIBRARY_JSON).`);
246
+ const rc = ctx.library.resolve(tr.connector, tr.operation, tr.version, tr.object);
247
+ // An entry `prepare` synthesized from Integration Service compiles in BPMN
248
+ // only — for a tool as for a step: `connectorToolDef` reads the same
249
+ // definition, and a synthesized one has no form or handles.
250
+ const noDefinition = synthesizedDefinitionRefusal(rc);
251
+ if (noDefinition)
252
+ throw noDefinition;
253
+ tdef = connectorToolDef(rc);
254
+ label = tr.name ?? rc.v1def?.display?.label ?? tr.operation;
255
+ // The connection rides the same three places it does for a `connector()`
256
+ // step, because the platform reads it from the same three (#867):
257
+ // * the node's `inputs.detail` — what `uip maestro flow node configure`
258
+ // writes on a `tool.connector.*` node, what `uip agent refresh
259
+ // --inline-in-flow` builds the tool's resource.json FROM, and what its
260
+ // shell-ify pass keeps ("where a connector tool's request config
261
+ // lives"). It is also what `bindings_v2.json` is derived from.
262
+ // * the top-level `bindings[]` pair the def's `model.context` placeholders
263
+ // (`<bindings.… connection>` / `<bindings.FolderKey>`) name.
264
+ // * the agent's `resources/<id>/resource.json` (below).
265
+ // Emitting none of them left the tool with no connection anywhere.
266
+ const where = `inline agent "${step}"'s connector tool "${tr.connector}/${tr.operation}"`;
267
+ const target = { key: tr.connector, action: tr.operation };
268
+ const conn = ctx.resolveBinding(tr.connection, 'connection', where, target);
269
+ const folder = ctx.resolveBinding(tr.folder, 'folder', where, target);
270
+ ctx.bindConnection({
271
+ model: rc.v1def?.model, connectorKey: rc.connectorKey, connectionId: conn,
272
+ ...(folder !== undefined ? { folderKey: folder } : {}),
273
+ });
274
+ const detail = connectorToolDetail(rc, conn, folder, `${step}Tool`);
275
+ extraInputs = { detail };
276
+ connectorTool = {
277
+ rc, detail, name: label,
278
+ description: tr.description ?? connectorToolDescription(rc),
279
+ iconUrl: String(tdef.display?.icon ?? ''),
280
+ };
281
+ }
282
+ else if (tr.kind === 'mcp') {
283
+ // Per-instance def minted like the ixp family's; the node carries the def's
284
+ // own defaults (server identity + tool selection) — the configuration lives
285
+ // on the node, not in a binding.
286
+ tdef = mcpToolDef(tr);
287
+ label = tr.name;
288
+ extraInputs = jsonClone(tdef.inputDefaults);
289
+ }
290
+ else if (tr.kind === 'a2a') {
291
+ tdef = a2aToolDef(tr);
292
+ label = tr.name;
293
+ extraInputs = jsonClone(tdef.inputDefaults);
294
+ }
295
+ else if (tr.kind === 'clientside') {
296
+ // A static bundled def: the flow declares only the CONTRACT — the calling
297
+ // application owns the implementation.
298
+ tdef = jsonClone(ctx.definition('uipath.agent.resource.tool.clientside', '1.0'));
299
+ label = tr.name;
300
+ extraInputs = {
301
+ ...jsonClone(tdef.inputDefaults),
302
+ name: tr.name,
303
+ ...(tr.description !== undefined ? { description: tr.description } : {}),
304
+ ...(tr.inputs !== undefined ? { inputSchema: fieldSchema(tr.inputs) } : {}),
305
+ ...(tr.returns !== undefined ? { outputSchema: fieldSchema(tr.returns) } : {}),
306
+ };
307
+ }
308
+ else if (tr.kind === 'httpRequest') {
309
+ // Each field is a mode triple: a FIXED author value rides as text-builder
310
+ // (headers/params as name/value rows, timeout numeric — the storage
311
+ // layer's own normalization), an omitted one keeps the definition's
312
+ // prompt-mode default so the MODEL fills it at call time.
313
+ tdef = jsonClone(ctx.definition('uipath.agent.resource.tool.builtin.httprequest', '1.0'));
314
+ label = tr.name ?? tdef.display.label;
315
+ extraInputs = jsonClone(tdef.inputDefaults);
316
+ const fix = (field, value) => {
317
+ const row = extraInputs[field];
318
+ extraInputs[field] = { ...row, mode: 'text-builder', textValue: value };
319
+ };
320
+ if (tr.url !== undefined)
321
+ fix('url', tr.url);
322
+ if (tr.method !== undefined)
323
+ fix('method', tr.method);
324
+ if (tr.headers !== undefined)
325
+ fix('headers', tr.headers);
326
+ if (tr.params !== undefined)
327
+ fix('params', tr.params);
328
+ if (tr.body !== undefined)
329
+ fix('body', tr.body);
330
+ if (tr.timeout !== undefined)
331
+ fix('timeout', tr.timeout);
332
+ // Always set, falling back to the definition's own text: the resource file
333
+ // hands this to the MODEL as the tool's description, and the node must
334
+ // carry the same one (#935).
335
+ extraInputs.description = tr.description ?? String(tdef.description ?? '');
336
+ }
337
+ else {
338
+ const meta = ownEntry(PROCESS_TOOL_META, tr.kind);
339
+ if (!meta)
340
+ throw new Error(`inline agent "${step}": unknown tool kind "${tr.kind}".`);
341
+ tdef = processToolDef(tr.kind, tr);
342
+ label = tr.name;
343
+ // The definition's `model.context` names `<bindings.name>` /
344
+ // `<bindings.folderPath>` — the same pair every published-resource STEP
345
+ // references — so the entries must exist at the top level (v1's current
346
+ // authoring doc says so for process tools; a def whose bindings resolve to
347
+ // nothing is a dangling reference).
348
+ const { entries } = processResourceBindings({ name: tr.name, folderPath: tr.folderPath, resourceSubType: meta.subType }, ctx.bindings);
349
+ for (const b of entries)
350
+ ctx.bind(b);
351
+ // The NODE stays minimal — `source` only. Both witnesses agree: the
352
+ // deployed corpus carries `inputs: {}` on every per-instance tool, and
353
+ // v1's current authoring doc says "inputs.source only, no instance model".
354
+ // The contract (inputSchema/outputSchema) lives on the DEFINITION's
355
+ // inputDefaults, where the registry's tenant-synthesized copy puts it —
356
+ // emitting it on the node too would set inputs the def's own schema does
357
+ // not declare (our own output would be flagged).
358
+ }
359
+ const tid = ctx.resourceNodeId(tr.nodeId, `${step}Tool`, `inline agent "${step}": ${tr.kind} tool "${label}"`);
360
+ const toolResourceId = tr.source ?? derivedToolSource(ctx.flowId, step, tr);
361
+ const toolInputs = { source: toolResourceId, ...extraInputs };
362
+ attach.push({
363
+ id: tid, definition: tdef, label, port: 'tool', inputs: toolInputs,
364
+ // `uip agent refresh` reads the tool's description off the node's display
365
+ // first, so the node carries the one the resource.json does.
366
+ ...(connectorTool ? { display: { description: connectorTool.description } } : {}),
367
+ });
368
+ // The other half, for the kinds whose file is DERIVABLE — see
369
+ // `toolResourceJson` for which are not, and why each is left to the designer
370
+ // rather than guessed.
371
+ const toolResource = connectorTool
372
+ ? connectorToolResourceJson(connectorTool, toolResourceId)
373
+ : tr.kind === 'builtin'
374
+ ? builtinToolResourceJson(tr.tool, label, toolInputs, { id: toolResourceId })
375
+ : tr.kind === 'httpRequest'
376
+ ? httpRequestToolResourceJson(label, toolInputs, { id: toolResourceId, canvasNodeId: tid })
377
+ : toolResourceJson(tr, { id: toolResourceId });
378
+ if (toolResource !== undefined) {
379
+ ctx.sidecar({ path: `${source}/resources/${toolResourceId}/resource.json`, json: toolResource }, tr.source !== undefined);
380
+ }
381
+ }
382
+ // ESCALATION — the agent's TOP handle; an Action Center app task a human
383
+ // completes. The node's inputs are the platform's `inputDefaults` shape with
384
+ // the author's values — the exact shape the deployed corpus carries.
385
+ const escalations = s.escalation === undefined ? [] : Array.isArray(s.escalation) ? s.escalation : [s.escalation];
386
+ for (const esc of escalations) {
387
+ const where = `inline agent "${step}": escalation "${esc.name}"`;
388
+ const channelId = fnv1aX4Uuid(`${ctx.flowId}/${step}/escalation/${esc.name}/channel`);
389
+ if (esc.variant === 'quick-form') {
390
+ // The INLINE-form escalation: the same schema rows a human task's quick
391
+ // form carries, on the bundled `.quick-form` definition (the tenant
392
+ // registry does not serve the family).
393
+ const qdef = jsonClone(ctx.definition('uipath.agent.resource.escalation.quick-form', '1.2'));
394
+ const qid = ctx.resourceNodeId(esc.nodeId, `${step}Escalation`, where);
395
+ const rows = (esc.fields ?? []).map((f) => {
396
+ const required = f.direction === 'input' ? undefined : f.required;
397
+ return {
398
+ id: f.id,
399
+ label: f.label ?? f.id,
400
+ type: wireFormFieldType(f.type),
401
+ direction: f.direction,
402
+ ...(typeof required === 'boolean' ? { required } : {}),
403
+ // The field's settings (`controlType`, a picker's `options`,
404
+ // `defaultValue`, `colSpan`, …), as the human task's rows carry them
405
+ // (#1235, #1250).
406
+ ...formFieldSettingsWire(f),
407
+ };
408
+ });
409
+ const qsource = esc.source ?? derivedEscalationSource(ctx.flowId, step, esc.name);
410
+ const schema = {
411
+ // The runtime refuses a quick form without one (`AGENT_STARTUP.
412
+ // INVALID_TOOL_CONFIG`: "has a quick form schema without a schemaId",
413
+ // measured 2026-10-05) — the same stable id a human task's form carries.
414
+ schemaId: schemaId(ctx.flowId, qid),
415
+ fields: rows,
416
+ outcomes: (esc.outcomes ?? []).map((o, i) => ({
417
+ id: outcomeSlug(o, i), name: o, type: 'string', isPrimary: i === 0, action: 'Continue',
418
+ })),
419
+ };
420
+ attach.push({
421
+ id: qid, definition: qdef, label: esc.name, port: 'escalation',
422
+ inputs: {
423
+ source: qsource,
424
+ name: esc.name,
425
+ description: esc.description ?? '',
426
+ type: 'quick-form',
427
+ schema,
428
+ recipients: (esc.recipients ?? []).map((v) => ({ type: 3, value: v })),
429
+ outcomeMapping: esc.outcomes && esc.outcomes.length
430
+ ? Object.fromEntries(esc.outcomes.map((o) => [o, 'continue']))
431
+ : null,
432
+ _additionalProps: {
433
+ taskTitle: esc.taskTitle ?? '',
434
+ priority: esc.priority ?? 'medium',
435
+ labels: esc.labels ?? [],
436
+ },
437
+ _notifications: false,
438
+ },
439
+ });
440
+ // The other half — without it the escalation is inert: see
441
+ // `escalationResourceJson`.
442
+ ctx.sidecar({
443
+ path: `${source}/resources/${qsource}/resource.json`,
444
+ json: escalationResourceJson(esc, { id: qsource, channelId, quickFormSchema: schema }),
445
+ }, esc.source !== undefined);
446
+ continue;
447
+ }
448
+ const app = esc.app;
449
+ const edef = escalationDef();
450
+ const eid = ctx.resourceNodeId(esc.nodeId, `${step}Escalation`, where);
451
+ const esource = esc.source ?? derivedEscalationSource(ctx.flowId, step, esc.name);
452
+ attach.push({
453
+ id: eid, definition: edef, label: esc.name, port: 'escalation',
454
+ inputs: {
455
+ source: esource,
456
+ name: esc.name,
457
+ description: esc.description ?? '',
458
+ type: 'app-task',
459
+ app: {
460
+ key: app.key,
461
+ name: app.name,
462
+ appName: app.name,
463
+ displayName: app.name,
464
+ folderPath: escalationAppFolder(app),
465
+ inputSchema: fieldSchema(app.inputs),
466
+ outputSchema: fieldSchema(app.outputs),
467
+ },
468
+ // `{type: 3, value: <email>}` is the deployed corpus's recipient shape
469
+ // (type 3 = email address).
470
+ recipients: (esc.recipients ?? []).map((v) => ({ type: 3, value: v })),
471
+ // Every deployed outcome maps to 'continue' — the agent resumes with the
472
+ // reviewer's answer whichever outcome they pick.
473
+ outcomeMapping: esc.outcomes && esc.outcomes.length
474
+ ? Object.fromEntries(esc.outcomes.map((o) => [o, 'continue']))
475
+ : null,
476
+ _additionalProps: {
477
+ taskTitle: esc.taskTitle ?? '',
478
+ priority: esc.priority ?? 'medium',
479
+ labels: esc.labels ?? [],
480
+ },
481
+ _notifications: false,
482
+ _appInputs: null,
483
+ },
484
+ });
485
+ ctx.sidecar({
486
+ path: `${source}/resources/${esource}/resource.json`,
487
+ json: escalationResourceJson(esc, { id: esource, channelId }),
488
+ }, esc.source !== undefined);
489
+ }
490
+ // MEMORY — one episodic-memory resource on the agent's `memory` handle (the
491
+ // 1.4 definition selected above). Same artifact shape as context.
492
+ if (s.memory !== undefined) {
493
+ const m = s.memory;
494
+ attach.push({
495
+ id: ctx.resourceNodeId(undefined, `${step}Memory`, `inline agent "${step}": memory "${m.name}"`),
496
+ definition: memoryResourceDef(m), label: m.name, port: 'memory',
497
+ inputs: {
498
+ source: fnv1aX4Uuid(`${ctx.flowId}/${step}/memory/${m.id}`),
499
+ name: m.name,
500
+ description: m.description ?? '',
501
+ dynamicFewShotLearning: m.dynamicFewShotLearning ?? true,
502
+ semanticSimilarity: m.semanticSimilarity ?? 0,
503
+ kValue: m.kValue ?? 3,
504
+ searchMode: m.searchMode ?? 'hybrid',
505
+ },
506
+ });
507
+ // No `features/<id>/feature.json` until `check` stops refusing memory
508
+ // (AGENT_MEMORY_NOT_AUTHORABLE); its shape maps cleanly off `AgentMemoryRef`
509
+ // but cannot be exercised while the handle does not exist.
510
+ }
511
+ return {
512
+ definition: { source: 'snapshot', nodeType: def.nodeType, version: def.version, manifest: def },
513
+ // Unlike the published families the inline agent KEEPS no node-level model:
514
+ // 29 of 29 deployed instances carry none (the def's `model.source: true` is
515
+ // what tells the serializer the node has a `source` input).
516
+ model: 'omit',
517
+ // The forward handle is `success`, not `output` — the definition declares
518
+ // `success` (with `isDefaultForType`) + `error` on the right, and 29 of 29
519
+ // deployed instances wire the outgoing edge to `success`. Named, because the
520
+ // definition's first handles are the artifact handles a resource attaches to.
521
+ port: 'success',
522
+ inputs,
523
+ ...(outputs !== undefined ? { outputs, replaceOutputs: true } : {}),
524
+ attach,
525
+ };
526
+ }
@@ -0,0 +1,20 @@
1
+ import type { FlowNodeType, FlowVersionedNodeType } from '../../../flow-node-type.js';
2
+ import type { ConversationalAgentInputs, CreateOutgoingCallInputs, EndCallInputs, InlineAgentInputs, VoiceAgentInputs } from './spec.js';
3
+ type AgentSpec = {
4
+ kind: 'createOutgoingCall';
5
+ inputs: CreateOutgoingCallInputs;
6
+ } | {
7
+ kind: 'endCall';
8
+ inputs: EndCallInputs;
9
+ } | {
10
+ kind: 'voiceAgent';
11
+ inputs: VoiceAgentInputs;
12
+ } | {
13
+ kind: 'conversationalAgent';
14
+ inputs: ConversationalAgentInputs;
15
+ } | {
16
+ kind: 'inlineAgent';
17
+ inputs: InlineAgentInputs;
18
+ };
19
+ export declare const agentNodeTypes: (FlowNodeType<AgentSpec> | FlowVersionedNodeType<AgentSpec>)[];
20
+ export {};