@uipath/maestro-builder-sdk 6.30.3 → 6.30.4

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.
@@ -32,3 +32,21 @@ export declare function parseContextIndexType(type: string): {
32
32
  slug: string;
33
33
  id: string;
34
34
  } | undefined;
35
+ /**
36
+ * The retrieval settings an index gets when the author sets none: what
37
+ * `contextResourceJson` (serialize.ts) writes into `resource.json` `settings`, and
38
+ * what decompile leaves out of the source because compile would write it anyway.
39
+ */
40
+ export declare const CONTEXT_INDEX_DEFAULTS: {
41
+ readonly retrievalMode: "semantic";
42
+ readonly threshold: 0;
43
+ readonly resultCount: 3;
44
+ };
45
+ /**
46
+ * The file extension each retrieval mode accepts by default. The platform's
47
+ * manifest defaults every mode's NODE to `All`, but its resource schema pins
48
+ * `structured`/`batchtransform` to `csv` and `deeprag` to `pdf`/`txt` — so a
49
+ * flat `All` default would emit a resource the platform refuses to parse for
50
+ * every mode but `semantic`.
51
+ */
52
+ export declare const CONTEXT_INDEX_DEFAULT_FILE_EXTENSION: Readonly<Record<string, string>>;
@@ -36,3 +36,22 @@ export function parseContextIndexType(type) {
36
36
  const dot = tail.lastIndexOf('.');
37
37
  return dot < 0 ? { slug: tail, id: '' } : { slug: tail.slice(0, dot), id: tail.slice(dot + 1) };
38
38
  }
39
+ /**
40
+ * The retrieval settings an index gets when the author sets none: what
41
+ * `contextResourceJson` (serialize.ts) writes into `resource.json` `settings`, and
42
+ * what decompile leaves out of the source because compile would write it anyway.
43
+ */
44
+ export const CONTEXT_INDEX_DEFAULTS = { retrievalMode: 'semantic', threshold: 0, resultCount: 3 };
45
+ /**
46
+ * The file extension each retrieval mode accepts by default. The platform's
47
+ * manifest defaults every mode's NODE to `All`, but its resource schema pins
48
+ * `structured`/`batchtransform` to `csv` and `deeprag` to `pdf`/`txt` — so a
49
+ * flat `All` default would emit a resource the platform refuses to parse for
50
+ * every mode but `semantic`.
51
+ */
52
+ export const CONTEXT_INDEX_DEFAULT_FILE_EXTENSION = {
53
+ semantic: 'All',
54
+ structured: 'csv',
55
+ deeprag: 'pdf',
56
+ batchtransform: 'csv',
57
+ };
@@ -144,9 +144,11 @@ export interface DecompileOptions {
144
144
  * (`{{input.start__output__notes}}`), so the recovered source declares its
145
145
  * inputs under those names — the same flow, not the same spelling. Without a
146
146
  * reader, a shell agent decompiles with empty prompts and a warning.
147
- * A context index placed by the canvas or the CLI keeps its real name and
148
- * folder only in `<agent source>/resources/<inputs.source>/resource.json`,
149
- * which is read the same way.
147
+ * A context index placed by the canvas or the CLI keeps its real name,
148
+ * folder and retrieval `settings` (mode, query, threshold, result count, file
149
+ * extension) only in `<agent source>/resources/<inputs.source>/resource.json`,
150
+ * which is read the same way. A setting `context: [...]` cannot express is
151
+ * reported through `warn` (an error when `bestEffort` is false).
150
152
  */
151
153
  readSidecar?: (relativePath: string) => string | undefined;
152
154
  }
package/dist/decompile.js CHANGED
@@ -36,7 +36,8 @@ import { FLOW_NODE_TYPES } from './flow-node-registry.js';
36
36
  import { SUBFLOW_START_LABEL } from './core/subflow-start.js';
37
37
  import { commentText } from './core/comment-text.js';
38
38
  import { tsLiteral, tsNumber, tsText } from './core/ts-literal.js';
39
- import { contextIndexSlug, parseContextIndexType } from './core/context-index.js';
39
+ import { ownEntry } from './core/own-entry.js';
40
+ import { CONTEXT_INDEX_DEFAULTS, CONTEXT_INDEX_DEFAULT_FILE_EXTENSION, contextIndexSlug, parseContextIndexType, } from './core/context-index.js';
40
41
  import { wireExprBody } from './core/wire-expr.js';
41
42
  import { hasExits } from './core/step-ports.js';
42
43
  import { parseIxpProjectType } from './core/actions.js';
@@ -914,7 +915,146 @@ function contextIndexIdentity(agent, c, rPlain) {
914
915
  + `will write a different node type. Set \`name\` to the index's real name`
915
916
  + (sidecar === undefined ? ', or keep the resources/ folder beside the .flow so decompile can read it.' : '.'));
916
917
  }
917
- return { name, id, folderPath: rPlain(c, 'folderPath') ?? sidecarText('folderPath') };
918
+ return { name, id, folderPath: rPlain(c, 'folderPath') ?? sidecarText('folderPath'), sidecar };
919
+ }
920
+ /** The retrieval modes `ContextIndexRef.retrievalMode` can hold. */
921
+ const CONTEXT_RETRIEVAL_MODES = new Set(['semantic', 'structured', 'deeprag', 'batchtransform']);
922
+ /** The `settings` keys of a context `resource.json` that {@link contextIndexSettings} reads or checks. */
923
+ const CONTEXT_SETTINGS_KEYS = new Set([
924
+ 'retrievalMode', 'query', 'folderPathPrefix', 'threshold', 'resultCount', 'fileExtension',
925
+ 'citationMode', 'webSearchGrounding', 'outputColumns',
926
+ ]);
927
+ /**
928
+ * A context index's retrieval settings, as the `context: [...]` entry's option
929
+ * rows (`retrievalMode`, `query`, `threshold`, `resultCount`, `fileExtension`),
930
+ * each left out when it is what compile writes anyway.
931
+ *
932
+ * The inverse of `contextResourceJson` (serialize.ts). Read from the sidecar's
933
+ * `settings` first: a node the canvas or the CLI placed keeps its inputs minimal
934
+ * (`inputs.source`), so `resource.json` is the only copy, and it is what the
935
+ * runtime reads. The node's own inputs (the SDK writes both) answer when there
936
+ * is no sidecar. Before #1183 neither was read, so a no-edit round trip reset
937
+ * every setting to the SDK default without a word.
938
+ *
939
+ * The query is variant-tagged in the sidecar and mode-tagged on the node:
940
+ *
941
+ * - `dynamic` / `prompt` → a plain string (the guidance the model reads);
942
+ * - `static` / `text-builder` whose text is a `=js:` expression → that
943
+ * expression, which compile writes back as `text-builder` / `static`;
944
+ * - `static` with `''` is the canvas's spelling of "no query", as the SDK's
945
+ * `dynamic` with `''` is: left out.
946
+ *
947
+ * A setting the SDK cannot express (a `static` query of plain text, an
948
+ * `argument` query, deeprag citations off, batchtransform web grounding off or
949
+ * output columns, a folder-path prefix, an unknown mode or key) is reported:
950
+ * a warning, or an error under `--strict`. Compile would write the SDK's
951
+ * value instead, so it is never dropped silently.
952
+ */
953
+ function contextIndexSettings(agent, c, sidecar) {
954
+ const settings = sidecar?.settings && typeof sidecar.settings === 'object' && !Array.isArray(sidecar.settings)
955
+ ? sidecar.settings : undefined;
956
+ const ni = (c.inputs ?? {});
957
+ const where = `context index "${c.id}" on agent "${agent.id}"`;
958
+ const lossy = (what) => {
959
+ const message = `${where}: ${what}, which \`context: [...]\` cannot express, so compile writes the SDK's `
960
+ + `value instead. Edit that setting in the canvas after merging, or keep the original resource.json.`;
961
+ if (runStrict)
962
+ throw new Error(`decompile: ${message}`);
963
+ warnOnce(message);
964
+ };
965
+ const textOf = (v) => (typeof v === 'string' ? v : undefined);
966
+ const numOf = (v) => {
967
+ const raw = unwrapPlain(v);
968
+ return typeof raw === 'number' && Number.isFinite(raw) ? raw : undefined;
969
+ };
970
+ const valueOf = (v) => (v && typeof v === 'object' ? v.value : undefined);
971
+ // Retrieval mode.
972
+ const rawMode = textOf(settings?.retrievalMode) ?? textOf(unwrapSource(ni.retrievalMode));
973
+ let mode = CONTEXT_INDEX_DEFAULTS.retrievalMode;
974
+ if (rawMode !== undefined && rawMode !== '') {
975
+ if (CONTEXT_RETRIEVAL_MODES.has(rawMode))
976
+ mode = rawMode;
977
+ else
978
+ lossy(`its retrieval mode is ${JSON.stringify(rawMode)}`);
979
+ }
980
+ const sidecarQuery = (() => {
981
+ const q = settings?.query;
982
+ if (!q || typeof q !== 'object')
983
+ return undefined;
984
+ if (q.variant === 'dynamic')
985
+ return { kind: 'prompt', text: textOf(q.description) ?? '' };
986
+ if (q.variant === 'static')
987
+ return { kind: 'text', text: textOf(q.value) ?? '' };
988
+ if (q.variant === 'argument')
989
+ return { kind: 'argument', text: textOf(q.value) ?? '' };
990
+ lossy(`its query has variant ${JSON.stringify(q.variant)}`);
991
+ return undefined;
992
+ })();
993
+ const nodeQuery = (() => {
994
+ const q = ni.query;
995
+ if (typeof q === 'string')
996
+ return q === '' ? undefined : { kind: q.startsWith('=js:') ? 'text' : 'prompt', text: q };
997
+ if (!q || typeof q !== 'object')
998
+ return undefined;
999
+ const t = q;
1000
+ if (t.mode === 'text-builder')
1001
+ return { kind: 'text', text: textOf(t.textValue) ?? '' };
1002
+ if (t.mode === 'variable')
1003
+ return { kind: 'argument', text: textOf(t.argumentPath) ?? '' };
1004
+ return { kind: 'prompt', text: textOf(t.promptValue) ?? '' };
1005
+ })();
1006
+ const query = sidecarQuery ?? nodeQuery;
1007
+ let querySrc;
1008
+ if (query?.kind === 'prompt' && query.text !== '')
1009
+ querySrc = tsLiteral(query.text);
1010
+ else if (query?.kind === 'text' && query.text.startsWith('=js:'))
1011
+ querySrc = tsLiteral(query.text);
1012
+ else if (query?.kind === 'text' && query.text !== '')
1013
+ lossy(`its query is static text (${JSON.stringify(query.text)})`);
1014
+ else if (query?.kind === 'argument')
1015
+ lossy(`its query is the agent argument ${JSON.stringify(query.text)}`);
1016
+ // Numbers and the file extension.
1017
+ const threshold = numOf(settings?.threshold) ?? numOf(ni.threshold);
1018
+ const resultCount = numOf(settings?.resultCount) ?? numOf(ni.resultCount);
1019
+ const fileExtension = textOf(valueOf(settings?.fileExtension)) ?? textOf(unwrapSource(ni.fileExtension));
1020
+ // The node's flat `All` is the platform's node default for every mode; only
1021
+ // the resource's per-mode default is what compile would write anyway.
1022
+ const defaultExtension = ownEntry(CONTEXT_INDEX_DEFAULT_FILE_EXTENSION, mode) ?? 'All';
1023
+ const extensionSrc = fileExtension === undefined || fileExtension === '' || fileExtension === defaultExtension
1024
+ || (settings?.fileExtension === undefined && fileExtension === 'All')
1025
+ ? undefined : tsLiteral(fileExtension);
1026
+ // What compile writes as constants; anything else has no field.
1027
+ if (mode === 'deeprag') {
1028
+ const citation = textOf(valueOf(settings?.citationMode)) ?? textOf(unwrapSource(ni.citations));
1029
+ if (citation !== undefined && !['Inline', 'enabled'].includes(citation))
1030
+ lossy(`its citation mode is ${JSON.stringify(citation)}`);
1031
+ }
1032
+ if (mode === 'batchtransform') {
1033
+ const grounding = textOf(valueOf(settings?.webSearchGrounding)) ?? textOf(valueOf(ni.webSearchGrounding));
1034
+ if (grounding !== undefined && !['Enabled', 'enabled'].includes(grounding))
1035
+ lossy(`its web search grounding is ${JSON.stringify(grounding)}`);
1036
+ const columns = settings?.outputColumns ?? ni.outputColumns;
1037
+ if (Array.isArray(columns) && columns.length > 0)
1038
+ lossy(`it has ${columns.length} output column(s)`);
1039
+ }
1040
+ // The folder-path prefix: variant-tagged in the sidecar, mode-tagged on the node.
1041
+ const field = (v, k) => (v && typeof v === 'object' ? textOf(v[k]) : undefined);
1042
+ const prefixText = settings?.folderPathPrefix !== undefined
1043
+ ? field(settings.folderPathPrefix, 'value') ?? field(settings.folderPathPrefix, 'description') ?? ''
1044
+ : field(ni.folderPathPrefix, 'textValue') ?? field(ni.folderPathPrefix, 'promptValue') ?? '';
1045
+ if (prefixText !== '')
1046
+ lossy(`its folder-path prefix is ${JSON.stringify(prefixText)}`);
1047
+ for (const k of Object.keys(settings ?? {})) {
1048
+ if (!CONTEXT_SETTINGS_KEYS.has(k))
1049
+ lossy(`its resource.json settings carry ${JSON.stringify(k)}`);
1050
+ }
1051
+ return [
1052
+ ['query', querySrc],
1053
+ ['retrievalMode', mode !== CONTEXT_INDEX_DEFAULTS.retrievalMode ? tsLiteral(mode) : undefined],
1054
+ ['threshold', threshold !== undefined && threshold !== CONTEXT_INDEX_DEFAULTS.threshold ? tsNumber(threshold) : undefined],
1055
+ ['resultCount', resultCount !== undefined && resultCount !== CONTEXT_INDEX_DEFAULTS.resultCount ? tsNumber(resultCount) : undefined],
1056
+ ['fileExtension', extensionSrc],
1057
+ ];
918
1058
  }
919
1059
  /**
920
1060
  * A context resource's `resource.json` sidecar, parsed; `undefined` when it is
@@ -1136,21 +1276,14 @@ function emitAgentCluster(node, imp, inputNames, graph) {
1136
1276
  return opts([['kind', tsLiteral('builtin')], ['tool', tsLiteral('summarize')]]); // unreachable in practice
1137
1277
  });
1138
1278
  const contextSrc = resource('context').map((c) => {
1139
- // `query` is a MODE TRIPLE, not a string: the author's value lands in
1140
- // `promptValue` (prompt mode) or `textValue` (text-builder). Reading the
1141
- // field itself finds an object and silently recovers nothing.
1142
- const q = rInputs(c).query;
1143
- const queryText = typeof q?.promptValue === 'string' && q.promptValue !== '' ? q.promptValue
1144
- : typeof q?.textValue === 'string' && q.textValue !== '' ? q.textValue
1145
- : typeof q === 'string' && q !== '' ? q
1146
- : undefined;
1147
- const { name, id, folderPath } = contextIndexIdentity(node, c, rPlain);
1279
+ const { name, id, folderPath, sidecar } = contextIndexIdentity(node, c, rPlain);
1148
1280
  return opts([
1149
1281
  ['name', tsLiteral(name)],
1150
1282
  ['id', tsLiteral(id)],
1151
1283
  ['folderPath', folderPath !== undefined ? tsLiteral(folderPath) : undefined],
1152
1284
  ['folderKey', rPlain(c, 'folderKey') !== undefined ? tsLiteral(rPlain(c, 'folderKey')) : undefined],
1153
- ['query', queryText !== undefined ? tsLiteral(queryText) : undefined],
1285
+ // `query` and the retrieval settings, from resource.json or the node (#1183).
1286
+ ...contextIndexSettings(node, c, sidecar),
1154
1287
  ]);
1155
1288
  });
1156
1289
  const escalationSrc = resource('escalation').map((e) => {
package/dist/serialize.js CHANGED
@@ -10,7 +10,7 @@ import ixpDefinition from './ixp-definition.json' with { type: 'json' };
10
10
  import { BUNDLED_DEFINITIONS, bundledVersions } from './flow-definitions.js';
11
11
  import { Expr, toExpr, SCHEDULE_PRESETS, parseIxpProjectType, flatNameOf, flatNameSegmentsOf } from './flow-sdk.js';
12
12
  import { FlowAction, FlowTrigger } from './core/node-classes.js';
13
- import { contextIndexType } from './core/context-index.js';
13
+ import { CONTEXT_INDEX_DEFAULTS, CONTEXT_INDEX_DEFAULT_FILE_EXTENSION, contextIndexType } from './core/context-index.js';
14
14
  import { connectorRawNodeRefusal } from './core/connector-raw-node.js';
15
15
  import { rawNodeInputProblem, registeredRawType } from './raw-node-advice.js';
16
16
  import { planContributionBindings } from './core/contribution-bindings.js';
@@ -855,19 +855,6 @@ function renderContextQuery(query, rename) {
855
855
  }
856
856
  return { ...base, promptValue: asText };
857
857
  }
858
- /**
859
- * The file extension each retrieval mode accepts by default. The platform's
860
- * manifest defaults every mode's NODE to `All`, but its resource schema pins
861
- * `structured`/`batchtransform` to `csv` and `deeprag` to `pdf`/`txt` — so a
862
- * flat `All` default would emit a resource the platform refuses to parse for
863
- * every mode but `semantic`.
864
- */
865
- const DEFAULT_FILE_EXTENSION = {
866
- semantic: 'All',
867
- structured: 'csv',
868
- deeprag: 'pdf',
869
- batchtransform: 'csv',
870
- };
871
858
  /**
872
859
  * The `resources/<id>/resource.json` an inline agent's context index needs.
873
860
  *
@@ -891,7 +878,7 @@ const DEFAULT_FILE_EXTENSION = {
891
878
  * every other binding with it.
892
879
  */
893
880
  function contextResourceJson(cx, spec) {
894
- const mode = cx.retrievalMode ?? 'semantic';
881
+ const mode = cx.retrievalMode ?? CONTEXT_INDEX_DEFAULTS.retrievalMode;
895
882
  return {
896
883
  $resourceType: 'context',
897
884
  id: spec.id,
@@ -920,10 +907,12 @@ function contextResourceJson(cx, spec) {
920
907
  query: spec.query.mode === 'text-builder'
921
908
  ? { variant: 'static', value: String(spec.query.textValue ?? '') }
922
909
  : { variant: 'dynamic', description: String(spec.query.promptValue ?? '') },
923
- folderPathPrefix: { variant: 'static' },
924
- threshold: cx.threshold ?? 0,
925
- resultCount: cx.resultCount ?? 3,
926
- fileExtension: { value: cx.fileExtension ?? ownEntry(DEFAULT_FILE_EXTENSION, mode) ?? 'All' },
910
+ // `value: ''`, as the canvas writes it (flow-workbench `mapContextQueryToWire`
911
+ // always sets the value), so a canvas index's resource round-trips unchanged.
912
+ folderPathPrefix: { variant: 'static', value: '' },
913
+ threshold: cx.threshold ?? CONTEXT_INDEX_DEFAULTS.threshold,
914
+ resultCount: cx.resultCount ?? CONTEXT_INDEX_DEFAULTS.resultCount,
915
+ fileExtension: { value: cx.fileExtension ?? ownEntry(CONTEXT_INDEX_DEFAULT_FILE_EXTENSION, mode) ?? 'All' },
927
916
  // Mode-specific keys the schema REQUIRES of those two modes and rejects
928
917
  // nowhere else, carrying the node's own constants through the enum's
929
918
  // spelling (the node says `enabled`; the resource says `Enabled`/`Inline`).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/maestro-builder-sdk",
3
- "version": "6.30.3",
3
+ "version": "6.30.4",
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": "cdac1f9944a11065ba6cc13061a0873f53683358"
95
+ "gitref": "09ce362aa97a2af0513e0c5883ccaa032df52a4a"
96
96
  }