@uipath/maestro-builder-sdk 6.9.3 → 6.9.5
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/README.md +0 -6
- package/dist/api-index.md +56 -56
- package/dist/api-members.md +92 -91
- package/dist/check.js +34 -0
- package/dist/cli/commands/bpmn.js +4 -4
- package/dist/cli/commands/case.js +4 -4
- package/dist/cli/commands/flow.d.ts +1 -1
- package/dist/cli/commands/flow.js +33 -13
- package/dist/cli/common.d.ts +6 -0
- package/dist/cli/common.js +8 -0
- package/dist/compile-cli.js +82 -1
- package/dist/core/actions.d.ts +6 -0
- package/dist/serialize.d.ts +5 -4
- package/dist/serialize.js +195 -3
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { addValue, inferCheckMode, invoke, loadTool } from '../common.js';
|
|
1
|
+
import { addValue, inferCheckMode, invoke, loadTool, retiredCompiledOption } from '../common.js';
|
|
2
2
|
export function registerCaseCommands(program) {
|
|
3
3
|
const family = program.command('case').description('Build, check, and merge Case artifacts.');
|
|
4
4
|
family.command('compile')
|
|
@@ -17,10 +17,10 @@ export function registerCaseCommands(program) {
|
|
|
17
17
|
await invoke('case compile', () => loadTool(import.meta.url, '../../case/compile-cli.js'), argv);
|
|
18
18
|
});
|
|
19
19
|
family.command('check')
|
|
20
|
-
.description('Check authored TypeScript
|
|
21
|
-
.argument('<input>', '
|
|
20
|
+
.description('Check authored TypeScript. Check a caseplan.json with `uip maestro case validate`.')
|
|
21
|
+
.argument('<input>', 'a .case.ts path or bare name')
|
|
22
22
|
.option('--source', 'check authored TypeScript')
|
|
23
|
-
.
|
|
23
|
+
.addOption(retiredCompiledOption())
|
|
24
24
|
.action(async (input, options) => {
|
|
25
25
|
let mode;
|
|
26
26
|
try {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Command } from 'commander';
|
|
2
2
|
export declare function registerFlowCommands(program: Command): void;
|
|
@@ -1,4 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Option } from 'commander';
|
|
2
|
+
import { addValue, emitOnlyEnabled, inferCheckMode, invoke, loadTool, retiredCompiledOption } from '../common.js';
|
|
3
|
+
/** The retired compiled check's flags: `[commander flags, option key, description]`. One table, so hiding and warning cannot drift. */
|
|
4
|
+
const RETIRED_COMPILED_CHECK_FLAGS = [
|
|
5
|
+
['--json', 'json', 'retired: compiled-check diagnostics as JSON'],
|
|
6
|
+
['--uip', 'uip', 'retired: resolve missing schemas with the UiPath CLI'],
|
|
7
|
+
['--max-errors <count>', 'maxErrors', 'retired: stop after this many compiled-check errors'],
|
|
8
|
+
['--script-determinism', 'scriptDeterminism', 'retired: check script blocks for non-deterministic calls'],
|
|
9
|
+
['--quiet', 'quiet', 'retired: suppress warnings and information'],
|
|
10
|
+
['--debug-internal', 'debugInternal', 'retired: include internal compile context'],
|
|
11
|
+
['--dump-ir', 'dumpIr', 'retired: print the generated intermediate representation'],
|
|
12
|
+
];
|
|
13
|
+
function retiredFlagsPassed(options) {
|
|
14
|
+
return RETIRED_COMPILED_CHECK_FLAGS
|
|
15
|
+
.filter(([, key]) => options[key] !== undefined && options[key] !== false)
|
|
16
|
+
.map(([flags]) => flags.split(' ')[0]);
|
|
17
|
+
}
|
|
2
18
|
export function registerFlowCommands(program) {
|
|
3
19
|
const flow = program.command('flow').description('Build and check Flow artifacts.');
|
|
4
20
|
flow.command('compile')
|
|
@@ -19,20 +35,18 @@ export function registerFlowCommands(program) {
|
|
|
19
35
|
argv.push('--no-check');
|
|
20
36
|
await invoke('flow compile', () => loadTool(import.meta.url, '../../compile-cli.js'), argv);
|
|
21
37
|
});
|
|
22
|
-
flow.command('check')
|
|
23
|
-
.description('Check authored TypeScript
|
|
24
|
-
.argument('<input>', '
|
|
38
|
+
const check = flow.command('check')
|
|
39
|
+
.description('Check authored TypeScript. Check a compiled .flow with `uip maestro flow validate`.')
|
|
40
|
+
.argument('<input>', 'a .flow.ts path or bare name')
|
|
25
41
|
.option('--source', 'check authored TypeScript')
|
|
26
|
-
.
|
|
42
|
+
.addOption(retiredCompiledOption())
|
|
27
43
|
.option('--library <dir>', 'connector library directory')
|
|
28
|
-
.option('--connectors-local <dir>', 'connection-resolved connector overlay')
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
.option('--debug-internal', 'include internal compile context')
|
|
35
|
-
.option('--dump-ir', 'print the generated intermediate representation')
|
|
44
|
+
.option('--connectors-local <dir>', 'connection-resolved connector overlay');
|
|
45
|
+
// Hidden, not removed: scripts that pass these keep parsing.
|
|
46
|
+
for (const [flags, , description] of RETIRED_COMPILED_CHECK_FLAGS) {
|
|
47
|
+
check.addOption(new Option(flags, description).hideHelp());
|
|
48
|
+
}
|
|
49
|
+
check
|
|
36
50
|
.action(async (input, options) => {
|
|
37
51
|
if (emitOnlyEnabled()) {
|
|
38
52
|
console.error('flow-sdk flow check: disabled by emit-only mode; use `uip maestro flow validate` or `uip maestro flow debug`');
|
|
@@ -49,6 +63,12 @@ export function registerFlowCommands(program) {
|
|
|
49
63
|
return;
|
|
50
64
|
}
|
|
51
65
|
if (mode === 'source') {
|
|
66
|
+
const ignored = retiredFlagsPassed(options);
|
|
67
|
+
// Not under `--quiet`: a caller asking for less output (an older
|
|
68
|
+
// `uip` still forwards it) must not get a new line because of it.
|
|
69
|
+
if (ignored.length > 0 && options.quiet !== true) {
|
|
70
|
+
console.error(`flow-sdk flow check: ignoring ${ignored.join(', ')} (used only by the retired compiled check)`);
|
|
71
|
+
}
|
|
52
72
|
const argv = [input];
|
|
53
73
|
addValue(argv, '--library', options.library);
|
|
54
74
|
addValue(argv, '--connectors-local', options.connectorsLocal);
|
package/dist/cli/common.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Option } from 'commander';
|
|
1
2
|
export type ToolRun = (argv: string[]) => Promise<number> | number;
|
|
2
3
|
export declare function loadTool(baseUrl: string, relativePath: string): Promise<{
|
|
3
4
|
run: ToolRun;
|
|
@@ -28,3 +29,8 @@ export declare function addValue(argv: string[], flag: string, value: unknown):
|
|
|
28
29
|
export declare function emitOnlyEnabled(cwd?: string, env?: NodeJS.ProcessEnv): boolean;
|
|
29
30
|
export type CheckMode = 'source' | 'compiled';
|
|
30
31
|
export declare function inferCheckMode(family: 'flow' | 'case' | 'bpmn', input: string, source: boolean, compiled: boolean): CheckMode;
|
|
32
|
+
/**
|
|
33
|
+
* `--compiled` on `<family> check`: hidden from `--help`, still accepted so a
|
|
34
|
+
* script that passes it gets the redirect to `uip maestro <family> validate`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function retiredCompiledOption(): Option;
|
package/dist/cli/common.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, join, resolve } from 'node:path';
|
|
3
|
+
import { Option } from 'commander';
|
|
3
4
|
export function loadTool(baseUrl, relativePath) {
|
|
4
5
|
return import(new URL(relativePath, baseUrl).href);
|
|
5
6
|
}
|
|
@@ -90,3 +91,10 @@ export function inferCheckMode(family, input, source, compiled) {
|
|
|
90
91
|
}
|
|
91
92
|
return source ? 'source' : compiled ? 'compiled' : inferred;
|
|
92
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* `--compiled` on `<family> check`: hidden from `--help`, still accepted so a
|
|
96
|
+
* script that passes it gets the redirect to `uip maestro <family> validate`.
|
|
97
|
+
*/
|
|
98
|
+
export function retiredCompiledOption() {
|
|
99
|
+
return new Option('--compiled', 'retired: a compiled artifact is checked by `uip maestro <family> validate`').hideHelp();
|
|
100
|
+
}
|
package/dist/compile-cli.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* product's own gates are supposed to answer. `.build()` still throws on
|
|
18
18
|
* structural problems; only the diagnostic pass is skipped.
|
|
19
19
|
*/
|
|
20
|
-
import { writeFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
20
|
+
import { writeFileSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync } from 'node:fs';
|
|
21
21
|
import { basename, dirname, join, resolve } from 'node:path';
|
|
22
22
|
import { resolveFlowFile, loadBuiltFlow } from './load.js';
|
|
23
23
|
import { serializeWithSidecars, connectorInputErrors } from './serialize.js';
|
|
@@ -32,6 +32,28 @@ function opt(argv, name) {
|
|
|
32
32
|
const i = argv.indexOf(name);
|
|
33
33
|
return i >= 0 ? argv[i + 1] : undefined;
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* The deployed-resource tool `type` values `compile` writes. NOT every
|
|
37
|
+
* `$resourceType: 'tool'`: `uip agent refresh` generates the `integration` ones
|
|
38
|
+
* from the flow's connector nodes into the same directory, so pruning by
|
|
39
|
+
* `$resourceType` alone would delete the generator's own output.
|
|
40
|
+
*/
|
|
41
|
+
const COMPILE_OWNED_TOOL_TYPES = new Set([
|
|
42
|
+
'process', 'api', 'processOrchestration', 'flow', 'agent', 'function',
|
|
43
|
+
]);
|
|
44
|
+
/**
|
|
45
|
+
* Does `compile` own this resource file — i.e. would this run have written it,
|
|
46
|
+
* so an unwritten one is stale rather than someone else's?
|
|
47
|
+
*
|
|
48
|
+
* Everything it says no to belongs to `uip agent refresh` (connector tools) or to
|
|
49
|
+
* the designer (escalation, mcp, and the kinds the SDK cannot derive).
|
|
50
|
+
*/
|
|
51
|
+
function compileOwnsResource(body) {
|
|
52
|
+
const kind = body?.$resourceType;
|
|
53
|
+
if (kind === 'context')
|
|
54
|
+
return true;
|
|
55
|
+
return kind === 'tool' && COMPILE_OWNED_TOOL_TYPES.has(String(body?.type));
|
|
56
|
+
}
|
|
35
57
|
export async function run(argv) {
|
|
36
58
|
if (argv.length === 0 || argv[0] === '-h' || argv[0] === '--help') {
|
|
37
59
|
console.error('usage: compile <flow.ts | BaseName> [-o out.flow] [--library <dir>] [--bindings <file>]');
|
|
@@ -152,6 +174,61 @@ export async function run(argv) {
|
|
|
152
174
|
writeFileSync(target, JSON.stringify(s.json, null, 2) + '\n');
|
|
153
175
|
console.log(`compile: wrote ${s.path}`);
|
|
154
176
|
}
|
|
177
|
+
// PRUNE the agent resources this compile owns but did not write this time.
|
|
178
|
+
// Compile otherwise only ever ADDS files, and an agent resource is keyed by a
|
|
179
|
+
// uuid derived from the step name and the resource's identity — so dropping a
|
|
180
|
+
// `context` from a step, or pointing it at a different index, orphans the old
|
|
181
|
+
// `resources/<uuid>/resource.json` instead of replacing it. Nothing later
|
|
182
|
+
// notices it is orphaned: `uip agent refresh` reads every file under
|
|
183
|
+
// `resources/` and declares it, so `bindings_v2.json` keeps binding an index
|
|
184
|
+
// the flow no longer references, and a deploy can fail on an index that is
|
|
185
|
+
// gone. Measured 2026-09-25 — compile with a context, remove it, recompile:
|
|
186
|
+
// the file survives and refresh still reports `Resources: 1`.
|
|
187
|
+
//
|
|
188
|
+
// Only the types THIS compile emits are pruned. `uip agent refresh` generates
|
|
189
|
+
// connector-tool resources into the same directory, and the designer writes
|
|
190
|
+
// the families the SDK cannot, so anything else found there is someone else's
|
|
191
|
+
// and is left alone.
|
|
192
|
+
const staleBindings = [];
|
|
193
|
+
const owned = new Set(sidecars
|
|
194
|
+
.filter((s) => /\/resources\/[^/]+\/resource\.json$/.test(s.path))
|
|
195
|
+
.map((s) => resolve(outDir, s.path)));
|
|
196
|
+
for (const agentDir of new Set(sidecars
|
|
197
|
+
.filter((s) => s.path.endsWith('/agent.json'))
|
|
198
|
+
.map((s) => dirname(resolve(outDir, s.path))))) {
|
|
199
|
+
const resourcesDir = join(agentDir, 'resources');
|
|
200
|
+
if (!existsSync(resourcesDir))
|
|
201
|
+
continue;
|
|
202
|
+
for (const entry of readdirSync(resourcesDir)) {
|
|
203
|
+
const file = join(resourcesDir, entry, 'resource.json');
|
|
204
|
+
if (!existsSync(file) || owned.has(file))
|
|
205
|
+
continue;
|
|
206
|
+
let body;
|
|
207
|
+
try {
|
|
208
|
+
body = JSON.parse(readFileSync(file, 'utf8'));
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
continue; // unreadable: not ours to delete
|
|
212
|
+
}
|
|
213
|
+
if (!compileOwnsResource(body))
|
|
214
|
+
continue;
|
|
215
|
+
const resourceType = body?.$resourceType;
|
|
216
|
+
// The binding `uip agent refresh` derived FROM this file has to go with it.
|
|
217
|
+
// Refresh will not retract it: with no resources left it writes nothing, and
|
|
218
|
+
// `mergeBindingsV2` preserves every non-connection entry, so the removed
|
|
219
|
+
// index would stay declared in `bindings_v2.json` and a deploy could still
|
|
220
|
+
// fail on it. Keyed the way refresh keys it — an index by its name.
|
|
221
|
+
const named = body?.indexName ?? body?.name;
|
|
222
|
+
const key = typeof named === 'string' && named !== '' ? named : undefined;
|
|
223
|
+
if (key !== undefined) {
|
|
224
|
+
// Keyed the way refresh keys it: an index by its name, a deployed-resource
|
|
225
|
+
// tool under `process` whatever its own type says.
|
|
226
|
+
staleBindings.push({ resource: resourceType === 'context' ? 'index' : 'process', key });
|
|
227
|
+
}
|
|
228
|
+
rmSync(join(resourcesDir, entry), { recursive: true, force: true });
|
|
229
|
+
console.log(`compile: removed stale ${join('resources', entry, 'resource.json')}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
155
232
|
// `bindings_v2.json` — the solution-resource sidecar `uip solution resources
|
|
156
233
|
// refresh` reads. Without it the connection is never declared, so the canvas
|
|
157
234
|
// and the VS Code extension flag the Flow's connection as invalid
|
|
@@ -167,6 +244,10 @@ export async function run(argv) {
|
|
|
167
244
|
// file for a flow that has no resources at all.
|
|
168
245
|
if (connections.length > 0 || existing !== undefined) {
|
|
169
246
|
const merged = mergeBindingsV2(existing, connections);
|
|
247
|
+
if (staleBindings.length > 0) {
|
|
248
|
+
const dropped = new Set(staleBindings.map((b) => `${b.resource}\u0000${b.key}`));
|
|
249
|
+
merged.resources = merged.resources.filter((r) => !dropped.has(`${r.resource}\u0000${r.key}`));
|
|
250
|
+
}
|
|
170
251
|
writeFileSync(sidecarPath, JSON.stringify(merged, null, 2) + '\n');
|
|
171
252
|
const kept = merged.resources.length - connections.length;
|
|
172
253
|
console.log(`compile: wrote bindings_v2.json (${connections.length} connection resource(s)`
|
package/dist/core/actions.d.ts
CHANGED
|
@@ -1827,6 +1827,12 @@ export interface ProcessToolRef {
|
|
|
1827
1827
|
name: string;
|
|
1828
1828
|
/** The Orchestrator folder it lives in, e.g. `'Shared'`. */
|
|
1829
1829
|
folderPath: string;
|
|
1830
|
+
/**
|
|
1831
|
+
* What the tool does. The agent runtime hands this to the MODEL as the tool's
|
|
1832
|
+
* description, so it is how the model decides when to call it — a tool with
|
|
1833
|
+
* only a name is one the model has to guess at.
|
|
1834
|
+
*/
|
|
1835
|
+
description?: string;
|
|
1830
1836
|
/** The resource's input arguments, by name and type — becomes its `inputSchema`. */
|
|
1831
1837
|
inputs?: Record<string, InlineAgentFieldType>;
|
|
1832
1838
|
/** What it returns, by name and type — becomes its `outputSchema`. */
|
package/dist/serialize.d.ts
CHANGED
|
@@ -23,10 +23,11 @@ export interface SerializeOpts {
|
|
|
23
23
|
warn?: (warning: SerializeWarning) => void;
|
|
24
24
|
/**
|
|
25
25
|
* Filled in by `serialize` with the extra files the flow needs beside the
|
|
26
|
-
* `.flow`, relative to it
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
26
|
+
* `.flow`, relative to it: one `<source>/agent.json` per inline agent, plus a
|
|
27
|
+
* `<source>/resources/<id>/resource.json` for each capability the compiler can
|
|
28
|
+
* derive. The node points at that directory and the platform resolves the
|
|
29
|
+
* agent's real configuration there, so a `.flow` shipped without them references
|
|
30
|
+
* a definition that is not on disk.
|
|
30
31
|
*
|
|
31
32
|
* An out-parameter rather than a second return value so no caller that ignores
|
|
32
33
|
* sidecars has to change — but a caller that WRITES the flow has to write these
|
package/dist/serialize.js
CHANGED
|
@@ -857,6 +857,172 @@ function renderContextQuery(query, rename) {
|
|
|
857
857
|
}
|
|
858
858
|
return { ...base, promptValue: asText };
|
|
859
859
|
}
|
|
860
|
+
/**
|
|
861
|
+
* The file extension each retrieval mode accepts by default. The platform's
|
|
862
|
+
* manifest defaults every mode's NODE to `All`, but its resource schema pins
|
|
863
|
+
* `structured`/`batchtransform` to `csv` and `deeprag` to `pdf`/`txt` — so a
|
|
864
|
+
* flat `All` default would emit a resource the platform refuses to parse for
|
|
865
|
+
* every mode but `semantic`.
|
|
866
|
+
*/
|
|
867
|
+
const DEFAULT_FILE_EXTENSION = {
|
|
868
|
+
semantic: 'All',
|
|
869
|
+
structured: 'csv',
|
|
870
|
+
deeprag: 'pdf',
|
|
871
|
+
batchtransform: 'csv',
|
|
872
|
+
};
|
|
873
|
+
/**
|
|
874
|
+
* The `resources/<id>/resource.json` an inline agent's context index needs.
|
|
875
|
+
*
|
|
876
|
+
* The node is only half of a grounded agent, the same split as the agent itself
|
|
877
|
+
* (see `inlineAgentJson`). The platform resolves an agent's capabilities from
|
|
878
|
+
* `<source>/resources/<resource-id>/resource.json`, and `uip agent refresh` turns
|
|
879
|
+
* those into the `bindings_v2.json` entries `uip solution resources refresh`
|
|
880
|
+
* syncs. Keyed by the node's `inputs.source`, which is what joins the two halves.
|
|
881
|
+
*
|
|
882
|
+
* On the CLI path the file is the only copy: refresh strips the node and
|
|
883
|
+
* re-derives it from here, so a `.flow` with the node and no file validates clean
|
|
884
|
+
* and leaves the agent ungrounded. (Studio Web is the other direction — its
|
|
885
|
+
* `mapContextResource` builds this file FROM the canvas node.)
|
|
886
|
+
*
|
|
887
|
+
* Shape and enums are the platform's `currentResourceStorageSchema`
|
|
888
|
+
* (`@uipath/agents-storage-schemas`): `description`, `folderPath`, `indexName` and
|
|
889
|
+
* all six `settings` keys are required, `fileExtension` is `{value}` rather than a
|
|
890
|
+
* bare string, and the retrieval mode pins which extensions it accepts — hence the
|
|
891
|
+
* per-mode default here against the node's flat `'All'`. An unparseable resource
|
|
892
|
+
* is worse than none: `uip agent refresh` falls back to `resources: []` and drops
|
|
893
|
+
* every other binding with it.
|
|
894
|
+
*/
|
|
895
|
+
function contextResourceJson(cx, spec) {
|
|
896
|
+
const mode = cx.retrievalMode ?? 'semantic';
|
|
897
|
+
return {
|
|
898
|
+
$resourceType: 'context',
|
|
899
|
+
id: spec.id,
|
|
900
|
+
// Null rather than absent: optional in the schema, but every deployed
|
|
901
|
+
// resource carries it, and a designer round-trip writes it back.
|
|
902
|
+
referenceKey: null,
|
|
903
|
+
name: cx.name,
|
|
904
|
+
description: `Context grounding index "${cx.name}".`,
|
|
905
|
+
contextType: 'index',
|
|
906
|
+
// Required by the schema, and load-bearing: this file carries no `indexId`,
|
|
907
|
+
// so `indexName` + `folderPath` is the whole locator, and `createIndexBinding`
|
|
908
|
+
// leaves the folder off the binding when it is empty. `check` warns when the
|
|
909
|
+
// author omits it — an index outside the deployment folder is then unresolvable.
|
|
910
|
+
folderPath: cx.folderPath ?? '',
|
|
911
|
+
indexName: cx.name,
|
|
912
|
+
settings: {
|
|
913
|
+
retrievalMode: mode,
|
|
914
|
+
// The resource's `query` is VARIANT-tagged where the node's is MODE-tagged,
|
|
915
|
+
// and the two vocabularies do not overlap. `prompt` — what a designer types
|
|
916
|
+
// as guidance — is the model-invoked `dynamic`, and its text is the
|
|
917
|
+
// `description` the model reads when deciding what to search for.
|
|
918
|
+
// `text-builder` — an expression the runtime templates — is the pre-fetched
|
|
919
|
+
// `static`, and its text is the `value`. Confirmed behaviourally: switching
|
|
920
|
+
// the SDK's `query` from a string to an expression turned the same agent's
|
|
921
|
+
// retrieval from a tool call into a pre-fetch.
|
|
922
|
+
query: spec.query.mode === 'text-builder'
|
|
923
|
+
? { variant: 'static', value: String(spec.query.textValue ?? '') }
|
|
924
|
+
: { variant: 'dynamic', description: String(spec.query.promptValue ?? '') },
|
|
925
|
+
folderPathPrefix: { variant: 'static' },
|
|
926
|
+
threshold: cx.threshold ?? 0,
|
|
927
|
+
resultCount: cx.resultCount ?? 3,
|
|
928
|
+
fileExtension: { value: cx.fileExtension ?? DEFAULT_FILE_EXTENSION[mode] ?? 'All' },
|
|
929
|
+
// Mode-specific keys the schema REQUIRES of those two modes and rejects
|
|
930
|
+
// nowhere else, carrying the node's own constants through the enum's
|
|
931
|
+
// spelling (the node says `enabled`; the resource says `Enabled`/`Inline`).
|
|
932
|
+
...(mode === 'deeprag' ? { citationMode: { value: 'Inline' } } : {}),
|
|
933
|
+
...(mode === 'batchtransform'
|
|
934
|
+
? { webSearchGrounding: { value: 'Enabled' }, outputColumns: [] }
|
|
935
|
+
: {}),
|
|
936
|
+
},
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
/** A `fieldSchema` object with every declared property marked required. */
|
|
940
|
+
function requireAll(schema) {
|
|
941
|
+
const names = Object.keys(schema.properties);
|
|
942
|
+
return names.length === 0 ? schema : { ...schema, required: names };
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* The resource `type` each deployed-resource tool kind carries in the agent
|
|
946
|
+
* project, which is NOT its node-type namespace: `maestro` mints
|
|
947
|
+
* `…tool.processorchestration.*` and its resource type is `processOrchestration`.
|
|
948
|
+
* Read off the platform's `currentResourceStorageSchema`; flow-workbench's
|
|
949
|
+
* `CANVAS_TO_STORAGE_TOOL_TYPE` maps them the same way.
|
|
950
|
+
*/
|
|
951
|
+
const TOOL_RESOURCE_TYPE = {
|
|
952
|
+
process: 'process', api: 'api', maestro: 'processOrchestration',
|
|
953
|
+
flow: 'flow', agent: 'agent', function: 'function',
|
|
954
|
+
};
|
|
955
|
+
/**
|
|
956
|
+
* The `resources/<id>/resource.json` a DEPLOYED-RESOURCE tool needs — the tool
|
|
957
|
+
* half of what `contextResourceJson` does for an index, and inert for the same
|
|
958
|
+
* reason (see that function).
|
|
959
|
+
*
|
|
960
|
+
* Shape from a real agent project (`WebResearchBriefingAgent`'s `CountSources`,
|
|
961
|
+
* a `kind: 'process'` tool), cross-checked against the platform schema: this
|
|
962
|
+
* family carries `argumentProperties` and `referenceKey` but no `iconUrl`, and
|
|
963
|
+
* `exampleCalls` is present-and-empty. `location: 'solution'` and an empty
|
|
964
|
+
* `properties.folderPath` are the inline-in-flow pair Studio Web's
|
|
965
|
+
* `mapToolResource` writes and uipcli's `agent validate` enforces — the folder
|
|
966
|
+
* itself lives in the flow's top-level `bindings[]`, which
|
|
967
|
+
* `processResourceBindings` already writes for this tool.
|
|
968
|
+
*
|
|
969
|
+
* Returns `undefined` for every OTHER kind. Which kinds get a file is measured,
|
|
970
|
+
* because `uip agent refresh` strips each resource node and re-derives it FROM
|
|
971
|
+
* the file: where the node is `source`-only the round-trip is lossless, and where
|
|
972
|
+
* the node carries the configuration the strip loses it and the rebuild cannot
|
|
973
|
+
* put it back, so writing the file turns a valid flow INVALID.
|
|
974
|
+
*
|
|
975
|
+
* * `ixp`, `clientside` — measured to fail exactly that way (`ixp` leaves the
|
|
976
|
+
* flow failing validate; `clientside` drops the four inputs its node needs).
|
|
977
|
+
* * `connector` — `uip agent refresh` GENERATES it from the flow's connector
|
|
978
|
+
* node, reconstructing a whole `properties` block the SDK should not duplicate.
|
|
979
|
+
* * `mcp`, `a2a` — need the server's `availableTools` and the remote agent's
|
|
980
|
+
* card, which are tenant reads.
|
|
981
|
+
* * `builtin`, `httpRequest` — need a `properties.toolType` that maps
|
|
982
|
+
* one-to-one for `batchtransform` alone; a wrong one selects a different tool.
|
|
983
|
+
*/
|
|
984
|
+
function toolResourceJson(tr, spec) {
|
|
985
|
+
const common = {
|
|
986
|
+
$resourceType: 'tool',
|
|
987
|
+
id: spec.id,
|
|
988
|
+
name: tr.name,
|
|
989
|
+
// The runtime hands this to the MODEL as the tool's description, so an empty
|
|
990
|
+
// one is a tool the model has to guess at from its name alone.
|
|
991
|
+
description: tr.description ?? '',
|
|
992
|
+
isEnabled: true,
|
|
993
|
+
// `required` matters here where it does not on the agent's own contract: the
|
|
994
|
+
// model reads this schema to build the call, and an argument the process needs
|
|
995
|
+
// but the schema calls optional fails at run time with nothing said at compile
|
|
996
|
+
// time. The corpus fixture lists every declared argument.
|
|
997
|
+
inputSchema: requireAll(fieldSchema(tr.inputs)),
|
|
998
|
+
outputSchema: fieldSchema(tr.returns),
|
|
999
|
+
// No policies: `inlineAgent`'s tool refs carry none, and the field is
|
|
1000
|
+
// required-but-emptyable.
|
|
1001
|
+
guardrail: { policies: [] },
|
|
1002
|
+
settings: {},
|
|
1003
|
+
argumentProperties: {},
|
|
1004
|
+
};
|
|
1005
|
+
const resourceType = TOOL_RESOURCE_TYPE[tr.kind];
|
|
1006
|
+
if (resourceType !== undefined) {
|
|
1007
|
+
return {
|
|
1008
|
+
...common,
|
|
1009
|
+
type: resourceType,
|
|
1010
|
+
location: 'solution',
|
|
1011
|
+
// The deployed resource's own key: what joins this tool to the release the
|
|
1012
|
+
// solution declares.
|
|
1013
|
+
referenceKey: tr.key,
|
|
1014
|
+
// `folderPath` is EMPTY on purpose, and the tenant folder is not lost: for
|
|
1015
|
+
// an inline-in-flow agent the folder lives in the flow's own top-level
|
|
1016
|
+
// `bindings[]`, which `processResourceBindings` already writes for this
|
|
1017
|
+
// tool. uipcli's `agent validate` says so where it enforces the pair —
|
|
1018
|
+
// *"Inline-in-flow agents store folder info in the flow's top-level
|
|
1019
|
+
// bindings[] rather than in the tool resource — Studio Web emits an empty
|
|
1020
|
+
// folderPath here"* — and every `inlineAgent` tool is inline by definition.
|
|
1021
|
+
properties: { processName: tr.name, folderPath: '', exampleCalls: [] },
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
1024
|
+
return undefined;
|
|
1025
|
+
}
|
|
860
1026
|
/**
|
|
861
1027
|
* The one TARGET handle every tool resource declares: `input`, artifact-typed,
|
|
862
1028
|
* fed by the two agent types' `tool` handles. Transcribed from `registry get`
|
|
@@ -4496,6 +4662,12 @@ export function serialize(built, opts = {}) {
|
|
|
4496
4662
|
// `inputDefaults` are the shape a designer-placed node has — so an omitted
|
|
4497
4663
|
// option emits the designer's value rather than nothing.
|
|
4498
4664
|
delete cnode.model;
|
|
4665
|
+
// ONE identity, spent twice: the node's `inputs.source` and the sidecar
|
|
4666
|
+
// resource's `id` are the same uuid, because that is what joins them. The
|
|
4667
|
+
// platform validator says so in its own refusal text — *"the resource id
|
|
4668
|
+
// from the parent inline agent's `resources[]`"*.
|
|
4669
|
+
const contextResourceId = stableUuid(`${built.id}/${step.name}/context/${cx.id}`);
|
|
4670
|
+
const contextQuery = renderContextQuery(cx.query, scope.rename);
|
|
4499
4671
|
cnode.inputs = {
|
|
4500
4672
|
// REQUIRED, and the platform's validator is what says so — measured
|
|
4501
4673
|
// 2026-07-31, omitting it: *"Node type
|
|
@@ -4504,7 +4676,7 @@ export function serialize(built, opts = {}) {
|
|
|
4504
4676
|
// node"* (MST-9265). It is the resource's own identity inside the
|
|
4505
4677
|
// project, so it is derived from flow + step + index rather than random,
|
|
4506
4678
|
// exactly like the agent's `source`: a recompile must not be a diff.
|
|
4507
|
-
source:
|
|
4679
|
+
source: contextResourceId,
|
|
4508
4680
|
indexId: cx.id,
|
|
4509
4681
|
indexName: cx.name,
|
|
4510
4682
|
...(cx.folderKey === undefined ? {} : { folderKey: cx.folderKey }),
|
|
@@ -4514,7 +4686,7 @@ export function serialize(built, opts = {}) {
|
|
|
4514
4686
|
// `{mode, textValue, promptValue, argumentPath}`, with the mode saying
|
|
4515
4687
|
// which field is live. A plain string is the `prompt` mode; a flow
|
|
4516
4688
|
// expression is `text-builder`, whose `textValue` the runtime templates.
|
|
4517
|
-
query:
|
|
4689
|
+
query: contextQuery,
|
|
4518
4690
|
threshold: cx.threshold ?? 0,
|
|
4519
4691
|
resultCount: cx.resultCount ?? 3,
|
|
4520
4692
|
fileExtension: cx.fileExtension ?? 'All',
|
|
@@ -4525,6 +4697,12 @@ export function serialize(built, opts = {}) {
|
|
|
4525
4697
|
};
|
|
4526
4698
|
scope.nodes.push(cnode);
|
|
4527
4699
|
addEdge(scope, { node: id, port: 'context' }, cid, 'input');
|
|
4700
|
+
// The other half — without it the node is inert: see
|
|
4701
|
+
// `contextResourceJson`.
|
|
4702
|
+
sidecars.push({
|
|
4703
|
+
path: `${source}/resources/${contextResourceId}/resource.json`,
|
|
4704
|
+
json: contextResourceJson(cx, { id: contextResourceId, query: contextQuery }),
|
|
4705
|
+
});
|
|
4528
4706
|
}
|
|
4529
4707
|
// TOOLS — one resource node per tool, joined to the agent's `tool` handle;
|
|
4530
4708
|
// the same artifact shape as context (no incoming control flow, no output,
|
|
@@ -4674,12 +4852,23 @@ export function serialize(built, opts = {}) {
|
|
|
4674
4852
|
: tr.kind === 'clientside' ? `clientside.${tr.name}`
|
|
4675
4853
|
: tr.kind === 'httpRequest' ? `httprequest.${tr.name ?? 'default'}`
|
|
4676
4854
|
: tr.key;
|
|
4855
|
+
const toolResourceId = stableUuid(`${built.id}/${step.name}/tool/${toolSeed}`);
|
|
4677
4856
|
tnode.inputs = {
|
|
4678
|
-
source:
|
|
4857
|
+
source: toolResourceId,
|
|
4679
4858
|
...extraInputs,
|
|
4680
4859
|
};
|
|
4681
4860
|
scope.nodes.push(tnode);
|
|
4682
4861
|
addEdge(scope, { node: id, port: 'tool' }, tid, 'input');
|
|
4862
|
+
// The other half, for the kinds whose file is DERIVABLE — see
|
|
4863
|
+
// `toolResourceJson` for which are not, and why each is left to the
|
|
4864
|
+
// generator or the designer rather than guessed.
|
|
4865
|
+
const toolResource = toolResourceJson(tr, { id: toolResourceId });
|
|
4866
|
+
if (toolResource !== undefined) {
|
|
4867
|
+
sidecars.push({
|
|
4868
|
+
path: `${source}/resources/${toolResourceId}/resource.json`,
|
|
4869
|
+
json: toolResource,
|
|
4870
|
+
});
|
|
4871
|
+
}
|
|
4683
4872
|
}
|
|
4684
4873
|
// ESCALATION — the agent's TOP handle; an Action Center app task a human
|
|
4685
4874
|
// completes. The node's inputs are the platform's `inputDefaults` shape
|
|
@@ -4787,6 +4976,9 @@ export function serialize(built, opts = {}) {
|
|
|
4787
4976
|
};
|
|
4788
4977
|
scope.nodes.push(mnode);
|
|
4789
4978
|
addEdge(scope, { node: id, port: 'memory' }, mid, 'input');
|
|
4979
|
+
// No `features/<id>/feature.json` until `check` stops refusing memory
|
|
4980
|
+
// (AGENT_MEMORY_NOT_AUTHORABLE); its shape maps cleanly off `AgentMemoryRef`
|
|
4981
|
+
// but cannot be exercised while the handle does not exist.
|
|
4790
4982
|
}
|
|
4791
4983
|
for (const t of tails)
|
|
4792
4984
|
addEdge(scope, t, id);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/maestro-builder-sdk",
|
|
3
|
-
"version": "6.9.
|
|
3
|
+
"version": "6.9.5",
|
|
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",
|
|
@@ -87,5 +87,5 @@
|
|
|
87
87
|
"@types/node": "^22.7.0",
|
|
88
88
|
"esbuild": "^0.28.1"
|
|
89
89
|
},
|
|
90
|
-
"gitref": "
|
|
90
|
+
"gitref": "00c45d3d66df22a4df5cacf627baa308f7d43532"
|
|
91
91
|
}
|