@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.
- package/dist/api-index.md +99 -99
- package/dist/api-members.md +307 -307
- package/dist/check.d.ts +0 -19
- package/dist/check.js +40 -1036
- package/dist/cli/commands/registry.js +15 -0
- package/dist/compile-cli.js +2 -1
- package/dist/core/actions.d.ts +1 -713
- package/dist/core/actions.js +0 -193
- package/dist/core/agent-sidecar.d.ts +186 -0
- package/dist/core/agent-sidecar.js +409 -0
- package/dist/core/agent-tool-resources.d.ts +62 -0
- package/dist/core/agent-tool-resources.js +81 -0
- package/dist/core/cli-spelling.d.ts +9 -0
- package/dist/core/cli-spelling.js +9 -0
- package/dist/{config.js → core/connector-configuration.js} +2 -2
- package/dist/core/library-cache.d.ts +0 -9
- package/dist/core/library-cache.js +0 -9
- package/dist/core/library.d.ts +47 -0
- package/dist/core/library.js +135 -34
- package/dist/core/list-envelope.d.ts +36 -1
- package/dist/core/list-envelope.js +24 -19
- package/dist/core/lookup-store.d.ts +4 -3
- package/dist/core/lookup-store.js +46 -38
- package/dist/core/node-id-placeholder.d.ts +8 -0
- package/dist/core/node-id-placeholder.js +10 -0
- package/dist/core/read-text.d.ts +26 -0
- package/dist/core/read-text.js +43 -0
- package/dist/core/ts-literal.d.ts +6 -0
- package/dist/core/ts-literal.js +15 -0
- package/dist/core/typed-raw-node.js +0 -5
- package/dist/decompile.js +34 -822
- package/dist/flow-node-registry.js +2 -1
- package/dist/flow-node-type.d.ts +130 -6
- package/dist/flow-sdk.d.ts +1 -0
- package/dist/flow-sdk.js +1 -0
- package/dist/nodes/agent/flow/check.d.ts +88 -0
- package/dist/nodes/agent/flow/check.js +873 -0
- package/dist/nodes/agent/flow/factories.d.ts +134 -0
- package/dist/nodes/agent/flow/factories.js +143 -0
- package/dist/nodes/agent/flow/family.d.ts +3 -0
- package/dist/nodes/agent/flow/family.js +8 -0
- package/dist/nodes/agent/flow/index.d.ts +3 -0
- package/dist/nodes/agent/flow/index.js +3 -0
- package/dist/nodes/agent/flow/inline-agent-lift.d.ts +44 -0
- package/dist/nodes/agent/flow/inline-agent-lift.js +572 -0
- package/dist/nodes/agent/flow/inline-agent.d.ts +15 -0
- package/dist/nodes/agent/flow/inline-agent.js +526 -0
- package/dist/nodes/agent/flow/node-type.d.ts +20 -0
- package/dist/nodes/agent/flow/node-type.js +422 -0
- package/dist/nodes/agent/flow/resources.d.ts +502 -0
- package/dist/nodes/agent/flow/resources.js +1409 -0
- package/dist/nodes/agent/flow/spec.d.ts +448 -0
- package/dist/nodes/agent/flow/spec.js +1 -0
- package/dist/nodes/process/flow/check.d.ts +40 -2
- package/dist/nodes/process/flow/check.js +156 -0
- package/dist/nodes/process/flow/factories.d.ts +58 -3
- package/dist/nodes/process/flow/factories.js +59 -2
- package/dist/nodes/process/flow/node-type.d.ts +4 -1
- package/dist/nodes/process/flow/node-type.js +181 -10
- package/dist/nodes/process/flow/spec.d.ts +112 -5
- package/dist/registry/describe-cli.d.ts +10 -0
- package/dist/registry/describe-cli.js +41 -0
- package/dist/registry/library-reader.d.ts +12 -2
- package/dist/registry/library-reader.js +17 -16
- package/dist/registry/lookup-specs.d.ts +17 -1
- package/dist/registry/lookup-specs.js +3 -7
- package/dist/registry/path-cli.js +2 -1
- package/dist/registry/search-cli.js +2 -1
- package/dist/serialize.d.ts +9 -54
- package/dist/serialize.js +47 -2763
- package/package.json +2 -2
- /package/dist/{config.d.ts → core/connector-configuration.d.ts} +0 -0
- /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 {};
|