@uipath/maestro-builder-sdk 6.31.6 → 6.31.8

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/check.js CHANGED
@@ -10,7 +10,7 @@ import { FlowNode } from './core/node-classes.js';
10
10
  import { planContributionBindings } from './core/contribution-bindings.js';
11
11
  import { definitionHasErrorPort, errorPortRefusal } from './core/error-port.js';
12
12
  import { actionVersion, bundledActionNodeType, bundledContainerDefinition, bundledDefinition, perCallDefinition, resolveContributionDefinition } from './serialize.js';
13
- import { FORM_FIELD_TYPES, formFieldTypeHint, formFieldTypeWhy } from './core/form-field-type.js';
13
+ import { FORM_FIELD_TYPES, formFieldTypeHint, formFieldTypeWhy, validFormFieldTypesText } from './core/form-field-type.js';
14
14
  import { AGENTIC_PROCESS_FORMS } from './core/agentic-process-forms.js';
15
15
  import { checkEventResolution, checkEventSubscription, eventParamsFor, } from './core/event-checks.js';
16
16
  import { checkCookedEscapes } from './flow-expr-check.js';
@@ -3416,7 +3416,7 @@ function checkInlineAgent(step, inputs, diags, opts = {}) {
3416
3416
  if (!FORM_FIELD_TYPES.includes(String(f?.type))) {
3417
3417
  at('INLINE_AGENT_ESCALATION_FIELD_TYPE_UNKNOWN', `Inline agent step "${step}"'s quick-form escalation gives the field "${String(f?.id ?? '?')}" the type `
3418
3418
  + `${JSON.stringify(f?.type)}, ${formFieldTypeWhy(f?.type, `which the form does not recognize — it would `
3419
- + `be published as a plain string`)}. Valid: ${FORM_FIELD_TYPES.join(', ')}.`, formFieldTypeHint(f?.type));
3419
+ + `be published as a plain string`)}. Valid: ${validFormFieldTypesText()}.`, formFieldTypeHint(f?.type));
3420
3420
  }
3421
3421
  }
3422
3422
  continue;
@@ -55,11 +55,22 @@ export interface ConnectorOpts {
55
55
  object?: string;
56
56
  }
57
57
  /**
58
- * A form field's type. The platform does not recognize a type outside this set:
59
- * older runtimes read it as text (so a number field becomes a text box), newer
60
- * ones reject the form. That is why `check` rejects anything outside this set.
58
+ * The platform's 11 canonical quick-form field types (`@uipath/hitl-schema-types`
59
+ * `fieldType`), which the designer saves. Each has its own value shape:
60
+ * `integer` → a JSON integer, `date` → `'2026-10-15'`, `datetime` → an ISO
61
+ * date-time, `file` → a binary-format string, `object` / `array` → JSON.
61
62
  */
62
- export type FormFieldType = 'text' | 'number' | 'boolean' | 'date-time';
63
+ export type CanonicalFormFieldType = 'string' | 'number' | 'integer' | 'float' | 'double' | 'boolean' | 'date' | 'datetime' | 'file' | 'object' | 'array';
64
+ /**
65
+ * A form field's type: one of the platform's canonical types, or `'text'` /
66
+ * `'date-time'`, the SDK's older spellings of `'string'` / `'datetime'` (the
67
+ * platform resolves both). A quick form with any other type fails the
68
+ * platform's validation, which is why `check` rejects it.
69
+ *
70
+ * @example
71
+ * hitl({ fields: [{ id: 'dueOn', type: 'date', direction: 'output' }], outcomes: ['Done'] })
72
+ */
73
+ export type FormFieldType = CanonicalFormFieldType | 'text' | 'date-time';
63
74
  /** A value the reviewer READS: shown on the form, filled in from the flow. */
64
75
  export interface ShownField {
65
76
  /** Field id — the key the answer object uses. Must be unique on the form. */
@@ -1,49 +1,94 @@
1
1
  /**
2
- * The product's spellings of the form-field types the SDK models.
2
+ * The quick-form field-type vocabulary: the product's own, transcribed.
3
3
  *
4
4
  * A quick form's field `type` is read by the product through
5
- * `@uipath/hitl-schema-types` `normalizeFieldType`. Its canonical stored values
6
- * are `string`, `number`, `boolean`, `datetime`, … and it accepts aliases for
7
- * each: `text` is an alias of `string`, `date-time` of `datetime`, and .NET
8
- * names such as `System.String` resolve too. The designer saves the canonical
9
- * value, so a canvas-built form says `"string"`; the SDK (like flow-v1's
10
- * serializer and `uip maestro flow hitl add`) writes `text`.
5
+ * `@uipath/hitl-schema-types` (`fieldType`, `resolveFieldType`,
6
+ * `FIELD_TYPE_TO_JSON_SCHEMA`). It has 11 canonical stored values — `string`,
7
+ * `number`, `integer`, `float`, `double`, `boolean`, `date`, `datetime`, `file`,
8
+ * `object`, `array` — and it resolves aliases onto them: `text` is a legacy
9
+ * alias of `string`, `date-time` of `datetime`, and .NET names such as
10
+ * `System.Int32` resolve too. A `quick` form whose type resolves to none of the
11
+ * 11 fails the product's validation.
11
12
  *
12
- * So `"string"` and `"text"` are the same field on the wire. This table maps
13
- * each product spelling of the four types {@link FormFieldType} models to the
14
- * SDK's spelling, so decompile hands the author source `check` accepts.
15
- * A type the SDK does not model (`integer`, `date`,
16
- * `file`, …) has no entry: it stays as written, and `check` reports it.
13
+ * That package is published only to GitHub Packages, so the SDK cannot depend
14
+ * on it at runtime. This module is a transcription, and
15
+ * `tests/hitl-field-type-contract.test.ts` runs the real package against it:
16
+ * the canonical set, each type's JSON Schema, and every alias below must agree
17
+ * with the pinned `@uipath/hitl-schema-types`. A canonical-set or JSON Schema
18
+ * change upstream fails there; a new alias does not. The test also pins how the
19
+ * package resolves the spellings this module leaves out, so a change in those
20
+ * shows up.
17
21
  *
18
- * Mirrors `resolveFieldType` in `@uipath/hitl-schema-types` 1.1.6, restricted
19
- * to the groups that resolve to `string`, `number`, `boolean` and `datetime`
20
- * (minus `singleSelect` / `enum` / `union` / …, which resolve to `string` but
21
- * are not a plain text box).
22
+ * Every SDK path reads field types from here: `check` (human tasks and inline
23
+ * agent quick-form escalations), decompile, and the serializers' output
24
+ * schemas.
22
25
  */
23
- import type { FormFieldType } from './actions.js';
26
+ import type { CanonicalFormFieldType } from './actions.js';
27
+ /** The product's 11 canonical quick-form field types, in its own order. */
28
+ export declare const CANONICAL_FORM_FIELD_TYPES: CanonicalFormFieldType[];
29
+ /** The SDK's legacy spellings (`text`, `date-time`), for diagnostics that list them. */
30
+ export declare const LEGACY_FORM_FIELD_TYPES: string[];
31
+ /** Every form-field type the SDK accepts in source: the 11 canonical ones and the SDK's legacy aliases. */
32
+ export declare const FORM_FIELD_TYPES: string[];
33
+ /**
34
+ * The tail of a "Valid: …" diagnostic: the canonical types, then the legacy
35
+ * spellings in parentheses.
36
+ *
37
+ * @example
38
+ * validFormFieldTypesText() // 'string, number, …, array (or the older text, date-time)'
39
+ */
40
+ export declare function validFormFieldTypesText(): string;
41
+ /** The product aliases, for the contract test. */
42
+ export declare const FORM_FIELD_TYPE_ALIASES: Readonly<Record<string, CanonicalFormFieldType>>;
43
+ /**
44
+ * The canonical type a wire or source spelling names, or `undefined` when it
45
+ * names none the SDK models.
46
+ *
47
+ * @example
48
+ * canonicalFormFieldType('integer') // 'integer'
49
+ * canonicalFormFieldType('text') // 'string'
50
+ * canonicalFormFieldType('System.Int32') // 'integer'
51
+ * canonicalFormFieldType('string[]') // 'array'
52
+ * canonicalFormFieldType('string | null') // 'string'
53
+ * canonicalFormFieldType('singleSelect') // undefined
54
+ */
55
+ export declare function canonicalFormFieldType(type: unknown): CanonicalFormFieldType | undefined;
24
56
  /**
25
- * The SDK's spelling of a wire form-field type, or `undefined` when the SDK
26
- * does not model that type.
57
+ * The spelling decompile writes into source for a wire field type: a canonical
58
+ * type or an SDK alias stays as written, so a canvas form (`"integer"`,
59
+ * `"date"`) and a classic-CLI form (`"text"`) both compile back to the bytes
60
+ * they came from; a product alias the SDK does not accept in source
61
+ * (`"System.Int32"`, `"string[]"`) becomes its canonical type; anything else
62
+ * stays verbatim for `check` to report.
27
63
  *
28
64
  * @example
29
- * sdkFormFieldType('string') // 'text'
30
- * sdkFormFieldType('datetime') // 'date-time'
31
- * sdkFormFieldType('integer') // undefined
65
+ * sourceFormFieldType('date') // 'date'
66
+ * sourceFormFieldType('text') // 'text'
67
+ * sourceFormFieldType('System.String') // 'string'
68
+ * sourceFormFieldType('string[]') // 'array'
69
+ * sourceFormFieldType('singleSelect') // 'singleSelect'
32
70
  */
33
- export declare function sdkFormFieldType(wire: unknown): FormFieldType | undefined;
71
+ export declare function sourceFormFieldType(wire: unknown): string;
34
72
  /**
35
- * Why a form-field type is refused: a product spelling of a type the SDK
36
- * models (`"string"` is the platform's own name for text), or a type
37
- * the SDK does not model at all. `unknownWhy` is the caller's reason for the
38
- * second case; the default is a human task's.
73
+ * Why a form-field type is refused: a product alias the SDK does not accept in
74
+ * source (`"System.Int32"` is the platform's .NET name for `integer`), a control
75
+ * spelling the platform accepts but the SDK does not model yet
76
+ * (`"singleSelect"`), or a type the product does not recognize at all.
77
+ * `unknownWhy` is the caller's reason for the last case; the default is a human
78
+ * task's.
39
79
  */
40
80
  export declare function formFieldTypeWhy(type: unknown, unknownWhy?: string): string;
41
- /** The form-field types the SDK models. */
42
- export declare const FORM_FIELD_TYPES: string[];
43
- /** The `suggestion` for an unknown form-field type: the nearest valid one, else `type: 'text'`. */
81
+ /** The `suggestion` for an unknown form-field type: its canonical type, the nearest valid one, else `type: 'string'`. */
44
82
  export declare function formFieldTypeHint(type: unknown): string;
45
- /** JSON-Schema type per form-field type, as flow-v1's form serializer maps them (quick-form escalations and human tasks). */
46
- export declare const FORM_FIELD_JSON_TYPE: Record<FormFieldType, {
83
+ /**
84
+ * The JSON Schema of a field's value, for the output (and escalation input)
85
+ * schemas the serializers write; `undefined` for a type the SDK does not model.
86
+ *
87
+ * @example
88
+ * formFieldJsonSchema('date') // { type: 'string', format: 'date' }
89
+ * formFieldJsonSchema('text') // { type: 'string' }
90
+ */
91
+ export declare function formFieldJsonSchema(type: unknown): {
47
92
  type: string;
48
93
  format?: string;
49
- }>;
94
+ } | undefined;
@@ -1,63 +1,197 @@
1
1
  import { nearestName } from './edit-distance.js';
2
- const PRODUCT_SPELLINGS = {
3
- text: 'text',
4
- string: 'text',
5
- String: 'text',
6
- 'System.String': 'text',
7
- 'System.Char': 'text',
8
- Char: 'text',
9
- number: 'number',
2
+ import { ownEntry } from './own-entry.js';
3
+ /**
4
+ * Each canonical type's JSON Schema, as `FIELD_TYPE_TO_JSON_SCHEMA` gives it.
5
+ * `Record<CanonicalFormFieldType, …>` makes tsc refuse a missing or extra one.
6
+ * `float` and `double` are both `number`: JSON Schema has no precision; `file`
7
+ * is `format: 'binary'` (the OpenAPI convention for an upload).
8
+ */
9
+ const CANONICAL_JSON_SCHEMA = {
10
+ string: { type: 'string' },
11
+ number: { type: 'number' },
12
+ integer: { type: 'integer' },
13
+ float: { type: 'number' },
14
+ double: { type: 'number' },
15
+ boolean: { type: 'boolean' },
16
+ date: { type: 'string', format: 'date' },
17
+ datetime: { type: 'string', format: 'date-time' },
18
+ file: { type: 'string', format: 'binary' },
19
+ object: { type: 'object' },
20
+ array: { type: 'array' },
21
+ };
22
+ /** The product's 11 canonical quick-form field types, in its own order. */
23
+ export const CANONICAL_FORM_FIELD_TYPES = Object.keys(CANONICAL_JSON_SCHEMA);
24
+ /**
25
+ * The SDK's own legacy spellings, accepted in source: `text` (what the SDK,
26
+ * flow-v1's serializer and `uip maestro flow hitl add` have always written) and
27
+ * `date-time`. The product resolves both.
28
+ */
29
+ const SDK_ALIASES = {
30
+ text: 'string',
31
+ 'date-time': 'datetime',
32
+ };
33
+ /** The SDK's legacy spellings (`text`, `date-time`), for diagnostics that list them. */
34
+ export const LEGACY_FORM_FIELD_TYPES = Object.keys(SDK_ALIASES);
35
+ /** Every form-field type the SDK accepts in source: the 11 canonical ones and the SDK's legacy aliases. */
36
+ export const FORM_FIELD_TYPES = [...CANONICAL_FORM_FIELD_TYPES, ...LEGACY_FORM_FIELD_TYPES];
37
+ /**
38
+ * The tail of a "Valid: …" diagnostic: the canonical types, then the legacy
39
+ * spellings in parentheses.
40
+ *
41
+ * @example
42
+ * validFormFieldTypesText() // 'string, number, …, array (or the older text, date-time)'
43
+ */
44
+ export function validFormFieldTypesText() {
45
+ return `${CANONICAL_FORM_FIELD_TYPES.join(', ')} (or the older ${LEGACY_FORM_FIELD_TYPES.join(', ')})`;
46
+ }
47
+ /**
48
+ * The product's other data-type spellings, each with the canonical type it
49
+ * resolves to (`resolveFieldType` in `@uipath/hitl-schema-types` 1.2.0). The
50
+ * .NET names come from forms built by RPA / agent tooling. The scope-walker
51
+ * shapes (`union`, `intersection`, `ref`, `any`) reach `field.type` when a
52
+ * canvas author binds a Flow variable; they carry no narrower shape, so they
53
+ * resolve to `string`. `T[]` and `a | b` are matched by pattern in
54
+ * `canonicalFormFieldType`.
55
+ *
56
+ * Deliberately left out: the CONTROL spellings `singleSelect`, `multiSelect`
57
+ * and `enum` (`CONTROL_FORM_FIELD_TYPES`). The product infers a `controlType`
58
+ * from those, so rewriting one to its data type would change how the form
59
+ * renders. Decompile keeps them as written, and `check` reports them.
60
+ */
61
+ const PRODUCT_ALIASES = {
62
+ ...SDK_ALIASES,
63
+ String: 'string',
64
+ 'System.String': 'string',
65
+ 'System.Char': 'string',
66
+ Char: 'string',
10
67
  Number: 'number',
11
- boolean: 'boolean',
68
+ Int32: 'integer',
69
+ Int64: 'integer',
70
+ 'System.Int32': 'integer',
71
+ 'System.Int64': 'integer',
72
+ 'System.Byte': 'integer',
73
+ 'System.Int16': 'integer',
74
+ Byte: 'integer',
75
+ Int16: 'integer',
76
+ UInt16: 'integer',
77
+ UInt32: 'integer',
78
+ UInt64: 'integer',
79
+ Float: 'float',
80
+ Single: 'float',
81
+ 'System.Single': 'float',
82
+ Double: 'double',
83
+ Decimal: 'double',
84
+ 'System.Double': 'double',
85
+ 'System.Decimal': 'double',
12
86
  Boolean: 'boolean',
13
87
  'System.Boolean': 'boolean',
14
- 'date-time': 'date-time',
15
- datetime: 'date-time',
16
- dateTime: 'date-time',
17
- DateTime: 'date-time',
18
- 'System.DateTime': 'date-time',
88
+ Date: 'date',
89
+ 'System.DateOnly': 'date',
90
+ DateOnly: 'date',
91
+ dateTime: 'datetime',
92
+ DateTime: 'datetime',
93
+ 'System.DateTime': 'datetime',
94
+ File: 'file',
95
+ Object: 'object',
96
+ DataTable: 'object',
97
+ QueueItem: 'object',
98
+ Array: 'array',
99
+ GenericValue: 'array',
100
+ list: 'array',
101
+ List: 'array',
102
+ union: 'string',
103
+ intersection: 'string',
104
+ ref: 'string',
105
+ any: 'string',
19
106
  };
20
107
  /**
21
- * The SDK's spelling of a wire form-field type, or `undefined` when the SDK
22
- * does not model that type.
108
+ * The product's control spellings: it accepts them as a field `type` and infers
109
+ * a picker control from them (`CONTROL_FOR_DECLARED_TYPE`). The SDK does not
110
+ * model them yet.
111
+ */
112
+ const CONTROL_FORM_FIELD_TYPES = ['singleSelect', 'multiSelect', 'enum'];
113
+ /** The product aliases, for the contract test. */
114
+ export const FORM_FIELD_TYPE_ALIASES = PRODUCT_ALIASES;
115
+ const isCanonical = (t) => typeof t === 'string' && Object.hasOwn(CANONICAL_JSON_SCHEMA, t);
116
+ /**
117
+ * The canonical type a wire or source spelling names, or `undefined` when it
118
+ * names none the SDK models.
119
+ *
120
+ * @example
121
+ * canonicalFormFieldType('integer') // 'integer'
122
+ * canonicalFormFieldType('text') // 'string'
123
+ * canonicalFormFieldType('System.Int32') // 'integer'
124
+ * canonicalFormFieldType('string[]') // 'array'
125
+ * canonicalFormFieldType('string | null') // 'string'
126
+ * canonicalFormFieldType('singleSelect') // undefined
127
+ */
128
+ export function canonicalFormFieldType(type) {
129
+ if (isCanonical(type))
130
+ return type;
131
+ if (typeof type !== 'string')
132
+ return undefined;
133
+ // The package's own order: the two scope-walker patterns before the names.
134
+ if (type.endsWith('[]'))
135
+ return 'array';
136
+ if (type.includes(' | '))
137
+ return 'string';
138
+ return Object.hasOwn(PRODUCT_ALIASES, type) ? PRODUCT_ALIASES[type] : undefined;
139
+ }
140
+ /**
141
+ * The spelling decompile writes into source for a wire field type: a canonical
142
+ * type or an SDK alias stays as written, so a canvas form (`"integer"`,
143
+ * `"date"`) and a classic-CLI form (`"text"`) both compile back to the bytes
144
+ * they came from; a product alias the SDK does not accept in source
145
+ * (`"System.Int32"`, `"string[]"`) becomes its canonical type; anything else
146
+ * stays verbatim for `check` to report.
23
147
  *
24
148
  * @example
25
- * sdkFormFieldType('string') // 'text'
26
- * sdkFormFieldType('datetime') // 'date-time'
27
- * sdkFormFieldType('integer') // undefined
149
+ * sourceFormFieldType('date') // 'date'
150
+ * sourceFormFieldType('text') // 'text'
151
+ * sourceFormFieldType('System.String') // 'string'
152
+ * sourceFormFieldType('string[]') // 'array'
153
+ * sourceFormFieldType('singleSelect') // 'singleSelect'
28
154
  */
29
- export function sdkFormFieldType(wire) {
30
- return typeof wire === 'string' && Object.hasOwn(PRODUCT_SPELLINGS, wire) ? PRODUCT_SPELLINGS[wire] : undefined;
155
+ export function sourceFormFieldType(wire) {
156
+ if (typeof wire === 'string' && FORM_FIELD_TYPES.includes(wire))
157
+ return wire;
158
+ return canonicalFormFieldType(wire) ?? String(wire);
31
159
  }
32
160
  /**
33
- * Why a form-field type is refused: a product spelling of a type the SDK
34
- * models (`"string"` is the platform's own name for text), or a type
35
- * the SDK does not model at all. `unknownWhy` is the caller's reason for the
36
- * second case; the default is a human task's.
37
- */
38
- export function formFieldTypeWhy(type, unknownWhy = `which the platform does not recognize. Older runtimes read it as text, newer ones reject `
39
- + `the form`) {
40
- const alias = sdkFormFieldType(type);
41
- return alias !== undefined
42
- ? `which is the platform's spelling of the SDK's '${alias}' — the SDK writes '${alias}'`
43
- : unknownWhy;
161
+ * Why a form-field type is refused: a product alias the SDK does not accept in
162
+ * source (`"System.Int32"` is the platform's .NET name for `integer`), a control
163
+ * spelling the platform accepts but the SDK does not model yet
164
+ * (`"singleSelect"`), or a type the product does not recognize at all.
165
+ * `unknownWhy` is the caller's reason for the last case; the default is a human
166
+ * task's.
167
+ */
168
+ export function formFieldTypeWhy(type, unknownWhy = `which is not a quick-form field type: the platform rejects the form`) {
169
+ const canonical = canonicalFormFieldType(type);
170
+ if (canonical !== undefined)
171
+ return `which is the platform's alias of '${canonical}' — the SDK writes '${canonical}'`;
172
+ if (typeof type === 'string' && CONTROL_FORM_FIELD_TYPES.includes(type)) {
173
+ return `which the platform accepts as a picker control but the SDK does not model yet`;
174
+ }
175
+ return unknownWhy;
44
176
  }
45
- /** Every FormFieldType, once; `Record<FormFieldType, …>` makes tsc refuse a missing or extra one. */
46
- const FORM_FIELD_TYPE_SET = { text: true, number: true, boolean: true, 'date-time': true };
47
- /** The form-field types the SDK models. */
48
- export const FORM_FIELD_TYPES = Object.keys(FORM_FIELD_TYPE_SET);
49
- /** The `suggestion` for an unknown form-field type: the nearest valid one, else `type: 'text'`. */
177
+ /** The `suggestion` for an unknown form-field type: its canonical type, the nearest valid one, else `type: 'string'`. */
50
178
  export function formFieldTypeHint(type) {
51
- const alias = sdkFormFieldType(type);
52
- if (alias !== undefined)
53
- return `type: '${alias}'`;
179
+ const canonical = canonicalFormFieldType(type);
180
+ if (canonical !== undefined)
181
+ return `type: '${canonical}'`;
54
182
  const nearest = nearestName(String(type), FORM_FIELD_TYPES);
55
- return nearest !== undefined ? `type: '${nearest}'` : `type: 'text'`;
183
+ return nearest !== undefined ? `type: '${nearest}'` : `type: 'string'`;
184
+ }
185
+ /**
186
+ * The JSON Schema of a field's value, for the output (and escalation input)
187
+ * schemas the serializers write; `undefined` for a type the SDK does not model.
188
+ *
189
+ * @example
190
+ * formFieldJsonSchema('date') // { type: 'string', format: 'date' }
191
+ * formFieldJsonSchema('text') // { type: 'string' }
192
+ */
193
+ export function formFieldJsonSchema(type) {
194
+ const canonical = canonicalFormFieldType(type);
195
+ const schema = canonical === undefined ? undefined : ownEntry(CANONICAL_JSON_SCHEMA, canonical);
196
+ return schema === undefined ? undefined : { ...schema };
56
197
  }
57
- /** JSON-Schema type per form-field type, as flow-v1's form serializer maps them (quick-form escalations and human tasks). */
58
- export const FORM_FIELD_JSON_TYPE = {
59
- text: { type: 'string' },
60
- number: { type: 'number' },
61
- boolean: { type: 'boolean' },
62
- 'date-time': { type: 'string', format: 'date-time' },
63
- };
package/dist/decompile.js CHANGED
@@ -50,7 +50,7 @@ import { OUTCOME_HANDLE_NODE_TYPES } from './core/hitl-routing.js';
50
50
  import { contributionPort, forwardFanOut } from './core/definition-handles.js';
51
51
  import { STICKY_NOTE_TYPE } from './core/definitionless-node-types.js';
52
52
  import { eventFilterFromTreeLeaf } from './core/event-filters.js';
53
- import { sdkFormFieldType } from './core/form-field-type.js';
53
+ import { sourceFormFieldType } from './core/form-field-type.js';
54
54
  /**
55
55
  * The trigger id of the flow currently being decompiled, so a reference through a
56
56
  * RENAMED trigger is still recognized as `input('x')` rather than falling back to
@@ -1304,7 +1304,7 @@ function emitAgentCluster(node, imp, inputNames, graph) {
1304
1304
  ['description', rPlain(e, 'description') !== undefined ? tsLiteral(rPlain(e, 'description')) : undefined],
1305
1305
  ['fields', rows.length ? `[${rows.map((f) => opts([
1306
1306
  ['id', tsText(f.id)],
1307
- ['type', tsLiteral(sdkFormFieldType(f.type ?? 'text') ?? String(f.type))],
1307
+ ['type', tsLiteral(sourceFormFieldType(f.type ?? 'string'))],
1308
1308
  ['direction', tsLiteral(String(f.direction ?? 'output'))],
1309
1309
  ])).join(', ')}]` : undefined],
1310
1310
  ['app', app === undefined ? undefined : opts([
@@ -0,0 +1,90 @@
1
+ /**
2
+ * merge-embedded-agent — keep an EMBEDDED agent embedded when a brownfield edit
3
+ * touches it (flow-builder-sdk#1220).
4
+ *
5
+ * An agent node stores its configuration (prompts, model, run settings) in one
6
+ * of two places:
7
+ *
8
+ * - embedded: on the node itself (`inputs.systemPrompt`, `inputs.model`, …).
9
+ * Older Studio Web saves, and any save with the self-contained flag on.
10
+ * - shell: the node keeps only its structural keys (`source`,
11
+ * `agentInputVariables`, `agentOutputVariables`, …) and the configuration
12
+ * lives in `<source>/agent.json`.
13
+ *
14
+ * The runtime and Studio Web pick the copy by `hasEmbeddedAgentContent`
15
+ * (`@uipath/flow-schema`): any prompt string on the node makes the node win and
16
+ * the sidecar is never read. Since #927 compile emits only shells. So when an
17
+ * edit changed an embedded agent's node (an input, an output, the label), the
18
+ * old merge took the edited SHELL node whole, and the agent's storage form
19
+ * flipped: the runtime then read the project's `<source>/agent.json`, which an
20
+ * embedded node had been shadowing and which is often stale. On corpus fixture
21
+ * `01-agent-input-binding` that silently changed the model from
22
+ * `gpt-4o-2024-11-20` to `gpt-5.4` and emptied the system prompt.
23
+ *
24
+ * The rule here is the same delta rule merge applies everywhere: the original
25
+ * node, plus what the author changed (`edited` minus `baseline`). The baseline
26
+ * and the edited node are both shells, so the configuration keys never appear in
27
+ * that delta and stay exactly as the original has them. Only the structural
28
+ * keys the author changed are taken from the edit. Without a baseline (a two-way
29
+ * merge), the edited node is taken, and every key the original has that the
30
+ * shell does not (the configuration) is put back.
31
+ *
32
+ * A prompt or model edit in the source does NOT reach an embedded agent: it
33
+ * lands in the edited `<source>/agent.json`, which the embedded node shadows.
34
+ * Merge reports that ({@link embeddedAgentFindings}), and refuses under
35
+ * `strict` any merged node that would no longer carry the original's embedded
36
+ * configuration, or whose kept prompt names an input the node no longer
37
+ * declares.
38
+ */
39
+ import type { MergeFinding } from './merge-roundtrip.js';
40
+ interface AgentNode {
41
+ id: string;
42
+ type: string;
43
+ inputs?: Record<string, unknown>;
44
+ [k: string]: unknown;
45
+ }
46
+ /**
47
+ * Whether `node` is an agent whose configuration is on the node, by
48
+ * `@uipath/flow-schema`'s `hasEmbeddedAgentContent`: a prompt string, or, on
49
+ * the voice node only, a `voice` settings object.
50
+ */
51
+ export declare function isEmbeddedAgent(node: {
52
+ type?: string;
53
+ inputs?: Record<string, unknown>;
54
+ } | undefined): boolean;
55
+ /**
56
+ * The merged node for an embedded original whose edited node is a shell: the
57
+ * original, plus the author's change to the node.
58
+ *
59
+ * @param orig - The original node (embedded).
60
+ * @param edited - The edited compile's node (a shell).
61
+ * @param base - The baseline compile's node, when the merge has a baseline.
62
+ * @returns The original node with the edit's changed structural inputs and changed top-level keys applied.
63
+ */
64
+ export declare function mergeEmbeddedAgentNode<N extends AgentNode>(orig: N, edited: N, base: N | undefined): N;
65
+ /**
66
+ * What a merged embedded agent needs said, per original embedded agent (root
67
+ * and subflows, matched by scope and node id):
68
+ *
69
+ * - `agent-storage` (refuses): the merged node no longer carries the original's
70
+ * embedded configuration, so the runtime would read `<source>/agent.json`
71
+ * instead — a model or prompt change the author never wrote.
72
+ * - `agent-prompt-input` (refuses): a kept prompt names `{{input.X}}` but the
73
+ * merged node declares no input `X` (the edit removed or renamed it), so the
74
+ * prompt would render the placeholder empty.
75
+ * - `agent-embedded-edit` (warns): the author edited the node; merge applied the
76
+ * node change and kept the original's prompts, model and settings, so a
77
+ * prompt or model edit in the source did not reach this agent.
78
+ *
79
+ * @param hasBaseline - Whether the merge had a baseline. Without one, merge
80
+ * cannot tell the author's change from the round trip's, so the
81
+ * `agent-embedded-edit` warning says the node may have been edited.
82
+ * @param scopes - Per scope (`''` = root, otherwise the subflow key): the original, merged and edited-node-ids.
83
+ */
84
+ export declare function embeddedAgentFindings(hasBaseline: boolean, scopes: Array<{
85
+ scope: string;
86
+ original: AgentNode[];
87
+ merged: AgentNode[];
88
+ edited: ReadonlySet<string>;
89
+ }>): MergeFinding[];
90
+ export {};