@uipath/maestro-builder-sdk 6.8.5 → 6.9.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.
- package/dist/api-index.md +68 -68
- package/dist/api-members.md +161 -161
- package/dist/check-cli.js +13 -16
- package/dist/check.d.ts +39 -0
- package/dist/check.js +166 -9
- package/dist/cli/commands/flow.js +2 -0
- package/dist/cli-library.d.ts +21 -0
- package/dist/cli-library.js +56 -0
- package/dist/compile-cli.js +12 -11
- package/dist/core/actions.d.ts +27 -11
- package/dist/core/actions.js +2 -2
- package/dist/core/library.d.ts +20 -0
- package/dist/core/library.js +97 -20
- package/dist/core/node-classes.d.ts +8 -0
- package/dist/core/node-classes.js +27 -3
- package/dist/core/typed-raw-node.d.ts +97 -0
- package/dist/core/typed-raw-node.js +199 -0
- package/dist/registry/library-build/build.js +2 -1
- package/dist/registry/library-build/context.d.ts +26 -0
- package/dist/registry/library-build/context.js +25 -12
- package/dist/registry/library-build/events.js +3 -2
- package/dist/registry/prepare/actions.d.ts +42 -5
- package/dist/registry/prepare/actions.js +90 -16
- package/dist/registry/prepare/connections.js +2 -3
- package/dist/registry/prepare/event.d.ts +15 -6
- package/dist/registry/prepare/event.js +19 -11
- package/dist/registry/prepare/messages.d.ts +32 -4
- package/dist/registry/prepare/messages.js +80 -15
- package/dist/registry/prepare/pipeline.js +15 -9
- package/dist/registry/prepare/resolve.js +2 -1
- package/dist/registry/uip/envelope.d.ts +44 -9
- package/dist/registry/uip/envelope.js +80 -0
- package/dist/serialize.js +16 -2
- package/package.json +2 -2
package/dist/check-cli.js
CHANGED
|
@@ -6,15 +6,15 @@
|
|
|
6
6
|
* Prints diagnostics; exits non-zero if any errors.
|
|
7
7
|
*/
|
|
8
8
|
import { existsSync } from 'node:fs';
|
|
9
|
-
import { join } from 'node:path';
|
|
10
9
|
import { resolveFlowFile, loadBuiltFlow } from './load.js';
|
|
11
10
|
import { check } from './check.js';
|
|
12
|
-
import {
|
|
11
|
+
import { eventResolveErrorFor, openCliLibrary } from './cli-library.js';
|
|
13
12
|
import { Bindings } from './bindings.js';
|
|
14
13
|
import { connectorInputErrors } from './serialize.js';
|
|
15
14
|
import { runWhenInvokedDirectly } from './cli-run.js';
|
|
16
15
|
import { ensureTypeScriptRuntime } from './node-runtime.js';
|
|
17
|
-
|
|
16
|
+
/** Flags that take a value, so the value is never read as the source argument. */
|
|
17
|
+
const VALUE_FLAGS = new Set(['--library', '--bindings', '--connectors-local']);
|
|
18
18
|
/**
|
|
19
19
|
* Library lookups for the checks whose facts live in the connector corpus:
|
|
20
20
|
* event parameters and measured list envelopes.
|
|
@@ -23,33 +23,30 @@ import { resolveLibraryDir } from './registry/cache.js';
|
|
|
23
23
|
* function of the built flow — with no library it simply cannot know whether an
|
|
24
24
|
* empty `where` is correct, so it fails open (a warning, not an error). Given a
|
|
25
25
|
* library, `compile` and `check` make the same call with the facts in hand.
|
|
26
|
-
* `--library`
|
|
26
|
+
* `--library` and `--connectors-local` mirror compile-cli's flags and defaults,
|
|
27
|
+
* through the same `openCliLibrary`.
|
|
27
28
|
*/
|
|
28
29
|
function checkOpts(argv) {
|
|
29
|
-
const flag = argv.indexOf('--library');
|
|
30
|
-
const libDir = resolveLibraryDir(flag >= 0 ? argv[flag + 1] : undefined);
|
|
31
30
|
// bindings.json beside the source, exactly as compile-cli finds it — so the
|
|
32
31
|
// own-name refusal compile would raise is reported here first.
|
|
33
32
|
const bindFlag = argv.indexOf('--bindings');
|
|
34
33
|
const bindFile = bindFlag >= 0 ? argv[bindFlag + 1] : (existsSync('bindings.json') ? 'bindings.json' : undefined);
|
|
35
34
|
const bindings = bindFile ? new Bindings(bindFile) : undefined;
|
|
36
|
-
if (!libDir || !existsSync(join(libDir, 'index.json')))
|
|
37
|
-
return bindings ? { bindings } : {};
|
|
38
35
|
// The overlay matters here as much as it does for compile: `resolutions.json`
|
|
39
36
|
// lives in it, and without it every already-resolved lookup would be reported
|
|
40
37
|
// as still owed — telling the author to re-run a `prepare` they already ran.
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
:
|
|
44
|
-
const library = new Library(libDir, { overlayDir });
|
|
38
|
+
const library = openCliLibrary(argv);
|
|
39
|
+
if (!library)
|
|
40
|
+
return bindings ? { bindings } : {};
|
|
45
41
|
return {
|
|
42
|
+
eventResolveError: eventResolveErrorFor(library),
|
|
46
43
|
eventParams: (connector, event, object) => {
|
|
47
44
|
try {
|
|
48
45
|
return library.eventParameterFields(connector, event, object);
|
|
49
46
|
}
|
|
50
47
|
catch {
|
|
51
|
-
// An unresolvable operation is EVENT_UNKNOWN's business
|
|
52
|
-
//
|
|
48
|
+
// An unresolvable operation is EVENT_UNKNOWN's business, reported from
|
|
49
|
+
// `eventResolveError` above; here it just means "unknown".
|
|
53
50
|
return undefined;
|
|
54
51
|
}
|
|
55
52
|
},
|
|
@@ -96,9 +93,9 @@ function checkOpts(argv) {
|
|
|
96
93
|
};
|
|
97
94
|
}
|
|
98
95
|
export async function run(argv) {
|
|
99
|
-
const arg = argv.find((a) => !a.startsWith('--')) ?? argv[0];
|
|
96
|
+
const arg = argv.find((a, i) => !a.startsWith('--') && !VALUE_FLAGS.has(argv[i - 1])) ?? argv[0];
|
|
100
97
|
if (!arg || arg === '-h' || arg === '--help') {
|
|
101
|
-
console.error('usage: check [--library <dir>] [--bindings <file>] <flow.ts | BaseName>');
|
|
98
|
+
console.error('usage: check [--library <dir>] [--connectors-local <dir>] [--bindings <file>] <flow.ts | BaseName>');
|
|
102
99
|
return 2;
|
|
103
100
|
}
|
|
104
101
|
const file = resolveFlowFile(arg);
|
package/dist/check.d.ts
CHANGED
|
@@ -75,6 +75,26 @@ export interface CheckOpts {
|
|
|
75
75
|
* and cannot be slowed down by one.
|
|
76
76
|
*/
|
|
77
77
|
eventParams?: (connector: string, event: string, object?: string) => EventParamFields | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* What `compile` would refuse a connector event subscription with, or
|
|
80
|
+
* `undefined` when the library resolves it. `kind` is the node form compile
|
|
81
|
+
* asks for: `trigger` for `onEvent` (the flow's trigger and every entry point),
|
|
82
|
+
* `event` for `waitForEvent`. Supplied by the CLIs from the same
|
|
83
|
+
* `library.resolveEvent(kind, connector, event, version, object)` call
|
|
84
|
+
* `serialize` makes (`eventResolveErrorFor` in `cli-library.ts`), so the two
|
|
85
|
+
* cannot disagree; omitted (no library) → not checked.
|
|
86
|
+
*
|
|
87
|
+
* Before this hook `check` could only warn EVENT_UNPREPARED here, because
|
|
88
|
+
* `eventParams` answers `undefined` for "cannot resolve" and for "no facts"
|
|
89
|
+
* alike: it printed `0 error(s)` on a source `compile` then refused
|
|
90
|
+
* (2026-09-23, `skill-flow-datafabric-trigger-lifecycle`, v2 commands 31 and 46).
|
|
91
|
+
*/
|
|
92
|
+
eventResolveError?: (kind: 'trigger' | 'event', subscription: {
|
|
93
|
+
connector: string;
|
|
94
|
+
event: string;
|
|
95
|
+
version?: string;
|
|
96
|
+
object?: string;
|
|
97
|
+
}) => string | undefined;
|
|
78
98
|
/**
|
|
79
99
|
* Resolve a connector event's FILTERABLE field names — the vocabulary a
|
|
80
100
|
* `filters` leaf may name — sourced the same way as `eventParams`. A GENERIC
|
|
@@ -144,3 +164,22 @@ export declare const SCHEDULE_PATTERN: string;
|
|
|
144
164
|
* and day names, and the Quartz specials `L W LW ? * #`.
|
|
145
165
|
*/
|
|
146
166
|
export declare const SCHEDULE_CRON_PATTERN: string;
|
|
167
|
+
/**
|
|
168
|
+
* The phrase in `text` that tells a model to answer in JSON TEXT, or `undefined`.
|
|
169
|
+
*
|
|
170
|
+
* `check` uses it for `INLINE_AGENT_PROMPT_JSON_TEXT`, passing the step's `returns`
|
|
171
|
+
* keys so the brace form only counts a brace that spells one of them. Without
|
|
172
|
+
* `returnKeys` (the example and doc sweeps) any quoted identifier key counts.
|
|
173
|
+
* `{{input.*}}` placeholders are removed first, so an input named `json` never
|
|
174
|
+
* matches.
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```ts
|
|
178
|
+
* jsonTextDirective('Return ONLY a JSON object with keys "subject" and "body".'); // 'Return ONLY a JSON'
|
|
179
|
+
* jsonTextDirective('Return ONLY {"category","priority"}.', ['category']); // '{"category",'
|
|
180
|
+
* jsonTextDirective('Return a result conforming to the output schema.'); // undefined
|
|
181
|
+
* jsonTextDirective('Do not return JSON.'); // undefined
|
|
182
|
+
* jsonTextDirective('Answer the question using the JSON data below.'); // undefined
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
export declare function jsonTextDirective(text: string, returnKeys?: readonly string[]): string | undefined;
|
package/dist/check.js
CHANGED
|
@@ -529,7 +529,7 @@ function checkFlow(built, ancestors, opts = {}) {
|
|
|
529
529
|
...(suggestion ? { suggestion } : {}),
|
|
530
530
|
});
|
|
531
531
|
checkEventSubscription(s.spec.subscription, `waitForEvent "${stepName}"`, push('error'), push('warning'), eventParamsFor(s.spec.subscription, opts));
|
|
532
|
-
checkEventResolution(s.spec.subscription, `waitForEvent "${stepName}"`, opts, push('error'), push('warning'), eventParamsFor(s.spec.subscription, opts));
|
|
532
|
+
checkEventResolution(s.spec.subscription, `waitForEvent "${stepName}"`, 'event', opts, push('error'), push('warning'), eventParamsFor(s.spec.subscription, opts));
|
|
533
533
|
}
|
|
534
534
|
if (s.spec.kind === 'subflow') {
|
|
535
535
|
// Only a real child goes in the map: a missing one is reported by
|
|
@@ -1955,12 +1955,18 @@ function eventParamsFor(subscription, opts) {
|
|
|
1955
1955
|
}
|
|
1956
1956
|
/**
|
|
1957
1957
|
* The event-side resolution rules — the trigger twin of `checkConnectorLookups`,
|
|
1958
|
-
* plus
|
|
1958
|
+
* plus three rules with no activity counterpart:
|
|
1959
1959
|
*
|
|
1960
|
-
* - `
|
|
1961
|
-
*
|
|
1962
|
-
*
|
|
1963
|
-
*
|
|
1960
|
+
* - `EVENT_UNKNOWN` — an ERROR: a library is loaded and it cannot resolve the
|
|
1961
|
+
* subscription, so `compile` will refuse it. The message is the resolver's
|
|
1962
|
+
* own (`eventResolveError`), the same text compile throws. Checked first; when
|
|
1963
|
+
* it fires, EVENT_UNPREPARED and the filter rules below are skipped for this
|
|
1964
|
+
* subscription, since there is no entry for them to read.
|
|
1965
|
+
* - `EVENT_UNPREPARED` — the event RESOLVES but the library knows nothing
|
|
1966
|
+
* about its parameters (or no `eventResolveError` resolver was supplied):
|
|
1967
|
+
* the fallback case for a connector the shipped library was not generated
|
|
1968
|
+
* against. A warning, because compile still succeeds. Prints the one
|
|
1969
|
+
* command that makes the event checkable.
|
|
1964
1970
|
* - `EVENT_FILTER_UNKNOWN_FIELD` — a filter leaf naming a field outside the
|
|
1965
1971
|
* prepared vocabulary is an ERROR, not a warning, because the platform's own
|
|
1966
1972
|
* configure DROPS an unmatched leaf and reports Success: the deployed
|
|
@@ -1972,7 +1978,7 @@ function eventParamsFor(subscription, opts) {
|
|
|
1972
1978
|
* (compile repeats it as the hard failure), with the recorded answer looked up
|
|
1973
1979
|
* under the event-form node type — the form `prepare` stores.
|
|
1974
1980
|
*/
|
|
1975
|
-
function checkEventResolution(subscription, where, opts, error, warn, eventParams) {
|
|
1981
|
+
function checkEventResolution(subscription, where, kind, opts, error, warn, eventParams) {
|
|
1976
1982
|
const sub = subscription;
|
|
1977
1983
|
if (!sub || typeof sub.connector !== 'string' || typeof sub.event !== 'string'
|
|
1978
1984
|
|| sub.connector === '' || sub.event === '')
|
|
@@ -1983,6 +1989,18 @@ function checkEventResolution(subscription, where, opts, error, warn, eventParam
|
|
|
1983
1989
|
// by interpolating them into template literals, which accept anything.
|
|
1984
1990
|
const connectorKey = sub.connector;
|
|
1985
1991
|
const eventName = sub.event;
|
|
1992
|
+
// Exactly what `serialize` passes to `resolveEvent` — `sub.version` and
|
|
1993
|
+
// `sub.object` as the author wrote them — so the verdict is compile's.
|
|
1994
|
+
const unresolved = opts.eventResolveError?.(kind, {
|
|
1995
|
+
connector: connectorKey,
|
|
1996
|
+
event: eventName,
|
|
1997
|
+
...(typeof sub.version === 'string' ? { version: sub.version } : {}),
|
|
1998
|
+
...(typeof sub.object === 'string' ? { object: sub.object } : {}),
|
|
1999
|
+
});
|
|
2000
|
+
if (unresolved !== undefined) {
|
|
2001
|
+
error('EVENT_UNKNOWN', `${where}: ${unresolved}`);
|
|
2002
|
+
return;
|
|
2003
|
+
}
|
|
1986
2004
|
const object = typeof sub.object === 'string' && sub.object !== '' ? sub.object : undefined;
|
|
1987
2005
|
if (eventParams?.objectUnprepared && object) {
|
|
1988
2006
|
// The generic template answers for every object, so resolution SUCCEEDS
|
|
@@ -2259,7 +2277,7 @@ function checkTrigger(spec, diags, opts = {}) {
|
|
|
2259
2277
|
if (spec?.kind === 'event') {
|
|
2260
2278
|
const sub = spec.subscription;
|
|
2261
2279
|
checkEventSubscription(sub, 'trigger', at, push('warning'), eventParamsFor(sub, opts));
|
|
2262
|
-
checkEventResolution(sub, 'trigger', opts, at, push('warning'), eventParamsFor(sub, opts));
|
|
2280
|
+
checkEventResolution(sub, 'trigger', 'trigger', opts, at, push('warning'), eventParamsFor(sub, opts));
|
|
2263
2281
|
return;
|
|
2264
2282
|
}
|
|
2265
2283
|
// manual() is the explicit spelling of the default — nothing to validate.
|
|
@@ -3136,6 +3154,106 @@ function checkAgentRead(name, field, rest, spec, step, diags) {
|
|
|
3136
3154
|
...(nearest ? { suggestion: `out('${name}', '${nearest}')` } : {}),
|
|
3137
3155
|
});
|
|
3138
3156
|
}
|
|
3157
|
+
// ─── an inline agent's prompt asking for JSON text ───────────────────────────────
|
|
3158
|
+
//
|
|
3159
|
+
// The phrase table behind `INLINE_AGENT_PROMPT_JSON_TEXT`. It is kept narrow on
|
|
3160
|
+
// purpose, because the rule is an error. Three shapes count, and each skips a
|
|
3161
|
+
// negation anywhere earlier in the same clause ("Do not return JSON", "Do not wrap
|
|
3162
|
+
// the answer in JSON", "Return the items, not as JSON"):
|
|
3163
|
+
//
|
|
3164
|
+
// - DIRECT: an output verb, then only words from a closed qualifier list, then
|
|
3165
|
+
// `json` — "Return ONLY a JSON object", "Return only the typed JSON contract".
|
|
3166
|
+
// - VIA: an output verb, up to two words, then `as` / `in` / `with`, qualifiers,
|
|
3167
|
+
// `json` — "Format your answer as JSON", "Respond with valid JSON".
|
|
3168
|
+
// - BRACE: a quoted-key brace whose key is one of the step's own `returns` keys —
|
|
3169
|
+
// `Return ONLY {"category","priority"}` next to `returns: { category, priority }`.
|
|
3170
|
+
//
|
|
3171
|
+
// A word outside the qualifier list ends a DIRECT match, so JSON as DATA does not
|
|
3172
|
+
// count in the DIRECT form: "Answer the question using the JSON data below", "Give
|
|
3173
|
+
// a summary of the JSON ticket", "Return the invoice number from the JSON". The VIA
|
|
3174
|
+
// form allows two free words, so it can still fire on JSON as a topic ("Answer in
|
|
3175
|
+
// Spanish with JSON examples"); the tail skips the common data nouns after `json`
|
|
3176
|
+
// (keys, data, record, examples, input) and the JSON-family FORMATS a string field
|
|
3177
|
+
// legitimately holds (JSON Schema, JSON Patch, JSON-LD, JSON Lines, …). `write` is
|
|
3178
|
+
// not a verb here: "You help users write JSON" is a topic, not an answer shape.
|
|
3179
|
+
//
|
|
3180
|
+
// The skills repo's preview-doc gate (tests/tasks/uipath-maestro-flow/_shared/
|
|
3181
|
+
// test_preview_inline_agent_prompts.py) ports this table to Python and loads a
|
|
3182
|
+
// byte-identical copy of tests/fixtures/inline-agent-prompt-vectors.json, so
|
|
3183
|
+
// change the table, the fixture and the port together.
|
|
3184
|
+
const JSON_TEXT_VERBS = 'return|respond|reply|output|answer|produce|emit|format|give|provide';
|
|
3185
|
+
/** Words that are only ever qualifiers of the answer's shape, never the thing it is about. */
|
|
3186
|
+
const JSON_TEXT_QUALIFIERS = [
|
|
3187
|
+
'only', 'just', 'exactly', 'strictly', 'solely', 'simply', 'a', 'an', 'one', 'single', 'the',
|
|
3188
|
+
'your', 'its', 'this', 'that', 'valid', 'raw', 'pure', 'plain', 'strict', 'compact', 'minified',
|
|
3189
|
+
'well-formed', 'properly', 'formatted', 'typed', 'declared', 'structured', 'following', 'same',
|
|
3190
|
+
'final', 'back', 'proper', 'correct', 'machine-readable', 'parseable', 'parsable',
|
|
3191
|
+
];
|
|
3192
|
+
/** A negation anywhere earlier in the same clause, or anywhere in the match's gap. */
|
|
3193
|
+
const JSON_TEXT_NEGATIONS = new Set(['not', 'never', 'no', 'dont', 'without', 'rather', 'instead', 'avoid']);
|
|
3194
|
+
const isJsonTextNegation = (w) => JSON_TEXT_NEGATIONS.has(w) || w.endsWith("n't") || w.endsWith('n’t');
|
|
3195
|
+
const JSON_TEXT_WORD = "[A-Za-z][\\w'’-]*";
|
|
3196
|
+
/** Words are separated by spaces, tabs or a comma — never a newline or a full stop. */
|
|
3197
|
+
const JSON_TEXT_SEP = '[ \\t]*,?[ \\t]+';
|
|
3198
|
+
const JSON_TEXT_QUAL = `(?:${[...JSON_TEXT_QUALIFIERS].sort((a, b) => b.length - a.length).join('|')})\\b`;
|
|
3199
|
+
// `(?<![-\w])` skips `--output json`; `(?!\.\w)` skips `JSON.parse` / `JSON.stringify`;
|
|
3200
|
+
// `(?!-(?:ld|rpc)\b)` skips JSON-LD / JSON-RPC (`\b` matches before the hyphen);
|
|
3201
|
+
// the last lookahead skips "the JSON below" / "the JSON provided" / "the JSON you
|
|
3202
|
+
// get", data nouns ("the JSON keys", "JSON examples") and JSON-family formats
|
|
3203
|
+
// ("JSON Schema", "JSON Patch", "the JSON path", "a JSON Web Token").
|
|
3204
|
+
const JSON_TEXT_TAIL = `json\\b(?!\\.\\w)(?!-(?:ld|rpc)\\b)(?![ \\t]+(?:below|above|provided|given|you`
|
|
3205
|
+
+ `|keys?|data|records?|examples?|inputs?`
|
|
3206
|
+
+ `|schemas?|patch|path|pointer|lines|rpc|web[ \\t]+tokens?)\\b)`;
|
|
3207
|
+
const JSON_TEXT_VERB = `(?<![-\\w])(?:${JSON_TEXT_VERBS})\\b`;
|
|
3208
|
+
const JSON_TEXT_DIRECT = new RegExp(`${JSON_TEXT_VERB}((?:${JSON_TEXT_SEP}${JSON_TEXT_QUAL}){0,5})${JSON_TEXT_SEP}${JSON_TEXT_TAIL}`, 'gi');
|
|
3209
|
+
const JSON_TEXT_VIA = new RegExp(`${JSON_TEXT_VERB}((?:${JSON_TEXT_SEP}${JSON_TEXT_WORD}){0,2}?)${JSON_TEXT_SEP}(?:as|in|with)`
|
|
3210
|
+
+ `((?:${JSON_TEXT_SEP}${JSON_TEXT_QUAL}){0,4})${JSON_TEXT_SEP}${JSON_TEXT_TAIL}`, 'gi');
|
|
3211
|
+
const escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
3212
|
+
/**
|
|
3213
|
+
* The phrase in `text` that tells a model to answer in JSON TEXT, or `undefined`.
|
|
3214
|
+
*
|
|
3215
|
+
* `check` uses it for `INLINE_AGENT_PROMPT_JSON_TEXT`, passing the step's `returns`
|
|
3216
|
+
* keys so the brace form only counts a brace that spells one of them. Without
|
|
3217
|
+
* `returnKeys` (the example and doc sweeps) any quoted identifier key counts.
|
|
3218
|
+
* `{{input.*}}` placeholders are removed first, so an input named `json` never
|
|
3219
|
+
* matches.
|
|
3220
|
+
*
|
|
3221
|
+
* @example
|
|
3222
|
+
* ```ts
|
|
3223
|
+
* jsonTextDirective('Return ONLY a JSON object with keys "subject" and "body".'); // 'Return ONLY a JSON'
|
|
3224
|
+
* jsonTextDirective('Return ONLY {"category","priority"}.', ['category']); // '{"category",'
|
|
3225
|
+
* jsonTextDirective('Return a result conforming to the output schema.'); // undefined
|
|
3226
|
+
* jsonTextDirective('Do not return JSON.'); // undefined
|
|
3227
|
+
* jsonTextDirective('Answer the question using the JSON data below.'); // undefined
|
|
3228
|
+
* ```
|
|
3229
|
+
*/
|
|
3230
|
+
export function jsonTextDirective(text, returnKeys) {
|
|
3231
|
+
if (typeof text !== 'string' || text === '')
|
|
3232
|
+
return undefined;
|
|
3233
|
+
// A placeholder becomes a hard break (`·` is neither a word nor a gap), and a
|
|
3234
|
+
// quoted or back-ticked `JSON` is read as the bare word.
|
|
3235
|
+
const t = text
|
|
3236
|
+
.replace(/\{\{\s*input\.[^}]*\}\}/g, ' · ')
|
|
3237
|
+
.replace(/[`"'“”](json)[`"'“”]/gi, ' $1 ');
|
|
3238
|
+
const words = (s) => (s.match(new RegExp(JSON_TEXT_WORD, 'g')) ?? []).map((w) => w.toLowerCase());
|
|
3239
|
+
const keys = returnKeys?.length ? returnKeys.map(escapeRegExp).join('|') : '[A-Za-z_]\\w*';
|
|
3240
|
+
const brace = new RegExp(`\\{[ \\t]*["'](?:${keys})["'][ \\t]*[,:}]`, 'g');
|
|
3241
|
+
for (const rule of [JSON_TEXT_DIRECT, JSON_TEXT_VIA, brace]) {
|
|
3242
|
+
rule.lastIndex = 0;
|
|
3243
|
+
for (const m of t.matchAll(rule)) {
|
|
3244
|
+
if (m.slice(1).some((g) => words(g ?? '').some(isJsonTextNegation)))
|
|
3245
|
+
continue;
|
|
3246
|
+
// Any negation earlier in the same clause: "Do not wrap the answer in JSON",
|
|
3247
|
+
// "No need to return JSON". A comma ends a clause, so "Do not guess, return
|
|
3248
|
+
// ONLY a JSON object" still counts.
|
|
3249
|
+
const clause = t.slice(0, m.index).split(/[.;:!?\n,]/).pop() ?? '';
|
|
3250
|
+
if (words(clause).some(isJsonTextNegation))
|
|
3251
|
+
continue;
|
|
3252
|
+
return m[0].trim();
|
|
3253
|
+
}
|
|
3254
|
+
}
|
|
3255
|
+
return undefined;
|
|
3256
|
+
}
|
|
3139
3257
|
/**
|
|
3140
3258
|
* Check an `inlineAgent(...)` call.
|
|
3141
3259
|
*
|
|
@@ -3144,7 +3262,7 @@ function checkAgentRead(name, field, rest, spec, step, diags) {
|
|
|
3144
3262
|
* rules can be certain rather than best-effort — the definition's own `required`
|
|
3145
3263
|
* list is checkable, and so is whether the prompts and the declared variables agree.
|
|
3146
3264
|
*
|
|
3147
|
-
*
|
|
3265
|
+
* Three rules exist because the PLATFORM does something with what you wrote:
|
|
3148
3266
|
*
|
|
3149
3267
|
* - `INLINE_AGENT_SCAFFOLD_MODEL` — the model the platform's own scaffold ships is
|
|
3150
3268
|
* stale, and v1's smoke check for this node type fails a flow that keeps it. A
|
|
@@ -3156,6 +3274,11 @@ function checkAgentRead(name, field, rest, spec, step, diags) {
|
|
|
3156
3274
|
* input the prompts never mention is pruned deployed while arriving locally: a
|
|
3157
3275
|
* disagreement between rungs and the platform, which is the one class that has to
|
|
3158
3276
|
* be said out loud rather than left to a run.
|
|
3277
|
+
* - `INLINE_AGENT_PROMPT_JSON_TEXT` — the platform returns `returns` as a typed
|
|
3278
|
+
* object: it becomes the `agent.json` `outputSchema`, and the agent runtime ends
|
|
3279
|
+
* a run with a structured call that fills exactly those fields. A prompt that
|
|
3280
|
+
* ALSO asks for JSON text makes the model pack its whole answer, serialized, into
|
|
3281
|
+
* one string field. See {@link jsonTextDirective}.
|
|
3159
3282
|
*/
|
|
3160
3283
|
function checkInlineAgent(step, inputs, diags) {
|
|
3161
3284
|
const at = (code, message, suggestion) => {
|
|
@@ -3223,6 +3346,40 @@ function checkInlineAgent(step, inputs, diags) {
|
|
|
3223
3346
|
+ `definition's default, \`{ content: 'string' }\`, which is the scaffold shape. Declare the fields the `
|
|
3224
3347
|
+ `agent must return, or drop the key and read \`content\`.`);
|
|
3225
3348
|
}
|
|
3349
|
+
// A prompt that asks for JSON TEXT while `returns` declares the fields. The
|
|
3350
|
+
// platform already returns those fields as a typed object — `returns` is the
|
|
3351
|
+
// agent.json `outputSchema`, and the runtime ends a run with a structured call
|
|
3352
|
+
// that fills exactly those keys — so the extra directive does not shape the
|
|
3353
|
+
// answer, it gets serialized INTO it: on 2026-09-23 a writer declaring
|
|
3354
|
+
// `{ subject, body }` came back with `body` = '{"subject":…,"body":…}' in 3 of 3
|
|
3355
|
+
// debug runs, and the flow mailed the JSON. `uip maestro flow validate` accepts
|
|
3356
|
+
// the prompt (it never reads prompt meaning), so this is where it is said. An
|
|
3357
|
+
// ERROR for the same reason `INLINE_AGENT_UNDECLARED_PLACEHOLDER` is one: the
|
|
3358
|
+
// platform accepts the shape and the run still delivers the wrong value, and a
|
|
3359
|
+
// warning is printed past while compile writes the .flow anyway. Only when
|
|
3360
|
+
// `returns` is declared: with the `{ content }` default, JSON text in `content`
|
|
3361
|
+
// may be exactly what the author reads back.
|
|
3362
|
+
const returnKeys = Object.keys(inputs?.returns ?? {});
|
|
3363
|
+
if (returnKeys.length) {
|
|
3364
|
+
for (const field of ['systemPrompt', 'userPrompt']) {
|
|
3365
|
+
const phrase = jsonTextDirective(String(inputs?.[field] ?? ''), returnKeys);
|
|
3366
|
+
if (phrase === undefined)
|
|
3367
|
+
continue;
|
|
3368
|
+
const rewrite = `Return a result conforming to the output schema. `
|
|
3369
|
+
+ returnKeys.map((k) => `${k}: <what it holds>.`).join(' ');
|
|
3370
|
+
at('INLINE_AGENT_PROMPT_JSON_TEXT', `Inline agent step "${step}"'s \`${field}\` tells the model to answer in JSON text ("${phrase}"), `
|
|
3371
|
+
+ `but \`returns\` already declares the answer: ${returnKeys.map((k) => `\`${k}\``).join(', ')}. `
|
|
3372
|
+
+ `The platform returns those fields as a typed object — \`returns\` becomes the agent.json `
|
|
3373
|
+
+ `\`outputSchema\`, and the agent runtime ends each run with a structured call that fills exactly `
|
|
3374
|
+
+ `those keys — so \`out('${step}', '${returnKeys[0]}')\` reads a value, not text to parse. Asking `
|
|
3375
|
+
+ `for JSON as well makes the model pack its whole answer, serialized, into one string field (for `
|
|
3376
|
+
+ `example a \`body\` that reads '{"subject":…,"body":…}'). Replace only that JSON instruction (keep the rest `
|
|
3377
|
+
+ `of the prompt) with one line per field, in the platform's own wording: "${rewrite}" Declare a field \`'object'\` or `
|
|
3378
|
+
+ `\`'array'\` if it should carry structure. \`uip maestro flow validate\` accepts this prompt, so `
|
|
3379
|
+
+ `nothing later catches it. If this is a false positive (the prompt only mentions JSON as data), `
|
|
3380
|
+
+ `compile with --no-check.`);
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3226
3383
|
// The prompts-vs-variables agreement, in both directions. Both prompts are
|
|
3227
3384
|
// searched, because flow-v1's pre-pass scans both.
|
|
3228
3385
|
const prompts = `${String(inputs?.systemPrompt ?? '')}\n${String(inputs?.userPrompt ?? '')}`;
|
|
@@ -25,6 +25,7 @@ export function registerFlowCommands(program) {
|
|
|
25
25
|
.option('--source', 'check authored TypeScript')
|
|
26
26
|
.option('--compiled', 'check the emitted artifact')
|
|
27
27
|
.option('--library <dir>', 'connector library directory')
|
|
28
|
+
.option('--connectors-local <dir>', 'connection-resolved connector overlay')
|
|
28
29
|
.option('--json', 'print compiled-check diagnostics as JSON')
|
|
29
30
|
.option('--uip', 'resolve missing schemas with the UiPath CLI')
|
|
30
31
|
.option('--max-errors <count>', 'stop after this many compiled-check errors')
|
|
@@ -50,6 +51,7 @@ export function registerFlowCommands(program) {
|
|
|
50
51
|
if (mode === 'source') {
|
|
51
52
|
const argv = [input];
|
|
52
53
|
addValue(argv, '--library', options.library);
|
|
54
|
+
addValue(argv, '--connectors-local', options.connectorsLocal);
|
|
53
55
|
await invoke('flow check', () => loadTool(import.meta.url, '../../check-cli.js'), argv);
|
|
54
56
|
return;
|
|
55
57
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CheckOpts } from './check.js';
|
|
2
|
+
import { Library } from './library.js';
|
|
3
|
+
/**
|
|
4
|
+
* The library for this invocation, or `undefined` when there is none.
|
|
5
|
+
*
|
|
6
|
+
* `--library <dir>`, else `$FLOW_SDK_LIBRARY_JSON`, else the cache `registry
|
|
7
|
+
* pull` filled (`resolveLibraryDir`). The overlay is `--connectors-local <dir>`,
|
|
8
|
+
* else `./connectors-local` when it has an `index.json` — the directory
|
|
9
|
+
* `registry prepare` writes by default.
|
|
10
|
+
*/
|
|
11
|
+
export declare function openCliLibrary(argv: readonly string[]): Library | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* `check`'s EVENT_UNKNOWN verdict: the message `library.resolveEvent` throws
|
|
14
|
+
* for a subscription, or `undefined` when it resolves.
|
|
15
|
+
*
|
|
16
|
+
* This is the call `serialize` makes for `onEvent` (kind `trigger`, for the
|
|
17
|
+
* flow's trigger and each entry point) and for `waitForEvent` (kind `event`),
|
|
18
|
+
* with the subscription's own `version` and `object`, so check reports an error
|
|
19
|
+
* exactly when compile would throw, with the same text.
|
|
20
|
+
*/
|
|
21
|
+
export declare function eventResolveErrorFor(library: Library): NonNullable<CheckOpts['eventResolveError']>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cli-library — the connector library a flow CLI opens, and the event verdict
|
|
3
|
+
* `check` shares with `compile`.
|
|
4
|
+
*
|
|
5
|
+
* `check-cli` and `compile-cli` used to open the library each in their own way:
|
|
6
|
+
* compile honoured `--connectors-local <dir>`, check ignored the flag and only
|
|
7
|
+
* auto-detected `./connectors-local`. As long as check only WARNED from the
|
|
8
|
+
* library that was harmless. Now check reports EVENT_UNKNOWN as an ERROR when
|
|
9
|
+
* the library cannot resolve an event, so a different library would make check
|
|
10
|
+
* refuse a source compile accepts. Both CLIs open it here instead.
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync } from 'node:fs';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
import { Library } from './library.js';
|
|
15
|
+
import { resolveLibraryDir } from './registry/cache.js';
|
|
16
|
+
/** The value after `name` in `argv`, or `undefined`. */
|
|
17
|
+
function flagValue(argv, name) {
|
|
18
|
+
const i = argv.indexOf(name);
|
|
19
|
+
return i >= 0 ? argv[i + 1] : undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The library for this invocation, or `undefined` when there is none.
|
|
23
|
+
*
|
|
24
|
+
* `--library <dir>`, else `$FLOW_SDK_LIBRARY_JSON`, else the cache `registry
|
|
25
|
+
* pull` filled (`resolveLibraryDir`). The overlay is `--connectors-local <dir>`,
|
|
26
|
+
* else `./connectors-local` when it has an `index.json` — the directory
|
|
27
|
+
* `registry prepare` writes by default.
|
|
28
|
+
*/
|
|
29
|
+
export function openCliLibrary(argv) {
|
|
30
|
+
const libDir = resolveLibraryDir(flagValue(argv, '--library'));
|
|
31
|
+
if (!libDir || !existsSync(join(libDir, 'index.json')))
|
|
32
|
+
return undefined;
|
|
33
|
+
const overlayDir = flagValue(argv, '--connectors-local')
|
|
34
|
+
?? (existsSync(join('connectors-local', 'index.json')) ? 'connectors-local' : undefined);
|
|
35
|
+
return new Library(libDir, { overlayDir });
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* `check`'s EVENT_UNKNOWN verdict: the message `library.resolveEvent` throws
|
|
39
|
+
* for a subscription, or `undefined` when it resolves.
|
|
40
|
+
*
|
|
41
|
+
* This is the call `serialize` makes for `onEvent` (kind `trigger`, for the
|
|
42
|
+
* flow's trigger and each entry point) and for `waitForEvent` (kind `event`),
|
|
43
|
+
* with the subscription's own `version` and `object`, so check reports an error
|
|
44
|
+
* exactly when compile would throw, with the same text.
|
|
45
|
+
*/
|
|
46
|
+
export function eventResolveErrorFor(library) {
|
|
47
|
+
return (kind, sub) => {
|
|
48
|
+
try {
|
|
49
|
+
library.resolveEvent(kind, sub.connector, sub.event, sub.version, sub.object);
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
return error instanceof Error ? error.message : String(error);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
package/dist/compile-cli.js
CHANGED
|
@@ -22,8 +22,7 @@ import { basename, dirname, join, resolve } from 'node:path';
|
|
|
22
22
|
import { resolveFlowFile, loadBuiltFlow } from './load.js';
|
|
23
23
|
import { serializeWithSidecars, connectorInputErrors } from './serialize.js';
|
|
24
24
|
import { check } from './check.js';
|
|
25
|
-
import {
|
|
26
|
-
import { resolveLibraryDir } from './registry/cache.js';
|
|
25
|
+
import { eventResolveErrorFor, openCliLibrary } from './cli-library.js';
|
|
27
26
|
import { Bindings } from './bindings.js';
|
|
28
27
|
import { runWhenInvokedDirectly } from './cli-run.js';
|
|
29
28
|
import { connectionResources, mergeBindingsV2, readBindingsV2 } from './bindings-v2.js';
|
|
@@ -50,14 +49,11 @@ export async function run(argv) {
|
|
|
50
49
|
// --library, else $FLOW_SDK_LIBRARY_JSON, else the shared cache `registry pull`
|
|
51
50
|
// filled. Resolving through one helper is what stops `pull` and `compile`
|
|
52
51
|
// disagreeing about where the library is — they did, and a pulled library was
|
|
53
|
-
// invisible to this command.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
// connection-resolved field schemas. See core/library.ts (LibraryOpts.overlayDir).
|
|
59
|
-
const overlayDir = opt(argv, '--connectors-local')
|
|
60
|
-
?? (existsSync(join('connectors-local', 'index.json')) ? 'connectors-local' : undefined);
|
|
52
|
+
// invisible to this command. The `prepare-connector`/`prepare-trigger` overlay
|
|
53
|
+
// is `--connectors-local`, else `./connectors-local` (like bindings.json); it
|
|
54
|
+
// shadows the baked library with full, connection-resolved field schemas. See
|
|
55
|
+
// core/library.ts (LibraryOpts.overlayDir). `check-cli` opens it the same way.
|
|
56
|
+
//
|
|
61
57
|
// Only load the library when it's actually present; flows without connectors
|
|
62
58
|
// (e.g. HTTP-only) then compile fine even if the connector cache isn't built.
|
|
63
59
|
// A connector action with no library resolves to a clear error in serialize().
|
|
@@ -66,11 +62,16 @@ export async function run(argv) {
|
|
|
66
62
|
// event operation declares any event parameters) can only be answered from the
|
|
67
63
|
// library, and answering it from an assumption instead is what made
|
|
68
64
|
// EVENT_NO_SCOPE an error for HTTP Webhook, whose only correct `where` is empty.
|
|
69
|
-
const library =
|
|
65
|
+
const library = openCliLibrary(argv);
|
|
66
|
+
const bindFile = opt(argv, '--bindings') ?? (existsSync('bindings.json') ? 'bindings.json' : undefined);
|
|
70
67
|
const bindings = new Bindings(bindFile);
|
|
71
68
|
if (!noCheck) {
|
|
72
69
|
const diags = check(built, library
|
|
73
70
|
? {
|
|
71
|
+
// The refusal serialize() would throw for an event it cannot resolve,
|
|
72
|
+
// printed as `✗ [EVENT_UNKNOWN]` before stopping instead of hiding
|
|
73
|
+
// behind "1 error(s); not emitting".
|
|
74
|
+
eventResolveError: eventResolveErrorFor(library),
|
|
74
75
|
eventParams: (connector, event) => {
|
|
75
76
|
try {
|
|
76
77
|
return library.eventParameterFields(connector, event);
|
package/dist/core/actions.d.ts
CHANGED
|
@@ -1376,16 +1376,18 @@ export interface InlineAgentInputs {
|
|
|
1376
1376
|
*/
|
|
1377
1377
|
model: string;
|
|
1378
1378
|
/**
|
|
1379
|
-
* The agent's standing instructions — who it is and what
|
|
1380
|
-
* Required by the definition (`minLength: 1`).
|
|
1379
|
+
* The agent's standing instructions — who it is, and what each `returns` field
|
|
1380
|
+
* should hold. Required by the definition (`minLength: 1`).
|
|
1381
1381
|
*
|
|
1382
1382
|
* **Write it as plain text, and reference a value as `{{input.<name>}}`** — the
|
|
1383
1383
|
* agent's own template syntax, and the same names `inputs` declares:
|
|
1384
1384
|
*
|
|
1385
1385
|
* ```ts
|
|
1386
|
-
* systemPrompt: 'You classify support email. Return
|
|
1386
|
+
* systemPrompt: 'You classify support email. Return a result conforming to the output '
|
|
1387
|
+
* + 'schema. category: billing | technical | account. priority: low | normal | high.',
|
|
1387
1388
|
* userPrompt: 'Classify this email:\n{{input.body}}',
|
|
1388
1389
|
* inputs: { body: input('body') },
|
|
1390
|
+
* returns: { category: 'string', priority: 'string' },
|
|
1389
1391
|
* ```
|
|
1390
1392
|
*
|
|
1391
1393
|
* Why a placeholder rather than an interpolated expression: an inline agent is two
|
|
@@ -1404,11 +1406,24 @@ export interface InlineAgentInputs {
|
|
|
1404
1406
|
* literal text reaches the model. See the inline-agent node reference (`website/reference/inline-agent.md`)
|
|
1405
1407
|
* §"The three prompt DIALECTS".
|
|
1406
1408
|
*
|
|
1407
|
-
*
|
|
1408
|
-
* `
|
|
1409
|
-
*
|
|
1410
|
-
*
|
|
1411
|
-
*
|
|
1409
|
+
* **The answer's shape is `returns`, not the prompt.** `returns` becomes the node's
|
|
1410
|
+
* `agentOutputVariables` and the `agent.json` `outputSchema` — what Studio Web's
|
|
1411
|
+
* Outputs editor writes — and the platform's agent runtime ends each run with a
|
|
1412
|
+
* built-in structured call (`end_execution`) that fills exactly those fields. So
|
|
1413
|
+
* `out('<step>', '<field>')` reads a typed value, not text to parse. Describe what
|
|
1414
|
+
* each field holds, in the product's own wording, as the example above does:
|
|
1415
|
+
* `Return a result conforming to the output schema. <field>: <how to fill it>.`
|
|
1416
|
+
*
|
|
1417
|
+
* Never ask for JSON TEXT as well ("Return ONLY a JSON object with keys …"). The
|
|
1418
|
+
* model then packs its whole answer, serialized, into ONE string field: a writer
|
|
1419
|
+
* declaring `{ subject, body }` came back on 2026-09-23 with
|
|
1420
|
+
* `body: '{"subject":"…","body":"Dear …"}'` in 3 of 3 debug runs, and the flow sent
|
|
1421
|
+
* that text on. A field that should carry structure is declared `'object'` or
|
|
1422
|
+
* `'array'` instead.
|
|
1423
|
+
*
|
|
1424
|
+
* @enforcedBy INLINE_AGENT_PROMPT_JSON_TEXT A prompt that asks for JSON text while
|
|
1425
|
+
* `returns` declares fields is refused; the platform accepts it and the run returns
|
|
1426
|
+
* the packed value.
|
|
1412
1427
|
*/
|
|
1413
1428
|
systemPrompt: string;
|
|
1414
1429
|
/**
|
|
@@ -1516,7 +1531,8 @@ export interface InlineAgentInputs {
|
|
|
1516
1531
|
* ```ts
|
|
1517
1532
|
* inlineAgent({
|
|
1518
1533
|
* model: 'gpt-5.4',
|
|
1519
|
-
* systemPrompt: 'You decide billing disputes from the SOPs. Return
|
|
1534
|
+
* systemPrompt: 'You decide billing disputes from the SOPs. Return a result conforming to the output '
|
|
1535
|
+
* + 'schema. determination: valid | invalid | needs_review. rationale: the SOP rule that decided it.',
|
|
1520
1536
|
* userPrompt: 'Dispute: {{input.description}}',
|
|
1521
1537
|
* inputs: { description: input('disputeDescription') },
|
|
1522
1538
|
* returns: { determination: 'string', rationale: 'string' },
|
|
@@ -3069,8 +3085,8 @@ export declare function agent(inputs: AgentInputs): ActionSpec;
|
|
|
3069
3085
|
* model: 'gpt-5.4',
|
|
3070
3086
|
* systemPrompt:
|
|
3071
3087
|
* 'You are a support triage assistant. Classify the email into exactly one ' +
|
|
3072
|
-
* 'category
|
|
3073
|
-
* '
|
|
3088
|
+
* 'category and one priority. Return a result conforming to the output schema. ' +
|
|
3089
|
+
* 'category: billing | technical | account. priority: low | normal | high.',
|
|
3074
3090
|
* userPrompt: 'Classify this email:\n{{input.body}}',
|
|
3075
3091
|
* inputs: { body: input('body') },
|
|
3076
3092
|
* returns: { category: 'string', priority: 'string' },
|
package/dist/core/actions.js
CHANGED
|
@@ -850,8 +850,8 @@ export function agent(inputs) {
|
|
|
850
850
|
* model: 'gpt-5.4',
|
|
851
851
|
* systemPrompt:
|
|
852
852
|
* 'You are a support triage assistant. Classify the email into exactly one ' +
|
|
853
|
-
* 'category
|
|
854
|
-
* '
|
|
853
|
+
* 'category and one priority. Return a result conforming to the output schema. ' +
|
|
854
|
+
* 'category: billing | technical | account. priority: low | normal | high.',
|
|
855
855
|
* userPrompt: 'Classify this email:\n{{input.body}}',
|
|
856
856
|
* inputs: { body: input('body') },
|
|
857
857
|
* returns: { category: 'string', priority: 'string' },
|
package/dist/core/library.d.ts
CHANGED
|
@@ -402,6 +402,26 @@ export declare class Library {
|
|
|
402
402
|
* that. It resorted to grepping the library's JSON out of `node_modules`.
|
|
403
403
|
*/
|
|
404
404
|
private describeMiss;
|
|
405
|
+
/** Every direct operation id under `prefix` (no further dot), across layers, sorted and de-duplicated. */
|
|
406
|
+
private opsUnder;
|
|
407
|
+
/** Whether any layer indexes `nodeType` (at `version`, when one is asked for). */
|
|
408
|
+
private carries;
|
|
409
|
+
/** The connector key is in no entry at all. */
|
|
410
|
+
private noConnector;
|
|
411
|
+
/**
|
|
412
|
+
* The event half of {@link describeMiss}: which of the connector's EVENTS the
|
|
413
|
+
* library carries, read from BOTH namespaces.
|
|
414
|
+
*
|
|
415
|
+
* Both, because the library stores almost every event in one form only: the
|
|
416
|
+
* baseline snapshot of 2026-09-23 (`2a4405dd…`) has 994 `.event.` entries and 4
|
|
417
|
+
* `.trigger.` ones, and a start trigger resolves from its `.event.` sibling
|
|
418
|
+
* ({@link resolveEvent}). Reading the asked namespace alone answered `No
|
|
419
|
+
* connector "uipath-uipath-dataservice"` for a typo'd `onEvent` event on a
|
|
420
|
+
* connector whose events were all right there, and the same words for a
|
|
421
|
+
* connector present with eight actions and no events at all (2026-09-23 eval,
|
|
422
|
+
* `skill-flow-datafabric-trigger-lifecycle`, v2 commands 45/46).
|
|
423
|
+
*/
|
|
424
|
+
private describeEventMiss;
|
|
405
425
|
/**
|
|
406
426
|
* Resolve the op WITHIN one layer, selecting the entry by `objectName` for a
|
|
407
427
|
* GENERIC operation. Returns undefined when the layer does not carry the op;
|