@uipath/maestro-builder-sdk 6.15.6 → 6.16.1

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/serialize.js CHANGED
@@ -45,7 +45,7 @@ import { declaredScriptShape, inferScriptShape } from './core/script-return.js';
45
45
  import { migrateToSchemaVersion } from './migrate.js';
46
46
  import { FLOW_SCHEMA_VERSIONS } from './format-profile.js';
47
47
  import { resolveSchemaVersion } from './schema-version.js';
48
- import { planFlowGlobals } from './flow-variables.js';
48
+ import { planFlowGlobals, planSharedInputs, sharedInputRoots } from './flow-variables.js';
49
49
  import { prepareCommand } from './core/cli-spelling.js';
50
50
  import { QUEUE_ITEM_RECORD_SCHEMA } from './core/queue-record.js';
51
51
  const HERE = dirname(fileURLToPath(import.meta.url));
@@ -1002,8 +1002,10 @@ const TOOL_RESOURCE_TYPE = {
1002
1002
  * and the file is the one `uip agent refresh` itself derives from it.
1003
1003
  * * `mcp`, `a2a` — need the server's `availableTools` and the remote agent's
1004
1004
  * card, which are tenant reads.
1005
- * * `builtin`, `httpRequest` — need a `properties.toolType` that maps
1006
- * one-to-one for `batchtransform` alone; a wrong one selects a different tool.
1005
+ * * `builtin` — has its own writer, {@link builtinToolResourceJson}: its
1006
+ * `toolType` is a fixed per-tool constant, so the file is derivable offline.
1007
+ * * `httpRequest` — its `http-request` toolType carries no request config in
1008
+ * the file, while the node carries all of it; not measured, so not written.
1007
1009
  */
1008
1010
  function toolResourceJson(tr, spec) {
1009
1011
  const common = {
@@ -1047,6 +1049,153 @@ function toolResourceJson(tr, spec) {
1047
1049
  }
1048
1050
  return undefined;
1049
1051
  }
1052
+ /**
1053
+ * The `properties.toolType` each platform built-in tool carries in the agent
1054
+ * project. Neither the node type nor the label: `analyzefiles` is the
1055
+ * designer's "Analyze Files" and its resource is `analyze-attachments`;
1056
+ * `summarize` is the designer's DeepRAG node (`manifest_node_deepRag_display_label:
1057
+ * "Summarize"` in the vendored workbench strings) and its resource is `deep-rag`.
1058
+ * Read off the platform's `builtInToolPropertiesSchemaV40` discriminated union
1059
+ * (vendored `flow-to-bpmn.mjs`), which also lists `load-attachments` and
1060
+ * `http-request`, and the uipath-agents skill's built-in-tools reference, which
1061
+ * owns the file's body. The runtime ignores an unknown toolType silently, so
1062
+ * this table is the whole contract — one that is wrong selects no tool at all.
1063
+ */
1064
+ const BUILTIN_TOOL_TYPE = {
1065
+ analyzefiles: 'analyze-attachments',
1066
+ summarize: 'deep-rag',
1067
+ batchtransform: 'batch-transform',
1068
+ };
1069
+ /** `inline` → `Inline`: the node's enum spelling to the resource schema's. */
1070
+ const enumValue = (v) => {
1071
+ const s = String(v ?? '');
1072
+ return s.charAt(0).toUpperCase() + s.slice(1);
1073
+ };
1074
+ /**
1075
+ * The `resources/<id>/resource.json` of a platform BUILT-IN tool (#920) — the
1076
+ * file the runtime builds the agent's tool list from. Without it the
1077
+ * `tool.builtin.*` node is inert, the same failure #806 fixed for deployed
1078
+ * resources: the agent runs with no built-in tool and the model never learns
1079
+ * it exists.
1080
+ *
1081
+ * Derived from the node's own inputs (`tdef.inputDefaults` with the author's
1082
+ * values over them), because those are what the file must agree with:
1083
+ * `uip agent refresh --inline-in-flow` shell-ifies every resource node down to
1084
+ * `{source, detail, itemsDescription}` and Studio Web re-hydrates the rest FROM
1085
+ * this file, so a value only on the node does not survive a refresh or a
1086
+ * designer round-trip.
1087
+ *
1088
+ * Shape: the skill's per-tool walkthroughs (`analyze-attachments.md`,
1089
+ * `deeprag/impl-json.md`, `batch-transform/impl-json.md`) checked against the
1090
+ * platform's `builtInToolResourceStorageSchemaV40`. Two vocabularies differ
1091
+ * from the node's, as they do for a context index (`contextResourceJson`): the
1092
+ * resource `query` is VARIANT-tagged where the node's is MODE-tagged, and its
1093
+ * enums are capitalized (`Inline`, `Enabled`). `analyze-attachments` declares
1094
+ * the model-facing call contract (`attachments` + `analysisTask` → `analysis`);
1095
+ * `deep-rag` and `batch-transform` declare empty schemas and carry their
1096
+ * configuration in `properties.settings`.
1097
+ */
1098
+ function builtinToolResourceJson(tool, label, inputs, spec) {
1099
+ const toolType = BUILTIN_TOOL_TYPE[tool];
1100
+ if (toolType === undefined)
1101
+ return undefined;
1102
+ const empty = { type: 'object', properties: {} };
1103
+ const common = {
1104
+ $resourceType: 'tool',
1105
+ id: spec.id,
1106
+ // Null, not absent: what identifies a built-in as NOT an external tool.
1107
+ referenceKey: null,
1108
+ name: label,
1109
+ type: 'internal',
1110
+ description: String(inputs.description ?? ''),
1111
+ isEnabled: true,
1112
+ settings: {},
1113
+ guardrail: { policies: [] },
1114
+ argumentProperties: {},
1115
+ };
1116
+ const query = inputs.query?.mode === 'text-builder'
1117
+ ? { variant: 'static', value: String(inputs.query.textValue ?? '') }
1118
+ : { variant: 'dynamic', description: String(inputs.query?.promptValue ?? '') };
1119
+ if (toolType === 'analyze-attachments') {
1120
+ return {
1121
+ ...common,
1122
+ inputSchema: {
1123
+ type: 'object',
1124
+ properties: {
1125
+ attachments: {
1126
+ type: 'array',
1127
+ items: { $ref: '#/definitions/job-attachment' },
1128
+ description: String(inputs.attachmentsDescription ?? ''),
1129
+ },
1130
+ analysisTask: { type: 'string', description: String(inputs.analysisTaskDescription ?? '') },
1131
+ },
1132
+ required: ['attachments', 'analysisTask'],
1133
+ definitions: {
1134
+ 'job-attachment': {
1135
+ type: 'object',
1136
+ properties: {
1137
+ ID: { type: 'string', description: 'Orchestrator attachment key' },
1138
+ FullName: { type: 'string', description: 'File name' },
1139
+ MimeType: { type: 'string', description: 'MIME type, e.g. "application/pdf", "image/png"' },
1140
+ Metadata: {
1141
+ type: 'object',
1142
+ description: 'Dictionary<string, string> of metadata',
1143
+ additionalProperties: { type: 'string' },
1144
+ },
1145
+ },
1146
+ required: ['ID'],
1147
+ 'x-uipath-resource-kind': 'JobAttachment',
1148
+ },
1149
+ },
1150
+ },
1151
+ outputSchema: {
1152
+ type: 'object',
1153
+ properties: {
1154
+ analysis: {
1155
+ type: 'string',
1156
+ description: 'Analysis result of the attachments (analysis, summary, extracted information, etc.)',
1157
+ },
1158
+ },
1159
+ required: ['analysis'],
1160
+ },
1161
+ properties: { toolType, exampleCalls: [] },
1162
+ };
1163
+ }
1164
+ if (toolType === 'deep-rag') {
1165
+ return {
1166
+ ...common,
1167
+ inputSchema: empty,
1168
+ outputSchema: empty,
1169
+ properties: {
1170
+ toolType,
1171
+ exampleCalls: [],
1172
+ settings: {
1173
+ contextType: 'attachments',
1174
+ query,
1175
+ folderPathPrefix: { variant: 'static' },
1176
+ fileExtension: { value: String(inputs.fileExtension?.value ?? 'pdf') },
1177
+ citationMode: { value: enumValue(inputs.citationMode?.value ?? 'inline') },
1178
+ },
1179
+ },
1180
+ };
1181
+ }
1182
+ return {
1183
+ ...common,
1184
+ inputSchema: empty,
1185
+ outputSchema: empty,
1186
+ properties: {
1187
+ toolType,
1188
+ exampleCalls: [],
1189
+ settings: {
1190
+ contextType: 'attachments',
1191
+ query,
1192
+ folderPathPrefix: { variant: 'static' },
1193
+ outputColumns: Array.isArray(inputs.outputColumns) ? inputs.outputColumns : [],
1194
+ webSearchGrounding: { value: enumValue(inputs.webSearchGrounding?.value ?? 'enabled') },
1195
+ },
1196
+ },
1197
+ };
1198
+ }
1050
1199
  /**
1051
1200
  * The one TARGET handle every tool resource declares: `input`, artifact-typed,
1052
1201
  * fed by the two agent types' `tool` handles. Transcribed from `registry get`
@@ -3959,16 +4108,38 @@ function misplacedLookupMessage(token) {
3959
4108
  * (`compile --no-check`, `emitFlow`, a direct `serialize()`) cannot write a
3960
4109
  * file `flow validate` rejects for a duplicate variable id.
3961
4110
  */
3962
- function emittableGlobals(built, where) {
4111
+ function emittableGlobals(built, where, kind = 'root') {
3963
4112
  // Entry-point inputs are rows of the same globals[], so they share the
3964
4113
  // namespace; `check` reports those as ENTRY_POINT_INPUT_COLLISION.
3965
4114
  const inputs = [...built.inputs, ...(built.entryPoints ?? []).flatMap((ep) => ep.inputs)];
3966
- const plan = planFlowGlobals({ inputs, outputs: built.outputs, vars: built.vars });
4115
+ // A variable an input feeds with `{ shared }` (#924) is one more `.var()`
4116
+ // unless the author declared it, so it goes through the same collision plan.
4117
+ const shared = sharedInputsOf(built, where, kind);
4118
+ const plan = planFlowGlobals({ inputs, outputs: built.outputs, vars: [...built.vars, ...shared.autoVars] });
3967
4119
  if (plan.problems.length) {
3968
4120
  throw new Error(`${where}: ${plan.problems.map((p) => `[${p.code}] ${p.message}`).join(' ')}`);
3969
4121
  }
3970
4122
  return plan;
3971
4123
  }
4124
+ /**
4125
+ * The flow's `{ shared }` input plan (#924), refused here as `check` refuses it
4126
+ * — so `compile --no-check` cannot write what `check` would have stopped.
4127
+ * Warnings (a root that feeds nothing) are `check`'s alone.
4128
+ */
4129
+ function sharedInputsOf(built, where, kind) {
4130
+ if (kind === 'subflow') {
4131
+ const marked = built.inputs.filter((i) => i.shared !== undefined);
4132
+ if (marked.length) {
4133
+ throw new Error(`${where}: [SHARED_INPUT_IN_SUBFLOW] input "${marked[0].name}" has { shared: "${marked[0].shared}" }, but a subflow `
4134
+ + `has one root — its caller — so there is nothing to merge. Read the input with input('${marked[0].name}').`);
4135
+ }
4136
+ }
4137
+ const plan = planSharedInputs({ roots: sharedInputRoots(built), outputs: built.outputs, vars: built.vars });
4138
+ const errors = plan.problems.filter((p) => p.level === 'error');
4139
+ if (errors.length)
4140
+ throw new Error(`${where}: ${errors.map((p) => `[${p.code}] ${p.message}`).join(' ')}`);
4141
+ return plan;
4142
+ }
3972
4143
  function newScope(outputs, vars = []) {
3973
4144
  return {
3974
4145
  nodes: [],
@@ -4417,7 +4588,7 @@ export function serialize(built, opts = {}) {
4417
4588
  * a null. It is emitted here, always, so it cannot be forgotten.
4418
4589
  */
4419
4590
  function emitSubflowBody(child, nodeId) {
4420
- const childGlobals = emittableGlobals(child, `subflow "${nodeId}"`);
4591
+ const childGlobals = emittableGlobals(child, `subflow "${nodeId}"`, 'subflow');
4421
4592
  const scope = newScope(childGlobals.outputs, childGlobals.vars);
4422
4593
  // Claim this copy's node ids UP FRONT, so the rename map is complete before
4423
4594
  // the first expression renders. A child's step names are free the first
@@ -5160,7 +5331,9 @@ export function serialize(built, opts = {}) {
5160
5331
  // designer rather than guessed.
5161
5332
  const toolResource = connectorTool
5162
5333
  ? connectorToolResourceJson(connectorTool, toolResourceId)
5163
- : toolResourceJson(tr, { id: toolResourceId });
5334
+ : tr.kind === 'builtin'
5335
+ ? builtinToolResourceJson(tr.tool, label, tnode.inputs, { id: toolResourceId })
5336
+ : toolResourceJson(tr, { id: toolResourceId });
5164
5337
  if (toolResource !== undefined) {
5165
5338
  sidecars.push({
5166
5339
  path: `${source}/resources/${toolResourceId}/resource.json`,
@@ -6544,6 +6717,30 @@ export function serialize(built, opts = {}) {
6544
6717
  }
6545
6718
  }
6546
6719
  }
6720
+ // ── Shared root inputs (#924) ────────────────────────────────────────────
6721
+ // An input marked `{ shared: '<var>' }` is copied into that variable on its
6722
+ // root's TRIGGER node: a `variableUpdates[<triggerId>]` row, the same
6723
+ // construct `{ updates }` writes for a step. On the trigger, the copy is done
6724
+ // before the root's own prefix steps run. The platform engine applies a start
6725
+ // event's output rows in order, so the row sees the trigger's input mapping
6726
+ // (measured live, #924). The default root's row is written against `start`
6727
+ // and renamed with every other `input()` read, so `.triggerId()` follows.
6728
+ {
6729
+ const roots = [
6730
+ { node: built.triggerId ?? 'start', read: 'start', inputs: built.inputs },
6731
+ ...entryPoints.map((ep) => ({ node: ep.id, read: ep.id, inputs: ep.inputs })),
6732
+ ];
6733
+ for (const r of roots) {
6734
+ const copies = {};
6735
+ for (const inp of r.inputs) {
6736
+ if (inp.shared !== undefined)
6737
+ copies[inp.shared] = new Expr(`$vars.${r.read}.output.${inp.name}`);
6738
+ }
6739
+ if (Object.keys(copies).length === 0)
6740
+ continue;
6741
+ root.variableUpdates[r.node] = [...(root.variableUpdates[r.node] ?? []), ...renderUpdates(copies, root.rename)];
6742
+ }
6743
+ }
6547
6744
  const globals = [];
6548
6745
  const triggerNodeId = built.triggerId ?? 'start';
6549
6746
  for (const inp of built.inputs)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/maestro-builder-sdk",
3
- "version": "6.15.6",
3
+ "version": "6.16.1",
4
4
  "description": "Build UiPath Flow, Case, and BPMN artifacts by writing TypeScript.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://docs.uipath.com/maestro",
@@ -92,5 +92,5 @@
92
92
  "@types/node": "^22.7.0",
93
93
  "esbuild": "^0.28.1"
94
94
  },
95
- "gitref": "d8d72580682f02833d28d720ee382ffe9d346f6e"
95
+ "gitref": "5ccf1b7bf45b98185d2f79546df9c86a7dccc5bd"
96
96
  }