@uipath/maestro-builder-sdk 6.30.3 → 6.31.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.
@@ -0,0 +1,5 @@
1
+ import type { BindingsV2Document, InlineAgentFiles } from './bindings-v2.js';
2
+ /** Read a `bindings_v2.json`, or `undefined` when absent or unparseable. */
3
+ export declare function readBindingsV2(path: string): BindingsV2Document | undefined;
4
+ /** Read one inline agent's directory the way refresh does; `undefined` when it has no readable `agent.json`. */
5
+ export declare function readInlineAgentFiles(agentDir: string): InlineAgentFiles | undefined;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Reading `bindings_v2.json` and an inline agent's directory from disk, for
3
+ * `compile-cli`. Apart from `bindings-v2.ts`, whose derivations `serialize` uses,
4
+ * so serializing a flow loads no `node:fs`.
5
+ */
6
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
7
+ import { join } from 'node:path';
8
+ import { isRecord } from './core/node-envelope.js';
9
+ /** Read a `bindings_v2.json`, or `undefined` when absent or unparseable. */
10
+ export function readBindingsV2(path) {
11
+ if (!existsSync(path))
12
+ return undefined;
13
+ try {
14
+ const parsed = JSON.parse(readFileSync(path, 'utf8'));
15
+ return isRecord(parsed) ? parsed : undefined;
16
+ }
17
+ catch {
18
+ // A hand-broken sidecar should not fail the compile; it is regenerated below.
19
+ return undefined;
20
+ }
21
+ }
22
+ /** Read one inline agent's directory the way refresh does; `undefined` when it has no readable `agent.json`. */
23
+ export function readInlineAgentFiles(agentDir) {
24
+ let agent;
25
+ try {
26
+ agent = JSON.parse(readFileSync(join(agentDir, 'agent.json'), 'utf8'));
27
+ }
28
+ catch {
29
+ return undefined;
30
+ }
31
+ const read = (sub, file, tag) => {
32
+ const dir = join(agentDir, sub);
33
+ if (!existsSync(dir))
34
+ return [];
35
+ const out = [];
36
+ for (const entry of readdirSync(dir).sort()) {
37
+ try {
38
+ const body = JSON.parse(readFileSync(join(dir, entry, file), 'utf8'));
39
+ if (isRecord(body) && body[tag])
40
+ out.push(body);
41
+ }
42
+ catch {
43
+ // Refresh skips a malformed or missing file the same way.
44
+ }
45
+ }
46
+ return out;
47
+ };
48
+ return { agent, resources: read('resources', 'resource.json', '$resourceType'), features: read('features', 'feature.json', '$featureType') };
49
+ }
@@ -59,8 +59,6 @@ export declare function connectionResources(flow: unknown): BindingsV2Resource[]
59
59
  * had put there.
60
60
  */
61
61
  export declare function mergeBindingsV2(existing: unknown, connections: BindingsV2Resource[]): BindingsV2Document;
62
- /** Read a `bindings_v2.json`, or `undefined` when absent or unparseable. */
63
- export declare function readBindingsV2(path: string): BindingsV2Document | undefined;
64
62
  /** The files of one inline agent, as `uip agent refresh` reads them. */
65
63
  export interface InlineAgentFiles {
66
64
  /** `<agent>/agent.json`. */
@@ -116,5 +114,3 @@ export declare function mergeInlineAgentResources(existing: BindingsV2Resource[]
116
114
  * @returns The rows to write.
117
115
  */
118
116
  export declare function refreshInlineAgentRows(resources: BindingsV2Resource[], agents: InlineAgentFiles[], removedResources: unknown[]): BindingsV2Resource[];
119
- /** Read one inline agent's directory the way refresh does; `undefined` when it has no readable `agent.json`. */
120
- export declare function readInlineAgentFiles(agentDir: string): InlineAgentFiles | undefined;
@@ -53,8 +53,6 @@
53
53
  * PRESERVED untouched and never invented ({@link mergeBindingsV2},
54
54
  * {@link mergeInlineAgentResources}).
55
55
  */
56
- import { existsSync, readdirSync, readFileSync } from 'node:fs';
57
- import { join } from 'node:path';
58
56
  import { BindingRefusal, connectionConnectorConflictMessage } from './core/binding-messages.js';
59
57
  import { isRecord } from './core/node-envelope.js';
60
58
  /** The document version pack emits. */
@@ -255,19 +253,6 @@ export function mergeBindingsV2(existing, connections) {
255
253
  const version = (isRecord(existing) && nonEmptyString(existing.version)) || DOCUMENT_VERSION;
256
254
  return { version, resources: [...connections, ...preserved] };
257
255
  }
258
- /** Read a `bindings_v2.json`, or `undefined` when absent or unparseable. */
259
- export function readBindingsV2(path) {
260
- if (!existsSync(path))
261
- return undefined;
262
- try {
263
- const parsed = JSON.parse(readFileSync(path, 'utf8'));
264
- return isRecord(parsed) ? parsed : undefined;
265
- }
266
- catch {
267
- // A hand-broken sidecar should not fail the compile; it is regenerated below.
268
- return undefined;
269
- }
270
- }
271
256
  // ─────────────────────────────────────────────────────────────────────────────
272
257
  // Inline-agent rows — the ones `uip agent refresh --inline-in-flow` derives
273
258
  // ─────────────────────────────────────────────────────────────────────────────
@@ -536,31 +521,3 @@ export function refreshInlineAgentRows(resources, agents, removedResources) {
536
521
  out = mergeInlineAgentResources(out, rows);
537
522
  return out;
538
523
  }
539
- /** Read one inline agent's directory the way refresh does; `undefined` when it has no readable `agent.json`. */
540
- export function readInlineAgentFiles(agentDir) {
541
- let agent;
542
- try {
543
- agent = JSON.parse(readFileSync(join(agentDir, 'agent.json'), 'utf8'));
544
- }
545
- catch {
546
- return undefined;
547
- }
548
- const read = (sub, file, tag) => {
549
- const dir = join(agentDir, sub);
550
- if (!existsSync(dir))
551
- return [];
552
- const out = [];
553
- for (const entry of readdirSync(dir).sort()) {
554
- try {
555
- const body = JSON.parse(readFileSync(join(dir, entry, file), 'utf8'));
556
- if (isRecord(body) && body[tag])
557
- out.push(body);
558
- }
559
- catch {
560
- // Refresh skips a malformed or missing file the same way.
561
- }
562
- }
563
- return out;
564
- };
565
- return { agent, resources: read('resources', 'resource.json', '$resourceType'), features: read('features', 'feature.json', '$featureType') };
566
- }
@@ -48,7 +48,7 @@
48
48
  */
49
49
  import { collectPreservation } from './decompile.js';
50
50
  import { applyPreservation } from './serialize.js';
51
- import { jsonClone } from '../core/json-file.js';
51
+ import { jsonClone } from '../core/json-clone.js';
52
52
  /** Stage labels in a document, in order. */
53
53
  function stageLabels(document) {
54
54
  return (document.nodes ?? [])
@@ -27,7 +27,8 @@ import { check } from './check.js';
27
27
  import { flowCheckOpts, openCliLibrary } from './cli-library.js';
28
28
  import { Bindings } from './bindings.js';
29
29
  import { flagValue, runWhenInvokedDirectly } from './cli-run.js';
30
- import { connectionResources, inlineAgentResources, mergeBindingsV2, readBindingsV2, refreshInlineAgentRows, readInlineAgentFiles, } from './bindings-v2.js';
30
+ import { connectionResources, inlineAgentResources, mergeBindingsV2, refreshInlineAgentRows } from './bindings-v2.js';
31
+ import { readBindingsV2, readInlineAgentFiles } from './bindings-v2-files.js';
31
32
  import { ensureTypeScriptRuntime } from './node-runtime.js';
32
33
  import { defaultBindingsFile } from './workdir.js';
33
34
  import { isWithin } from './path-within.js';
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The refusal `Library.resolve` throws. Apart from `core/library.ts`, which reads
3
+ * the connector library from disk, so `serialize` can recognise the refusal
4
+ * without loading `node:fs` (FB015). `core/library.ts` re-exports both.
5
+ */
6
+ /** Why `Library.resolve` refused a connector action. */
7
+ export type ConnectorResolveCode =
8
+ /** The library carries no such operation (or no such connector, or not at that version). */
9
+ 'CONNECTOR_NOT_IN_LIBRARY'
10
+ /** A GENERIC operation (one entry per object) named without an `object`. */
11
+ | 'CONNECTOR_OBJECT_REQUIRED'
12
+ /** An `object` on a single, non-generic operation. */
13
+ | 'CONNECTOR_OBJECT_NOT_GENERIC'
14
+ /**
15
+ * The index lists the operation, but its entry file or `.v1def.json` sidecar is
16
+ * missing or not valid JSON: the library on disk is incomplete (#1015).
17
+ */
18
+ | 'CONNECTOR_LIBRARY_ENTRY_UNREADABLE';
19
+ /**
20
+ * The refusal `Library.resolve` throws, with a `code` for each reason.
21
+ *
22
+ * Typed so a caller can tell a refusal from a bug without matching on message
23
+ * text: `check` reports it under this code with this message, and a compile
24
+ * that throws it carries the same code into its `--json` diagnostics (#948).
25
+ */
26
+ export declare class ConnectorResolveError extends Error {
27
+ readonly code: ConnectorResolveCode;
28
+ constructor(code: ConnectorResolveCode, message: string);
29
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The refusal `Library.resolve` throws. Apart from `core/library.ts`, which reads
3
+ * the connector library from disk, so `serialize` can recognise the refusal
4
+ * without loading `node:fs` (FB015). `core/library.ts` re-exports both.
5
+ */
6
+ /**
7
+ * The refusal `Library.resolve` throws, with a `code` for each reason.
8
+ *
9
+ * Typed so a caller can tell a refusal from a bug without matching on message
10
+ * text: `check` reports it under this code with this message, and a compile
11
+ * that throws it carries the same code into its `--json` diagnostics (#948).
12
+ */
13
+ export class ConnectorResolveError extends Error {
14
+ code;
15
+ constructor(code, message) {
16
+ super(message);
17
+ this.name = 'ConnectorResolveError';
18
+ this.code = code;
19
+ }
20
+ }
@@ -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
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * A deep copy of a JSON value. Apart from `core/json-file.ts`, which writes files,
3
+ * so the modules that only copy values load no `node:fs`.
4
+ */
5
+ /** `JSON.parse(JSON.stringify(value))`: a deep copy of a JSON value that drops `undefined` and functions, the semantics every copy relied on. */
6
+ export declare function jsonClone<T>(value: T): T;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * A deep copy of a JSON value. Apart from `core/json-file.ts`, which writes files,
3
+ * so the modules that only copy values load no `node:fs`.
4
+ */
5
+ /** `JSON.parse(JSON.stringify(value))`: a deep copy of a JSON value that drops `undefined` and functions, the semantics every copy relied on. */
6
+ export function jsonClone(value) {
7
+ return JSON.parse(JSON.stringify(value));
8
+ }
@@ -1,3 +1 @@
1
1
  export declare function writeJsonFile(path: string, value: unknown): void;
2
- /** `JSON.parse(JSON.stringify(value))`: a deep copy of a JSON value that drops `undefined` and functions, the semantics every copy relied on. */
3
- export declare function jsonClone<T>(value: T): T;
@@ -10,7 +10,3 @@ import { writeFileSync } from 'node:fs';
10
10
  export function writeJsonFile(path, value) {
11
11
  writeFileSync(path, JSON.stringify(value, null, 2) + '\n');
12
12
  }
13
- /** `JSON.parse(JSON.stringify(value))`: a deep copy of a JSON value that drops `undefined` and functions, the semantics every copy relied on. */
14
- export function jsonClone(value) {
15
- return JSON.parse(JSON.stringify(value));
16
- }
@@ -218,30 +218,7 @@ export interface LibraryOpts {
218
218
  */
219
219
  overlayDir?: string;
220
220
  }
221
- /** Why {@link Library.resolve} refused a connector action. */
222
- export type ConnectorResolveCode =
223
- /** The library carries no such operation (or no such connector, or not at that version). */
224
- 'CONNECTOR_NOT_IN_LIBRARY'
225
- /** A GENERIC operation (one entry per object) named without an `object`. */
226
- | 'CONNECTOR_OBJECT_REQUIRED'
227
- /** An `object` on a single, non-generic operation. */
228
- | 'CONNECTOR_OBJECT_NOT_GENERIC'
229
- /**
230
- * The index lists the operation, but its entry file or `.v1def.json` sidecar is
231
- * missing or not valid JSON: the library on disk is incomplete (#1015).
232
- */
233
- | 'CONNECTOR_LIBRARY_ENTRY_UNREADABLE';
234
- /**
235
- * The refusal {@link Library.resolve} throws, with a `code` for each reason.
236
- *
237
- * Typed so a caller can tell a refusal from a bug without matching on message
238
- * text: `check` reports it under this code with this message, and a compile
239
- * that throws it carries the same code into its `--json` diagnostics (#948).
240
- */
241
- export declare class ConnectorResolveError extends Error {
242
- readonly code: ConnectorResolveCode;
243
- constructor(code: ConnectorResolveCode, message: string);
244
- }
221
+ export { ConnectorResolveError, type ConnectorResolveCode } from './connector-resolve-error.js';
245
222
  export declare class Library {
246
223
  private layers;
247
224
  /** The LIST-ENVELOPE LEDGER, overlay first so a prepared entry can add a row. */
@@ -15,21 +15,8 @@ import { loadListEnvelopes, lookupListEnvelope } from './list-envelope.js';
15
15
  import { lookupSpecOf } from './lookups.js';
16
16
  import { loadByoaLedger, loadInvariantCollections, loadLookupResolutions } from './lookup-store.js';
17
17
  import { ownEntry } from './own-entry.js';
18
- /**
19
- * The refusal {@link Library.resolve} throws, with a `code` for each reason.
20
- *
21
- * Typed so a caller can tell a refusal from a bug without matching on message
22
- * text: `check` reports it under this code with this message, and a compile
23
- * that throws it carries the same code into its `--json` diagnostics (#948).
24
- */
25
- export class ConnectorResolveError extends Error {
26
- code;
27
- constructor(code, message) {
28
- super(message);
29
- this.name = 'ConnectorResolveError';
30
- this.code = code;
31
- }
32
- }
18
+ import { ConnectorResolveError } from './connector-resolve-error.js';
19
+ export { ConnectorResolveError } from './connector-resolve-error.js';
33
20
  export class Library {
34
21
  layers = [];
35
22
  /** The LIST-ENVELOPE LEDGER, overlay first so a prepared entry can add a row. */
@@ -1,2 +1,22 @@
1
+ /**
2
+ * The TypeScript compiler, loaded on first use.
3
+ *
4
+ * Every builder entry reaches the expression and script checkers, and loading the compiler
5
+ * costs ~120 ms that a flow which never runs those checks should not pay (FB009). The
6
+ * specifier stays a literal at the call so the architecture lint sees the edge (as a lazy
7
+ * one); FB005 keeps this the only definition.
8
+ *
9
+ * A host without Node (a browser sandbox that bundles the compiler) hands it over before
10
+ * the first check: `globalThis[Symbol.for('uipath.maestro-builder-sdk.typescript')] = ts`.
11
+ * Otherwise `createRequire` comes from `process.getBuiltinModule`, not an `import`, so the
12
+ * modules that check a flow load no `node:` builtin (FB015 exempts this fallback).
13
+ * `process` is read through `globalThis`, as in `core/cli-spelling.ts`, so a host without
14
+ * one gets the error below instead of a `ReferenceError`.
15
+ *
16
+ * The triple-slash reference is load-bearing: tests type-check authored and generated
17
+ * code against `flow-sdk.ts`'s graph without `@types/node`, and that graph reaches other
18
+ * `node:` imports by type (`core/library-cache.ts`, `core/bindings.ts`). This reference is
19
+ * what brings the Node types into that program. It is not emitted into the .d.ts.
20
+ */
1
21
  import type * as TS from 'typescript';
2
22
  export declare function typescript(): typeof TS;
@@ -1,18 +1,13 @@
1
- /// <reference types="node" />
2
- /**
3
- * The TypeScript compiler, loaded on first use.
4
- *
5
- * Every builder entry reaches the expression and script checkers, and loading the compiler
6
- * costs ~120 ms that a flow which never runs those checks should not pay (FB009). The
7
- * specifier stays a literal at the call so the architecture lint sees the edge (as a lazy
8
- * one); FB005 keeps this the only definition.
9
- *
10
- * The triple-slash reference: tests type-check generated code against `flow-sdk.ts`'s
11
- * import graph without `@types/node` in scope, and this is the one `node:` import in that
12
- * graph. Without it they fail with TS2307 on 'node:module'. It is not emitted into the .d.ts.
13
- */
14
- import { createRequire } from 'node:module';
1
+ const HOST_TYPESCRIPT = Symbol.for('uipath.maestro-builder-sdk.typescript');
15
2
  let typescriptModule;
16
3
  export function typescript() {
17
- return (typescriptModule ??= createRequire(import.meta.url)('typescript'));
4
+ return (typescriptModule ??= globalThis[HOST_TYPESCRIPT] ?? fromNode());
5
+ }
6
+ function fromNode() {
7
+ const getBuiltinModule = globalThis.process?.getBuiltinModule;
8
+ if (getBuiltinModule === undefined) {
9
+ throw new Error("no TypeScript compiler: outside Node, set globalThis[Symbol.for('uipath.maestro-builder-sdk.typescript')] to the 'typescript' module before checking a flow");
10
+ }
11
+ const { createRequire } = getBuiltinModule('node:module');
12
+ return createRequire(import.meta.url)('typescript');
18
13
  }
@@ -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/merge-cli.js CHANGED
@@ -42,7 +42,8 @@
42
42
  import { reportResult } from './cli-result.js';
43
43
  import { writeJsonFile } from './core/json-file.js';
44
44
  import { existsSync, mkdirSync, readdirSync, readFileSync } from 'node:fs';
45
- import { readBindingsV2, readInlineAgentFiles, refreshInlineAgentRows } from './bindings-v2.js';
45
+ import { refreshInlineAgentRows } from './bindings-v2.js';
46
+ import { readBindingsV2, readInlineAgentFiles } from './bindings-v2-files.js';
46
47
  import { basename, dirname, join, resolve } from 'node:path';
47
48
  import { MergeRefusedError, mergeFlowWithSidecars } from './merge.js';
48
49
  import { sidecarSetFromList } from './merge-sidecars.js';
@@ -64,7 +64,7 @@
64
64
  *
65
65
  * Pure: the caller reads the files ({@link SidecarSet}) and writes the result.
66
66
  */
67
- import { jsonClone } from './core/json-file.js';
67
+ import { jsonClone } from './core/json-clone.js';
68
68
  /** The `{ path, json }` list `serializeWithSidecars` returns, as a {@link SidecarSet}. */
69
69
  export function sidecarSetFromList(list) {
70
70
  return (source) => {
package/dist/merge.js CHANGED
@@ -75,7 +75,7 @@
75
75
  * declare. See merge-roundtrip.ts.
76
76
  */
77
77
  import { bindingIdentity } from './core/binding-identity.js';
78
- import { jsonClone } from './core/json-file.js';
78
+ import { jsonClone } from './core/json-clone.js';
79
79
  import { DEFINITIONLESS_NODE_TYPES } from './core/definitionless-node-types.js';
80
80
  import { MergeRefusedError, mergedFileFindings, roundTripFindings } from './merge-roundtrip.js';
81
81
  import { placeAddedNodes } from './node-placement.js';
@@ -6,7 +6,7 @@
6
6
  * codes and messages unchanged.
7
7
  */
8
8
  import { Expr, toExpr } from '../../../core/expr.js';
9
- import { jsonClone } from '../../../core/json-file.js';
9
+ import { jsonClone } from '../../../core/json-clone.js';
10
10
  import { checkConversational } from './check.js';
11
11
  /**
12
12
  * The definition's `inputDefaults`, which supply the fixed fields the platform's
@@ -10,7 +10,7 @@
10
10
  * express yet.
11
11
  */
12
12
  import { toExpr } from '../../../core/expr.js';
13
- import { jsonClone } from '../../../core/json-file.js';
13
+ import { jsonClone } from '../../../core/json-clone.js';
14
14
  export const DOCUMENT_DIAGNOSTICS = {
15
15
  DOC_NO_FILEREF: { severity: 'error', summary: 'no fileRef, so nothing to classify or extract from' },
16
16
  EXTRACT_SCHEMA_SHAPE: { severity: 'error', summary: 'a Dynamic Extract schema that is not an object' },
@@ -16,7 +16,7 @@ import { Expr, toExpr } from '../../../core/expr.js';
16
16
  import { FORM_FIELD_JSON_TYPE, sdkFormFieldType } from '../../../core/form-field-type.js';
17
17
  import { isAnswerField } from '../../../core/hitl-answers.js';
18
18
  import { OUTCOME_HANDLE_NODE_TYPES, hitlExitModel, outcomeIdOf, outcomeSlug } from '../../../core/hitl-routing.js';
19
- import { jsonClone } from '../../../core/json-file.js';
19
+ import { jsonClone } from '../../../core/json-clone.js';
20
20
  import { ownEntry } from '../../../core/own-entry.js';
21
21
  import { schemaId } from '../../../core/stable-id.js';
22
22
  import { wireExprBody } from '../../../core/wire-expr.js';
@@ -7,7 +7,7 @@
7
7
  * messages unchanged. Decompile now also recovers `returns` (see `liftReturns`).
8
8
  */
9
9
  import { Expr } from '../../../core/expr.js';
10
- import { jsonClone } from '../../../core/json-file.js';
10
+ import { jsonClone } from '../../../core/json-clone.js';
11
11
  import { wireExprBody } from '../../../core/wire-expr.js';
12
12
  import { checkHttpRead, checkHttpStep, plainHttpOnErrorMessage } from './check.js';
13
13
  const PLAIN = 'core.action.http';
@@ -1,5 +1,5 @@
1
1
  import { Expr } from '../../../core/expr.js';
2
- import { jsonClone } from '../../../core/json-file.js';
2
+ import { jsonClone } from '../../../core/json-clone.js';
3
3
  import { checkQueueItem } from './check.js';
4
4
  import { QUEUE_ITEM_RECORD_SCHEMA } from './record.js';
5
5
  const CREATE = 'core.action.queue.create';
@@ -5,7 +5,7 @@
5
5
  * source, codes and messages unchanged.
6
6
  */
7
7
  import { declaredScriptShape, inferScriptShape } from '../../../core/script-return.js';
8
- import { jsonClone } from '../../../core/json-file.js';
8
+ import { jsonClone } from '../../../core/json-clone.js';
9
9
  import { checkScript } from './check.js';
10
10
  /**
11
11
  * Declare what a `core.action.script` node actually publishes.
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import { Expr } from '../../../core/expr.js';
10
10
  import { wireExprBody } from '../../../core/wire-expr.js';
11
- import { jsonClone } from '../../../core/json-file.js';
11
+ import { jsonClone } from '../../../core/json-clone.js';
12
12
  import { VARIANT_OPERATION } from './spec.js';
13
13
  import { checkTransform } from './check.js';
14
14
  /**
@@ -23,7 +23,7 @@ import { safeCacheName } from "../uip/response-cache.js";
23
23
  import { schemaCacheScope, writeCache } from "./context.js";
24
24
  import { objectsComeFromTheConnection } from "./generic-expand.js";
25
25
  import { codePointSlice, get, isPyDict, item, pyIter, pyOr, pyTruthy } from "./py.js";
26
- import { jsonClone } from "../../core/json-file.js";
26
+ import { jsonClone } from "../../core/json-clone.js";
27
27
  /**
28
28
  * `Parameters[].type` on a `triggers objects` row routes the value into one of
29
29
  * three `--detail` buckets at emit time. Everything unrecognized is an event
@@ -21,7 +21,7 @@ import { messageOf } from "../errors.js";
21
21
  import { isHttpPassthrough, normalizeFieldKeys, pick } from "./canonical.js";
22
22
  import { isDescribeObject, isDescribeOperation, isResourcesList } from "./context.js";
23
23
  import { get, item, pyIter, pyOr, pyTruthy } from "./py.js";
24
- import { jsonClone } from "../../core/json-file.js";
24
+ import { jsonClone } from "../../core/json-clone.js";
25
25
  /**
26
26
  * `_generic_templates_by_op`: bucket Generic CRUD entries by IS operation
27
27
  * name per connector. Generic CRUD actions carry an `operation` verb
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';
@@ -20,7 +20,7 @@ import { stepExits } from './flow-step-exits.js';
20
20
  import { resolveVersionCarried } from './core/nodes/versioned.js';
21
21
  import { indexCarriedDefinitions } from './core/carried-definitions.js';
22
22
  import { FORM_FIELD_JSON_TYPE } from './core/form-field-type.js';
23
- import { ConnectorResolveError } from './core/library.js';
23
+ import { ConnectorResolveError } from './core/connector-resolve-error.js';
24
24
  import { connectionConnectors } from './bindings-v2.js';
25
25
  import { BindingRefusal, GUID_RE, bindingLabelRefusal, bindingMissingMessage, missingBindingLabels } from './core/binding-messages.js';
26
26
  import { ByoaRefusal, byoaUnverified } from './core/byoa.js';
@@ -64,7 +64,7 @@ import { resourceNodeSortOrder } from './core/process-resource-sort-order.js';
64
64
  import { types } from './core/expr.js';
65
65
  import { SUBFLOW_START_LABEL } from './core/subflow-start.js';
66
66
  import { ownEntry } from './core/own-entry.js';
67
- import { jsonClone } from './core/json-file.js';
67
+ import { jsonClone } from './core/json-clone.js';
68
68
  // core-definitions.json is an object keyed by "<nodeType>@<version>".
69
69
  const DEFS = BUNDLED_DEFINITIONS;
70
70
  // FIRST occurrence wins: with multiple bundled versions of one family (HITL
@@ -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.31.0",
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": "21719d7a1fd422a6886d9021c02cf2f124c4f627"
96
96
  }