@nxisai/agent-harness 0.2.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/README.md +434 -0
- package/dist/a2ui/cards.d.ts +55 -0
- package/dist/a2ui/cards.d.ts.map +1 -0
- package/dist/a2ui/cards.js +133 -0
- package/dist/a2ui/cards.js.map +1 -0
- package/dist/a2ui/emit.d.ts +33 -0
- package/dist/a2ui/emit.d.ts.map +1 -0
- package/dist/a2ui/emit.js +116 -0
- package/dist/a2ui/emit.js.map +1 -0
- package/dist/a2ui/form.d.ts +20 -0
- package/dist/a2ui/form.d.ts.map +1 -0
- package/dist/a2ui/form.js +92 -0
- package/dist/a2ui/form.js.map +1 -0
- package/dist/a2ui/host.d.ts +34 -0
- package/dist/a2ui/host.d.ts.map +1 -0
- package/dist/a2ui/host.js +47 -0
- package/dist/a2ui/host.js.map +1 -0
- package/dist/a2ui/index.d.ts +23 -0
- package/dist/a2ui/index.d.ts.map +1 -0
- package/dist/a2ui/index.js +20 -0
- package/dist/a2ui/index.js.map +1 -0
- package/dist/a2ui/stepper.d.ts +26 -0
- package/dist/a2ui/stepper.d.ts.map +1 -0
- package/dist/a2ui/stepper.js +162 -0
- package/dist/a2ui/stepper.js.map +1 -0
- package/dist/a2ui/theme.d.ts +21 -0
- package/dist/a2ui/theme.d.ts.map +1 -0
- package/dist/a2ui/theme.js +134 -0
- package/dist/a2ui/theme.js.map +1 -0
- package/dist/a2ui/to-v09.d.ts +31 -0
- package/dist/a2ui/to-v09.d.ts.map +1 -0
- package/dist/a2ui/to-v09.js +104 -0
- package/dist/a2ui/to-v09.js.map +1 -0
- package/dist/engine.d.ts +209 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +505 -0
- package/dist/engine.js.map +1 -0
- package/dist/harness/harness.d.ts +284 -0
- package/dist/harness/harness.d.ts.map +1 -0
- package/dist/harness/harness.js +568 -0
- package/dist/harness/harness.js.map +1 -0
- package/dist/harness/plan.d.ts +32 -0
- package/dist/harness/plan.d.ts.map +1 -0
- package/dist/harness/plan.js +68 -0
- package/dist/harness/plan.js.map +1 -0
- package/dist/harness/policy.d.ts +49 -0
- package/dist/harness/policy.d.ts.map +1 -0
- package/dist/harness/policy.js +34 -0
- package/dist/harness/policy.js.map +1 -0
- package/dist/harness/renderer.d.ts +163 -0
- package/dist/harness/renderer.d.ts.map +1 -0
- package/dist/harness/renderer.js +12 -0
- package/dist/harness/renderer.js.map +1 -0
- package/dist/harness/router/coordinator.d.ts +120 -0
- package/dist/harness/router/coordinator.d.ts.map +1 -0
- package/dist/harness/router/coordinator.js +145 -0
- package/dist/harness/router/coordinator.js.map +1 -0
- package/dist/harness/router/rules.d.ts +48 -0
- package/dist/harness/router/rules.d.ts.map +1 -0
- package/dist/harness/router/rules.js +38 -0
- package/dist/harness/router/rules.js.map +1 -0
- package/dist/harness/slots.d.ts +73 -0
- package/dist/harness/slots.d.ts.map +1 -0
- package/dist/harness/slots.js +68 -0
- package/dist/harness/slots.js.map +1 -0
- package/dist/harness/tools/bridge.d.ts +71 -0
- package/dist/harness/tools/bridge.d.ts.map +1 -0
- package/dist/harness/tools/bridge.js +271 -0
- package/dist/harness/tools/bridge.js.map +1 -0
- package/dist/harness/tools/client.d.ts +11 -0
- package/dist/harness/tools/client.d.ts.map +1 -0
- package/dist/harness/tools/client.js +21 -0
- package/dist/harness/tools/client.js.map +1 -0
- package/dist/harness/tools/discovery.d.ts +13 -0
- package/dist/harness/tools/discovery.d.ts.map +1 -0
- package/dist/harness/tools/discovery.js +43 -0
- package/dist/harness/tools/discovery.js.map +1 -0
- package/dist/harness/tools/local-context.d.ts +38 -0
- package/dist/harness/tools/local-context.d.ts.map +1 -0
- package/dist/harness/tools/local-context.js +55 -0
- package/dist/harness/tools/local-context.js.map +1 -0
- package/dist/harness/tools/schema.d.ts +52 -0
- package/dist/harness/tools/schema.d.ts.map +1 -0
- package/dist/harness/tools/schema.js +175 -0
- package/dist/harness/tools/schema.js.map +1 -0
- package/dist/harness/tools/source.d.ts +65 -0
- package/dist/harness/tools/source.d.ts.map +1 -0
- package/dist/harness/tools/source.js +89 -0
- package/dist/harness/tools/source.js.map +1 -0
- package/dist/harness/tools/webmcp.d.ts +50 -0
- package/dist/harness/tools/webmcp.d.ts.map +1 -0
- package/dist/harness/tools/webmcp.js +114 -0
- package/dist/harness/tools/webmcp.js.map +1 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/types.d.ts +123 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +2 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/types.d.ts +223 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/agent-fullscreen.d.ts +41 -0
- package/dist/ui/agent-fullscreen.d.ts.map +1 -0
- package/dist/ui/agent-fullscreen.js +2821 -0
- package/dist/ui/agent-fullscreen.js.map +1 -0
- package/dist/ui/config.d.ts +88 -0
- package/dist/ui/config.d.ts.map +1 -0
- package/dist/ui/config.js +96 -0
- package/dist/ui/config.js.map +1 -0
- package/dist/ui/index.d.ts +22 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +19 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/tailwind.generated.d.ts +2 -0
- package/dist/ui/tailwind.generated.d.ts.map +1 -0
- package/dist/ui/tailwind.generated.js +3 -0
- package/dist/ui/tailwind.generated.js.map +1 -0
- package/dist/webmcp-contract.d.ts +57 -0
- package/dist/webmcp-contract.d.ts.map +1 -0
- package/dist/webmcp-contract.js +11 -0
- package/dist/webmcp-contract.js.map +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turns a parsed WebMCP action into an A2UI message stream.
|
|
3
|
+
*
|
|
4
|
+
* The model never authors A2UI: it picks a tool and fills parameters, and this
|
|
5
|
+
* deterministic code writes every envelope. Asking a small model to produce
|
|
6
|
+
* nested JSON with JSON Pointers and catalog constraints would be the least
|
|
7
|
+
* reliable part of an in-browser A2UI setup, and this avoids it.
|
|
8
|
+
*
|
|
9
|
+
* Transport is a function call, since the agent and renderer share a JavaScript
|
|
10
|
+
* context, which satisfies A2UI's ordered-delivery requirement for free.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
import type { NxisAction } from '../webmcp-contract.js';
|
|
15
|
+
/** One A2UI protocol message, authored against the v1.0 spec. */
|
|
16
|
+
export interface A2uiMessage {
|
|
17
|
+
version: 'v1.0';
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Build the full message stream for an action.
|
|
22
|
+
*
|
|
23
|
+
* @param action - parsed action from nxis.js `readActions()`
|
|
24
|
+
* @param prefill - values already known (the device-local profile), keyed by valueName
|
|
25
|
+
*/
|
|
26
|
+
export declare function emitActionSurface(action: NxisAction, prefill?: Record<string, unknown>): A2uiMessage[];
|
|
27
|
+
/**
|
|
28
|
+
* Values the agent infers mid-conversation arrive as data-model patches rather
|
|
29
|
+
* than a rebuilt surface, so the form updates under the user without losing
|
|
30
|
+
* focus or anything they have already typed.
|
|
31
|
+
*/
|
|
32
|
+
export declare function emitPrefill(surfaceId: string, valueName: string, value: unknown): A2uiMessage;
|
|
33
|
+
//# sourceMappingURL=emit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../src/a2ui/emit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAkC,MAAM,uBAAuB,CAAC;AAWxF,iEAAiE;AACjE,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAsDD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,UAAU,EAClB,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACpC,WAAW,EAAE,CA0Cf;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAK7F"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turns a parsed WebMCP action into an A2UI message stream.
|
|
3
|
+
*
|
|
4
|
+
* The model never authors A2UI: it picks a tool and fills parameters, and this
|
|
5
|
+
* deterministic code writes every envelope. Asking a small model to produce
|
|
6
|
+
* nested JSON with JSON Pointers and catalog constraints would be the least
|
|
7
|
+
* reliable part of an in-browser A2UI setup, and this avoids it.
|
|
8
|
+
*
|
|
9
|
+
* Transport is a function call, since the agent and renderer share a JavaScript
|
|
10
|
+
* context, which satisfies A2UI's ordered-delivery requirement for free.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
const CATALOG = 'https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json';
|
|
15
|
+
/**
|
|
16
|
+
* A leading option that carries no label and reads as a prompt ("Select…",
|
|
17
|
+
* "Choose a service…") is the HTML `<option>` placeholder convention, not a
|
|
18
|
+
* real choice. A2UI has no placeholder slot on ChoicePicker, so it becomes the
|
|
19
|
+
* label and is dropped from `options`, since otherwise the agent can submit
|
|
20
|
+
* "Choose a service…" as a literal answer.
|
|
21
|
+
*/
|
|
22
|
+
function splitPlaceholder(options) {
|
|
23
|
+
const [first, ...rest] = options;
|
|
24
|
+
const looksLikePrompt = first && !first.name && /[…:]\s*$/.test(first.value);
|
|
25
|
+
return looksLikePrompt
|
|
26
|
+
? { placeholder: first.value, rest }
|
|
27
|
+
: { rest: options };
|
|
28
|
+
}
|
|
29
|
+
/** Map one PropertyValueSpecification to a component, or null if it is data-only. */
|
|
30
|
+
function fieldComponent(pvs) {
|
|
31
|
+
const id = `field_${pvs.valueName}`;
|
|
32
|
+
const path = { path: `/form/${pvs.valueName}` };
|
|
33
|
+
const label = pvs.description ?? pvs.valueName;
|
|
34
|
+
// A prefilled field with no description is context the form carries, not
|
|
35
|
+
// something to ask a human about. It stays in the data model and is submitted;
|
|
36
|
+
// it just gets no component. `business` is exactly this.
|
|
37
|
+
if (!pvs.description && pvs.defaultValue !== undefined)
|
|
38
|
+
return null;
|
|
39
|
+
if (pvs['nxis:valueOption']?.length) {
|
|
40
|
+
const { placeholder, rest } = splitPlaceholder(pvs['nxis:valueOption']);
|
|
41
|
+
return {
|
|
42
|
+
id,
|
|
43
|
+
component: 'ChoicePicker',
|
|
44
|
+
label: placeholder ? `${label} — ${placeholder}` : label,
|
|
45
|
+
variant: 'mutuallyExclusive',
|
|
46
|
+
options: rest.map((o) => ({ label: o.name ?? o.value, value: o.value })),
|
|
47
|
+
value: path,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// valueMaxLength is absent on this action, so long-text is inferred from the
|
|
51
|
+
// field name. Crude, but wrong only in that a textarea renders as one line.
|
|
52
|
+
const longText = /description|message|notes|details/.test(pvs.valueName);
|
|
53
|
+
return {
|
|
54
|
+
id,
|
|
55
|
+
component: 'TextField',
|
|
56
|
+
label,
|
|
57
|
+
variant: longText ? 'longText' : 'shortText',
|
|
58
|
+
value: path,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Build the full message stream for an action.
|
|
63
|
+
*
|
|
64
|
+
* @param action - parsed action from nxis.js `readActions()`
|
|
65
|
+
* @param prefill - values already known (the device-local profile), keyed by valueName
|
|
66
|
+
*/
|
|
67
|
+
export function emitActionSurface(action, prefill = {}) {
|
|
68
|
+
const fields = action.input ?? [];
|
|
69
|
+
// Data model first: every field, whether or not it gets a component.
|
|
70
|
+
const dataModel = {};
|
|
71
|
+
for (const pvs of fields) {
|
|
72
|
+
dataModel[pvs.valueName] =
|
|
73
|
+
prefill[pvs.valueName] ?? pvs.defaultValue ?? '';
|
|
74
|
+
}
|
|
75
|
+
const fieldComponents = fields
|
|
76
|
+
.map(fieldComponent)
|
|
77
|
+
.filter((c) => c !== null);
|
|
78
|
+
const components = [
|
|
79
|
+
// Inline components are cards. See stepper.ts.
|
|
80
|
+
{ id: 'root', component: 'Card', child: 'body' },
|
|
81
|
+
{ id: 'body', component: 'Column', children: [
|
|
82
|
+
'heading', ...fieldComponents.map((c) => c.id), 'submit',
|
|
83
|
+
] },
|
|
84
|
+
{ id: 'heading', component: 'Text', text: action.description ?? action.name, variant: 'body' },
|
|
85
|
+
...fieldComponents,
|
|
86
|
+
{ id: 'submit_label', component: 'Text', text: 'Submit' },
|
|
87
|
+
{
|
|
88
|
+
id: 'submit',
|
|
89
|
+
component: 'Button',
|
|
90
|
+
child: 'submit_label',
|
|
91
|
+
variant: 'primary',
|
|
92
|
+
// The event name carries the action @id, so the handler knows which
|
|
93
|
+
// WebMCP tool to invoke without a second lookup.
|
|
94
|
+
action: { event: { name: 'nxis.submit', context: { actionId: action['@id'] } } },
|
|
95
|
+
},
|
|
96
|
+
];
|
|
97
|
+
const surfaceId = `action_${action.name}`;
|
|
98
|
+
return [
|
|
99
|
+
{
|
|
100
|
+
version: 'v1.0',
|
|
101
|
+
createSurface: { surfaceId, catalogId: CATALOG, components, dataModel: { form: dataModel } },
|
|
102
|
+
},
|
|
103
|
+
];
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Values the agent infers mid-conversation arrive as data-model patches rather
|
|
107
|
+
* than a rebuilt surface, so the form updates under the user without losing
|
|
108
|
+
* focus or anything they have already typed.
|
|
109
|
+
*/
|
|
110
|
+
export function emitPrefill(surfaceId, valueName, value) {
|
|
111
|
+
return {
|
|
112
|
+
version: 'v1.0',
|
|
113
|
+
updateDataModel: { surfaceId, path: `/form/${valueName}`, value },
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=emit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit.js","sourceRoot":"","sources":["../../src/a2ui/emit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds an A2UI form from a tool's JSON Schema.
|
|
3
|
+
*
|
|
4
|
+
* The general counterpart to `emit.ts`, which starts from a WebMCP action
|
|
5
|
+
* extracted from page JSON-LD. This one starts from the schema that remote MCP
|
|
6
|
+
* tools expose and that {@link toolSchema} normalises to, producing the same
|
|
7
|
+
* output surface from a different input.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import type { JsonSchema } from '../types.js';
|
|
12
|
+
import type { A2uiMessage } from './emit.js';
|
|
13
|
+
/**
|
|
14
|
+
* Build the form surface for a tool.
|
|
15
|
+
*
|
|
16
|
+
* Submit and Cancel dispatch action events carrying the tool name, so one
|
|
17
|
+
* handler can serve every form without tracking which surface is live.
|
|
18
|
+
*/
|
|
19
|
+
export declare function emitToolForm(toolName: string, description: string, schema: JsonSchema, values?: Record<string, unknown>, surfaceId?: string): A2uiMessage[];
|
|
20
|
+
//# sourceMappingURL=form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../src/a2ui/form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAkD7C;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,UAAU,EAClB,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,SAAS,SAAa,GACrB,WAAW,EAAE,CA0Cf"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds an A2UI form from a tool's JSON Schema.
|
|
3
|
+
*
|
|
4
|
+
* The general counterpart to `emit.ts`, which starts from a WebMCP action
|
|
5
|
+
* extracted from page JSON-LD. This one starts from the schema that remote MCP
|
|
6
|
+
* tools expose and that {@link toolSchema} normalises to, producing the same
|
|
7
|
+
* output surface from a different input.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
const CATALOG = 'https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json';
|
|
12
|
+
const humanize = (s) => s.replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/[_-]+/g, ' ')
|
|
13
|
+
.replace(/^\w/, c => c.toUpperCase());
|
|
14
|
+
/** Enum values may be bare scalars or {const,title}-style objects. */
|
|
15
|
+
function enumOptions(values) {
|
|
16
|
+
return values.map(v => {
|
|
17
|
+
if (v && typeof v === 'object') {
|
|
18
|
+
const o = v;
|
|
19
|
+
const value = String(o.const ?? o.value ?? '');
|
|
20
|
+
return { label: String(o.title ?? o.name ?? value), value };
|
|
21
|
+
}
|
|
22
|
+
return { label: humanize(String(v)), value: String(v) };
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function fieldComponent(key, spec, required) {
|
|
26
|
+
const id = `f_${key}`;
|
|
27
|
+
const path = { path: `/form/${key}` };
|
|
28
|
+
// The required marker is part of the label, since the basic catalog has no
|
|
29
|
+
// requiredness of its own. Validation stays with the caller regardless.
|
|
30
|
+
const label = `${spec.description || humanize(key)}${required ? ' *' : ''}`;
|
|
31
|
+
const enumValues = spec.enum ?? spec.items?.enum;
|
|
32
|
+
if (Array.isArray(enumValues) && enumValues.length) {
|
|
33
|
+
return {
|
|
34
|
+
id, component: 'ChoicePicker', label,
|
|
35
|
+
variant: spec.type === 'array' ? 'multipleSelection' : 'mutuallyExclusive',
|
|
36
|
+
options: enumOptions(enumValues),
|
|
37
|
+
value: path,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
if (spec.type === 'boolean')
|
|
41
|
+
return { id, component: 'CheckBox', label, value: path };
|
|
42
|
+
const variant = spec.type === 'number' || spec.type === 'integer' ? 'number'
|
|
43
|
+
: spec.format === 'password' ? 'obscured'
|
|
44
|
+
: /description|message|notes|details|body/.test(key) ? 'longText'
|
|
45
|
+
: 'shortText';
|
|
46
|
+
return { id, component: 'TextField', label, variant, value: path };
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Build the form surface for a tool.
|
|
50
|
+
*
|
|
51
|
+
* Submit and Cancel dispatch action events carrying the tool name, so one
|
|
52
|
+
* handler can serve every form without tracking which surface is live.
|
|
53
|
+
*/
|
|
54
|
+
export function emitToolForm(toolName, description, schema, values = {}, surfaceId = 'toolform') {
|
|
55
|
+
const props = schema.properties ?? {};
|
|
56
|
+
const required = new Set(schema.required ?? []);
|
|
57
|
+
const fields = Object.entries(props).map(([key, spec]) => fieldComponent(key, spec ?? {}, required.has(key)));
|
|
58
|
+
// Seed by type: a CheckBox bound to '' is not merely empty, it is the wrong
|
|
59
|
+
// type for the component and does not round-trip through the data model.
|
|
60
|
+
const dataModel = {};
|
|
61
|
+
for (const [key, spec] of Object.entries(props)) {
|
|
62
|
+
const fallback = spec?.type === 'boolean' ? false
|
|
63
|
+
: spec?.type === 'number' || spec?.type === 'integer' ? null
|
|
64
|
+
: '';
|
|
65
|
+
dataModel[key] = values[key] ?? fallback;
|
|
66
|
+
}
|
|
67
|
+
const components = [
|
|
68
|
+
// Inline components are cards. See stepper.ts.
|
|
69
|
+
{ id: 'root', component: 'Card', child: 'body' },
|
|
70
|
+
{ id: 'body', component: 'Column',
|
|
71
|
+
children: ['eyebrow', 'title', ...(description ? ['desc'] : []), ...fields.map(f => f.id), 'actions'] },
|
|
72
|
+
{ id: 'eyebrow', component: 'Text', text: 'DETAILS NEEDED', variant: 'caption' },
|
|
73
|
+
// Body, not a heading: markdown headings would pick up
|
|
74
|
+
// --a2ui-font-family-title, but only with a MarkdownRenderer in context.
|
|
75
|
+
// Without one the raw "###" is printed. See stepper.ts.
|
|
76
|
+
{ id: 'title', component: 'Text', text: humanize(toolName), variant: 'body' },
|
|
77
|
+
...(description ? [{ id: 'desc', component: 'Text', text: description, variant: 'caption' }] : []),
|
|
78
|
+
...fields,
|
|
79
|
+
{ id: 'actions', component: 'Row', children: ['cancel', 'submit'], justify: 'end' },
|
|
80
|
+
{ id: 'cancel_label', component: 'Text', text: 'Cancel' },
|
|
81
|
+
{ id: 'cancel', component: 'Button', child: 'cancel_label',
|
|
82
|
+
action: { event: { name: 'nxis.cancel', context: { tool: toolName } } } },
|
|
83
|
+
{ id: 'submit_label', component: 'Text', text: 'Submit' },
|
|
84
|
+
{ id: 'submit', component: 'Button', child: 'submit_label', variant: 'primary',
|
|
85
|
+
action: { event: { name: 'nxis.submit', context: { tool: toolName } } } },
|
|
86
|
+
];
|
|
87
|
+
return [{
|
|
88
|
+
version: 'v1.0',
|
|
89
|
+
createSurface: { surfaceId, catalogId: CATALOG, components, dataModel: { form: dataModel } },
|
|
90
|
+
}];
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=form.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form.js","sourceRoot":"","sources":["../../src/a2ui/form.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mounts A2UI messages into a container element.
|
|
3
|
+
*
|
|
4
|
+
* Wraps the emit, downgrade, process and mount sequence every A2UI surface
|
|
5
|
+
* needs, so callers deal in messages and a container rather than in message
|
|
6
|
+
* processor lifecycles.
|
|
7
|
+
*
|
|
8
|
+
* Works inside a shadow root, since `<a2ui-surface>` is a custom element and
|
|
9
|
+
* upgrades wherever it is appended.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import '@a2ui/lit/v0_9';
|
|
14
|
+
import type { A2uiMessage } from './emit.js';
|
|
15
|
+
/** A live A2UI surface, and the handle used to tear it down. */
|
|
16
|
+
export interface MountedSurface {
|
|
17
|
+
/** The processor, for reading the live data model or sending further messages. */
|
|
18
|
+
processor: any;
|
|
19
|
+
/** The mounted custom element. */
|
|
20
|
+
element: HTMLElement;
|
|
21
|
+
/** Current value of one top-level data-model key on this surface. */
|
|
22
|
+
read(key: string): unknown;
|
|
23
|
+
/** Push a v1.0 message (e.g. a prefill patch) into the live surface. */
|
|
24
|
+
send(messages: A2uiMessage[]): void;
|
|
25
|
+
dispose(): void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Render `messages` into `container`.
|
|
29
|
+
*
|
|
30
|
+
* @param onAction - Called when the renderer dispatches a button action. The
|
|
31
|
+
* event carries whatever `action.event.context` the emitter attached.
|
|
32
|
+
*/
|
|
33
|
+
export declare function mountSurface(container: HTMLElement, messages: A2uiMessage[], onAction?: (event: any) => void): MountedSurface | null;
|
|
34
|
+
//# sourceMappingURL=host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/a2ui/host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAG7C,gEAAgE;AAChE,MAAM,WAAW,cAAc;IAC7B,kFAAkF;IAClF,SAAS,EAAE,GAAG,CAAC;IACf,kCAAkC;IAClC,OAAO,EAAE,WAAW,CAAC;IACrB,qEAAqE;IACrE,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,wEAAwE;IACxE,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IACpC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,WAAW,EACtB,QAAQ,EAAE,WAAW,EAAE,EACvB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,GAC9B,cAAc,GAAG,IAAI,CA6BvB"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mounts A2UI messages into a container element.
|
|
3
|
+
*
|
|
4
|
+
* Wraps the emit, downgrade, process and mount sequence every A2UI surface
|
|
5
|
+
* needs, so callers deal in messages and a container rather than in message
|
|
6
|
+
* processor lifecycles.
|
|
7
|
+
*
|
|
8
|
+
* Works inside a shadow root, since `<a2ui-surface>` is a custom element and
|
|
9
|
+
* upgrades wherever it is appended.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import { MessageProcessor } from '@a2ui/web_core/v0_9';
|
|
14
|
+
import { basicCatalog } from '@a2ui/lit/v0_9';
|
|
15
|
+
import '@a2ui/lit/v0_9';
|
|
16
|
+
import { toV09 } from './to-v09.js';
|
|
17
|
+
/**
|
|
18
|
+
* Render `messages` into `container`.
|
|
19
|
+
*
|
|
20
|
+
* @param onAction - Called when the renderer dispatches a button action. The
|
|
21
|
+
* event carries whatever `action.event.context` the emitter attached.
|
|
22
|
+
*/
|
|
23
|
+
export function mountSurface(container, messages, onAction) {
|
|
24
|
+
const processor = new MessageProcessor([basicCatalog], (event) => onAction?.(event));
|
|
25
|
+
processor.processMessages(toV09(messages));
|
|
26
|
+
// One surface per mount; the first is the one just created.
|
|
27
|
+
const first = processor.model.surfacesMap.entries().next();
|
|
28
|
+
if (first.done)
|
|
29
|
+
return null;
|
|
30
|
+
const [, surface] = first.value;
|
|
31
|
+
const element = document.createElement('a2ui-surface');
|
|
32
|
+
element.surface = surface;
|
|
33
|
+
container.appendChild(element);
|
|
34
|
+
return {
|
|
35
|
+
processor,
|
|
36
|
+
element,
|
|
37
|
+
// DataModel exposes get(path); reading the surface's own model avoids
|
|
38
|
+
// depending on the sendDataModel flag that getClientDataModel requires.
|
|
39
|
+
read: (key) => surface?.dataModel?.get(`/${key}`),
|
|
40
|
+
send: (msgs) => processor.processMessages(toV09(msgs)),
|
|
41
|
+
dispose: () => {
|
|
42
|
+
element.remove();
|
|
43
|
+
processor.dispose?.();
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/a2ui/host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,gBAAgB,CAAC;AAGxB,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAepC;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAC1B,SAAsB,EACtB,QAAuB,EACvB,QAA+B;IAE/B,MAAM,SAAS,GAAG,IAAI,gBAAgB,CACpC,CAAC,YAAmB,CAAC,EACrB,CAAC,KAAU,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAClC,CAAC;IAEF,SAAS,CAAC,eAAe,CAAC,KAAK,CAAC,QAAQ,CAAQ,CAAC,CAAC;IAElD,4DAA4D;IAC5D,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC;IAC3D,IAAI,KAAK,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC,KAA0B,CAAC;IAErD,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,cAAc,CAAQ,CAAC;IAC9D,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC;IAC1B,SAAS,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAE/B,OAAO;QACL,SAAS;QACT,OAAO;QACP,sEAAsE;QACtE,wEAAwE;QACxE,IAAI,EAAE,CAAC,GAAW,EAAE,EAAE,CAAE,OAAe,EAAE,SAAS,EAAE,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;QAClE,IAAI,EAAE,CAAC,IAAmB,EAAE,EAAE,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,CAAQ,CAAC;QAC5E,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,CAAC,MAAM,EAAE,CAAC;YAChB,SAAiB,CAAC,OAAO,EAAE,EAAE,CAAC;QACjC,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2UI surface emitters.
|
|
3
|
+
*
|
|
4
|
+
* Turn a tool's schema, a clarification plan, or typed-retrieval results into
|
|
5
|
+
* A2UI messages, for rendering through an A2UI renderer rather than the
|
|
6
|
+
* packaged element.
|
|
7
|
+
*
|
|
8
|
+
* Messages are authored against the v1.0 spec and downgraded by {@link toV09}
|
|
9
|
+
* before rendering, since published renderers support v0.9 and earlier.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
export { emitActionSurface, emitPrefill } from './emit.js';
|
|
14
|
+
export type { A2uiMessage } from './emit.js';
|
|
15
|
+
export { emitToolForm } from './form.js';
|
|
16
|
+
export { emitAsk, emitStep, emitConfirm } from './stepper.js';
|
|
17
|
+
export { emitCardsSurface, emitResultsSurface, emitAppendResult, toCardData } from './cards.js';
|
|
18
|
+
export type { ResultCardData, CardRow, CardTag } from './cards.js';
|
|
19
|
+
export { mountSurface } from './host.js';
|
|
20
|
+
export type { MountedSurface } from './host.js';
|
|
21
|
+
export { toV09 } from './to-v09.js';
|
|
22
|
+
export { A2UI_THEME_CSS, NXIS_PRIMARY } from './theme.js';
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/a2ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC3D,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAChG,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2UI surface emitters.
|
|
3
|
+
*
|
|
4
|
+
* Turn a tool's schema, a clarification plan, or typed-retrieval results into
|
|
5
|
+
* A2UI messages, for rendering through an A2UI renderer rather than the
|
|
6
|
+
* packaged element.
|
|
7
|
+
*
|
|
8
|
+
* Messages are authored against the v1.0 spec and downgraded by {@link toV09}
|
|
9
|
+
* before rendering, since published renderers support v0.9 and earlier.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
export { emitActionSurface, emitPrefill } from './emit.js';
|
|
14
|
+
export { emitToolForm } from './form.js';
|
|
15
|
+
export { emitAsk, emitStep, emitConfirm } from './stepper.js';
|
|
16
|
+
export { emitCardsSurface, emitResultsSurface, emitAppendResult, toCardData } from './cards.js';
|
|
17
|
+
export { mountSurface } from './host.js';
|
|
18
|
+
export { toV09 } from './to-v09.js';
|
|
19
|
+
export { A2UI_THEME_CSS, NXIS_PRIMARY } from './theme.js';
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/a2ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEhG,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two prompt surfaces: asking for missing values, and confirming a write.
|
|
3
|
+
*
|
|
4
|
+
* The stepper never recreates its surface. Steps arrive as component updates
|
|
5
|
+
* against a live surface whose data model already holds every answer, so moving
|
|
6
|
+
* between steps changes the components without touching the data, and nothing
|
|
7
|
+
* already entered is lost.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import type { A2uiMessage } from './emit.js';
|
|
12
|
+
import type { ClarificationPlan } from '../harness/plan.js';
|
|
13
|
+
import type { Slot } from '../harness/slots.js';
|
|
14
|
+
/** Create the surface, showing the first step. */
|
|
15
|
+
export declare function emitAsk(toolName: string, plan: ClarificationPlan, known: Record<string, unknown>, surfaceId?: string): A2uiMessage[];
|
|
16
|
+
/** Move to another step: components only, so answers already typed survive. */
|
|
17
|
+
export declare function emitStep(surfaceId: string, toolName: string, plan: ClarificationPlan, index: number): A2uiMessage[];
|
|
18
|
+
/**
|
|
19
|
+
* The write confirmation: what is about to be sent, read-only.
|
|
20
|
+
*
|
|
21
|
+
* Not a form: nothing is missing, so there is nothing to fill in,
|
|
22
|
+
* showing inputs would imply otherwise and invite editing that was not asked
|
|
23
|
+
* for. Edit is available, as a button, for when it genuinely was.
|
|
24
|
+
*/
|
|
25
|
+
export declare function emitConfirm(toolName: string, slots: Slot[], surfaceId?: string): A2uiMessage[];
|
|
26
|
+
//# sourceMappingURL=stepper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stepper.d.ts","sourceRoot":"","sources":["../../src/a2ui/stepper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,iBAAiB,EAAY,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AA2GhD,kDAAkD;AAClD,wBAAgB,OAAO,CACrB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,iBAAiB,EACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,SAAQ,GAChB,WAAW,EAAE,CAqBf;AAED,+EAA+E;AAC/E,wBAAgB,QAAQ,CACtB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,iBAAiB,EACvB,KAAK,EAAE,MAAM,GACZ,WAAW,EAAE,CAMf;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,IAAI,EAAE,EACb,SAAS,SAAY,GACpB,WAAW,EAAE,CAkCf"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two prompt surfaces: asking for missing values, and confirming a write.
|
|
3
|
+
*
|
|
4
|
+
* The stepper never recreates its surface. Steps arrive as component updates
|
|
5
|
+
* against a live surface whose data model already holds every answer, so moving
|
|
6
|
+
* between steps changes the components without touching the data, and nothing
|
|
7
|
+
* already entered is lost.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
const CATALOG = 'https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json';
|
|
12
|
+
const humanize = (s) => s.replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/[_-]+/g, ' ')
|
|
13
|
+
.replace(/^\w/, c => c.toUpperCase());
|
|
14
|
+
function labelFor(slot) {
|
|
15
|
+
return slot.schema.description || humanize(slot.name);
|
|
16
|
+
}
|
|
17
|
+
function enumOptions(values) {
|
|
18
|
+
return values
|
|
19
|
+
.map(v => String(v))
|
|
20
|
+
// A leading placeholder option is a markup convention rather than a
|
|
21
|
+
// choice, and offering it would allow it to be submitted as an answer.
|
|
22
|
+
.filter(v => !/[…:]\s*$/.test(v))
|
|
23
|
+
.map(v => ({ label: humanize(v), value: v }));
|
|
24
|
+
}
|
|
25
|
+
/** One input bound to /form/<name>. */
|
|
26
|
+
function inputFor(slot) {
|
|
27
|
+
const id = `f_${slot.name}`;
|
|
28
|
+
const value = { path: `/form/${slot.name}` };
|
|
29
|
+
const label = labelFor(slot);
|
|
30
|
+
const spec = slot.schema;
|
|
31
|
+
const values = spec.enum ?? spec.items?.enum;
|
|
32
|
+
if (Array.isArray(values) && values.length) {
|
|
33
|
+
return { id, component: 'ChoicePicker', label, variant: 'mutuallyExclusive',
|
|
34
|
+
options: enumOptions(values), value };
|
|
35
|
+
}
|
|
36
|
+
if (spec.type === 'boolean')
|
|
37
|
+
return { id, component: 'CheckBox', label, value };
|
|
38
|
+
const variant = spec.type === 'number' || spec.type === 'integer' ? 'number'
|
|
39
|
+
: /description|message|notes|details/.test(slot.name) ? 'longText'
|
|
40
|
+
: 'shortText';
|
|
41
|
+
return { id, component: 'TextField', label, variant, value };
|
|
42
|
+
}
|
|
43
|
+
function stepComponents(step, plan, toolName) {
|
|
44
|
+
const fields = step.slots.map(inputFor);
|
|
45
|
+
const isLast = step.index === plan.steps.length - 1;
|
|
46
|
+
const isFirst = step.index === 0;
|
|
47
|
+
const actionIds = [
|
|
48
|
+
...(plan.stepped && !isFirst ? ['back'] : []),
|
|
49
|
+
'cancel',
|
|
50
|
+
isLast ? 'submit' : 'next',
|
|
51
|
+
];
|
|
52
|
+
// Same header shape as the review and submitted cards: an uppercase eyebrow
|
|
53
|
+
// then the detail. Uppercased in the string itself because no CSS of
|
|
54
|
+
// ours reaches inside these components.
|
|
55
|
+
//
|
|
56
|
+
// The headline is NOT Manrope. --a2ui-font-family-title applies only to
|
|
57
|
+
// markdown headings, and Text falls back to rendering the raw string unless
|
|
58
|
+
// a MarkdownRenderer is provided through Lit context, so "### Foo" renders as
|
|
59
|
+
// literal hashes. Reaching the display face here needs @a2ui/markdown-it
|
|
60
|
+
// wired into the surface, not a formatting trick.
|
|
61
|
+
const heading = [
|
|
62
|
+
{ id: 'eyebrow', component: 'Text',
|
|
63
|
+
text: plan.stepped
|
|
64
|
+
? `STEP ${step.index + 1} OF ${plan.steps.length}`
|
|
65
|
+
: 'ONE MORE DETAIL',
|
|
66
|
+
variant: 'caption' },
|
|
67
|
+
{ id: 'headline', component: 'Text', text: step.title, variant: 'body' },
|
|
68
|
+
];
|
|
69
|
+
return [
|
|
70
|
+
// Every inline component is a card: the surface is a thing placed in the
|
|
71
|
+
// conversation, and the card edge is what separates it from the message
|
|
72
|
+
// bubbles either side. Card takes one child, so the content column sits
|
|
73
|
+
// inside it rather than being the root itself.
|
|
74
|
+
{ id: 'root', component: 'Card', child: 'body' },
|
|
75
|
+
{ id: 'body', component: 'Column',
|
|
76
|
+
children: [...heading.map(h => h.id), ...fields.map(f => f.id), 'actions'] },
|
|
77
|
+
...heading,
|
|
78
|
+
...fields,
|
|
79
|
+
{ id: 'actions', component: 'Row', children: actionIds, justify: 'end' },
|
|
80
|
+
{ id: 'back_label', component: 'Text', text: 'Back' },
|
|
81
|
+
{ id: 'back', component: 'Button', child: 'back_label',
|
|
82
|
+
action: { event: { name: 'nxis.back', context: { tool: toolName, step: step.index } } } },
|
|
83
|
+
{ id: 'cancel_label', component: 'Text', text: 'Cancel' },
|
|
84
|
+
{ id: 'cancel', component: 'Button', child: 'cancel_label',
|
|
85
|
+
action: { event: { name: 'nxis.cancel', context: { tool: toolName } } } },
|
|
86
|
+
{ id: 'next_label', component: 'Text', text: 'Next' },
|
|
87
|
+
{ id: 'next', component: 'Button', child: 'next_label', variant: 'primary',
|
|
88
|
+
action: { event: { name: 'nxis.next', context: { tool: toolName, step: step.index } } } },
|
|
89
|
+
{ id: 'submit_label', component: 'Text', text: 'Submit' },
|
|
90
|
+
{ id: 'submit', component: 'Button', child: 'submit_label', variant: 'primary',
|
|
91
|
+
action: { event: { name: 'nxis.submit', context: { tool: toolName } } } },
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
/** Create the surface, showing the first step. */
|
|
95
|
+
export function emitAsk(toolName, plan, known, surfaceId = 'ask') {
|
|
96
|
+
// Seed every gap so its input has a value to bind to, and carry the known
|
|
97
|
+
// values along: they are submitted with the answers even though no step
|
|
98
|
+
// ever displays them.
|
|
99
|
+
const form = { ...known };
|
|
100
|
+
for (const step of plan.steps) {
|
|
101
|
+
for (const slot of step.slots) {
|
|
102
|
+
if (form[slot.name] === undefined) {
|
|
103
|
+
form[slot.name] = slot.schema.type === 'boolean' ? false : '';
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return [{
|
|
108
|
+
version: 'v1.0',
|
|
109
|
+
createSurface: {
|
|
110
|
+
surfaceId, catalogId: CATALOG,
|
|
111
|
+
components: stepComponents(plan.steps[0], plan, toolName),
|
|
112
|
+
dataModel: { form, step: 0 },
|
|
113
|
+
},
|
|
114
|
+
}];
|
|
115
|
+
}
|
|
116
|
+
/** Move to another step: components only, so answers already typed survive. */
|
|
117
|
+
export function emitStep(surfaceId, toolName, plan, index) {
|
|
118
|
+
return [
|
|
119
|
+
{ version: 'v1.0',
|
|
120
|
+
updateComponents: { surfaceId, components: stepComponents(plan.steps[index], plan, toolName) } },
|
|
121
|
+
{ version: 'v1.0', updateDataModel: { surfaceId, path: '/step', value: index } },
|
|
122
|
+
];
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* The write confirmation: what is about to be sent, read-only.
|
|
126
|
+
*
|
|
127
|
+
* Not a form: nothing is missing, so there is nothing to fill in,
|
|
128
|
+
* showing inputs would imply otherwise and invite editing that was not asked
|
|
129
|
+
* for. Edit is available, as a button, for when it genuinely was.
|
|
130
|
+
*/
|
|
131
|
+
export function emitConfirm(toolName, slots, surfaceId = 'confirm') {
|
|
132
|
+
const rows = slots.map(s => ({ label: labelFor(s), value: String(s.value ?? '') }));
|
|
133
|
+
const components = [
|
|
134
|
+
// The review is a card for the same reason the inputs are: it is one
|
|
135
|
+
// reviewable object, and its edge is what says "this is what will be sent"
|
|
136
|
+
// rather than "this is more conversation".
|
|
137
|
+
{ id: 'root', component: 'Card', child: 'body' },
|
|
138
|
+
{ id: 'body', component: 'Column', children: ['eyebrow', 'headline', 'rows', 'actions'] },
|
|
139
|
+
{ id: 'eyebrow', component: 'Text', text: 'READY TO SEND', variant: 'caption' },
|
|
140
|
+
{ id: 'headline', component: 'Text', text: humanize(toolName), variant: 'body' },
|
|
141
|
+
{ id: 'rows', component: 'List',
|
|
142
|
+
children: { path: '/rows', componentId: 'row_tpl' }, direction: 'vertical' },
|
|
143
|
+
{ id: 'row_tpl', component: 'Row', children: ['row_label', 'row_value'] },
|
|
144
|
+
{ id: 'row_label', component: 'Text', text: '${label}', variant: 'caption' },
|
|
145
|
+
{ id: 'row_value', component: 'Text', text: '${value}' },
|
|
146
|
+
{ id: 'actions', component: 'Row', children: ['edit', 'cancel', 'send'], justify: 'end' },
|
|
147
|
+
{ id: 'edit_label', component: 'Text', text: 'Edit' },
|
|
148
|
+
{ id: 'edit', component: 'Button', child: 'edit_label',
|
|
149
|
+
action: { event: { name: 'nxis.edit', context: { tool: toolName } } } },
|
|
150
|
+
{ id: 'cancel_label', component: 'Text', text: 'Cancel' },
|
|
151
|
+
{ id: 'cancel', component: 'Button', child: 'cancel_label',
|
|
152
|
+
action: { event: { name: 'nxis.cancel', context: { tool: toolName } } } },
|
|
153
|
+
{ id: 'send_label', component: 'Text', text: 'Submit' },
|
|
154
|
+
{ id: 'send', component: 'Button', child: 'send_label', variant: 'primary',
|
|
155
|
+
action: { event: { name: 'nxis.submit', context: { tool: toolName } } } },
|
|
156
|
+
];
|
|
157
|
+
return [{
|
|
158
|
+
version: 'v1.0',
|
|
159
|
+
createSurface: { surfaceId, catalogId: CATALOG, components, dataModel: { rows } },
|
|
160
|
+
}];
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=stepper.js.map
|