@uipath/maestro-builder-sdk 6.16.14 → 6.17.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 +108 -107
- package/dist/api-members.md +295 -291
- package/dist/bindings-v2.d.ts +39 -1
- package/dist/bindings-v2.js +289 -9
- package/dist/bpmn/compile-cli.js +11 -2
- package/dist/bpmn/decompile.js +2 -1
- package/dist/bpmn/registry-fallback.js +9 -7
- package/dist/case/compile-cli.js +16 -6
- package/dist/case/decompile-cli.js +2 -1
- package/dist/case/decompile.js +3 -2
- package/dist/case/merge-cli.js +3 -2
- package/dist/check.js +219 -37
- package/dist/cli-result.d.ts +9 -0
- package/dist/cli-result.js +12 -0
- package/dist/compile-cli.js +78 -53
- package/dist/core/actions.d.ts +70 -16
- package/dist/core/agentic-process-forms.d.ts +51 -0
- package/dist/core/agentic-process-forms.js +49 -0
- package/dist/core/binding-messages.d.ts +5 -0
- package/dist/core/comment-text.d.ts +29 -0
- package/dist/core/comment-text.js +40 -0
- package/dist/core/contribution-bindings.d.ts +73 -0
- package/dist/core/contribution-bindings.js +105 -0
- package/dist/core/expr-check.js +7 -2
- package/dist/core/json-file.d.ts +1 -0
- package/dist/core/json-file.js +12 -0
- package/dist/core/script-return.js +4 -1
- package/dist/core/typed-raw-node.js +1 -0
- package/dist/core/typescript-module.d.ts +2 -0
- package/dist/core/typescript-module.js +18 -0
- package/dist/core-definitions.json +210 -0
- package/dist/decompile-cli.js +2 -1
- package/dist/decompile.js +64 -24
- package/dist/emit.js +4 -3
- package/dist/flow-sdk.d.ts +14 -9
- package/dist/flow-sdk.js +14 -4
- package/dist/flow-step-tree.d.ts +2 -3
- package/dist/flow-step-tree.js +2 -3
- package/dist/load.js +1 -1
- package/dist/merge-cli.js +3 -2
- package/dist/merge.d.ts +2 -1
- package/dist/merge.js +0 -0
- package/dist/path-within.d.ts +33 -0
- package/dist/path-within.js +41 -0
- package/dist/registry/archive/extract.js +2 -5
- package/dist/registry/curated-overlay.js +3 -2
- package/dist/registry/generators/descriptors.js +20 -18
- package/dist/registry/generators/triggers.js +4 -4
- package/dist/registry/prepare/messages.js +2 -1
- package/dist/registry/prepare/source-labels.js +60 -1
- package/dist/registry/prepare-cli.js +14 -4
- package/dist/registry/pull-cli.js +3 -2
- package/dist/registry/uip/client.d.ts +28 -3
- package/dist/registry/uip/client.js +95 -34
- package/dist/registry/uip/host.d.ts +41 -0
- package/dist/registry/uip/host.js +312 -0
- package/dist/serialize.d.ts +7 -0
- package/dist/serialize.js +390 -270
- package/dist/workdir.js +1 -1
- package/package.json +3 -3
package/dist/serialize.js
CHANGED
|
@@ -14,6 +14,7 @@ import { Expr, toExpr, SCHEDULE_PRESETS, DELAY_PRESETS, parseIxpProjectType, fla
|
|
|
14
14
|
import { FlowAction, FlowTrigger } from './core/node-classes.js';
|
|
15
15
|
import { connectorRawNodeRefusal } from './core/connector-raw-node.js';
|
|
16
16
|
import { dataFabricUnknownInputs } from './core/typed-raw-node.js';
|
|
17
|
+
import { planContributionBindings } from './core/contribution-bindings.js';
|
|
17
18
|
import { isAnswerField } from './core/hitl-answers.js';
|
|
18
19
|
import { connectionConnectors } from './bindings-v2.js';
|
|
19
20
|
import { BindingRefusal, GUID_RE, bindingMissingMessage, bindingSelfNameMessage, bindingUndeclaredMessage, missingBindingLabels, undeclaredBinding } from './core/binding-messages.js';
|
|
@@ -49,6 +50,8 @@ import { resolveSchemaVersion } from './schema-version.js';
|
|
|
49
50
|
import { planFlowGlobals, planSharedInputs, sharedInputRoots } from './flow-variables.js';
|
|
50
51
|
import { prepareCommand } from './core/cli-spelling.js';
|
|
51
52
|
import { QUEUE_ITEM_RECORD_SCHEMA } from './core/queue-record.js';
|
|
53
|
+
import { AGENTIC_PROCESS_FORMS } from './core/agentic-process-forms.js';
|
|
54
|
+
import { types } from './core/expr.js';
|
|
52
55
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
53
56
|
// core-definitions.json is an object keyed by "<nodeType>@<version>".
|
|
54
57
|
const DEFS = JSON.parse(readFileSync(join(HERE, 'core-definitions.json'), 'utf8'));
|
|
@@ -143,6 +146,53 @@ const SUBFLOW_OUTPUT = {
|
|
|
143
146
|
};
|
|
144
147
|
/** The RPA-workflow node type family. The process's release key is the suffix. */
|
|
145
148
|
const RPA_WORKFLOW_PREFIX = 'uipath.core.rpa-workflow.';
|
|
149
|
+
/**
|
|
150
|
+
* Where a process resource lives, as ONE slot every process-resource definition
|
|
151
|
+
* shares. In the platform model "in this solution" is orthogonal to the
|
|
152
|
+
* resource type: flow-core's single `createModel` (`@uipath/flow-core`
|
|
153
|
+
* `manifest/mappers/node-manifest-builder.ts`, what `uip maestro flow registry
|
|
154
|
+
* get --local` and Studio Web both run) adds `projectId`, `projectName` and
|
|
155
|
+
* `isInSolution: true` to the model of ANY process resource built from a sibling
|
|
156
|
+
* project.
|
|
157
|
+
*
|
|
158
|
+
* The in-solution shape, transcribed from `registry get --local` for a sibling
|
|
159
|
+
* Flow (2026-10-08) and from uipath-cli's `buildInSolutionNodeManifests`:
|
|
160
|
+
* - `resourceKey` is the bare key (the sibling's `resource.key`), not
|
|
161
|
+
* `<folderPath>.<name>`; the folder default is `''`;
|
|
162
|
+
* - no `section: 'Published'`;
|
|
163
|
+
* - `projectId` on the definition AND on the model, with `projectName` and
|
|
164
|
+
* `isInSolution: true` (the marker the canvas reads);
|
|
165
|
+
* - description `(In-solution) <name>`, tags `in-solution` / `local`, and the
|
|
166
|
+
* `open-workflow` toolbar action.
|
|
167
|
+
*/
|
|
168
|
+
function processResourceLocation(spec) {
|
|
169
|
+
if (spec.location === 'in-solution') {
|
|
170
|
+
return {
|
|
171
|
+
inSolution: true,
|
|
172
|
+
folderPath: '',
|
|
173
|
+
resourceKey: spec.key,
|
|
174
|
+
description: `(In-solution) ${spec.name}`,
|
|
175
|
+
tags: ['in-solution', 'local'],
|
|
176
|
+
definitionExtras: {
|
|
177
|
+
toolbarExtensions: {
|
|
178
|
+
design: { actions: [{ id: 'open-workflow', icon: 'external-link', label: 'Open' }] },
|
|
179
|
+
},
|
|
180
|
+
projectId: spec.projectId,
|
|
181
|
+
},
|
|
182
|
+
modelExtras: { projectId: spec.projectId, projectName: spec.name, isInSolution: true },
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
const folderPath = spec.folderPath ?? '';
|
|
186
|
+
return {
|
|
187
|
+
inSolution: false,
|
|
188
|
+
folderPath,
|
|
189
|
+
resourceKey: `${folderPath}.${spec.name}`,
|
|
190
|
+
description: `(${folderPath})`,
|
|
191
|
+
tags: [],
|
|
192
|
+
definitionExtras: {},
|
|
193
|
+
modelExtras: {},
|
|
194
|
+
};
|
|
195
|
+
}
|
|
146
196
|
/**
|
|
147
197
|
* Build the definition for one deployed RPA process.
|
|
148
198
|
*
|
|
@@ -177,7 +227,8 @@ const RPA_WORKFLOW_PREFIX = 'uipath.core.rpa-workflow.';
|
|
|
177
227
|
* element while publishing a null step output.
|
|
178
228
|
*/
|
|
179
229
|
function rpaWorkflowDef(spec) {
|
|
180
|
-
const
|
|
230
|
+
const loc = processResourceLocation(spec);
|
|
231
|
+
const { resourceKey } = loc;
|
|
181
232
|
const properties = {};
|
|
182
233
|
for (const [k, v] of Object.entries(spec.inputs)) {
|
|
183
234
|
properties[k] = { type: typeof v === 'number' ? 'number' : typeof v === 'boolean' ? 'boolean' : 'string' };
|
|
@@ -187,8 +238,8 @@ function rpaWorkflowDef(spec) {
|
|
|
187
238
|
version: '1.0.0',
|
|
188
239
|
category: 'rpa-workflow',
|
|
189
240
|
runtimeConstraints: { exclude: ['api-function'] },
|
|
190
|
-
description:
|
|
191
|
-
tags:
|
|
241
|
+
description: loc.description,
|
|
242
|
+
tags: loc.tags,
|
|
192
243
|
sortOrder: 530,
|
|
193
244
|
supportsErrorHandling: true,
|
|
194
245
|
display: { label: spec.name, icon: 'rpa' },
|
|
@@ -196,11 +247,12 @@ function rpaWorkflowDef(spec) {
|
|
|
196
247
|
{ position: 'left', handles: [{ id: 'input', type: 'target', handleType: 'input' }] },
|
|
197
248
|
{ position: 'right', handles: [{ id: 'output', type: 'source', handleType: 'output' }] },
|
|
198
249
|
],
|
|
250
|
+
...loc.definitionExtras,
|
|
199
251
|
model: {
|
|
200
252
|
type: 'bpmn:ServiceTask',
|
|
201
253
|
serviceType: 'Orchestrator.StartJob',
|
|
202
254
|
version: 'v2',
|
|
203
|
-
section: 'Published',
|
|
255
|
+
...(loc.inSolution ? {} : { section: 'Published' }),
|
|
204
256
|
bindings: {
|
|
205
257
|
resource: 'process',
|
|
206
258
|
resourceSubType: 'Process',
|
|
@@ -208,9 +260,10 @@ function rpaWorkflowDef(spec) {
|
|
|
208
260
|
orchestratorType: 'process',
|
|
209
261
|
values: [
|
|
210
262
|
{ name: 'name', propertyAttribute: 'name', default: spec.name },
|
|
211
|
-
{ name: 'folderPath', propertyAttribute: 'folderPath', default:
|
|
263
|
+
{ name: 'folderPath', propertyAttribute: 'folderPath', default: loc.folderPath },
|
|
212
264
|
],
|
|
213
265
|
},
|
|
266
|
+
...loc.modelExtras,
|
|
214
267
|
context: [
|
|
215
268
|
{ name: 'name', type: 'string', value: '<bindings.name>' },
|
|
216
269
|
{ name: 'folderPath', type: 'string', value: '<bindings.folderPath>' },
|
|
@@ -453,41 +506,6 @@ function publishedFunctionDef(spec) {
|
|
|
453
506
|
debug: { runtime: 'bpmnEngine' },
|
|
454
507
|
};
|
|
455
508
|
}
|
|
456
|
-
const AGENTIC_PROCESS_PREFIX = 'uipath.core.agentic-process.';
|
|
457
|
-
/**
|
|
458
|
-
* The three published forms under the Agentic Process umbrella (design §2.1).
|
|
459
|
-
* One public factory, three wire identities — transcribed from flow-v1's
|
|
460
|
-
* `RESOURCE_TYPE_METADATA` (ProcessOrchestration / Flow / CaseManagement):
|
|
461
|
-
* node-type segment, category, icon, resource subtype, `orchestratorType`
|
|
462
|
-
* (`resourceType.toLowerCase()`, per `createModel`), and the sync/async
|
|
463
|
-
* service-type pair. All three declare the fire-and-forget switch.
|
|
464
|
-
*/
|
|
465
|
-
const AGENTIC_PROCESS_FORMS = {
|
|
466
|
-
bpmn: {
|
|
467
|
-
prefix: AGENTIC_PROCESS_PREFIX,
|
|
468
|
-
category: 'agentic-process',
|
|
469
|
-
icon: 'agentic-process',
|
|
470
|
-
resourceSubType: 'ProcessOrchestration',
|
|
471
|
-
orchestratorType: 'processorchestration',
|
|
472
|
-
serviceType: 'Orchestrator.StartAgenticProcess',
|
|
473
|
-
},
|
|
474
|
-
flow: {
|
|
475
|
-
prefix: 'uipath.core.flow.',
|
|
476
|
-
category: 'flow',
|
|
477
|
-
icon: 'flow-project',
|
|
478
|
-
resourceSubType: 'Flow',
|
|
479
|
-
orchestratorType: 'flow',
|
|
480
|
-
serviceType: 'Orchestrator.StartFlowProcess',
|
|
481
|
-
},
|
|
482
|
-
case: {
|
|
483
|
-
prefix: 'uipath.core.case-management.',
|
|
484
|
-
category: 'case-management',
|
|
485
|
-
icon: 'case-management',
|
|
486
|
-
resourceSubType: 'CaseManagement',
|
|
487
|
-
orchestratorType: 'casemanagement',
|
|
488
|
-
serviceType: 'Orchestrator.StartCaseMgmtProcess',
|
|
489
|
-
},
|
|
490
|
-
};
|
|
491
509
|
/**
|
|
492
510
|
* Build the definition for one deployed agentic process (a Maestro process
|
|
493
511
|
* orchestration).
|
|
@@ -529,7 +547,8 @@ const AGENTIC_PROCESS_FORMS = {
|
|
|
529
547
|
*/
|
|
530
548
|
function agenticProcessDef(spec) {
|
|
531
549
|
const form = AGENTIC_PROCESS_FORMS[spec.form ?? 'bpmn'];
|
|
532
|
-
const
|
|
550
|
+
const loc = processResourceLocation(spec);
|
|
551
|
+
const { resourceKey } = loc;
|
|
533
552
|
const properties = {};
|
|
534
553
|
for (const [k, v] of Object.entries(spec.inputs)) {
|
|
535
554
|
properties[k] = { type: typeof v === 'number' ? 'number' : typeof v === 'boolean' ? 'boolean' : 'string' };
|
|
@@ -539,8 +558,8 @@ function agenticProcessDef(spec) {
|
|
|
539
558
|
version: '1.0.0',
|
|
540
559
|
category: form.category,
|
|
541
560
|
runtimeConstraints: { exclude: ['api-function'] },
|
|
542
|
-
description:
|
|
543
|
-
tags:
|
|
561
|
+
description: loc.description,
|
|
562
|
+
tags: loc.tags,
|
|
544
563
|
sortOrder: 507,
|
|
545
564
|
supportsErrorHandling: true,
|
|
546
565
|
display: { label: spec.name, icon: form.icon },
|
|
@@ -548,11 +567,12 @@ function agenticProcessDef(spec) {
|
|
|
548
567
|
{ position: 'left', handles: [{ id: 'input', type: 'target', handleType: 'input' }] },
|
|
549
568
|
{ position: 'right', handles: [{ id: 'output', type: 'source', handleType: 'output' }] },
|
|
550
569
|
],
|
|
570
|
+
...loc.definitionExtras,
|
|
551
571
|
model: {
|
|
552
572
|
type: 'bpmn:ServiceTask',
|
|
553
573
|
serviceType: form.serviceType,
|
|
554
574
|
version: 'v2',
|
|
555
|
-
section: 'Published',
|
|
575
|
+
...(loc.inSolution ? {} : { section: 'Published' }),
|
|
556
576
|
bindings: {
|
|
557
577
|
resource: 'process',
|
|
558
578
|
resourceSubType: form.resourceSubType,
|
|
@@ -560,9 +580,10 @@ function agenticProcessDef(spec) {
|
|
|
560
580
|
orchestratorType: form.orchestratorType,
|
|
561
581
|
values: [
|
|
562
582
|
{ name: 'name', propertyAttribute: 'name', default: spec.name },
|
|
563
|
-
{ name: 'folderPath', propertyAttribute: 'folderPath', default:
|
|
583
|
+
{ name: 'folderPath', propertyAttribute: 'folderPath', default: loc.folderPath },
|
|
564
584
|
],
|
|
565
585
|
},
|
|
586
|
+
...loc.modelExtras,
|
|
566
587
|
context: [
|
|
567
588
|
{ name: 'name', type: 'string', value: '<bindings.name>' },
|
|
568
589
|
{ name: 'folderPath', type: 'string', value: '<bindings.folderPath>' },
|
|
@@ -741,28 +762,6 @@ function agentDef(spec) {
|
|
|
741
762
|
debug: { runtime: 'bpmnEngine' },
|
|
742
763
|
};
|
|
743
764
|
}
|
|
744
|
-
/**
|
|
745
|
-
* Build the definition for the INLINE autonomous agent.
|
|
746
|
-
*
|
|
747
|
-
* This is the one node type in the agent family that is the SAME on every tenant —
|
|
748
|
-
* it carries its own configuration instead of referencing a resource — so
|
|
749
|
-
* `uip maestro flow registry get uipath.agent.autonomous` is a direct oracle rather
|
|
750
|
-
* than a per-instance answer, and the def can be built from constants without a
|
|
751
|
-
* corpus vote. Transcribed 2026-07-29: `version: '1.2'`, `sortOrder: 5`,
|
|
752
|
-
* `supportsErrorHandling: true`, `model.source: true`,
|
|
753
|
-
* `Orchestrator.StartInlineAgentJob`, the three required inputs, the artifact
|
|
754
|
-
* handles (escalation / context / tool) and `success` + `error` on the right with
|
|
755
|
-
* `isDefaultForType` on `success`.
|
|
756
|
-
*
|
|
757
|
-
* The deployed corpus (29 `uipath.agent.autonomous` nodes, 05-18 → 07-29) agrees on
|
|
758
|
-
* everything a `.flow` carries and settles the one thing the def leaves open:
|
|
759
|
-
* `outputs.output.source` is `=result.response` in 27 of 27 that declare outputs —
|
|
760
|
-
* unanimous here, unlike the published family, because the platform's
|
|
761
|
-
* append-`=this` fallback only fires for a node that declares no `output` at all.
|
|
762
|
-
* `typeVersion` in that corpus is 1.1 ×10, 1.2 ×15, 1.3 ×4; we emit the registry's
|
|
763
|
-
* 1.2. (`shared/sample-flows/inline-agent.flow` says 1.0, which appears in **none**
|
|
764
|
-
* of the 29 — the same bundled-sample era gap as the published family's.)
|
|
765
|
-
*/
|
|
766
765
|
/**
|
|
767
766
|
* The definition for ONE Context Grounding index resource, transcribed from the
|
|
768
767
|
* platform's own registry entry (`uip maestro flow registry get
|
|
@@ -984,6 +983,45 @@ const CONNECTOR_TOOL_RESOURCE_TYPE = 'integration';
|
|
|
984
983
|
* on its own it says nothing about who owns a file: `properties.toolType` does.
|
|
985
984
|
*/
|
|
986
985
|
const INTERNAL_TOOL_RESOURCE_TYPE = 'internal';
|
|
986
|
+
/**
|
|
987
|
+
* Where an agent schema property points to declare "this is a FILE":
|
|
988
|
+
* `{ $ref: JOB_ATTACHMENT_REF }`, with {@link jobAttachmentDefinition} under the
|
|
989
|
+
* same schema's `definitions['job-attachment']`.
|
|
990
|
+
*/
|
|
991
|
+
const JOB_ATTACHMENT_REF = '#/definitions/job-attachment';
|
|
992
|
+
/**
|
|
993
|
+
* The canonical `job-attachment` definition an agent schema's file field
|
|
994
|
+
* `$ref`s into — the uipath-agents skill's `agent-definition.md` § File
|
|
995
|
+
* Attachments ("Schema is fixed — copy verbatim"), and the same block the
|
|
996
|
+
* platform's own analyze-attachments tool contract carries.
|
|
997
|
+
*
|
|
998
|
+
* It tells the agent runtime that an input is an Orchestrator attachment, so a
|
|
999
|
+
* file tool (Analyze Files) can resolve the attachment's `ID`.
|
|
1000
|
+
*
|
|
1001
|
+
* A function, not a shared object: each schema gets its own copy, so an edit
|
|
1002
|
+
* to one emitted file cannot reach another.
|
|
1003
|
+
*
|
|
1004
|
+
* (The case serializer keeps its own copy in `case/entry-points.ts`: that one
|
|
1005
|
+
* mirrors the platform's `entry-points.json` packager byte for byte, and its
|
|
1006
|
+
* `MimeType` description differs.)
|
|
1007
|
+
*/
|
|
1008
|
+
function jobAttachmentDefinition() {
|
|
1009
|
+
return {
|
|
1010
|
+
type: 'object',
|
|
1011
|
+
properties: {
|
|
1012
|
+
ID: { type: 'string', description: 'Orchestrator attachment key' },
|
|
1013
|
+
FullName: { type: 'string', description: 'File name' },
|
|
1014
|
+
MimeType: { type: 'string', description: 'MIME type, e.g. "application/pdf", "image/png"' },
|
|
1015
|
+
Metadata: {
|
|
1016
|
+
type: 'object',
|
|
1017
|
+
description: 'Dictionary<string, string> of metadata',
|
|
1018
|
+
additionalProperties: { type: 'string' },
|
|
1019
|
+
},
|
|
1020
|
+
},
|
|
1021
|
+
required: ['ID'],
|
|
1022
|
+
'x-uipath-resource-kind': 'JobAttachment',
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
987
1025
|
/** The `properties.toolType` of the built-in HTTP-request tool's file (#935). */
|
|
988
1026
|
const HTTP_REQUEST_TOOL_TYPE = 'http-request';
|
|
989
1027
|
/**
|
|
@@ -1139,29 +1177,13 @@ function builtinToolResourceJson(tool, label, inputs, spec) {
|
|
|
1139
1177
|
properties: {
|
|
1140
1178
|
attachments: {
|
|
1141
1179
|
type: 'array',
|
|
1142
|
-
items: { $ref:
|
|
1180
|
+
items: { $ref: JOB_ATTACHMENT_REF },
|
|
1143
1181
|
description: String(inputs.attachmentsDescription ?? ''),
|
|
1144
1182
|
},
|
|
1145
1183
|
analysisTask: { type: 'string', description: String(inputs.analysisTaskDescription ?? '') },
|
|
1146
1184
|
},
|
|
1147
1185
|
required: ['attachments', 'analysisTask'],
|
|
1148
|
-
definitions: {
|
|
1149
|
-
'job-attachment': {
|
|
1150
|
-
type: 'object',
|
|
1151
|
-
properties: {
|
|
1152
|
-
ID: { type: 'string', description: 'Orchestrator attachment key' },
|
|
1153
|
-
FullName: { type: 'string', description: 'File name' },
|
|
1154
|
-
MimeType: { type: 'string', description: 'MIME type, e.g. "application/pdf", "image/png"' },
|
|
1155
|
-
Metadata: {
|
|
1156
|
-
type: 'object',
|
|
1157
|
-
description: 'Dictionary<string, string> of metadata',
|
|
1158
|
-
additionalProperties: { type: 'string' },
|
|
1159
|
-
},
|
|
1160
|
-
},
|
|
1161
|
-
required: ['ID'],
|
|
1162
|
-
'x-uipath-resource-kind': 'JobAttachment',
|
|
1163
|
-
},
|
|
1164
|
-
},
|
|
1186
|
+
definitions: { 'job-attachment': jobAttachmentDefinition() },
|
|
1165
1187
|
},
|
|
1166
1188
|
outputSchema: {
|
|
1167
1189
|
type: 'object',
|
|
@@ -1324,6 +1346,24 @@ const QUICK_FORM_FIELD_SCHEMA = {
|
|
|
1324
1346
|
text: { type: 'string' }, number: { type: 'number' }, boolean: { type: 'boolean' },
|
|
1325
1347
|
'date-time': { type: 'string', format: 'date-time' },
|
|
1326
1348
|
};
|
|
1349
|
+
/**
|
|
1350
|
+
* The folder an app escalation names: the author's `folderPath`, or
|
|
1351
|
+
* `solution_folder` when they gave none — an app that ships in this solution.
|
|
1352
|
+
*
|
|
1353
|
+
* `solution_folder` is the platform's own spelling for that case: it is the
|
|
1354
|
+
* `Folder` that `uip solution resources list` reports for a solution-internal
|
|
1355
|
+
* app, and what the agents skill tells authors to copy into
|
|
1356
|
+
* `channels[].properties.folderName`. The SDK used to write `""`, which no
|
|
1357
|
+
* product writer produces (flow-builder-sdk#967). Measured, the two are the
|
|
1358
|
+
* same everywhere it counts: the agent tool's binding generator drops both
|
|
1359
|
+
* from the App binding (`resolveFolderPathBindingValue`), `uip agent refresh`
|
|
1360
|
+
* plus `uip solution resources refresh` derive byte-identical files from
|
|
1361
|
+
* either, and a live debug resolves the app in the debug folder for both. So
|
|
1362
|
+
* this changes the vocabulary, not the behaviour.
|
|
1363
|
+
*/
|
|
1364
|
+
function escalationAppFolder(app) {
|
|
1365
|
+
return app.folderPath ? app.folderPath : 'solution_folder';
|
|
1366
|
+
}
|
|
1327
1367
|
/**
|
|
1328
1368
|
* The `resources/<id>/resource.json` an inline agent's ESCALATION needs — the
|
|
1329
1369
|
* escalation half of what `toolResourceJson` does for a tool, and inert without
|
|
@@ -1400,7 +1440,7 @@ function escalationResourceJson(esc, spec) {
|
|
|
1400
1440
|
// refresh` imports; `folderName` is the app's Orchestrator folder.
|
|
1401
1441
|
resourceKey: app.key,
|
|
1402
1442
|
appName: app.name,
|
|
1403
|
-
folderName: app
|
|
1443
|
+
folderName: escalationAppFolder(app),
|
|
1404
1444
|
// The app's deploy version (its action schema's `version`). The SDK does
|
|
1405
1445
|
// not read the action schema, so this is the platform's own default — the
|
|
1406
1446
|
// storage migration that introduced the field writes `1` when absent.
|
|
@@ -2183,134 +2223,88 @@ function memoryResourceDef(spec) {
|
|
|
2183
2223
|
},
|
|
2184
2224
|
};
|
|
2185
2225
|
}
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
description: 'Agent response',
|
|
2269
|
-
// `=result.response`, not `=this` — 27 of 27 deployed instances, and the
|
|
2270
|
-
// engine's own inline dispatch returns `{ response: { …declared keys } }`.
|
|
2271
|
-
source: '=result.response',
|
|
2272
|
-
var: 'output',
|
|
2273
|
-
// NO per-instance schema here, and that is the whole point of this comment:
|
|
2274
|
-
// `definitions[]` is keyed by node TYPE, and every inline agent in a flow
|
|
2275
|
-
// shares this ONE entry. A flow with two agents (an analyst and a writer,
|
|
2276
|
-
// say) therefore cannot have both contracts here — whichever was emitted
|
|
2277
|
-
// last would win, and every read against the other resolved to the wrong
|
|
2278
|
-
// shape. Measured on GA row 7's port, whose four `.return()` mappings off
|
|
2279
|
-
// the ANALYST drew 25 undeclared-field errors quoting the WRITER's fields
|
|
2280
|
-
// (`Available at "$vars.disputeAnalystAgent.output": "subject", "body"`) on
|
|
2281
|
-
// a flow that is correct.
|
|
2282
|
-
//
|
|
2283
|
-
// The instance is where an authored contract belongs, and the SDK already
|
|
2284
|
-
// writes it there (`node.outputs.output.schema`, below). A reader that
|
|
2285
|
-
// refines per node then picks it up — applying an instance schema when the
|
|
2286
|
-
// definition's is GENERIC and never overriding a definition that declares
|
|
2287
|
-
// a shape, which is right in general and was
|
|
2288
|
-
// exactly what this def defeated.
|
|
2289
|
-
//
|
|
2290
|
-
// Deployed truth agrees: v1's own two-agent BillingDisputeResolution
|
|
2291
|
-
// artifact (1.0, 2026-07-15) carries `properties: { content: {…} }` on the
|
|
2292
|
-
// shared definition and `schema: null` on both agent nodes.
|
|
2293
|
-
},
|
|
2294
|
-
error: {
|
|
2295
|
-
type: 'object',
|
|
2296
|
-
description: 'Error information if the node fails',
|
|
2297
|
-
source: '=Error',
|
|
2298
|
-
var: 'error',
|
|
2299
|
-
},
|
|
2300
|
-
},
|
|
2301
|
-
model: {
|
|
2302
|
-
source: true,
|
|
2303
|
-
type: 'bpmn:ServiceTask',
|
|
2304
|
-
serviceType: 'Orchestrator.StartInlineAgentJob',
|
|
2305
|
-
version: 'v2',
|
|
2306
|
-
context: [
|
|
2307
|
-
{ name: '_label', type: 'string', value: '' },
|
|
2308
|
-
{ name: 'name', type: 'string', value: '' },
|
|
2309
|
-
{ name: 'entryPoint', type: 'string', value: '' },
|
|
2310
|
-
],
|
|
2311
|
-
},
|
|
2312
|
-
debug: { runtime: 'bpmnEngine' },
|
|
2313
|
-
};
|
|
2226
|
+
/** Numeric dotted compare: '1.10' > '1.9'. */
|
|
2227
|
+
function compareVersions(a, b) {
|
|
2228
|
+
const pa = a.split('.').map(Number);
|
|
2229
|
+
const pb = b.split('.').map(Number);
|
|
2230
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
2231
|
+
const d = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
2232
|
+
if (d !== 0)
|
|
2233
|
+
return d;
|
|
2234
|
+
}
|
|
2235
|
+
return 0;
|
|
2236
|
+
}
|
|
2237
|
+
/**
|
|
2238
|
+
* The inline agent's bundled versions, oldest first, and the newest of them.
|
|
2239
|
+
* The newest bundled pair is the default, so there is no version literal in
|
|
2240
|
+
* this file: when the registry serves a newer version, `check:definitions`
|
|
2241
|
+
* reports the missing pair, `sync:definitions` adds it, and the default follows.
|
|
2242
|
+
*/
|
|
2243
|
+
const INLINE_AGENT_VERSIONS = Object.keys(DEFS)
|
|
2244
|
+
.filter((k) => k.startsWith(`${INLINE_AGENT_TYPE}@`))
|
|
2245
|
+
.map((k) => k.slice(INLINE_AGENT_TYPE.length + 1))
|
|
2246
|
+
.sort(compareVersions);
|
|
2247
|
+
const INLINE_AGENT_DEFAULT_VERSION = INLINE_AGENT_VERSIONS[INLINE_AGENT_VERSIONS.length - 1];
|
|
2248
|
+
/** True when a definition declares the agent's `memory` artifact handle. */
|
|
2249
|
+
function declaresMemoryHandle(def) {
|
|
2250
|
+
return (def?.handleConfiguration ?? []).some((g) => (g?.handles ?? []).some((h) => h?.id === 'memory'));
|
|
2251
|
+
}
|
|
2252
|
+
/**
|
|
2253
|
+
* The definition for the INLINE autonomous agent: the bundled pair for
|
|
2254
|
+
* `version` (the newest by default), plus an explicit overlay of the details
|
|
2255
|
+
* the registry payload does not carry.
|
|
2256
|
+
*
|
|
2257
|
+
* This is the one node type in the agent family that is the SAME on every
|
|
2258
|
+
* tenant — it carries its own configuration instead of referencing a resource —
|
|
2259
|
+
* so `uip maestro flow registry get uipath.agent.autonomous` is a direct oracle
|
|
2260
|
+
* and the bundle entry is the registry's definition as last synced
|
|
2261
|
+
* (`sync:definitions` writes it through unchanged; `check:definitions --deep`
|
|
2262
|
+
* reports content that has moved since). Versions and content both come from
|
|
2263
|
+
* there.
|
|
2264
|
+
*
|
|
2265
|
+
* The overlay, and nothing else:
|
|
2266
|
+
*
|
|
2267
|
+
* * `outputDefinition.output.source` is `=result.response`. The registry's
|
|
2268
|
+
* definition declares no `source`; the deployed corpus (29 `uipath.agent.autonomous` nodes, 05-18 → 07-29) has
|
|
2269
|
+
* `=result.response` in 27 of 27 that declare outputs, and the engine's own
|
|
2270
|
+
* inline dispatch returns `{ response: { …declared keys } }`. Without it the
|
|
2271
|
+
* node's `output` is the whole result envelope rather than the declared keys.
|
|
2272
|
+
* It is applied at every version; the registry payload has no `source`.
|
|
2273
|
+
* * The `memory` handle is kept only when the flow attaches memory. It is
|
|
2274
|
+
* LOCAL content (#431) on the bundled 1.4, absent from the registry's 1.4
|
|
2275
|
+
* (`check.ts` AGENT_MEMORY_NOT_AUTHORABLE), so an agent without memory gets
|
|
2276
|
+
* the registry's handle set.
|
|
2277
|
+
*
|
|
2278
|
+
* NO per-instance schema goes on the definition: `definitions[]` is keyed by
|
|
2279
|
+
* node TYPE, and every inline agent in a flow shares this one entry. A flow
|
|
2280
|
+
* with two agents (an analyst and a writer, say) therefore cannot have both
|
|
2281
|
+
* contracts here — whichever was emitted last would win, and every read against
|
|
2282
|
+
* the other resolved to the wrong shape (GA row 7's port: 25 undeclared-field
|
|
2283
|
+
* errors on a correct flow). The authored contract goes on the NODE
|
|
2284
|
+
* (`node.outputs.output.schema`, in the `inlineAgent` arm), where a reader that
|
|
2285
|
+
* refines per node picks it up.
|
|
2286
|
+
*
|
|
2287
|
+
* The bundled 1.2 is the pre-#956 default, kept so a flow this SDK compiled
|
|
2288
|
+
* before — and a decompile of one, which pins `{ version: '1.2' }` — still
|
|
2289
|
+
* compiles. The corpus also carries 1.1 and 1.3; `shared/sample-flows/
|
|
2290
|
+
* inline-agent.flow` says 1.0, which appears in none of the 29.
|
|
2291
|
+
*/
|
|
2292
|
+
function inlineAgentDef(version, withMemory) {
|
|
2293
|
+
const bundled = DEFS[`${INLINE_AGENT_TYPE}@${version}`];
|
|
2294
|
+
if (!bundled)
|
|
2295
|
+
return undefined;
|
|
2296
|
+
const def = clone(bundled);
|
|
2297
|
+
const output = def.outputDefinition?.output;
|
|
2298
|
+
if (output)
|
|
2299
|
+
output.source = '=result.response';
|
|
2300
|
+
if (!withMemory) {
|
|
2301
|
+
for (const group of def.handleConfiguration ?? []) {
|
|
2302
|
+
if (Array.isArray(group?.handles))
|
|
2303
|
+
group.handles = group.handles.filter((h) => h?.id !== 'memory');
|
|
2304
|
+
}
|
|
2305
|
+
def.handleConfiguration = (def.handleConfiguration ?? []).filter((g) => g?.handles?.length);
|
|
2306
|
+
}
|
|
2307
|
+
return def;
|
|
2314
2308
|
}
|
|
2315
2309
|
/**
|
|
2316
2310
|
* Classify a RENDERED input value (the output of {@link renderValue}).
|
|
@@ -3934,7 +3928,7 @@ function describeDeclared(bindings) {
|
|
|
3934
3928
|
* exactly (design §2.6/§4.2): the named version resolves or compilation fails,
|
|
3935
3929
|
* and a contributor that ignored the author's requested version is rejected.
|
|
3936
3930
|
*/
|
|
3937
|
-
function resolveContributionDefinition(ref, requestedVersion, where) {
|
|
3931
|
+
export function resolveContributionDefinition(ref, requestedVersion, where) {
|
|
3938
3932
|
if (!ref || typeof ref.nodeType !== 'string' || !ref.nodeType || typeof ref.version !== 'string' || !ref.version) {
|
|
3939
3933
|
throw new Error(`${where}: contribute() returned a DefinitionReference without an exact nodeType + version.`);
|
|
3940
3934
|
}
|
|
@@ -4419,10 +4413,16 @@ function typeAgentInputSchemas(scope, globals) {
|
|
|
4419
4413
|
if (g.direction === 'in' && g.triggerNodeId)
|
|
4420
4414
|
lookup.set(`${g.triggerNodeId}.output.${g.id}`, { type: g.type, schema: g.schema });
|
|
4421
4415
|
}
|
|
4422
|
-
for (const {
|
|
4416
|
+
for (const { schema, refs } of scope.agentSchemas) {
|
|
4423
4417
|
for (const r of refs) {
|
|
4424
|
-
properties[r.flatName] = jsonSchemaForRef(r.binding, lookup);
|
|
4418
|
+
schema.properties[r.flatName] = jsonSchemaForRef(r.binding, lookup);
|
|
4425
4419
|
}
|
|
4420
|
+
// A file property is a `$ref`, and a `$ref` resolves against THIS schema's
|
|
4421
|
+
// `definitions` — so the block is added exactly when a file property is
|
|
4422
|
+
// present (a schema with no file keeps the shape it always had).
|
|
4423
|
+
const hasFile = Object.values(schema.properties).some((p) => p?.$ref === JOB_ATTACHMENT_REF);
|
|
4424
|
+
if (hasFile)
|
|
4425
|
+
schema.definitions = { ...schema.definitions, 'job-attachment': jobAttachmentDefinition() };
|
|
4426
4426
|
}
|
|
4427
4427
|
}
|
|
4428
4428
|
/** One property's schema — `{}` when the type cannot be established. See {@link typeAgentInputSchemas}. */
|
|
@@ -4512,17 +4512,58 @@ function walkSchemaType(schema, segments) {
|
|
|
4512
4512
|
}
|
|
4513
4513
|
return typeof current?.type === 'string' ? current.type : undefined;
|
|
4514
4514
|
}
|
|
4515
|
-
/**
|
|
4515
|
+
/**
|
|
4516
|
+
* A resolved type → its JSON-Schema property.
|
|
4517
|
+
*
|
|
4518
|
+
* Every type a flow can DECLARE (`types.*`) has its own case, and the switch is
|
|
4519
|
+
* exhaustive over {@link TypeDesc}: adding a type to `types` without deciding
|
|
4520
|
+
* what an agent sees for it is a compile error here, not a silent `{}`.
|
|
4521
|
+
*
|
|
4522
|
+
* `file` → `{ $ref: '#/definitions/job-attachment' }`; the caller adds the
|
|
4523
|
+
* definition (see `typeAgentInputSchemas`).
|
|
4524
|
+
*
|
|
4525
|
+
* Typeless `{}` is the answer for `any` and for "unknown" (`undefined`,
|
|
4526
|
+
* or a type string from a node definition that is not in the SDK's
|
|
4527
|
+
* vocabulary): that is v1's own rule for a type it cannot establish
|
|
4528
|
+
* (`buildAgentInputTypeResolver` → `'any'` → a property with no `type`), and it
|
|
4529
|
+
* keeps the runtime's pydantic model from refusing a value the SDK only
|
|
4530
|
+
* guessed at.
|
|
4531
|
+
*/
|
|
4516
4532
|
function jsonSchemaForType(type) {
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
// sidecar does not carry.)
|
|
4521
|
-
if (!type || type === 'any' || type === 'file' || type === 'octet-stream')
|
|
4533
|
+
if (type === 'octet-stream')
|
|
4534
|
+
return { $ref: JOB_ATTACHMENT_REF }; // v1's alias for file
|
|
4535
|
+
if (type === undefined || !isTypeDesc(type))
|
|
4522
4536
|
return {};
|
|
4523
|
-
|
|
4524
|
-
return {
|
|
4525
|
-
|
|
4537
|
+
switch (type) {
|
|
4538
|
+
case 'file': return { $ref: JOB_ATTACHMENT_REF };
|
|
4539
|
+
case 'any': return {};
|
|
4540
|
+
// A bare `type: 'array'` makes the runtime's `jsonschema_to_pydantic`
|
|
4541
|
+
// reject a valid array (v1's note at `uipath.ts:118-123`, MST-9544).
|
|
4542
|
+
case 'array': return { type: 'array', items: {} };
|
|
4543
|
+
case 'string':
|
|
4544
|
+
case 'number':
|
|
4545
|
+
case 'integer':
|
|
4546
|
+
case 'boolean':
|
|
4547
|
+
case 'object':
|
|
4548
|
+
return { type };
|
|
4549
|
+
// The case vocabulary's widths and date kinds, as JSON Schema spells them
|
|
4550
|
+
// (the same table `case/entry-points.ts` projects with).
|
|
4551
|
+
case 'float': return { type: 'number', format: 'float' };
|
|
4552
|
+
case 'double': return { type: 'number', format: 'double' };
|
|
4553
|
+
case 'date': return { type: 'string', format: 'date' };
|
|
4554
|
+
case 'datetime': return { type: 'string', format: 'date-time' };
|
|
4555
|
+
// A case `jsonSchema` variable's shape lives in its `body`, which this
|
|
4556
|
+
// lookup does not carry — so its type is not established here.
|
|
4557
|
+
case 'jsonSchema': return {};
|
|
4558
|
+
default: {
|
|
4559
|
+
const unmapped = type;
|
|
4560
|
+
throw new Error(`jsonSchemaForType: no agent schema mapping for type '${String(unmapped)}'`);
|
|
4561
|
+
}
|
|
4562
|
+
}
|
|
4563
|
+
}
|
|
4564
|
+
const TYPE_DESCS = new Set(Object.values(types));
|
|
4565
|
+
function isTypeDesc(type) {
|
|
4566
|
+
return TYPE_DESCS.has(type);
|
|
4526
4567
|
}
|
|
4527
4568
|
/**
|
|
4528
4569
|
* An End node's `outputs` map: every variable this scope exposes as a flow
|
|
@@ -4638,6 +4679,61 @@ export function serialize(built, opts = {}) {
|
|
|
4638
4679
|
* A bindings entry the node does not reference is not a bound resource.
|
|
4639
4680
|
*/
|
|
4640
4681
|
const resourceBindings = new Map();
|
|
4682
|
+
/**
|
|
4683
|
+
* Hoist a contribution's own bindings, then close every `<bindings.NAME>` its
|
|
4684
|
+
* definition references and it did not supply, from the definition's own
|
|
4685
|
+
* `model.bindings` (flow-builder-sdk#942). Shared by the three contribution
|
|
4686
|
+
* sites (step, trigger, entry point), so a `rawNode` and a hand-written
|
|
4687
|
+
* subclass get the same entries a typed emitter would. `check` runs the same
|
|
4688
|
+
* plan dry (`checkContribution` in `check.ts`), so it reports what this throws.
|
|
4689
|
+
*/
|
|
4690
|
+
function hoistContributionBindings(def, supplied, where) {
|
|
4691
|
+
for (const b of supplied ?? [])
|
|
4692
|
+
resourceBindings.set(b.id, b);
|
|
4693
|
+
const plan = planContributionBindings(def, supplied);
|
|
4694
|
+
if (plan.problems.length) {
|
|
4695
|
+
throw new BindingRefusal('CONTRIBUTION_BINDING_UNRESOLVED', `${where}: ${plan.problems.join(' ')}`);
|
|
4696
|
+
}
|
|
4697
|
+
if (plan.entries.length === 0)
|
|
4698
|
+
return;
|
|
4699
|
+
// A process reference is the name + folderPath pair every typed process step
|
|
4700
|
+
// emits: go through the same builder, so a raw node and a typed step on ONE
|
|
4701
|
+
// process share one pair instead of shadowing each other.
|
|
4702
|
+
const byName = new Map(plan.entries.map((e) => [e.name, e]));
|
|
4703
|
+
const pairName = byName.get('name');
|
|
4704
|
+
const pairFolder = byName.get('folderPath');
|
|
4705
|
+
if (plan.resource === 'process' && plan.entries.length === 2 && pairName?.propertyAttribute === 'name'
|
|
4706
|
+
&& pairFolder?.propertyAttribute === 'folderPath' && pairName.default !== undefined
|
|
4707
|
+
&& pairFolder.default !== undefined) {
|
|
4708
|
+
const { entries } = processResourceBindings({
|
|
4709
|
+
name: pairName.default,
|
|
4710
|
+
folderPath: pairFolder.default,
|
|
4711
|
+
resourceSubType: pairName.resourceSubType,
|
|
4712
|
+
resourceKey: plan.resourceKey,
|
|
4713
|
+
}, resourceBindings);
|
|
4714
|
+
for (const b of entries) {
|
|
4715
|
+
// processResourceBindings types the subtype to the families it knows; keep
|
|
4716
|
+
// the definition's own spelling (or none) verbatim.
|
|
4717
|
+
if (pairName.resourceSubType === undefined)
|
|
4718
|
+
delete b.resourceSubType;
|
|
4719
|
+
resourceBindings.set(b.id, b);
|
|
4720
|
+
}
|
|
4721
|
+
return;
|
|
4722
|
+
}
|
|
4723
|
+
for (const e of plan.entries) {
|
|
4724
|
+
const same = [...resourceBindings.values()].some((b) => b.resource === e.resource
|
|
4725
|
+
&& b.resourceKey === e.resourceKey && b.name === e.name && b.propertyAttribute === e.propertyAttribute);
|
|
4726
|
+
if (same)
|
|
4727
|
+
continue;
|
|
4728
|
+
const slug = e.resourceKey.replace(/[^A-Za-z0-9]/g, '') || 'Resource';
|
|
4729
|
+
const cap = (t) => t.charAt(0).toUpperCase() + t.slice(1);
|
|
4730
|
+
const stem = `b${cap(slug)}${cap(e.name.replace(/[^A-Za-z0-9]/g, ''))}`;
|
|
4731
|
+
let id = stem;
|
|
4732
|
+
for (let n = 2; resourceBindings.has(id); n++)
|
|
4733
|
+
id = `${stem}${n}`;
|
|
4734
|
+
resourceBindings.set(id, { id, ...e });
|
|
4735
|
+
}
|
|
4736
|
+
}
|
|
4641
4737
|
/**
|
|
4642
4738
|
* Extra files the flow needs beside the `.flow` — see `SerializeOpts.sidecars`.
|
|
4643
4739
|
* Written into the caller's array when one was passed, so a caller that wants them
|
|
@@ -4733,13 +4829,15 @@ export function serialize(built, opts = {}) {
|
|
|
4733
4829
|
* (design §2.6): resolution is exact — `<type>@<version>` from the bundle, or
|
|
4734
4830
|
* the version of the definition already in hand — and a version the SDK
|
|
4735
4831
|
* cannot resolve exactly fails compilation rather than floating to a default.
|
|
4832
|
+
* An undefined `label` takes the definition's `display.label`, which is what
|
|
4833
|
+
* the canvas shows on a freshly dropped node.
|
|
4736
4834
|
*/
|
|
4737
4835
|
function makeNode(type, id, label, o = {}) {
|
|
4738
4836
|
let def = o.def ?? defByType.get(type);
|
|
4739
4837
|
if (o.requestedVersion !== undefined && def?.version !== o.requestedVersion) {
|
|
4740
4838
|
const exact = o.def ? undefined : DEFS[`${type}@${o.requestedVersion}`];
|
|
4741
4839
|
if (!exact) {
|
|
4742
|
-
throw new Error(`"${label}" requests ${type}@${o.requestedVersion}, but this SDK resolves only `
|
|
4840
|
+
throw new Error(`"${label ?? id}" requests ${type}@${o.requestedVersion}, but this SDK resolves only `
|
|
4743
4841
|
+ `${type}@${def?.version ?? '<none>'}. Versions are exact — omit { version } to use `
|
|
4744
4842
|
+ `the pinned default, or request a version this SDK ships.`);
|
|
4745
4843
|
}
|
|
@@ -4752,7 +4850,7 @@ export function serialize(built, opts = {}) {
|
|
|
4752
4850
|
type,
|
|
4753
4851
|
typeVersion: def?.version ?? '1.0.0',
|
|
4754
4852
|
ui: { position: { x: 256 + col * 288, y: 144 + (o.parentId ? 160 : 0) }, size: { width: 96, height: 96 }, collapsed: false },
|
|
4755
|
-
display: { label, ...(def?.display?.icon ? { icon: def.display.icon } : {}) },
|
|
4853
|
+
display: { label: label ?? def?.display?.label ?? id, ...(def?.display?.icon ? { icon: def.display.icon } : {}) },
|
|
4756
4854
|
};
|
|
4757
4855
|
col++;
|
|
4758
4856
|
// A Data Fabric node gets no node-level `model`, whichever path emits it
|
|
@@ -4876,7 +4974,7 @@ export function serialize(built, opts = {}) {
|
|
|
4876
4974
|
if (customTrigger) {
|
|
4877
4975
|
const contribution = customTrigger.contribute(built.triggerOptions?.version !== undefined ? { requestedVersion: built.triggerOptions.version } : {});
|
|
4878
4976
|
const def = resolveContributionDefinition(contribution.definition, built.triggerOptions?.version, 'trigger');
|
|
4879
|
-
const node = makeNode(def.nodeType, triggerId, def.display?.label ?? 'Start', { def, requestedVersion: built.triggerOptions?.version });
|
|
4977
|
+
const node = makeNode(def.nodeType, triggerId, built.triggerOptions?.label ?? def.display?.label ?? 'Start', { def, requestedVersion: built.triggerOptions?.version });
|
|
4880
4978
|
const inputs = renderDeep(contribution.inputs ?? {}, NO_RENAME);
|
|
4881
4979
|
if (def.model?.entryPointId === true && inputs.entryPointId === undefined) {
|
|
4882
4980
|
inputs.entryPointId = stableId(`${built.id}:start:entryPoint`);
|
|
@@ -4884,25 +4982,26 @@ export function serialize(built, opts = {}) {
|
|
|
4884
4982
|
inputs.isDefaultEntryPoint = true;
|
|
4885
4983
|
}
|
|
4886
4984
|
node.inputs = inputs;
|
|
4887
|
-
|
|
4888
|
-
resourceBindings.set(b.id, b);
|
|
4985
|
+
hoistContributionBindings(def, contribution.bindings, 'trigger');
|
|
4889
4986
|
root.nodes.push(node);
|
|
4890
4987
|
}
|
|
4988
|
+
// The author's `.trigger(spec, { label })`; makeNode falls back to the definition's label.
|
|
4989
|
+
const rootLabel = built.triggerOptions?.label;
|
|
4891
4990
|
const trigger = customTrigger
|
|
4892
4991
|
? root.nodes[root.nodes.length - 1]
|
|
4893
4992
|
: eventTriggerRc
|
|
4894
|
-
? makeNode(eventTriggerRc.nodeType, triggerId,
|
|
4993
|
+
? makeNode(eventTriggerRc.nodeType, triggerId, rootLabel, { def: eventTriggerRc.v1def, requestedVersion: built.triggerOptions?.version })
|
|
4895
4994
|
: built.trigger?.kind === 'scheduled'
|
|
4896
|
-
? makeNode(NODE_TYPE.scheduledTrigger, triggerId,
|
|
4995
|
+
? makeNode(NODE_TYPE.scheduledTrigger, triggerId, rootLabel, {
|
|
4897
4996
|
requestedVersion: scheduledVersion(built.trigger.inputs, built.triggerOptions?.version),
|
|
4898
4997
|
})
|
|
4899
4998
|
: built.trigger?.kind === 'form'
|
|
4900
|
-
? makeNode(NODE_TYPE.formTrigger, triggerId,
|
|
4999
|
+
? makeNode(NODE_TYPE.formTrigger, triggerId, rootLabel, { requestedVersion: built.triggerOptions?.version })
|
|
4901
5000
|
: built.trigger?.kind === 'conversation'
|
|
4902
|
-
? makeNode(NODE_TYPE.conversationTrigger, triggerId,
|
|
5001
|
+
? makeNode(NODE_TYPE.conversationTrigger, triggerId, rootLabel, { requestedVersion: built.triggerOptions?.version })
|
|
4903
5002
|
: built.trigger?.kind === 'voice'
|
|
4904
|
-
? makeNode(NODE_TYPE.voiceTrigger, triggerId,
|
|
4905
|
-
: makeNode(NODE_TYPE.trigger, triggerId,
|
|
5003
|
+
? makeNode(NODE_TYPE.voiceTrigger, triggerId, rootLabel, { requestedVersion: built.triggerOptions?.version })
|
|
5004
|
+
: makeNode(NODE_TYPE.trigger, triggerId, rootLabel, { requestedVersion: built.triggerOptions?.version });
|
|
4906
5005
|
if (!customTrigger) {
|
|
4907
5006
|
trigger.inputs = eventTriggerRc && built.trigger?.kind === 'event'
|
|
4908
5007
|
? {
|
|
@@ -5020,8 +5119,7 @@ export function serialize(built, opts = {}) {
|
|
|
5020
5119
|
if (contribution.outputs) {
|
|
5021
5120
|
node.outputs = { ...(node.outputs ?? {}), ...subNodeId(clone(contribution.outputs), id) };
|
|
5022
5121
|
}
|
|
5023
|
-
|
|
5024
|
-
resourceBindings.set(b.id, b);
|
|
5122
|
+
hoistContributionBindings(def, contribution.bindings, where);
|
|
5025
5123
|
scope.nodes.push(node);
|
|
5026
5124
|
for (const t of tails)
|
|
5027
5125
|
addEdge(scope, t, id);
|
|
@@ -5179,16 +5277,30 @@ export function serialize(built, opts = {}) {
|
|
|
5179
5277
|
// required: it is what the platform scaffolds, so a flow that reads
|
|
5180
5278
|
// `content` is a real (if toy) flow. `check` says so.
|
|
5181
5279
|
: { content: 'string' };
|
|
5182
|
-
//
|
|
5183
|
-
//
|
|
5184
|
-
//
|
|
5185
|
-
//
|
|
5186
|
-
//
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5280
|
+
// ONE default version for every call shape — the newest bundled pair (see
|
|
5281
|
+
// `inlineAgentDef`). `mode` and `memory` used to pick the version too (1.3
|
|
5282
|
+
// and 1.4), so a plain agent got a superseded 1.2 and each option moved
|
|
5283
|
+
// the node to another version as a side effect (#956). Both now live in
|
|
5284
|
+
// the sidecar and on edges; neither selects a definition. An explicit
|
|
5285
|
+
// `{ version }` (what decompile writes back) resolves exactly.
|
|
5286
|
+
const version = step.options?.version ?? INLINE_AGENT_DEFAULT_VERSION;
|
|
5287
|
+
// `definitions[]` holds one entry per type@version, so a flow where any
|
|
5288
|
+
// agent attaches memory keeps the handle for all of them.
|
|
5289
|
+
const withMemory = s.memory !== undefined
|
|
5290
|
+
|| declaresMemoryHandle(emittedDefs.get(`${INLINE_AGENT_TYPE}@${version}`));
|
|
5291
|
+
const def = inlineAgentDef(version, withMemory);
|
|
5292
|
+
if (!def) {
|
|
5293
|
+
throw new Error(`"${step.name}" requests ${INLINE_AGENT_TYPE}@${version}, but this SDK resolves only `
|
|
5294
|
+
+ `${INLINE_AGENT_VERSIONS.map((v) => `${INLINE_AGENT_TYPE}@${v}`).join(', ')}. Versions are exact — `
|
|
5295
|
+
+ `omit { version } to use the default (${INLINE_AGENT_DEFAULT_VERSION}), or request a version this SDK ships.`);
|
|
5296
|
+
}
|
|
5297
|
+
if (s.memory !== undefined && !declaresMemoryHandle(def)) {
|
|
5298
|
+
throw new Error(`"${step.name}" attaches \`memory\`, but ${INLINE_AGENT_TYPE}@${version} declares no \`memory\` handle. `
|
|
5299
|
+
+ (version === INLINE_AGENT_DEFAULT_VERSION
|
|
5300
|
+
? `Pin a version that has it with inlineAgent({ ..., version: '<x.y>' }) `
|
|
5301
|
+
+ `(bundled with memory: ${INLINE_AGENT_VERSIONS.filter((v) => declaresMemoryHandle(DEFS[`${INLINE_AGENT_TYPE}@${v}`])).join(', ') || 'none'}), or drop \`memory\`.`
|
|
5302
|
+
: `Drop { version: '${version}' } to use ${INLINE_AGENT_DEFAULT_VERSION}, or drop \`memory\`.`));
|
|
5303
|
+
}
|
|
5192
5304
|
const id = stepUid(scope, step.name);
|
|
5193
5305
|
// `source` is the agent's directory name. Derived from the flow id + step
|
|
5194
5306
|
// name rather than random so a recompile is byte-identical — a v4-shaped uuid
|
|
@@ -5277,7 +5389,7 @@ export function serialize(built, opts = {}) {
|
|
|
5277
5389
|
// The schema's property TYPES need this scope's finished variables, which
|
|
5278
5390
|
// do not exist yet — park them (the `properties` object is filled in
|
|
5279
5391
|
// place when the scope closes). See `typeAgentInputSchemas`.
|
|
5280
|
-
scope.agentSchemas.push({
|
|
5392
|
+
scope.agentSchemas.push({ schema: agentJson.inputSchema, refs: plan.refs });
|
|
5281
5393
|
// GROUNDING — one resource node per context index, joined to the agent's own
|
|
5282
5394
|
// `context` handle. An ARTIFACT, not a step: it takes no incoming control
|
|
5283
5395
|
// flow, produces no output, and never reaches the End node. The edge runs OUT
|
|
@@ -5626,7 +5738,7 @@ export function serialize(built, opts = {}) {
|
|
|
5626
5738
|
name: app.name,
|
|
5627
5739
|
appName: app.name,
|
|
5628
5740
|
displayName: app.name,
|
|
5629
|
-
folderPath: app
|
|
5741
|
+
folderPath: escalationAppFolder(app),
|
|
5630
5742
|
inputSchema: fieldSchema(app.inputs),
|
|
5631
5743
|
outputSchema: fieldSchema(app.outputs),
|
|
5632
5744
|
},
|
|
@@ -5693,21 +5805,28 @@ export function serialize(built, opts = {}) {
|
|
|
5693
5805
|
// downstream in the engine.
|
|
5694
5806
|
const s = spec.inputs;
|
|
5695
5807
|
const nodeInputs = s.inputs ?? {};
|
|
5696
|
-
const subType = spec.kind === 'apiWorkflow' ? 'Api'
|
|
5697
|
-
: spec.kind === 'agenticProcess' ? 'ProcessOrchestration'
|
|
5698
|
-
: spec.kind === 'publishedFunction' ? 'Function'
|
|
5699
|
-
: 'Process';
|
|
5700
5808
|
const fireAndForget = spec.kind === 'agenticProcess' && spec.inputs.completion === 'fire-and-forget';
|
|
5701
5809
|
const def = spec.kind === 'publishedFunction'
|
|
5702
|
-
? publishedFunctionDef({ key: spec.inputs.key, name: s.name, folderPath:
|
|
5810
|
+
? publishedFunctionDef({ key: spec.inputs.key, name: s.name, folderPath: spec.inputs.folderPath, inputs: nodeInputs, returns: spec.inputs.returns })
|
|
5703
5811
|
: spec.kind === 'apiWorkflow'
|
|
5704
|
-
? apiWorkflowDef({ key: spec.inputs.key, name: s.name, folderPath:
|
|
5812
|
+
? apiWorkflowDef({ key: spec.inputs.key, name: s.name, folderPath: spec.inputs.folderPath, inputs: nodeInputs, returns: spec.inputs.returns })
|
|
5705
5813
|
: spec.kind === 'agenticProcess'
|
|
5706
|
-
? agenticProcessDef({
|
|
5707
|
-
|
|
5814
|
+
? agenticProcessDef({
|
|
5815
|
+
key: spec.inputs.key, name: s.name, folderPath: s.folderPath, location: spec.inputs.location,
|
|
5816
|
+
projectId: spec.inputs.projectId, inputs: nodeInputs, returns: spec.inputs.returns, form: spec.inputs.form,
|
|
5817
|
+
})
|
|
5818
|
+
: rpaWorkflowDef({
|
|
5819
|
+
key: spec.inputs.key, name: s.name, folderPath: s.folderPath, location: spec.inputs.location,
|
|
5820
|
+
projectId: spec.inputs.projectId, inputs: nodeInputs, returns: spec.inputs.returns,
|
|
5821
|
+
});
|
|
5708
5822
|
// The bindings first: two steps on the same process share ONE pair, and the
|
|
5709
5823
|
// definition's `model.context` names ids that have to exist.
|
|
5710
|
-
|
|
5824
|
+
// Read off the definition: one kind carries several subtypes (agenticProcess by `form`).
|
|
5825
|
+
// The pair's key and folder come off it too: an in-solution step's resourceKey is the
|
|
5826
|
+
// bare sibling key and its folder is `''`.
|
|
5827
|
+
const subType = def.model.bindings.resourceSubType;
|
|
5828
|
+
const pairFolder = def.model.bindings.values.find((v) => v.name === 'folderPath').default;
|
|
5829
|
+
const { entries } = processResourceBindings({ name: s.name, folderPath: pairFolder, resourceSubType: subType, resourceKey: def.model.bindings.resourceKey }, resourceBindings);
|
|
5711
5830
|
for (const b of entries)
|
|
5712
5831
|
resourceBindings.set(b.id, b);
|
|
5713
5832
|
const id = stepUid(scope, step.name);
|
|
@@ -5917,7 +6036,7 @@ export function serialize(built, opts = {}) {
|
|
|
5917
6036
|
});
|
|
5918
6037
|
if (plan.refs.length > 0) {
|
|
5919
6038
|
const agentJson = sidecars[sidecars.length - 1].json;
|
|
5920
|
-
scope.agentSchemas.push({
|
|
6039
|
+
scope.agentSchemas.push({ schema: agentJson.inputSchema, refs: plan.refs });
|
|
5921
6040
|
}
|
|
5922
6041
|
for (const t of tails)
|
|
5923
6042
|
addEdge(scope, t, id);
|
|
@@ -6885,19 +7004,20 @@ export function serialize(built, opts = {}) {
|
|
|
6885
7004
|
takenIds.add(ep.id);
|
|
6886
7005
|
const spec = ep.trigger;
|
|
6887
7006
|
const requestedVersion = ep.options?.version;
|
|
7007
|
+
// The author's label; makeNode falls back to the definition's label.
|
|
7008
|
+
const epLabel = ep.options?.label;
|
|
6888
7009
|
const customEp = spec instanceof FlowTrigger && !('kind' in spec) ? spec : undefined;
|
|
6889
7010
|
const epSpec = spec;
|
|
6890
7011
|
let node;
|
|
6891
7012
|
if (customEp) {
|
|
6892
7013
|
const contribution = customEp.contribute(requestedVersion !== undefined ? { requestedVersion } : {});
|
|
6893
7014
|
const def = resolveContributionDefinition(contribution.definition, requestedVersion, `entryPoint "${ep.id}"`);
|
|
6894
|
-
node = makeNode(def.nodeType, ep.id, def.display?.label ?? ep.id, { def, requestedVersion });
|
|
7015
|
+
node = makeNode(def.nodeType, ep.id, ep.options?.label ?? def.display?.label ?? ep.id, { def, requestedVersion });
|
|
6895
7016
|
node.inputs = {
|
|
6896
7017
|
entryPointId: stableId(`${built.id}:${ep.id}:entryPoint`),
|
|
6897
7018
|
...renderDeep(contribution.inputs ?? {}, NO_RENAME),
|
|
6898
7019
|
};
|
|
6899
|
-
|
|
6900
|
-
resourceBindings.set(b.id, b);
|
|
7020
|
+
hoistContributionBindings(def, contribution.bindings, `entryPoint "${ep.id}"`);
|
|
6901
7021
|
}
|
|
6902
7022
|
else if (epSpec.kind === 'event') {
|
|
6903
7023
|
if (!opts.library)
|
|
@@ -6905,7 +7025,7 @@ export function serialize(built, opts = {}) {
|
|
|
6905
7025
|
const sub = epSpec.subscription;
|
|
6906
7026
|
const rc = opts.library.resolveEvent('trigger', sub.connector, sub.event, sub.version, sub.object);
|
|
6907
7027
|
refuseUnverifiedByoa(opts, 'trigger', sub);
|
|
6908
|
-
node = makeNode(rc.nodeType, ep.id,
|
|
7028
|
+
node = makeNode(rc.nodeType, ep.id, epLabel, { def: rc.v1def, requestedVersion });
|
|
6909
7029
|
node.inputs = {
|
|
6910
7030
|
entryPointId: stableId(`${built.id}:${ep.id}:entryPoint`),
|
|
6911
7031
|
detail: eventDetail(rc, sub, ep.id, opts, `onEvent() entry point "${ep.id}"`),
|
|
@@ -6920,7 +7040,7 @@ export function serialize(built, opts = {}) {
|
|
|
6920
7040
|
resourceBindings.set(b.id, b);
|
|
6921
7041
|
}
|
|
6922
7042
|
else if (epSpec.kind === 'scheduled') {
|
|
6923
|
-
node = makeNode(NODE_TYPE.scheduledTrigger, ep.id,
|
|
7043
|
+
node = makeNode(NODE_TYPE.scheduledTrigger, ep.id, epLabel, {
|
|
6924
7044
|
requestedVersion: scheduledVersion(epSpec.inputs, requestedVersion),
|
|
6925
7045
|
});
|
|
6926
7046
|
node.inputs = {
|
|
@@ -6929,22 +7049,22 @@ export function serialize(built, opts = {}) {
|
|
|
6929
7049
|
};
|
|
6930
7050
|
}
|
|
6931
7051
|
else if (epSpec.kind === 'form') {
|
|
6932
|
-
node = makeNode(NODE_TYPE.formTrigger, ep.id,
|
|
7052
|
+
node = makeNode(NODE_TYPE.formTrigger, ep.id, epLabel, { requestedVersion });
|
|
6933
7053
|
node.inputs = {
|
|
6934
7054
|
entryPointId: stableId(`${built.id}:${ep.id}:entryPoint`),
|
|
6935
7055
|
schema: { fields: formTriggerFields(ep.inputs), outcomes: [] },
|
|
6936
7056
|
};
|
|
6937
7057
|
}
|
|
6938
7058
|
else if (epSpec.kind === 'conversation') {
|
|
6939
|
-
node = makeNode(NODE_TYPE.conversationTrigger, ep.id,
|
|
7059
|
+
node = makeNode(NODE_TYPE.conversationTrigger, ep.id, epLabel, { requestedVersion });
|
|
6940
7060
|
node.inputs = { entryPointId: stableId(`${built.id}:${ep.id}:entryPoint`) };
|
|
6941
7061
|
}
|
|
6942
7062
|
else if (epSpec.kind === 'voice') {
|
|
6943
|
-
node = makeNode(NODE_TYPE.voiceTrigger, ep.id,
|
|
7063
|
+
node = makeNode(NODE_TYPE.voiceTrigger, ep.id, epLabel, { requestedVersion });
|
|
6944
7064
|
node.inputs = { entryPointId: stableId(`${built.id}:${ep.id}:entryPoint`) };
|
|
6945
7065
|
}
|
|
6946
7066
|
else if (epSpec.kind === 'manual') {
|
|
6947
|
-
node = makeNode(NODE_TYPE.trigger, ep.id,
|
|
7067
|
+
node = makeNode(NODE_TYPE.trigger, ep.id, epLabel, { requestedVersion });
|
|
6948
7068
|
node.inputs = { entryPointId: stableId(`${built.id}:${ep.id}:entryPoint`) };
|
|
6949
7069
|
}
|
|
6950
7070
|
else {
|