@uipath/maestro-builder-sdk 6.16.4 → 6.16.6

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.
@@ -23,12 +23,8 @@ import { basename, dirname, join, resolve } from 'node:path';
23
23
  import { defaultSourceOut, workDirBeside, writeSource } from './workdir.js';
24
24
  import { decompile } from './decompile.js';
25
25
  import { resolveFlowRefs } from './ref-resolve.js';
26
- import { runWhenInvokedDirectly } from './cli-run.js';
26
+ import { flagValue, runWhenInvokedDirectly } from './cli-run.js';
27
27
  import { PACKAGE_NAME } from './package-name.js';
28
- function opt(argv, name) {
29
- const i = argv.indexOf(name);
30
- return i >= 0 ? argv[i + 1] : undefined;
31
- }
32
28
  /** Derive a PascalCase base name from the flow name/id for the default output file. */
33
29
  function baseName(flow) {
34
30
  const src = flow.name ?? flow.id ?? 'Flow';
@@ -58,7 +54,7 @@ export function run(argv) {
58
54
  read: (path) => readFileSync(path, 'utf8'),
59
55
  });
60
56
  const ts = decompile(flow, {
61
- importSpecifier: opt(argv, '--import') ?? PACKAGE_NAME,
57
+ importSpecifier: flagValue(argv, '--import') ?? PACKAGE_NAME,
62
58
  bestEffort: !argv.includes('--strict'),
63
59
  // Findings the source cannot carry on its own (a node no trigger reaches, a
64
60
  // pinned core version this SDK lacks, a file-format version outside the
@@ -75,7 +71,7 @@ export function run(argv) {
75
71
  }
76
72
  },
77
73
  });
78
- const out = opt(argv, '-o') ?? defaultSourceOut(`${baseName(flow)}.flow.ts`);
74
+ const out = flagValue(argv, '-o') ?? defaultSourceOut(`${baseName(flow)}.flow.ts`);
79
75
  writeSource(out, ts);
80
76
  console.log(`flow-decompile: wrote ${basename(out)}`);
81
77
  reportResult({ path: resolve(out) });
package/dist/decompile.js CHANGED
@@ -1023,28 +1023,24 @@ function connectorObjectName(configuration) {
1023
1023
  * Returns `undefined` when the node is not one of them, so the caller can fall
1024
1024
  * through to the next arm.
1025
1025
  */
1026
+ /** The `maxIterations` Studio Web writes into every inline agent's `agent.json` (flow-workbench `getDefaultAgentContent()`). */
1027
+ const STUDIO_WEB_DEFAULT_MAX_ITERATIONS = 25;
1026
1028
  /**
1027
- * An AGENT and its attached resources — the inline autonomous agent, the
1028
- * conversational agent, and the voice agent.
1029
- *
1030
- * The cluster is a node plus artifact nodes on its `tool` / `context` /
1031
- * `escalation` / `memory` handles, so this walks those edges and recovers each
1032
- * resource as an argument rather than as a step (see {@link ARTIFACT_PORTS}).
1029
+ * The agent configuration a SHELL agent node keeps in its sidecar, read from
1030
+ * `<source>/agent.json` in the node's own input names: the prompts, the model,
1031
+ * the run settings (`temperature`, `maxTokenPerResponse`, `maxIterations`,
1032
+ * `mode`), the `guardrails` and (voice) the `voice` settings. Empty when the
1033
+ * node carries prompts itself (an embedded node, e.g. a `.flow` saved by Studio
1034
+ * Web with the self-contained flag on), or when no sidecar can be read.
1033
1035
  *
1034
- * **The author's input NAMES are not recoverable, and that is by design.** The
1035
- * platform does not send an agent the names you declared: it keys each argument
1036
- * by the reference PATH, `__`-joined (`$vars.prep.output` → `prep__output`), and
1037
- * only those flat names survive in the emitted file. Recovery therefore uses
1038
- * them for both the `inputs` keys and the `{{input.…}}` placeholders — the same
1039
- * arguments reach the model, spelled the platform's way. (Node ids are
1040
- * preserved exactly; only these logical names change.)
1041
- */
1042
- /**
1043
- * The agent configuration a SHELL agent node keeps in its sidecar: the prompts,
1044
- * the model and (voice) the `voice` settings, read from `<source>/agent.json`
1045
- * in the node's own input names. Empty when the node carries prompts itself (an
1046
- * embedded node, e.g. a `.flow` saved by Studio Web with the self-contained
1047
- * flag on), or when no sidecar can be read.
1036
+ * A run setting equal to the default a sidecar writer fills in (`temperature`
1037
+ * 0, `maxTokens` 16384, `mode` `'standard'`) is not recovered: recompiling
1038
+ * without it writes the same sidecar, and recovering it would add an argument
1039
+ * the author never wrote to every agent. `mode: 'standard'` is the exception on
1040
+ * a 1.3 node, where naming it is what selected that definition. The same goes
1041
+ * for the inline agent's `maxIterations` 25: the SDK omits it when unset, but
1042
+ * Studio Web always writes it (its `getDefaultAgentContent()` default), so
1043
+ * every Studio Web-saved agent would otherwise decompile with `maxIterations: 25`.
1048
1044
  */
1049
1045
  function sidecarAgentInputs(node) {
1050
1046
  const inputs = (node.inputs ?? {});
@@ -1057,7 +1053,8 @@ function sidecarAgentInputs(node) {
1057
1053
  const raw = runReadSidecar?.(path);
1058
1054
  if (raw === undefined) {
1059
1055
  warnOnce(`agent step "${node.id}" carries no prompts and ${path} was not found beside the .flow, `
1060
- + 'so its prompts and model decompile empty. Decompile the .flow from inside its project directory.');
1056
+ + 'so its prompts, model and run settings decompile empty. Keep <source>/agent.json beside the .flow '
1057
+ + '(download the whole project, not just the .flow).');
1061
1058
  return {};
1062
1059
  }
1063
1060
  let agent;
@@ -1065,7 +1062,7 @@ function sidecarAgentInputs(node) {
1065
1062
  agent = JSON.parse(raw);
1066
1063
  }
1067
1064
  catch {
1068
- warnOnce(`agent step "${node.id}": ${path} is not valid JSON, so its prompts and model decompile empty.`);
1065
+ warnOnce(`agent step "${node.id}": ${path} is not valid JSON, so its prompts, model and run settings decompile empty.`);
1069
1066
  return {};
1070
1067
  }
1071
1068
  const messages = (Array.isArray(agent?.messages) ? agent.messages : []);
@@ -1076,13 +1073,50 @@ function sidecarAgentInputs(node) {
1076
1073
  const settings = (agent?.settings ?? {});
1077
1074
  const system = content('system');
1078
1075
  const user = content('user');
1076
+ const isVoice = node.type === T.voiceAgent;
1077
+ const numberUnless = (v, dflt) => typeof v === 'number' && v !== dflt ? v : undefined;
1078
+ // The voice agent's temperature and token cap live in `settings.voice`, not here.
1079
+ const temperature = isVoice ? undefined : numberUnless(settings.temperature, 0);
1080
+ const maxTokenPerResponse = isVoice ? undefined : numberUnless(settings.maxTokens, 16384);
1081
+ // Studio Web's default for the inline agent; the other families keep any value.
1082
+ const maxIterations = node.type === T.inlineAgent
1083
+ ? numberUnless(settings.maxIterations, STUDIO_WEB_DEFAULT_MAX_ITERATIONS)
1084
+ : typeof settings.maxIterations === 'number' ? settings.maxIterations : undefined;
1085
+ // `mode` is a harness choice on the inline agent only; the conversational and
1086
+ // voice sidecars always carry their family's fixed value. Naming it is also
1087
+ // what selects the 1.3 definition, so on a 1.3 node even `'standard'` was the
1088
+ // author's.
1089
+ const mode = node.type === T.inlineAgent && typeof settings.mode === 'string'
1090
+ && (settings.mode !== 'standard' || node.typeVersion === '1.3')
1091
+ ? settings.mode : undefined;
1079
1092
  return {
1080
1093
  ...(system === undefined ? {} : { systemPrompt: system }),
1081
1094
  ...(user === undefined ? {} : { userPrompt: user }),
1082
1095
  ...(typeof settings.model === 'string' ? { model: settings.model } : {}),
1083
- ...(node.type === T.voiceAgent && settings.voice && typeof settings.voice === 'object' ? { voice: settings.voice } : {}),
1096
+ ...(temperature === undefined ? {} : { temperature }),
1097
+ ...(maxTokenPerResponse === undefined ? {} : { maxTokenPerResponse }),
1098
+ ...(maxIterations === undefined ? {} : { maxIterations }),
1099
+ ...(mode === undefined ? {} : { mode }),
1100
+ ...(Array.isArray(agent?.guardrails) && agent.guardrails.length > 0 ? { guardrails: agent.guardrails } : {}),
1101
+ ...(isVoice && settings.voice && typeof settings.voice === 'object' ? { voice: settings.voice } : {}),
1084
1102
  };
1085
1103
  }
1104
+ /**
1105
+ * An AGENT and its attached resources — the inline autonomous agent, the
1106
+ * conversational agent, and the voice agent.
1107
+ *
1108
+ * The cluster is a node plus artifact nodes on its `tool` / `context` /
1109
+ * `escalation` / `memory` handles, so this walks those edges and recovers each
1110
+ * resource as an argument rather than as a step (see {@link ARTIFACT_PORTS}).
1111
+ *
1112
+ * **The author's input NAMES are not recoverable, and that is by design.** The
1113
+ * platform does not send an agent the names you declared: it keys each argument
1114
+ * by the reference PATH, `__`-joined (`$vars.prep.output` → `prep__output`), and
1115
+ * only those flat names survive in the emitted file. Recovery therefore uses
1116
+ * them for both the `inputs` keys and the `{{input.…}}` placeholders — the same
1117
+ * arguments reach the model, spelled the platform's way. (Node ids are
1118
+ * preserved exactly; only these logical names change.)
1119
+ */
1086
1120
  function emitAgentCluster(node, imp, inputNames, graph) {
1087
1121
  // A key on the node wins over the sidecar's copy of it.
1088
1122
  const i = { ...sidecarAgentInputs(node), ...(node.inputs ?? {}) };
@@ -1094,10 +1128,12 @@ function emitAgentCluster(node, imp, inputNames, graph) {
1094
1128
  const raw = unwrapPlain(v);
1095
1129
  return typeof raw === 'number' ? String(raw) : undefined;
1096
1130
  };
1097
- // Prompts: invert `renderInlineAgentPrompt`. It replaced each
1098
- // `{{input.<name>}}` with that input's rendered binding, so the bindings in
1099
- // `agentInputVariables` are exactly what to put back — longest first, so a
1100
- // shorter binding cannot eat a longer one's prefix.
1131
+ // Prompts. A sidecar prompt already speaks `{{input.<flatName>}}`, so this
1132
+ // leaves it alone. An EMBEDDED node's prompt (Studio Web with the
1133
+ // self-contained flag on, or an SDK before #927) carries each input as its
1134
+ // rendered binding instead; the bindings in `agentInputVariables` are exactly
1135
+ // what to put back — longest first, so a shorter binding cannot eat a longer
1136
+ // one's prefix.
1101
1137
  const vars = (Array.isArray(i.agentInputVariables) ? i.agentInputVariables : []);
1102
1138
  const refs = vars
1103
1139
  .filter((v) => typeof v.id === 'string' && typeof v.binding === 'string')
@@ -1359,10 +1395,8 @@ function emitAgentCluster(node, imp, inputNames, graph) {
1359
1395
  // `settings` is required on ConversationalAgentInputs, so an empty one
1360
1396
  // stays as `{}`, which check then reports as CONV_AGENT_NO_TURN.
1361
1397
  ['settings', settingsSrc || '{}'],
1362
- ['endExchange', unwrapPlain(i.endExchange) === false ? 'false' : undefined],
1363
1398
  ['temperature', num(i.temperature)],
1364
1399
  ['maxTokenPerResponse', num(i.maxTokenPerResponse)],
1365
- ['modelMaxTokens', num(i.modelMaxTokens)],
1366
1400
  ['maxIterations', num(i.maxIterations)],
1367
1401
  ['guardrails', guardrails],
1368
1402
  ['source', str(plain(i.source) ?? '')],
@@ -1376,7 +1410,6 @@ function emitAgentCluster(node, imp, inputNames, graph) {
1376
1410
  ['returns', returns],
1377
1411
  ['temperature', num(i.temperature)],
1378
1412
  ['maxTokenPerResponse', num(i.maxTokenPerResponse)],
1379
- ['modelMaxTokens', num(i.modelMaxTokens)],
1380
1413
  ['maxIterations', num(i.maxIterations)],
1381
1414
  ['mode', plain(i.mode) !== undefined ? str(plain(i.mode)) : undefined],
1382
1415
  ['guardrails', guardrails],
package/dist/merge-cli.js CHANGED
@@ -15,11 +15,7 @@ import { reportResult } from './cli-result.js';
15
15
  import { readFileSync, writeFileSync } from 'node:fs';
16
16
  import { basename, resolve } from 'node:path';
17
17
  import { mergeFlow } from './merge.js';
18
- import { runWhenInvokedDirectly } from './cli-run.js';
19
- function opt(argv, name) {
20
- const i = argv.indexOf(name);
21
- return i >= 0 ? argv[i + 1] : undefined;
22
- }
18
+ import { flagValue, runWhenInvokedDirectly } from './cli-run.js';
23
19
  export function run(argv) {
24
20
  if (argv.length === 0 || argv[0] === '-h' || argv[0] === '--help') {
25
21
  console.error('usage: flow-merge <original.flow> <edited.flow> [-o merged.flow] [--baseline <baseline.flow>]');
@@ -34,13 +30,13 @@ export function run(argv) {
34
30
  }
35
31
  const original = JSON.parse(readFileSync(originalPath, 'utf8'));
36
32
  const edited = JSON.parse(readFileSync(editedPath, 'utf8'));
37
- const baselinePath = opt(argv, '--baseline');
33
+ const baselinePath = flagValue(argv, '--baseline');
38
34
  const baseline = baselinePath ? JSON.parse(readFileSync(baselinePath, 'utf8')) : undefined;
39
35
  const merged = mergeFlow(original, edited, {
40
36
  baseline,
41
37
  warn: (m) => console.error(`flow-merge: warning: ${m}`),
42
38
  });
43
- const out = opt(argv, '-o') ?? 'merged.flow';
39
+ const out = flagValue(argv, '-o') ?? 'merged.flow';
44
40
  writeFileSync(out, JSON.stringify(merged, null, 2) + '\n');
45
41
  console.log(`flow-merge: wrote ${basename(out)} (${(merged.nodes ?? []).length} nodes, ${(merged.edges ?? []).length} edges)`);
46
42
  reportResult({ path: resolve(out), nodes: (merged.nodes ?? []).length, edges: (merged.edges ?? []).length });
@@ -17,6 +17,7 @@
17
17
  * everything else is pure over the parsed reply.
18
18
  */
19
19
  import { compareCodePoints, sortedStrings } from "../compat/compare.js";
20
+ import { editDistance } from "../../core/edit-distance.js";
20
21
  import { registrySearch } from "../uip/commands.js";
21
22
  import { failureReason, findJsonDocument, tail } from "../uip/envelope.js";
22
23
  import { isPlainObject, pyOr } from "./support.js";
@@ -81,18 +82,6 @@ export function closestActions(action, candidates) {
81
82
  });
82
83
  return scored.map(({ candidate }) => candidate);
83
84
  }
84
- /** Levenshtein distance, two rows. Short strings only (operation ids). */
85
- function editDistance(a, b) {
86
- let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
87
- for (let i = 1; i <= a.length; i++) {
88
- const cur = [i];
89
- for (let j = 1; j <= b.length; j++) {
90
- cur[j] = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
91
- }
92
- prev = cur;
93
- }
94
- return prev[b.length];
95
- }
96
85
  /**
97
86
  * {@link closestActions}, kept only where the candidate is plausibly what was
98
87
  * meant: it shares MOST of the wanted id's words (`list-all-records` →
package/dist/serialize.js CHANGED
@@ -21,11 +21,11 @@ import { ByoaRefusal, byoaUnverified } from './core/byoa.js';
21
21
  import { OUTCOME_HANDLE_NODE_TYPES, assertHitlExitInvariant, hitlExitModel, hitlExitViolation, outcomeSlug } from './core/hitl-routing.js';
22
22
  import { declaredExits, hasExits, stopsAtEnd } from './core/step-ports.js';
23
23
  import { assertNodeEnvelope } from './core/node-envelope.js';
24
- import { buildConfiguration, transportHttpMethod } from './config.js';
24
+ import { buildConfiguration } from './config.js';
25
25
  import { stableId } from './core/stable-id.js';
26
26
  import { readEventFilter, eventFilterProblem, eventFilterJmes, eventFilterTreeLeaf } from './core/event-filters.js';
27
27
  import { FLOW_EXPR_DIALECT } from './core/connector-checks.js';
28
- import { buildConnectorInputs, connectorInputErrors as coreConnectorInputErrors, multipartBodyFieldName } from './core/connector-inputs.js';
28
+ import { buildConnectorInputs, connectorInputErrors as coreConnectorInputErrors, multipartBodyFieldName, transportHttpMethod } from './core/connector-inputs.js';
29
29
  /**
30
30
  * What `compile` would refuse these connector inputs with, or `undefined` when it
31
31
  * would accept them — Flow's binding of the shared validator.
@@ -5110,15 +5110,18 @@ export function serialize(built, opts = {}) {
5110
5110
  // on the first save. With no prompt strings the converter also keeps the
5111
5111
  // `agentInputVariables` below as written (`canPruneAgentInputs` is false),
5112
5112
  // and `uip maestro flow debug` reconciles them against the sidecar's
5113
- // `inputSchema` — the shape the v1 skill and `uip agent refresh` write.
5113
+ // `inputSchema`.
5114
+ //
5115
+ // The run settings (`mode`, `temperature`, `maxTokenPerResponse`,
5116
+ // `maxIterations`, `guardrails`) live in the sidecar too. The node keeps
5117
+ // exactly the keys Studio Web's own strip keeps (`toAgentShellInputs`,
5118
+ // @uipath/flow-schema): anything else is discarded on hydrate, and while
5119
+ // present it makes Studio Web "trust the .flow" when the sidecar folder is
5120
+ // missing (`flowNodeHasRealInputs`), flushing a prompt-less agent.json.
5121
+ // `modelMaxTokens` is written nowhere: the designer derives it from the
5122
+ // selected model.
5114
5123
  node.inputs = {
5115
5124
  source,
5116
- ...(s.mode === undefined ? {} : { mode: s.mode }),
5117
- ...(s.temperature === undefined ? {} : { temperature: s.temperature }),
5118
- ...(s.maxTokenPerResponse === undefined ? {} : { maxTokenPerResponse: s.maxTokenPerResponse }),
5119
- ...(s.modelMaxTokens === undefined ? {} : { modelMaxTokens: s.modelMaxTokens }),
5120
- ...(s.maxIterations === undefined ? {} : { maxIterations: s.maxIterations }),
5121
- ...(s.guardrails === undefined ? {} : { guardrails: s.guardrails }),
5122
5125
  // The two DESCRIPTOR ARRAYS. `agentInputVariables` entries carry the
5123
5126
  // binding expression; `agentOutputVariables` entries are name + type only,
5124
5127
  // and the runtime's structured final call fills exactly these keys.
@@ -5695,20 +5698,15 @@ export function serialize(built, opts = {}) {
5695
5698
  if (v !== undefined)
5696
5699
  settings[key] = v;
5697
5700
  }
5698
- // A SHELL node, like the inline agent's (#927): the system prompt and the
5699
- // model live only in the sidecar, so Studio Web reads the sidecar instead
5700
- // of letting a node copy shadow it.
5701
+ // A SHELL node, like the inline agent's (#927): exactly the keys
5702
+ // `toAgentShellInputs` keeps. The system prompt, the model and the run
5703
+ // settings live only in the sidecar (`metadata.isConversational` there is
5704
+ // the family flag). `endExchange` is written nowhere: the platform retired
5705
+ // it (the node's v1.7 migration drops it, and the converter always sends
5706
+ // `conversationalService.endExchange = ''`).
5701
5707
  node.inputs = {
5702
5708
  source,
5703
- // The family's own flag — every instance of this node IS conversational.
5704
- isConversational: true,
5705
5709
  conversationalAgentSettings: settings,
5706
- ...(s.endExchange === undefined ? {} : { endExchange: s.endExchange }),
5707
- ...(s.temperature === undefined ? {} : { temperature: s.temperature }),
5708
- ...(s.maxTokenPerResponse === undefined ? {} : { maxTokenPerResponse: s.maxTokenPerResponse }),
5709
- ...(s.modelMaxTokens === undefined ? {} : { modelMaxTokens: s.modelMaxTokens }),
5710
- ...(s.maxIterations === undefined ? {} : { maxIterations: s.maxIterations }),
5711
- ...(s.guardrails === undefined ? {} : { guardrails: s.guardrails }),
5712
5710
  };
5713
5711
  scope.nodes.push(node);
5714
5712
  sidecars.push({
@@ -5771,13 +5769,11 @@ export function serialize(built, opts = {}) {
5771
5769
  // one makes Studio Web treat the `.flow` as authoritative and skip the
5772
5770
  // sidecar (`hasEmbeddedAgentContent`). `uip maestro flow debug` builds the
5773
5771
  // voice agent from the sidecar (`packageInlineAgents`).
5772
+ // The node keeps exactly the keys `toAgentShellInputs` keeps;
5773
+ // `maxIterations` and `metadata.isConversational` are in the sidecar.
5774
5774
  node.inputs = {
5775
5775
  source,
5776
5776
  callContext: renderValue(toExpr(s.callContext), scope.rename),
5777
- // The platform's own flag for this family — every voice agent IS
5778
- // conversational, and the definition declares the field.
5779
- isConversational: true,
5780
- ...(s.maxIterations === undefined ? {} : { maxIterations: s.maxIterations }),
5781
5777
  ...(plan.refs.length === 0 ? {} : {
5782
5778
  agentInputVariables: plan.refs.map((r) => ({
5783
5779
  id: r.flatName,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/maestro-builder-sdk",
3
- "version": "6.16.4",
3
+ "version": "6.16.6",
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": "eac0393e29eed1fe0992c8923b88964e50483eaf"
95
+ "gitref": "36462ef66bdae191ba107334d402dddaed067b2e"
96
96
  }