@uipath/maestro-builder-sdk 6.24.0 → 6.25.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 +115 -115
- package/dist/api-members.md +351 -351
- package/dist/check.js +1 -392
- package/dist/core/actions.d.ts +0 -304
- package/dist/core/actions.js +0 -54
- package/dist/core/form-field-type.d.ts +16 -0
- package/dist/core/form-field-type.js +33 -0
- package/dist/core/hitl-routing.d.ts +17 -3
- package/dist/core/stable-id.d.ts +9 -0
- package/dist/core/stable-id.js +16 -0
- package/dist/core/step-ports.d.ts +25 -1
- package/dist/core/step-ports.js +6 -47
- package/dist/core/typed-raw-node.js +0 -8
- package/dist/decompile.js +7 -191
- package/dist/flow-node-registry.js +2 -1
- package/dist/flow-node-type.d.ts +45 -1
- package/dist/flow-sdk.d.ts +1 -0
- package/dist/flow-sdk.js +1 -0
- package/dist/flow-step-exits.js +1 -1
- package/dist/nodes/hitl/flow/check.d.ts +38 -0
- package/dist/nodes/hitl/flow/check.js +357 -0
- package/dist/nodes/hitl/flow/factories.d.ts +58 -0
- package/dist/nodes/hitl/flow/factories.js +59 -0
- package/dist/nodes/hitl/flow/family.d.ts +3 -0
- package/dist/nodes/hitl/flow/family.js +8 -0
- package/dist/nodes/hitl/flow/index.d.ts +3 -0
- package/dist/nodes/hitl/flow/index.js +3 -0
- package/dist/nodes/hitl/flow/node-type.d.ts +7 -0
- package/dist/nodes/hitl/flow/node-type.js +601 -0
- package/dist/nodes/hitl/flow/spec.d.ts +265 -0
- package/dist/nodes/hitl/flow/spec.js +1 -0
- package/dist/serialize.d.ts +2 -4
- package/dist/serialize.js +35 -344
- package/package.json +2 -2
package/dist/decompile.js
CHANGED
|
@@ -45,7 +45,7 @@ import { outputBackingGlobal, outputBackingName } from './flow-output-backing.js
|
|
|
45
45
|
import { mapJsCode } from './core/js-code-spans.js';
|
|
46
46
|
import { missingBindingLabels } from './core/binding-messages.js';
|
|
47
47
|
import { prepareCommand } from './core/cli-spelling.js';
|
|
48
|
-
import { OUTCOME_HANDLE_NODE_TYPES
|
|
48
|
+
import { OUTCOME_HANDLE_NODE_TYPES } from './core/hitl-routing.js';
|
|
49
49
|
import { STICKY_NOTE_TYPE } from './core/definitionless-node-types.js';
|
|
50
50
|
import { eventFilterFromTreeLeaf } from './core/event-filters.js';
|
|
51
51
|
import { sdkFormFieldType } from './core/form-field-type.js';
|
|
@@ -226,9 +226,6 @@ const T = {
|
|
|
226
226
|
inlineAgent: 'uipath.agent.autonomous',
|
|
227
227
|
conversationalAgent: 'uipath.agent.conversational',
|
|
228
228
|
voiceAgent: 'uipath.agent.voice',
|
|
229
|
-
hitlQuickForm: 'uipath.human-in-the-loop.quick-form',
|
|
230
|
-
hitlActionApp: 'uipath.human-in-the-loop.coded-action-app',
|
|
231
|
-
hitlDocValidation: 'uipath.human-in-the-loop.document-validation',
|
|
232
229
|
triggerVoice: 'core.trigger.voice',
|
|
233
230
|
createOutgoingCall: 'uipath.conversational.voice.create-outgoing-call',
|
|
234
231
|
endCall: 'uipath.conversational.voice.end-call',
|
|
@@ -560,7 +557,7 @@ function registeredImpl(node) {
|
|
|
560
557
|
* the node. A node at a version the type does not register is lifted by its
|
|
561
558
|
* default version's implementation, as every built-in family lifts any version.
|
|
562
559
|
*/
|
|
563
|
-
function liftRegistered(node, impl = registeredImpl(node)) {
|
|
560
|
+
function liftRegistered(node, impl = registeredImpl(node), graph) {
|
|
564
561
|
if (!impl)
|
|
565
562
|
return undefined;
|
|
566
563
|
const version = String(node.typeVersion ?? '');
|
|
@@ -574,6 +571,8 @@ function liftRegistered(node, impl = registeredImpl(node)) {
|
|
|
574
571
|
// when the file carries none (a hand-trimmed or SDK-written file).
|
|
575
572
|
definition: () => runDefs.get(`${node.type}@${version}`) ?? BUNDLED_DEFINITIONS[`${node.type}@${version}`] ?? runDefs.get(node.type),
|
|
576
573
|
warn: warnOnce,
|
|
574
|
+
outPorts: () => (graph?.outEdges(node.id) ?? []).map((e) => e.sourcePort),
|
|
575
|
+
convergedFanOut: () => graph?.convergedFanOut(node.id) === true,
|
|
577
576
|
};
|
|
578
577
|
const spec = impl.deserialize(node, ctx);
|
|
579
578
|
return spec === undefined ? undefined : { impl, spec };
|
|
@@ -586,8 +585,8 @@ function liftRegistered(node, impl = registeredImpl(node)) {
|
|
|
586
585
|
* `{ version }` the type does not register, with a warning. `undefined` when the type is not registered, or the node type declines
|
|
587
586
|
* the node; the caller's branches take it from there.
|
|
588
587
|
*/
|
|
589
|
-
function emitRegisteredSpec(node, imp, inputNames) {
|
|
590
|
-
const lifted = liftRegistered(node);
|
|
588
|
+
function emitRegisteredSpec(node, imp, inputNames, graph) {
|
|
589
|
+
const lifted = liftRegistered(node, registeredImpl(node), graph);
|
|
591
590
|
if (!lifted)
|
|
592
591
|
return undefined;
|
|
593
592
|
const { impl, spec } = lifted;
|
|
@@ -629,7 +628,7 @@ function emitRegisteredSpec(node, imp, inputNames) {
|
|
|
629
628
|
function emitStepSpec(node, imp, inputNames, o, graph) {
|
|
630
629
|
// A registered node type lifts itself; every other type falls through to the
|
|
631
630
|
// branches below until its family is ported (FB014's pins are the list).
|
|
632
|
-
const lifted = emitRegisteredSpec(node, imp, inputNames);
|
|
631
|
+
const lifted = emitRegisteredSpec(node, imp, inputNames, graph);
|
|
633
632
|
if (lifted !== undefined)
|
|
634
633
|
return lifted;
|
|
635
634
|
switch (node.type) {
|
|
@@ -651,11 +650,6 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
|
|
|
651
650
|
case T.conversationalAgent:
|
|
652
651
|
case T.voiceAgent:
|
|
653
652
|
return emitAgentCluster(node, imp, inputNames, graph);
|
|
654
|
-
case T.hitl:
|
|
655
|
-
case T.hitlQuickForm:
|
|
656
|
-
case T.hitlActionApp:
|
|
657
|
-
case T.hitlDocValidation:
|
|
658
|
-
return emitHitl(node, imp, inputNames, graph);
|
|
659
653
|
default:
|
|
660
654
|
// A connector action node: `uipath.connector.<key>.<action>` (but NOT the
|
|
661
655
|
// event nodes `uipath.connector.event.*` / `.trigger.*`, which are triggers).
|
|
@@ -1260,184 +1254,6 @@ function emitAgentCluster(node, imp, inputNames, graph) {
|
|
|
1260
1254
|
['source', tsLiteral(plain(i.source) ?? '')],
|
|
1261
1255
|
])})`;
|
|
1262
1256
|
}
|
|
1263
|
-
/**
|
|
1264
|
-
* A HUMAN TASK — the base node plus its three sub-typed variants.
|
|
1265
|
-
*
|
|
1266
|
-
* `hitlInputs` is the widest lowering in the serializer, so this inverts it
|
|
1267
|
-
* field by field. Three of its outputs are DERIVED and deliberately not
|
|
1268
|
-
* recovered: `schema.schemaId` (a stable hash of the flow and node ids),
|
|
1269
|
-
* `type: 'quick'` (the base node's discriminator), and the `variable`/`binding`
|
|
1270
|
-
* wiring each field row carries — all of them are re-emitted from what comes
|
|
1271
|
-
* back here.
|
|
1272
|
-
*
|
|
1273
|
-
* A value equal to what serialize would have DEFAULTED is omitted rather than
|
|
1274
|
-
* recovered: the step's own name for `title`, `'Low'` for `priority`, and the
|
|
1275
|
-
* definition's own `inputDefaults.recipient` for delivery. Recovering those
|
|
1276
|
-
* would add arguments the author never wrote to every task.
|
|
1277
|
-
*/
|
|
1278
|
-
function emitHitl(node, imp, inputNames, graph) {
|
|
1279
|
-
const i = (node.inputs ?? {});
|
|
1280
|
-
const schema = (i.schema ?? {});
|
|
1281
|
-
const plain = (v) => {
|
|
1282
|
-
const raw = unwrapSource(v);
|
|
1283
|
-
return raw === undefined || raw === '' ? undefined : raw;
|
|
1284
|
-
};
|
|
1285
|
-
const variant = node.type === T.hitlQuickForm ? 'quick-form'
|
|
1286
|
-
: node.type === T.hitlActionApp ? 'action-app'
|
|
1287
|
-
: node.type === T.hitlDocValidation ? 'document-validation'
|
|
1288
|
-
: undefined;
|
|
1289
|
-
// A field row's binding is a variable PATH (`vars.x`), not an expression —
|
|
1290
|
-
// serialize rewrote the author's `$vars.x` on the way out, so put it back.
|
|
1291
|
-
const bindingExpr = (v) => {
|
|
1292
|
-
const raw = plain(v);
|
|
1293
|
-
if (raw === undefined)
|
|
1294
|
-
return undefined;
|
|
1295
|
-
const js = wireExprBody(raw);
|
|
1296
|
-
return emitBareExpr(js.startsWith('vars.') ? `$${js}` : js, imp, inputNames);
|
|
1297
|
-
};
|
|
1298
|
-
const rows = (Array.isArray(schema.fields) ? schema.fields : []);
|
|
1299
|
-
const fields = rows.map((f) => {
|
|
1300
|
-
const id = String(f.id ?? '');
|
|
1301
|
-
const direction = String(f.direction ?? 'output');
|
|
1302
|
-
return opts([
|
|
1303
|
-
['id', tsLiteral(id)],
|
|
1304
|
-
// serialize defaults a row's label to its id.
|
|
1305
|
-
['label', typeof f.label === 'string' && f.label !== id ? tsLiteral(f.label) : undefined],
|
|
1306
|
-
// The product's own spelling (`"string"`, `"datetime"`, …) → the SDK's (#1143).
|
|
1307
|
-
['type', tsLiteral(sdkFormFieldType(f.type ?? 'text') ?? String(f.type))],
|
|
1308
|
-
['direction', tsLiteral(direction)],
|
|
1309
|
-
['value', direction === 'input' || direction === 'inOut' ? bindingExpr(f.binding) : undefined],
|
|
1310
|
-
['required', f.required === true ? 'true' : undefined],
|
|
1311
|
-
]);
|
|
1312
|
-
});
|
|
1313
|
-
const outcomeRows = (Array.isArray(schema.outcomes) ? schema.outcomes : []);
|
|
1314
|
-
const outcomes = outcomeRows.map((o, idx) => {
|
|
1315
|
-
const name = String(o.name ?? '');
|
|
1316
|
-
// The file's id comes back only when serialize would not derive it from the
|
|
1317
|
-
// name: a designer-drawn task's ids (`outcome-1778015958049`) are not slugs,
|
|
1318
|
-
// and merge keeps the ORIGINAL node, so recompiled edges must use its ids
|
|
1319
|
-
// (#1130). An SDK-written task's ids are slugs and stay implicit.
|
|
1320
|
-
const id = typeof o.id === 'string' && o.id !== '' && o.id !== outcomeSlug(name, idx) ? o.id : undefined;
|
|
1321
|
-
// A bare string is the shorthand; `action: 'End'` or a kept id needs the object.
|
|
1322
|
-
return o.action === 'End' || id !== undefined
|
|
1323
|
-
? opts([
|
|
1324
|
-
['name', tsLiteral(name)],
|
|
1325
|
-
['action', o.action === 'End' ? tsLiteral('End') : undefined],
|
|
1326
|
-
['id', id !== undefined ? tsLiteral(id) : undefined],
|
|
1327
|
-
])
|
|
1328
|
-
: tsLiteral(name);
|
|
1329
|
-
});
|
|
1330
|
-
// Delivery: only an override comes back. The definition's own default is what
|
|
1331
|
-
// serialize emits when the author wrote nothing.
|
|
1332
|
-
const def = runDefs.get(`${node.type}@${node.typeVersion}`) ?? runDefs.get(node.type);
|
|
1333
|
-
const defaultRecipient = JSON.stringify(def?.inputDefaults?.recipient ?? null);
|
|
1334
|
-
const rec = i.recipient;
|
|
1335
|
-
let recipientSrc;
|
|
1336
|
-
if (rec !== undefined && JSON.stringify(rec) !== defaultRecipient) {
|
|
1337
|
-
const assignee = (rec.assignee ?? {});
|
|
1338
|
-
const channels = Array.isArray(rec.channels) ? rec.channels : undefined;
|
|
1339
|
-
recipientSrc = opts([
|
|
1340
|
-
['channels', channels ? `[${channels.map((c) => tsLiteral(c)).join(', ')}]` : undefined],
|
|
1341
|
-
['assignee', opts([
|
|
1342
|
-
['type', tsLiteral(String(assignee.type ?? 'user'))],
|
|
1343
|
-
['value', typeof assignee.value === 'string' ? tsLiteral(assignee.value) : undefined],
|
|
1344
|
-
['displayName', typeof assignee.displayName === 'string' ? tsLiteral(assignee.displayName) : undefined],
|
|
1345
|
-
])],
|
|
1346
|
-
]);
|
|
1347
|
-
}
|
|
1348
|
-
// The deployed app that owns the form (action-app, and a custom-render
|
|
1349
|
-
// validation station). `appInputBindings` maps the app's own parameter names
|
|
1350
|
-
// to `=`-prefixed expressions.
|
|
1351
|
-
const app = i.app;
|
|
1352
|
-
// `app.inputs` is a VALUE map — what to send the app, keyed by the app's own
|
|
1353
|
-
// parameter names — and it lowers to a SIBLING key, `appInputBindings`, whose
|
|
1354
|
-
// values are `=vars.…` paths (or literals). Not a type map, and not inside
|
|
1355
|
-
// `app`: both are easy to assume and both round-trip wrong.
|
|
1356
|
-
const bindings = (i.appInputBindings ?? {});
|
|
1357
|
-
const appInputs = Object.keys(bindings).length === 0 ? undefined : objLit(Object.entries(bindings).map(([k, v]) => {
|
|
1358
|
-
const raw = String(v ?? '');
|
|
1359
|
-
return [k, raw.startsWith('=') ? emitBareExpr(wireExprBody(raw), imp, inputNames) : tsLiteral(raw)];
|
|
1360
|
-
}));
|
|
1361
|
-
const appSrc = app === undefined ? undefined : opts([
|
|
1362
|
-
// `displayName` is serialize's echo of `name`; only `name` is authored.
|
|
1363
|
-
['name', tsText(app.name)],
|
|
1364
|
-
['key', tsText(app.key)],
|
|
1365
|
-
['folderPath', typeof app.folderPath === 'string' && app.folderPath !== '' ? tsLiteral(app.folderPath) : undefined],
|
|
1366
|
-
['appSystemName', app.appSystemName === null ? 'null'
|
|
1367
|
-
: typeof app.appSystemName === 'string' ? tsLiteral(app.appSystemName) : undefined],
|
|
1368
|
-
['inputs', appInputs],
|
|
1369
|
-
]);
|
|
1370
|
-
// The validation station's own inputs ride as PLAIN `$vars.…` paths. Anything
|
|
1371
|
-
// but a `$vars.` reference stays the wire text verbatim.
|
|
1372
|
-
const stationExpr = (v) => {
|
|
1373
|
-
const raw = plain(v);
|
|
1374
|
-
if (raw === undefined)
|
|
1375
|
-
return undefined;
|
|
1376
|
-
const js = wireExprBody(raw);
|
|
1377
|
-
return js.startsWith('$vars.') ? emitBareExpr(js, imp, inputNames) : tsLiteral(raw);
|
|
1378
|
-
};
|
|
1379
|
-
const render = plain(i.validationRenderType);
|
|
1380
|
-
const documentSrc = node.type !== T.hitlDocValidation ? undefined : opts([
|
|
1381
|
-
['extractionResult', stationExpr(i.extractionResult) ?? tsLiteral('')],
|
|
1382
|
-
['storageBucket', plain(i.storageBucket) !== undefined ? tsLiteral(plain(i.storageBucket)) : undefined],
|
|
1383
|
-
['documentId', plain(i.documentId) !== undefined ? tsLiteral(plain(i.documentId)) : undefined],
|
|
1384
|
-
// 'standard' is the definition's default.
|
|
1385
|
-
['render', render !== undefined && render !== 'standard' ? tsLiteral(render) : undefined],
|
|
1386
|
-
['taxonomy', stationExpr(i.taxonomy)],
|
|
1387
|
-
]);
|
|
1388
|
-
// On the base node the VERSION says it: 1.1 routes per outcome, 1.2 adds the
|
|
1389
|
-
// error output (and implies the routing). Everywhere else — quick-form, a
|
|
1390
|
-
// base task on 1.0 — the EDGES say it: outcomes that lead to different places
|
|
1391
|
-
// are routed per outcome (`outcomePorts: true`, which a pinned 1.0 keeps at
|
|
1392
|
-
// 1.0), and outcomes that all lead to one step are a fan-out, which the
|
|
1393
|
-
// task's default recompiles to.
|
|
1394
|
-
const version = String(node.typeVersion ?? '');
|
|
1395
|
-
const exposeError = version === '1.2';
|
|
1396
|
-
const outEdges = graph?.outEdges(node.id) ?? [];
|
|
1397
|
-
const derivesHandles = OUTCOME_HANDLE_NODE_TYPES.has(String(node.type));
|
|
1398
|
-
const outcomePorts = (node.type === T.hitl && version === '1.1')
|
|
1399
|
-
|| (derivesHandles && !versionRoutesHitl(node) && graph !== undefined && !graph.convergedFanOut(node.id)
|
|
1400
|
-
&& outEdges.some((e) => e.sourcePort.startsWith('outcome-')));
|
|
1401
|
-
// A lone `completed` edge on a task with several outcomes is the shape the
|
|
1402
|
-
// designer stopped drawing: before flow-workbench #3512 (09-08) it was
|
|
1403
|
-
// unconditioned, so every outcome continued down it; since then Studio Web and
|
|
1404
|
-
// the converter remap it to the primary outcome only. Recompiling writes one
|
|
1405
|
-
// `outcome-<id>` edge per outcome to the same step — the first meaning — so
|
|
1406
|
-
// this is the one place decompile→compile is deliberately not exact. Say so.
|
|
1407
|
-
const legacyCompleted = derivesHandles && outcomeIdsOfNode(node).length > 1
|
|
1408
|
-
&& outEdges.some((e) => e.sourcePort === 'completed');
|
|
1409
|
-
// Both a converged fan-out and a legacy lone `completed` mean "every outcome
|
|
1410
|
-
// continues to the next step". Say so in the source with `outcomePorts: false`
|
|
1411
|
-
// rather than leaving it to the `{ version }` pin, so the intent survives an
|
|
1412
|
-
// author dropping the pin.
|
|
1413
|
-
const fanOut = !outcomePorts && derivesHandles && !versionRoutesHitl(node) && outcomeIdsOfNode(node).length > 1
|
|
1414
|
-
&& (legacyCompleted || graph?.convergedFanOut(node.id) === true);
|
|
1415
|
-
if (legacyCompleted) {
|
|
1416
|
-
warnOnce(`human task ${tsLiteral(node.id)} leaves on the legacy 'completed' handle, which Studio Web no longer draws `
|
|
1417
|
-
+ `once a task has outcomes (it reads the edge as the primary outcome only). Recompiling emits one `
|
|
1418
|
-
+ `outcome-<id> edge per outcome to the same step, so every outcome continues — what the edge meant `
|
|
1419
|
-
+ `before flow-workbench #3512.`);
|
|
1420
|
-
}
|
|
1421
|
-
const title = plain(i.title);
|
|
1422
|
-
const priority = plain(i.priority);
|
|
1423
|
-
return `${imp.use('hitl')}(${opts([
|
|
1424
|
-
['variant', variant !== undefined ? tsLiteral(variant) : undefined],
|
|
1425
|
-
// serialize defaults the title to the step's own name.
|
|
1426
|
-
['title', title !== undefined && title !== node.id ? tsLiteral(title) : undefined],
|
|
1427
|
-
['priority', priority !== undefined && priority !== 'Low' ? tsLiteral(priority) : undefined],
|
|
1428
|
-
['labels', plain(i.labels) !== undefined ? tsLiteral(plain(i.labels)) : undefined],
|
|
1429
|
-
['recipient', recipientSrc],
|
|
1430
|
-
['app', appSrc],
|
|
1431
|
-
['document', documentSrc],
|
|
1432
|
-
// An app task and a validation station own no inline form; an empty array
|
|
1433
|
-
// there is serialize's own, not the author's.
|
|
1434
|
-
['fields', fields.length ? `[${fields.join(', ')}]`
|
|
1435
|
-
: (variant === 'action-app' || variant === 'document-validation') ? undefined : '[]'],
|
|
1436
|
-
['outcomes', `[${outcomes.join(', ')}]`],
|
|
1437
|
-
['outcomePorts', outcomePorts ? 'true' : fanOut ? 'false' : undefined],
|
|
1438
|
-
['exposeError', exposeError ? 'true' : undefined],
|
|
1439
|
-
])})`;
|
|
1440
|
-
}
|
|
1441
1257
|
/**
|
|
1442
1258
|
* A connector EVENT subscription, shared by the trigger (`onEvent`) and the
|
|
1443
1259
|
* mid-flow wait (`waitForEvent`) — the same node body in both places, so the
|
|
@@ -13,11 +13,12 @@ import { conversationFlowFamily } from './nodes/conversation/flow/family.js';
|
|
|
13
13
|
import { dataFabricFlowFamily } from './nodes/data-fabric/flow/family.js';
|
|
14
14
|
import { delayFlowFamily } from './nodes/delay/flow/family.js';
|
|
15
15
|
import { documentFlowFamily } from './nodes/document/flow/family.js';
|
|
16
|
+
import { hitlFlowFamily } from './nodes/hitl/flow/family.js';
|
|
16
17
|
import { httpFlowFamily } from './nodes/http/flow/family.js';
|
|
17
18
|
import { mockFlowFamily } from './nodes/mock/flow/family.js';
|
|
18
19
|
import { queueFlowFamily } from './nodes/queue/flow/family.js';
|
|
19
20
|
import { scriptFlowFamily } from './nodes/script/flow/family.js';
|
|
20
21
|
import { transformFlowFamily } from './nodes/transform/flow/family.js';
|
|
21
22
|
/** The families, in no significant order. Adding one is the whole of registering it. */
|
|
22
|
-
export const FLOW_NODE_FAMILIES = [aiPatternsFlowFamily, conversationFlowFamily, dataFabricFlowFamily, delayFlowFamily, documentFlowFamily, httpFlowFamily, mockFlowFamily, queueFlowFamily, scriptFlowFamily, transformFlowFamily];
|
|
23
|
+
export const FLOW_NODE_FAMILIES = [aiPatternsFlowFamily, conversationFlowFamily, dataFabricFlowFamily, delayFlowFamily, documentFlowFamily, hitlFlowFamily, httpFlowFamily, mockFlowFamily, queueFlowFamily, scriptFlowFamily, transformFlowFamily];
|
|
23
24
|
export const FLOW_NODE_TYPES = new NodeTypeRegistry('flow', FLOW_NODE_FAMILIES, { hasBundledDefinition });
|
package/dist/flow-node-type.d.ts
CHANGED
|
@@ -42,17 +42,40 @@ export interface FlowNodeContribution extends Omit<NodeContribution, 'definition
|
|
|
42
42
|
model?: 'definition' | 'omit';
|
|
43
43
|
/** The forward port the next step's edge leaves from. Default: the definition's default source handle. */
|
|
44
44
|
port?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Several forward ports, every one of which continues to the next step — a
|
|
47
|
+
* fan-out (a human task that does not route per outcome leaves on each
|
|
48
|
+
* outcome's handle). `endsRun` marks one the step list ends with an End
|
|
49
|
+
* instead (an `action: 'End'` outcome). Wins over `port`.
|
|
50
|
+
*/
|
|
51
|
+
fanOut?: ReadonlyArray<{
|
|
52
|
+
readonly port: string;
|
|
53
|
+
readonly endsRun?: boolean;
|
|
54
|
+
}>;
|
|
55
|
+
/**
|
|
56
|
+
* `outputs` REPLACES the definition's `outputDefinition` on the node instead of
|
|
57
|
+
* being merged over it — for an instance whose output slots are its own (a
|
|
58
|
+
* human task's form decides them). Replaced outputs are written verbatim: no
|
|
59
|
+
* `{nodeId}` substitution, which a merged contribution's outputs get.
|
|
60
|
+
*/
|
|
61
|
+
replaceOutputs?: boolean;
|
|
45
62
|
}
|
|
46
63
|
/** What `serialize` may ask of the serializer, for one placement. */
|
|
47
64
|
export interface FlowSerializeContext {
|
|
48
65
|
/** The step name the author gave this node. */
|
|
49
66
|
readonly step: string;
|
|
67
|
+
/** The id this node is emitted under (rename-aware for a reused subflow copy). */
|
|
68
|
+
readonly nodeId: string;
|
|
69
|
+
/** The flow's id, as the file's top-level `id` carries it. */
|
|
70
|
+
readonly flowId: string;
|
|
50
71
|
/**
|
|
51
72
|
* The version being emitted, always set: the author's `{ version }` when the step
|
|
52
73
|
* names one, else what `select()` or the default chose. It does not say whether
|
|
53
74
|
* the author pinned it.
|
|
54
75
|
*/
|
|
55
76
|
readonly version: string;
|
|
77
|
+
/** The author's `{ version }`, when the step names one; undefined when `select()` or the default chose. */
|
|
78
|
+
readonly pinnedVersion: string | undefined;
|
|
56
79
|
/** Render one value (an `Expr`, or a literal) as the file stores it, with this scope's rename map. */
|
|
57
80
|
render(value: unknown): unknown;
|
|
58
81
|
/**
|
|
@@ -128,6 +151,17 @@ export interface FlowDeserializeContext {
|
|
|
128
151
|
definition(): unknown;
|
|
129
152
|
/** Report something the lift could not keep. Decompile prints it once. */
|
|
130
153
|
warn(message: string): void;
|
|
154
|
+
/** The source ports this node's out-edges leave from, in edge order (an empty list outside a graph). */
|
|
155
|
+
outPorts(): readonly string[];
|
|
156
|
+
/**
|
|
157
|
+
* Whether this node is a human task (base or quick-form, not routing by its
|
|
158
|
+
* 1.1/1.2 version) whose every outcome in `inputs.schema.outcomes` is wired, all
|
|
159
|
+
* to ONE target, with no other exit edge: a fan-out that converges, which the
|
|
160
|
+
* source spells as continuing every outcome to the next step rather than as
|
|
161
|
+
* arms. The decompiler's graph answers it from the node's outcomes, not from
|
|
162
|
+
* the type's `exits()`, so it is `false` for any other node.
|
|
163
|
+
*/
|
|
164
|
+
convergedFanOut(): boolean;
|
|
131
165
|
}
|
|
132
166
|
/** What `print` may ask of the decompiler. Every method returns source text. */
|
|
133
167
|
export interface FlowPrintContext {
|
|
@@ -254,10 +288,20 @@ export interface FlowNodeType<Spec> extends NodeType<Spec, FlowNodeContribution,
|
|
|
254
288
|
* and the port each leaves on — or why it has none to route. What
|
|
255
289
|
* `.stepSwitch()` routes over, what an arm's `value` and a `.stepToList` port
|
|
256
290
|
* are checked against, and what decompile reads a fully wired node back as.
|
|
291
|
+
* `pinnedVersion` is the author's `{ version }`, when the step names one: a
|
|
292
|
+
* human task's routing depends on whether it is pinned, not only on the version.
|
|
257
293
|
* Omitted: the type has no author-declared fan-out. The `error` port is never
|
|
258
294
|
* one of these (`.onError()` routes it).
|
|
259
295
|
*/
|
|
260
|
-
exits?(spec: Spec): DeclaredExit[] | NoExits;
|
|
296
|
+
exits?(spec: Spec, pinnedVersion?: string): DeclaredExit[] | NoExits;
|
|
297
|
+
/**
|
|
298
|
+
* Whether `port` is a forward handle the PRODUCT derives for this spec, which
|
|
299
|
+
* the definition does not list — a human task's `outcome-<id>` handles, drawn
|
|
300
|
+
* from its outcomes at every version while the definition declares only
|
|
301
|
+
* `completed`. Serialize refuses a forward port that is neither declared by
|
|
302
|
+
* the definition, an exit of the type, nor derived.
|
|
303
|
+
*/
|
|
304
|
+
derivesPort?(spec: Spec, port: string): boolean;
|
|
261
305
|
}
|
|
262
306
|
/** A Flow node type with several versions. */
|
|
263
307
|
export type FlowVersionedNodeType<Spec> = VersionedNodeType<Spec, FlowNodeContribution, FlowContexts, FlowNodeType<Spec>>;
|
package/dist/flow-sdk.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export * from './nodes/conversation/flow/index.js';
|
|
|
23
23
|
export * from './nodes/data-fabric/flow/index.js';
|
|
24
24
|
export * from './nodes/delay/flow/index.js';
|
|
25
25
|
export * from './nodes/document/flow/index.js';
|
|
26
|
+
export * from './nodes/hitl/flow/index.js';
|
|
26
27
|
export * from './nodes/http/flow/index.js';
|
|
27
28
|
export * from './nodes/mock/flow/index.js';
|
|
28
29
|
export * from './nodes/queue/flow/index.js';
|
package/dist/flow-sdk.js
CHANGED
|
@@ -27,6 +27,7 @@ export * from './nodes/conversation/flow/index.js';
|
|
|
27
27
|
export * from './nodes/data-fabric/flow/index.js';
|
|
28
28
|
export * from './nodes/delay/flow/index.js';
|
|
29
29
|
export * from './nodes/document/flow/index.js';
|
|
30
|
+
export * from './nodes/hitl/flow/index.js';
|
|
30
31
|
export * from './nodes/http/flow/index.js';
|
|
31
32
|
export * from './nodes/mock/flow/index.js';
|
|
32
33
|
export * from './nodes/queue/flow/index.js';
|
package/dist/flow-step-exits.js
CHANGED
|
@@ -26,5 +26,5 @@ export function stepExits(spec, pinnedVersion) {
|
|
|
26
26
|
catch {
|
|
27
27
|
impl = resolveVersion(entry.type, spec, undefined, 'exits');
|
|
28
28
|
}
|
|
29
|
-
return impl.exits?.(spec) ?? declaredExits(spec, pinnedVersion);
|
|
29
|
+
return impl.exits?.(spec, pinnedVersion) ?? declaredExits(spec, pinnedVersion);
|
|
30
30
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The HITL family's rules: the form, outcomes, variant and delivery of one human
|
|
3
|
+
* task (`checkHitl`), and a read of its result (`checkHitlRead`). Moved from
|
|
4
|
+
* check.ts in Phase 4 of docs/NODE_TYPE_ARCHITECTURE_DESIGN.md; codes and
|
|
5
|
+
* messages unchanged. The rules that need the rest of the flow — an outcome no
|
|
6
|
+
* route takes, an outcome nothing downstream tells apart, a port the task does
|
|
7
|
+
* not draw — stay in check.ts, which walks the flow.
|
|
8
|
+
*/
|
|
9
|
+
import type { DiagnosticCatalog } from '../../../core/nodes/family.js';
|
|
10
|
+
import type { OutputPathRead } from '../../../core/nodes/node-type.js';
|
|
11
|
+
import type { FlowCheckContext } from '../../../flow-node-type.js';
|
|
12
|
+
import type { HitlInputs } from './spec.js';
|
|
13
|
+
export declare const HITL_DIAGNOSTICS: DiagnosticCatalog;
|
|
14
|
+
/**
|
|
15
|
+
* A human task's form.
|
|
16
|
+
*
|
|
17
|
+
* Everything here is a mistake no later rung can see, which is the test for
|
|
18
|
+
* earning a place in `check` rather than in the docs: the flow compiles, deploys,
|
|
19
|
+
* and shows a person a form with something quietly missing from it. These catch it
|
|
20
|
+
* at rung 1, in the author's own vocabulary.
|
|
21
|
+
*/
|
|
22
|
+
export declare function checkHitl(inputs: HitlInputs, ctx: FlowCheckContext): void;
|
|
23
|
+
/**
|
|
24
|
+
* A read of a human task's output: `out('<step>', '<field>')`.
|
|
25
|
+
*
|
|
26
|
+
* The node publishes an object keyed by the form's ANSWER fields plus `Action`.
|
|
27
|
+
* Two mistakes are silent at run time and both are caught here:
|
|
28
|
+
*
|
|
29
|
+
* - reading a field the form does not answer (a shown field, or a typo) —
|
|
30
|
+
* `undefined`, offline and deployed;
|
|
31
|
+
* - reading `$vars.<step>.status`, the platform's own projection of the chosen
|
|
32
|
+
* outcome. It resolves *deployed*, so the flow works in production and reads
|
|
33
|
+
* `undefined` on this SDK's offline rungs — a divergence, which is why the read
|
|
34
|
+
* is redirected rather than merely flagged. (A runner that derives declared
|
|
35
|
+
* output variables resolves `status` offline as well; the surface still points
|
|
36
|
+
* at one spelling so a flow reads the same everywhere.)
|
|
37
|
+
*/
|
|
38
|
+
export declare function checkHitlRead({ node: name, field, rest, reader: step }: OutputPathRead, form: HitlInputs | undefined, report: (code: string, message: string, suggestion?: string) => void): void;
|