@assistant-ui/react-generative-ui 0.0.19 → 0.0.21
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/JSONGenerativeUI.client.d.ts +14 -15
- package/dist/JSONGenerativeUI.client.d.ts.map +1 -1
- package/dist/JSONGenerativeUI.client.js +28 -8
- package/dist/JSONGenerativeUI.client.js.map +1 -1
- package/dist/JSONGenerativeUI.server.d.ts +5 -7
- package/dist/JSONGenerativeUI.server.d.ts.map +1 -1
- package/dist/JSONGenerativeUI.shared.d.ts +35 -36
- package/dist/JSONGenerativeUI.shared.d.ts.map +1 -1
- package/dist/a2ui/convert.d.ts +7 -7
- package/dist/a2ui/convert.d.ts.map +1 -1
- package/dist/a2ui/convert.js +148 -28
- package/dist/a2ui/convert.js.map +1 -1
- package/dist/a2ui/reducer.d.ts +1 -3
- package/dist/a2ui/reducer.d.ts.map +1 -1
- package/dist/a2ui/reducer.js +8 -0
- package/dist/a2ui/reducer.js.map +1 -1
- package/dist/a2ui/snapshot.d.ts +3 -0
- package/dist/a2ui/snapshot.d.ts.map +1 -0
- package/dist/a2ui/snapshot.js +33 -0
- package/dist/a2ui/snapshot.js.map +1 -0
- package/dist/a2ui/types.d.ts +50 -40
- package/dist/a2ui/types.d.ts.map +1 -1
- package/dist/a2ui/types.js.map +1 -1
- package/dist/a2ui.d.ts +5 -4
- package/dist/a2ui.d.ts.map +1 -0
- package/dist/a2ui.js +2 -1
- package/dist/actionRegistry.d.ts +12 -14
- package/dist/actionRegistry.d.ts.map +1 -1
- package/dist/actionRegistry.js.map +1 -1
- package/dist/buildPresentParameters.d.ts +2 -4
- package/dist/buildPresentParameters.d.ts.map +1 -1
- package/dist/buildPresentParameters.js +16 -4
- package/dist/buildPresentParameters.js.map +1 -1
- package/dist/constants.d.ts +0 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/convert/boundSpec.d.ts +0 -2
- package/dist/convert/boundSpec.d.ts.map +1 -1
- package/dist/convert/copyBounded.d.ts +2 -4
- package/dist/convert/copyBounded.d.ts.map +1 -1
- package/dist/convert/isElement.d.ts +1 -3
- package/dist/convert/isElement.d.ts.map +1 -1
- package/dist/convert/takeRun.d.ts +3 -5
- package/dist/convert/takeRun.d.ts.map +1 -1
- package/dist/defineGenerativeComponents.d.ts +1 -3
- package/dist/defineGenerativeComponents.d.ts.map +1 -1
- package/dist/generativeUIToJSX.d.ts +4 -6
- package/dist/generativeUIToJSX.d.ts.map +1 -1
- package/dist/index.d.ts +3 -13
- package/dist/index.d.ts.map +1 -0
- package/dist/index.server.d.ts +3 -13
- package/dist/index.server.d.ts.map +1 -0
- package/dist/index.shared.d.ts +15 -11
- package/dist/index.shared.d.ts.map +1 -0
- package/dist/ir.d.ts +17 -19
- package/dist/ir.d.ts.map +1 -1
- package/dist/renderGenerativeUI.d.ts +2 -4
- package/dist/renderGenerativeUI.d.ts.map +1 -1
- package/dist/scopeSchema.d.ts +6 -0
- package/dist/scopeSchema.d.ts.map +1 -0
- package/dist/scopeSchema.js +56 -0
- package/dist/scopeSchema.js.map +1 -0
- package/dist/slack/constants.d.ts +8 -9
- package/dist/slack/constants.d.ts.map +1 -1
- package/dist/slack/decodeBlockAction.d.ts +1 -3
- package/dist/slack/decodeBlockAction.d.ts.map +1 -1
- package/dist/slack/fromSlackBlocks.d.ts +1 -3
- package/dist/slack/fromSlackBlocks.d.ts.map +1 -1
- package/dist/slack/toSlackBlocks.d.ts +1 -3
- package/dist/slack/toSlackBlocks.d.ts.map +1 -1
- package/dist/slack/toSlackBlocks.js +1 -1
- package/dist/slack/types.d.ts +78 -80
- package/dist/slack/types.d.ts.map +1 -1
- package/dist/slack.d.ts +5 -5
- package/dist/slack.d.ts.map +1 -0
- package/dist/teams/constants.d.ts +1 -3
- package/dist/teams/constants.d.ts.map +1 -1
- package/dist/teams/decodeSubmitData.d.ts +1 -3
- package/dist/teams/decodeSubmitData.d.ts.map +1 -1
- package/dist/teams/toAdaptiveCard.d.ts +4 -6
- package/dist/teams/toAdaptiveCard.d.ts.map +1 -1
- package/dist/teams/toTeamsAttachments.d.ts +1 -3
- package/dist/teams/toTeamsAttachments.d.ts.map +1 -1
- package/dist/teams/types.d.ts +108 -109
- package/dist/teams/types.d.ts.map +1 -1
- package/dist/teams.d.ts +5 -5
- package/dist/teams.d.ts.map +1 -0
- package/dist/types.d.ts +36 -37
- package/dist/types.d.ts.map +1 -1
- package/dist/vocabulary/alert.d.ts +21 -23
- package/dist/vocabulary/alert.d.ts.map +1 -1
- package/dist/vocabulary/collectFormValues.d.ts +8 -10
- package/dist/vocabulary/collectFormValues.d.ts.map +1 -1
- package/dist/vocabulary/data.d.ts +45 -47
- package/dist/vocabulary/data.d.ts.map +1 -1
- package/dist/vocabulary/dispatch.d.ts +2 -4
- package/dist/vocabulary/dispatch.d.ts.map +1 -1
- package/dist/vocabulary/fact.d.ts +8 -10
- package/dist/vocabulary/fact.d.ts.map +1 -1
- package/dist/vocabulary/form.d.ts +7 -9
- package/dist/vocabulary/form.d.ts.map +1 -1
- package/dist/vocabulary/icon.d.ts +37 -39
- package/dist/vocabulary/icon.d.ts.map +1 -1
- package/dist/vocabulary/index.d.ts +1 -3
- package/dist/vocabulary/index.d.ts.map +1 -1
- package/dist/vocabulary/interactive.d.ts +87 -86
- package/dist/vocabulary/interactive.d.ts.map +1 -1
- package/dist/vocabulary/interactive.js +4 -4
- package/dist/vocabulary/interactive.js.map +1 -1
- package/dist/vocabulary/layout.d.ts +75 -77
- package/dist/vocabulary/layout.d.ts.map +1 -1
- package/dist/vocabulary/list.d.ts +10 -12
- package/dist/vocabulary/list.d.ts.map +1 -1
- package/dist/vocabulary/media.d.ts +21 -23
- package/dist/vocabulary/media.d.ts.map +1 -1
- package/dist/vocabulary/text.d.ts +53 -55
- package/dist/vocabulary/text.d.ts.map +1 -1
- package/dist/vocabulary/toTextContent.d.ts +0 -2
- package/dist/vocabulary/toTextContent.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/JSONGenerativeUI.client.tsx +57 -15
- package/src/JSONGenerativeUI.test.tsx +298 -4
- package/src/a2ui/convert.test.ts +717 -0
- package/src/a2ui/convert.ts +229 -41
- package/src/a2ui/reducer.test.ts +18 -0
- package/src/a2ui/reducer.ts +16 -0
- package/src/a2ui/snapshot.test.ts +52 -0
- package/src/a2ui/snapshot.ts +52 -0
- package/src/a2ui/types.ts +16 -0
- package/src/a2ui.ts +2 -0
- package/src/actionRegistry.ts +5 -5
- package/src/buildPresentParameters.test.ts +246 -0
- package/src/buildPresentParameters.ts +18 -3
- package/src/scopeSchema.test.ts +72 -0
- package/src/scopeSchema.ts +71 -0
- package/src/vocabulary/interactive.dispatch.test.tsx +17 -3
- package/src/vocabulary/interactive.test.tsx +19 -0
- package/src/vocabulary/interactive.tsx +4 -1
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { JSONGenerativeUIOptions, PresentTool, PresentToolOptions, PromptUserTool } from "./JSONGenerativeUI.shared.js";
|
|
2
|
-
//#region src/JSONGenerativeUI.client.d.ts
|
|
1
|
+
import { type JSONGenerativeUIOptions, type PresentTool, type PresentToolOptions, type PromptUserTool } from "./JSONGenerativeUI.shared.js";
|
|
3
2
|
/**
|
|
4
3
|
* Client build of {@link JSONGenerativeUI}, resolved through the package's
|
|
5
4
|
* `default` export condition (browser and SSR).
|
|
@@ -12,18 +11,18 @@ import { JSONGenerativeUIOptions, PresentTool, PresentToolOptions, PromptUserToo
|
|
|
12
11
|
* interactive components can fire `$action` through `$dispatch`.
|
|
13
12
|
*/
|
|
14
13
|
export declare class JSONGenerativeUI {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
14
|
+
private readonly library;
|
|
15
|
+
private readonly parameters;
|
|
16
|
+
private readonly actions;
|
|
17
|
+
private readonly completedPromptToolCallIds;
|
|
18
|
+
constructor(options: JSONGenerativeUIOptions);
|
|
19
|
+
/**
|
|
20
|
+
* The surface a `present` call paints into. It owns the vertical rhythm
|
|
21
|
+
* between top-level blocks, which the host's message container does not
|
|
22
|
+
* provide, and stays out of the way while it has nothing to show.
|
|
23
|
+
*/
|
|
24
|
+
private readonly render;
|
|
25
|
+
present(options?: PresentToolOptions): PresentTool;
|
|
26
|
+
promptUser(): PromptUserTool;
|
|
27
27
|
}
|
|
28
|
-
//#endregion
|
|
29
28
|
//# sourceMappingURL=JSONGenerativeUI.client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSONGenerativeUI.client.d.ts","
|
|
1
|
+
{"version":3,"file":"JSONGenerativeUI.client.d.ts","sourceRoot":"","sources":["../src/JSONGenerativeUI.client.tsx"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,uBAAuB,EAE5B,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACpB,qCAAkC;AAanC;;;;;;;;;;GAUG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6B;IACrD,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAqB;gBAEpD,OAAO,EAAE,uBAAuB;IAM5C;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAqDrB;IAEF,OAAO,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,WAAW;IASlD,UAAU,IAAI,cAAc;CAO7B"}
|
|
@@ -25,6 +25,7 @@ var JSONGenerativeUI = class {
|
|
|
25
25
|
library;
|
|
26
26
|
parameters;
|
|
27
27
|
actions;
|
|
28
|
+
completedPromptToolCallIds = /* @__PURE__ */ new Set();
|
|
28
29
|
constructor(options) {
|
|
29
30
|
this.library = options.library;
|
|
30
31
|
this.parameters = buildPresentParameters(options.library);
|
|
@@ -35,13 +36,32 @@ var JSONGenerativeUI = class {
|
|
|
35
36
|
* between top-level blocks, which the host's message container does not
|
|
36
37
|
* provide, and stays out of the way while it has nothing to show.
|
|
37
38
|
*/
|
|
38
|
-
render = ({ args, status }
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
render = ({ args, status, addResult, result, toolCallId, unstable_recordInteraction }, completesPrompt = false) => {
|
|
40
|
+
const actions = this.actions;
|
|
41
|
+
const dispatch = actions ? (action) => {
|
|
42
|
+
if (unstable_recordInteraction) try {
|
|
43
|
+
unstable_recordInteraction({
|
|
44
|
+
type: "action",
|
|
45
|
+
payload: action
|
|
46
|
+
}).catch(() => {});
|
|
47
|
+
} catch {}
|
|
48
|
+
const actionResult = actions.dispatch(action);
|
|
49
|
+
if (completesPrompt && actionResult !== void 0 && result === void 0) Promise.resolve(actionResult).then((response) => {
|
|
50
|
+
if (response !== void 0 && !this.completedPromptToolCallIds.has(toolCallId)) {
|
|
51
|
+
this.completedPromptToolCallIds.add(toolCallId);
|
|
52
|
+
addResult(response);
|
|
53
|
+
}
|
|
54
|
+
}).catch(() => {});
|
|
55
|
+
return actionResult;
|
|
56
|
+
} : void 0;
|
|
57
|
+
return /* @__PURE__ */ jsx("div", {
|
|
58
|
+
"data-aui": "root",
|
|
59
|
+
children: renderGenerativeUI(args, this.library, {
|
|
60
|
+
status: uiStatus(status),
|
|
61
|
+
...dispatch ? { dispatch } : {}
|
|
62
|
+
})
|
|
63
|
+
});
|
|
64
|
+
};
|
|
45
65
|
present(options) {
|
|
46
66
|
return {
|
|
47
67
|
...presentToolBase(this.parameters, options),
|
|
@@ -54,7 +74,7 @@ var JSONGenerativeUI = class {
|
|
|
54
74
|
return {
|
|
55
75
|
...promptUserToolBase(this.parameters),
|
|
56
76
|
unstable_backendDefault: { parameters: true },
|
|
57
|
-
render: this.render
|
|
77
|
+
render: (props) => this.render(props, true)
|
|
58
78
|
};
|
|
59
79
|
}
|
|
60
80
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSONGenerativeUI.client.js","names":[],"sources":["../src/JSONGenerativeUI.client.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { buildPresentParameters } from \"./buildPresentParameters\";\nimport {\n presentToolBase,\n promptUserToolBase,\n type JSONGenerativeUIOptions,\n type PresentParameters,\n type PresentTool,\n type PresentToolOptions,\n type PromptUserTool,\n} from \"./JSONGenerativeUI.shared\";\nimport { type ActionRegistry } from \"./actionRegistry\";\nimport { renderGenerativeUI } from \"./renderGenerativeUI\";\nimport type { GenerativeUILibrary, GenerativeUIStatus } from \"./types\";\n\n/** Maps a tool-call part status to the generative-UI streaming status. Only a\n * `complete` call has fully-arrived args; `running` and `incomplete`\n * (aborted/errored, so args may be partial) both render as `\"streaming\"` so a\n * non-streaming component is never handed partial props. */\nfunction uiStatus(status: { type: string }): GenerativeUIStatus {\n return status.type === \"complete\" ? \"done\" : \"streaming\";\n}\n\n/**\n * Client build of {@link JSONGenerativeUI}, resolved through the package's\n * `default` export condition (browser and SSR).\n *\n * `present` is a frontend tool that renders the model's `{ $type, ...props }`\n * tree against the library and resolves immediately. `prompt_user` is a\n * human-in-the-loop tool: the model pauses and the rendered UI supplies the\n * result. Both draw the tree the same way, so they share one `render`. The\n * `actions` registry (if provided) is threaded into the render context so\n * interactive components can fire `$action` through `$dispatch`.\n */\nexport class JSONGenerativeUI {\n private readonly library: GenerativeUILibrary;\n private readonly parameters: PresentParameters;\n private readonly actions: ActionRegistry | undefined;\n\n constructor(options: JSONGenerativeUIOptions) {\n this.library = options.library;\n this.parameters = buildPresentParameters(options.library);\n this.actions = options.actions;\n }\n\n /**\n * The surface a `present` call paints into. It owns the vertical rhythm\n * between top-level blocks, which the host's message container does not\n * provide, and stays out of the way while it has nothing to show.\n */\n private readonly render = ({\n
|
|
1
|
+
{"version":3,"file":"JSONGenerativeUI.client.js","names":[],"sources":["../src/JSONGenerativeUI.client.tsx"],"sourcesContent":["import type { ToolCallMessagePartProps } from \"@assistant-ui/react\";\nimport type { ReactNode } from \"react\";\nimport { buildPresentParameters } from \"./buildPresentParameters\";\nimport {\n presentToolBase,\n promptUserToolBase,\n type JSONGenerativeUIOptions,\n type PresentParameters,\n type PresentTool,\n type PresentToolOptions,\n type PromptUserTool,\n} from \"./JSONGenerativeUI.shared\";\nimport { type ActionRegistry } from \"./actionRegistry\";\nimport { renderGenerativeUI } from \"./renderGenerativeUI\";\nimport type { GenerativeUILibrary, GenerativeUIStatus } from \"./types\";\n\n/** Maps a tool-call part status to the generative-UI streaming status. Only a\n * `complete` call has fully-arrived args; `running` and `incomplete`\n * (aborted/errored, so args may be partial) both render as `\"streaming\"` so a\n * non-streaming component is never handed partial props. */\nfunction uiStatus(status: { type: string }): GenerativeUIStatus {\n return status.type === \"complete\" ? \"done\" : \"streaming\";\n}\n\n/**\n * Client build of {@link JSONGenerativeUI}, resolved through the package's\n * `default` export condition (browser and SSR).\n *\n * `present` is a frontend tool that renders the model's `{ $type, ...props }`\n * tree against the library and resolves immediately. `prompt_user` is a\n * human-in-the-loop tool: the model pauses and the rendered UI supplies the\n * result. Both draw the tree the same way, so they share one `render`. The\n * `actions` registry (if provided) is threaded into the render context so\n * interactive components can fire `$action` through `$dispatch`.\n */\nexport class JSONGenerativeUI {\n private readonly library: GenerativeUILibrary;\n private readonly parameters: PresentParameters;\n private readonly actions: ActionRegistry | undefined;\n private readonly completedPromptToolCallIds = new Set<string>();\n\n constructor(options: JSONGenerativeUIOptions) {\n this.library = options.library;\n this.parameters = buildPresentParameters(options.library);\n this.actions = options.actions;\n }\n\n /**\n * The surface a `present` call paints into. It owns the vertical rhythm\n * between top-level blocks, which the host's message container does not\n * provide, and stays out of the way while it has nothing to show.\n */\n private readonly render = (\n {\n args,\n status,\n addResult,\n result,\n toolCallId,\n unstable_recordInteraction,\n }: ToolCallMessagePartProps<Record<string, unknown>, any>,\n completesPrompt = false,\n ): ReactNode => {\n const actions = this.actions;\n const dispatch = actions\n ? (action: Parameters<ActionRegistry[\"dispatch\"]>[0]) => {\n if (unstable_recordInteraction) {\n try {\n void unstable_recordInteraction({\n type: \"action\",\n payload: action,\n }).catch(() => {});\n } catch {}\n }\n\n const actionResult = actions.dispatch(action);\n if (\n completesPrompt &&\n actionResult !== undefined &&\n result === undefined\n ) {\n void Promise.resolve(actionResult)\n .then((response) => {\n if (\n response !== undefined &&\n !this.completedPromptToolCallIds.has(toolCallId)\n ) {\n this.completedPromptToolCallIds.add(toolCallId);\n addResult(response);\n }\n })\n .catch(() => {});\n }\n return actionResult;\n }\n : undefined;\n\n return (\n <div data-aui=\"root\">\n {renderGenerativeUI(args, this.library, {\n status: uiStatus(status),\n ...(dispatch ? { dispatch } : {}),\n })}\n </div>\n );\n };\n\n present(options?: PresentToolOptions): PresentTool {\n return {\n ...presentToolBase(this.parameters, options),\n unstable_backendDefault: { parameters: true },\n execute: async () => ({}),\n render: this.render,\n };\n }\n\n promptUser(): PromptUserTool {\n return {\n ...promptUserToolBase(this.parameters),\n unstable_backendDefault: { parameters: true },\n render: (props) => this.render(props, true),\n };\n }\n}\n"],"mappings":";;;;;;;;;AAoBA,SAAS,SAAS,QAA8C;CAC9D,OAAO,OAAO,SAAS,aAAa,SAAS;AAC/C;;;;;;;;;;;;AAaA,IAAa,mBAAb,MAA8B;CAC5B;CACA;CACA;CACA,6CAA8C,IAAI,IAAY;CAE9D,YAAY,SAAkC;EAC5C,KAAK,UAAU,QAAQ;EACvB,KAAK,aAAa,uBAAuB,QAAQ,OAAO;EACxD,KAAK,UAAU,QAAQ;CACzB;;;;;;CAOA,UACE,EACE,MACA,QACA,WACA,QACA,YACA,8BAEF,kBAAkB,UACJ;EACd,MAAM,UAAU,KAAK;EACrB,MAAM,WAAW,WACZ,WAAsD;GACrD,IAAI,4BACF,IAAI;IACF,2BAAgC;KAC9B,MAAM;KACN,SAAS;IACX,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;GACnB,QAAQ,CAAC;GAGX,MAAM,eAAe,QAAQ,SAAS,MAAM;GAC5C,IACE,mBACA,iBAAiB,KAAA,KACjB,WAAW,KAAA,GAEX,QAAa,QAAQ,YAAY,CAAC,CAC/B,MAAM,aAAa;IAClB,IACE,aAAa,KAAA,KACb,CAAC,KAAK,2BAA2B,IAAI,UAAU,GAC/C;KACA,KAAK,2BAA2B,IAAI,UAAU;KAC9C,UAAU,QAAQ;IACpB;GACF,CAAC,CAAC,CACD,YAAY,CAAC,CAAC;GAEnB,OAAO;EACT,IACA,KAAA;EAEJ,OACE,oBAAC,OAAD;GAAK,YAAS;GACX,UAAA,mBAAmB,MAAM,KAAK,SAAS;IACtC,QAAQ,SAAS,MAAM;IACvB,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;GACjC,CAAC;EACE,CAAA;CAET;CAEA,QAAQ,SAA2C;EACjD,OAAO;GACL,GAAG,gBAAgB,KAAK,YAAY,OAAO;GAC3C,yBAAyB,EAAE,YAAY,KAAK;GAC5C,SAAS,aAAa,CAAC;GACvB,QAAQ,KAAK;EACf;CACF;CAEA,aAA6B;EAC3B,OAAO;GACL,GAAG,mBAAmB,KAAK,UAAU;GACrC,yBAAyB,EAAE,YAAY,KAAK;GAC5C,SAAS,UAAU,KAAK,OAAO,OAAO,IAAI;EAC5C;CACF;AACF"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { JSONGenerativeUIOptions, PresentTool, PresentToolOptions, PromptUserTool } from "./JSONGenerativeUI.shared.js";
|
|
2
|
-
//#region src/JSONGenerativeUI.server.d.ts
|
|
1
|
+
import { type JSONGenerativeUIOptions, type PresentTool, type PresentToolOptions, type PromptUserTool } from "./JSONGenerativeUI.shared.js";
|
|
3
2
|
/**
|
|
4
3
|
* Server build of {@link JSONGenerativeUI}, resolved through the package's
|
|
5
4
|
* `react-server` export condition.
|
|
@@ -14,10 +13,9 @@ import { JSONGenerativeUIOptions, PresentTool, PresentToolOptions, PromptUserToo
|
|
|
14
13
|
* tools; on the server it is structurally absent and never read.
|
|
15
14
|
*/
|
|
16
15
|
export declare class JSONGenerativeUI {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
private readonly parameters;
|
|
17
|
+
constructor(options: JSONGenerativeUIOptions);
|
|
18
|
+
present(options?: PresentToolOptions): PresentTool;
|
|
19
|
+
promptUser(): PromptUserTool;
|
|
21
20
|
}
|
|
22
|
-
//#endregion
|
|
23
21
|
//# sourceMappingURL=JSONGenerativeUI.server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSONGenerativeUI.server.d.ts","
|
|
1
|
+
{"version":3,"file":"JSONGenerativeUI.server.d.ts","sourceRoot":"","sources":["../src/JSONGenerativeUI.server.tsx"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,uBAAuB,EAE5B,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACpB,qCAAkC;AAEnC;;;;;;;;;;;;GAYG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;gBAEnC,OAAO,EAAE,uBAAuB;IAI5C,OAAO,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,WAAW;IAIlD,UAAU,IAAI,cAAc;CAG7B"}
|
|
@@ -1,38 +1,37 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
//#region src/JSONGenerativeUI.shared.d.ts
|
|
1
|
+
import type { ToolDefinition } from "@assistant-ui/react";
|
|
2
|
+
import type { JSONSchema7 } from "json-schema";
|
|
3
|
+
import type { ActionRegistry } from "./actionRegistry.js";
|
|
4
|
+
import type { GenerativeUILibrary } from "./types.js";
|
|
6
5
|
/** Options for {@link JSONGenerativeUI}. */
|
|
7
6
|
export type JSONGenerativeUIOptions = {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
7
|
+
/**
|
|
8
|
+
* The components the model is allowed to render, keyed by the `$type` it
|
|
9
|
+
* selects them with. Author it with `defineGenerativeComponents({ ... })` so a
|
|
10
|
+
* `"use generative"` build can split each `render` from its `properties`.
|
|
11
|
+
*/
|
|
12
|
+
library: GenerativeUILibrary;
|
|
13
|
+
/**
|
|
14
|
+
* Host-provided map from `$action.type` to its handler. Interactive
|
|
15
|
+
* components (`Button`/`Select`/`Input`/`DatePicker`) call `$dispatch($action)`
|
|
16
|
+
* on their event, which resolves through this registry. Omit it for a
|
|
17
|
+
* read-only render where model-emitted actions degrade to a no-op.
|
|
18
|
+
*/
|
|
19
|
+
actions?: ActionRegistry;
|
|
21
20
|
};
|
|
22
21
|
/** Options for {@link JSONGenerativeUI.present}. */
|
|
23
22
|
export type PresentToolOptions = {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Set `"standalone"` to render the component on its own surface (outside the
|
|
25
|
+
* chain-of-thought trace), e.g. a full-bleed artifact like a card. Omit it for
|
|
26
|
+
* the default inline rendering — there is no `"inline"` value because that is
|
|
27
|
+
* already the default.
|
|
28
|
+
*/
|
|
29
|
+
display?: "standalone";
|
|
31
30
|
};
|
|
32
31
|
type BackendDefaultMetadata = {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
unstable_backendDefault?: {
|
|
33
|
+
parameters?: boolean;
|
|
34
|
+
};
|
|
36
35
|
};
|
|
37
36
|
/** The `present` tool, as the model sees it (no client `render`/`execute`). */
|
|
38
37
|
export type PresentTool = ToolDefinition<Record<string, unknown>, Record<string, never>> & BackendDefaultMetadata;
|
|
@@ -46,19 +45,19 @@ export type PresentParameters = JSONSchema7;
|
|
|
46
45
|
* Takes the already-built `parameters` so it isn't recomputed per tool.
|
|
47
46
|
*/
|
|
48
47
|
export declare function presentToolBase(parameters: PresentParameters, options?: PresentToolOptions): {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
display?: "standalone";
|
|
49
|
+
type: "frontend";
|
|
50
|
+
description: string;
|
|
51
|
+
parameters: JSONSchema7;
|
|
53
52
|
};
|
|
54
53
|
/**
|
|
55
54
|
* The schema-only half of the `prompt_user` tool, shared by both builds. The
|
|
56
55
|
* server build returns exactly this; the client build adds `render`.
|
|
57
56
|
*/
|
|
58
57
|
export declare function promptUserToolBase(parameters: PresentParameters): {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
type: "human";
|
|
59
|
+
description: string;
|
|
60
|
+
parameters: JSONSchema7;
|
|
62
61
|
};
|
|
63
|
-
|
|
62
|
+
export {};
|
|
64
63
|
//# sourceMappingURL=JSONGenerativeUI.shared.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSONGenerativeUI.shared.d.ts","
|
|
1
|
+
{"version":3,"file":"JSONGenerativeUI.shared.d.ts","sourceRoot":"","sources":["../src/JSONGenerativeUI.shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,4BAAyB;AACvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAgB;AAEnD,4CAA4C;AAC5C,MAAM,MAAM,uBAAuB,GAAG;IACpC;;;;OAIG;IACH,OAAO,EAAE,mBAAmB,CAAC;IAC7B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B,CAAC;AAEF,oDAAoD;AACpD,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB,CAAC;AAEF,KAAK,sBAAsB,GAAG;IAC5B,uBAAuB,CAAC,EAAE;QACxB,UAAU,CAAC,EAAE,OAAO,CAAC;KACtB,CAAC;CACH,CAAC;AAEF,+EAA+E;AAC/E,MAAM,MAAM,WAAW,GAAG,cAAc,CACtC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvB,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CACtB,GACC,sBAAsB,CAAC;AAEzB,yEAAyE;AACzE,MAAM,MAAM,cAAc,GAAG,cAAc,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,GAC3E,sBAAsB,CAAC;AAWzB,4FAA4F;AAC5F,MAAM,MAAM,iBAAiB,GAAG,WAAW,CAAC;AAE5C;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,iBAAiB,EAC7B,OAAO,CAAC,EAAE,kBAAkB;;;;;EAQ7B;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,iBAAiB;;;;EAM/D"}
|
package/dist/a2ui/convert.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { UIElement } from "../ir.js";
|
|
2
|
-
import { A2uiSurfaceState } from "./types.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { type UIElement } from "../ir.js";
|
|
2
|
+
import { type A2uiSurfaceState } from "./types.js";
|
|
3
|
+
export declare function convertSurfaceToUISpec(surface: A2uiSurfaceState, options?: {
|
|
4
|
+
readonly keepUnknownComponents?: boolean;
|
|
5
|
+
}): {
|
|
6
|
+
spec: UIElement | null;
|
|
7
|
+
warnings: string[];
|
|
7
8
|
};
|
|
8
|
-
//#endregion
|
|
9
9
|
//# sourceMappingURL=convert.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convert.d.ts","
|
|
1
|
+
{"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../../src/a2ui/convert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,SAAS,EAAE,iBAAc;AACnD,OAAO,EAEL,KAAK,gBAAgB,EAEtB,mBAAgB;AAynBjB,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE;IAAE,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAAO,GACzD;IACD,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CA+BA"}
|
package/dist/a2ui/convert.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ICON_NAMES } from "../ir.js";
|
|
1
2
|
import { A2UI_SURFACE_ID } from "./types.js";
|
|
2
3
|
//#region src/a2ui/convert.ts
|
|
3
4
|
const DEPTH_CAP = 32;
|
|
@@ -6,13 +7,23 @@ const NODE_BUDGET = 5e3;
|
|
|
6
7
|
const SUPPORTED_COMPONENTS = /* @__PURE__ */ new Set([
|
|
7
8
|
"Text",
|
|
8
9
|
"Image",
|
|
10
|
+
"Icon",
|
|
9
11
|
"Row",
|
|
10
12
|
"Column",
|
|
13
|
+
"List",
|
|
11
14
|
"Card",
|
|
12
15
|
"Divider",
|
|
13
16
|
"Button",
|
|
14
17
|
"TextField",
|
|
15
|
-
"CheckBox"
|
|
18
|
+
"CheckBox",
|
|
19
|
+
"ChoicePicker",
|
|
20
|
+
"DateTimeInput"
|
|
21
|
+
]);
|
|
22
|
+
const ICON_NAME_SET = new Set(ICON_NAMES);
|
|
23
|
+
const ICON_SIZE_SET = /* @__PURE__ */ new Set([
|
|
24
|
+
"sm",
|
|
25
|
+
"md",
|
|
26
|
+
"lg"
|
|
16
27
|
]);
|
|
17
28
|
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
18
29
|
const isPlainObject = (value) => {
|
|
@@ -86,11 +97,17 @@ const reserveNode = (context) => {
|
|
|
86
97
|
context.emittedNodes++;
|
|
87
98
|
return true;
|
|
88
99
|
};
|
|
89
|
-
const
|
|
100
|
+
const childReferences = (node) => {
|
|
90
101
|
const children = node["children"];
|
|
91
|
-
|
|
102
|
+
const references = Array.isArray(children) ? [...children] : [];
|
|
103
|
+
if (node["child"] !== void 0) references.push(node["child"]);
|
|
104
|
+
if (node["component"] === "Modal") references.push(node["trigger"], node["content"]);
|
|
105
|
+
if (node["component"] === "Tabs" && Array.isArray(node["tabs"])) for (const tab of node["tabs"]) references.push(isRecord(tab) ? tab["child"] : void 0);
|
|
106
|
+
return references;
|
|
107
|
+
};
|
|
108
|
+
const childrenOf = (node, dataSource, context, depth, visited) => {
|
|
92
109
|
const result = [];
|
|
93
|
-
for (const childId of
|
|
110
|
+
for (const childId of childReferences(node)) {
|
|
94
111
|
if (typeof childId !== "string") {
|
|
95
112
|
context.warnings.push(`Component "${String(node["id"] ?? "")}" has a malformed child reference.`);
|
|
96
113
|
continue;
|
|
@@ -100,21 +117,38 @@ const childrenOf = (node, dataSource, context, depth, visited) => {
|
|
|
100
117
|
}
|
|
101
118
|
return result;
|
|
102
119
|
};
|
|
103
|
-
const
|
|
120
|
+
const textLabel = (node, children, context) => {
|
|
121
|
+
const references = childReferences(node);
|
|
122
|
+
const [reference] = references;
|
|
123
|
+
const [child] = children;
|
|
124
|
+
if (references.length !== 1 || children.length !== 1 || typeof reference !== "string" || !child || context.surface.components.get(reference)?.["component"] !== "Text") return;
|
|
125
|
+
const text = child.$type === "Header" ? child["text"] : child["value"];
|
|
126
|
+
return typeof text === "string" ? text : void 0;
|
|
127
|
+
};
|
|
128
|
+
const mappedAction = (node, props, context) => {
|
|
104
129
|
const action = props["action"];
|
|
105
|
-
const
|
|
130
|
+
const event = isRecord(action) && isRecord(action["event"]) ? action["event"] : action;
|
|
131
|
+
const actionName = typeof event === "string" ? event : isRecord(event) && typeof event["name"] === "string" ? event["name"] : void 0;
|
|
106
132
|
if (!actionName) return void 0;
|
|
107
|
-
const
|
|
108
|
-
const resolvedContext = rawContext === void 0 ? void 0 : materialize(rawContext, dataSource);
|
|
133
|
+
const actionContext = isRecord(event) ? event["context"] : void 0;
|
|
109
134
|
return {
|
|
110
135
|
type: "a2ui:action",
|
|
111
136
|
name: actionName,
|
|
112
137
|
surfaceId: context.surfaceId,
|
|
113
138
|
sourceComponentId: typeof node["id"] === "string" ? node["id"] : "",
|
|
114
|
-
...
|
|
139
|
+
...actionContext !== void 0 ? { context: actionContext } : {}
|
|
115
140
|
};
|
|
116
141
|
};
|
|
117
|
-
const
|
|
142
|
+
const choiceOptions = (value) => {
|
|
143
|
+
if (!Array.isArray(value)) return [];
|
|
144
|
+
const options = [];
|
|
145
|
+
for (const option of value) if (isRecord(option) && typeof option["label"] === "string" && typeof option["value"] === "string") options.push({
|
|
146
|
+
label: option["label"],
|
|
147
|
+
value: option["value"]
|
|
148
|
+
});
|
|
149
|
+
return options;
|
|
150
|
+
};
|
|
151
|
+
const mappedProps = (node, props, context) => {
|
|
118
152
|
const component = node["component"];
|
|
119
153
|
if (component === "Text") {
|
|
120
154
|
const text = stringProp(props, ["text", "value"]);
|
|
@@ -134,7 +168,11 @@ const mappedProps = (node, props, dataSource, context) => {
|
|
|
134
168
|
}
|
|
135
169
|
if (component === "Image") {
|
|
136
170
|
const src = stringProp(props, ["src", "url"]);
|
|
137
|
-
const alt = stringProp(props, [
|
|
171
|
+
const alt = stringProp(props, [
|
|
172
|
+
"alt",
|
|
173
|
+
"altText",
|
|
174
|
+
"description"
|
|
175
|
+
]);
|
|
138
176
|
const size = props["size"];
|
|
139
177
|
const round = props["round"];
|
|
140
178
|
return {
|
|
@@ -145,6 +183,16 @@ const mappedProps = (node, props, dataSource, context) => {
|
|
|
145
183
|
...typeof round === "boolean" ? { round } : {}
|
|
146
184
|
};
|
|
147
185
|
}
|
|
186
|
+
if (component === "Icon") {
|
|
187
|
+
const name = stringProp(props, ["name"]);
|
|
188
|
+
if (!name || !ICON_NAME_SET.has(name)) return void 0;
|
|
189
|
+
const size = props["size"];
|
|
190
|
+
return {
|
|
191
|
+
$type: "Icon",
|
|
192
|
+
name,
|
|
193
|
+
...typeof size === "string" && ICON_SIZE_SET.has(size) ? { size } : {}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
148
196
|
if (component === "Row") {
|
|
149
197
|
const gap = props["gap"];
|
|
150
198
|
const align = firstDefined(props, ["align", "alignment"]);
|
|
@@ -165,6 +213,15 @@ const mappedProps = (node, props, dataSource, context) => {
|
|
|
165
213
|
...typeof align === "string" ? { align } : {}
|
|
166
214
|
};
|
|
167
215
|
}
|
|
216
|
+
if (component === "List") {
|
|
217
|
+
const direction = props["direction"];
|
|
218
|
+
const align = props["align"];
|
|
219
|
+
if (direction === "horizontal") return {
|
|
220
|
+
$type: "Row",
|
|
221
|
+
...typeof align === "string" ? { align } : {}
|
|
222
|
+
};
|
|
223
|
+
return { $type: "ListView" };
|
|
224
|
+
}
|
|
168
225
|
if (component === "Card") {
|
|
169
226
|
const title = props["title"];
|
|
170
227
|
const padding = props["padding"];
|
|
@@ -185,7 +242,7 @@ const mappedProps = (node, props, dataSource, context) => {
|
|
|
185
242
|
const buttonStyle = props["buttonStyle"];
|
|
186
243
|
const block = props["block"];
|
|
187
244
|
const submit = props["submit"];
|
|
188
|
-
const action = mappedAction(node, props,
|
|
245
|
+
const action = mappedAction(node, props, context);
|
|
189
246
|
return {
|
|
190
247
|
$type: "Button",
|
|
191
248
|
...label !== void 0 ? { label } : {},
|
|
@@ -222,14 +279,49 @@ const mappedProps = (node, props, dataSource, context) => {
|
|
|
222
279
|
...typeof defaultChecked === "boolean" ? { defaultChecked } : {}
|
|
223
280
|
};
|
|
224
281
|
}
|
|
282
|
+
if (component === "ChoicePicker") {
|
|
283
|
+
const options = choiceOptions(props["options"]);
|
|
284
|
+
const value = props["value"];
|
|
285
|
+
const defaultValue = typeof value === "string" ? value : Array.isArray(value) && typeof value[0] === "string" ? value[0] : void 0;
|
|
286
|
+
if (props["variant"] === "radio" || props["variant"] === "single" || props["variant"] === "singleSelection" || props["displayStyle"] === "radio" || props["variant"] === "mutuallyExclusive" && props["displayStyle"] !== "chips") return {
|
|
287
|
+
$type: "RadioGroup",
|
|
288
|
+
options,
|
|
289
|
+
...label !== void 0 ? { label } : {},
|
|
290
|
+
...name !== void 0 ? { name } : {},
|
|
291
|
+
...defaultValue !== void 0 ? { defaultValue } : {}
|
|
292
|
+
};
|
|
293
|
+
const placeholder = stringProp(props, ["placeholder"]);
|
|
294
|
+
return {
|
|
295
|
+
$type: "Select",
|
|
296
|
+
options,
|
|
297
|
+
...placeholder !== void 0 ? { placeholder } : {},
|
|
298
|
+
...label !== void 0 ? { label } : {},
|
|
299
|
+
...name !== void 0 ? { name } : {}
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
if (component === "DateTimeInput") {
|
|
303
|
+
const value = stringProp(props, ["value"]);
|
|
304
|
+
const min = stringProp(props, ["min"]);
|
|
305
|
+
const max = stringProp(props, ["max"]);
|
|
306
|
+
return {
|
|
307
|
+
$type: "DatePicker",
|
|
308
|
+
...value !== void 0 ? { value } : {},
|
|
309
|
+
...min !== void 0 ? { min } : {},
|
|
310
|
+
...max !== void 0 ? { max } : {},
|
|
311
|
+
...label !== void 0 ? { label } : {},
|
|
312
|
+
...name !== void 0 ? { name } : {}
|
|
313
|
+
};
|
|
314
|
+
}
|
|
225
315
|
};
|
|
226
|
-
const convertTemplate = (node, templateChildren, dataSource, context, depth, visited) => {
|
|
316
|
+
const convertTemplate = (node, templateChildren, dataSource, context, depth, visited, retained, mappedContainer) => {
|
|
227
317
|
if (!reserveNode(context)) return null;
|
|
318
|
+
const horizontalList = node["component"] === "List" && materialize(node["direction"], dataSource) === "horizontal";
|
|
319
|
+
const container = mappedContainer ?? retained ?? { $type: horizontalList ? "Row" : "ListView" };
|
|
228
320
|
const list = resolvePointer(dataSource, templateChildren.template.path);
|
|
229
321
|
if (!Array.isArray(list)) {
|
|
230
322
|
context.warnings.push(`Template on component "${String(node["id"] ?? "")}" did not resolve to a list.`);
|
|
231
323
|
return {
|
|
232
|
-
|
|
324
|
+
...container,
|
|
233
325
|
children: []
|
|
234
326
|
};
|
|
235
327
|
}
|
|
@@ -240,15 +332,17 @@ const convertTemplate = (node, templateChildren, dataSource, context, depth, vis
|
|
|
240
332
|
}
|
|
241
333
|
const children = [];
|
|
242
334
|
for (let index = 0; index < itemCount; index++) {
|
|
243
|
-
if (!reserveNode(context)) break;
|
|
335
|
+
if (!retained && !horizontalList && !reserveNode(context)) break;
|
|
244
336
|
const child = convertComponent(templateChildren.template.componentId, list[index], context, depth + 1, visited);
|
|
245
|
-
|
|
337
|
+
if (retained || horizontalList) {
|
|
338
|
+
if (child) children.push(child);
|
|
339
|
+
} else children.push({
|
|
246
340
|
$type: "ListViewItem",
|
|
247
341
|
...child ? { children: child } : {}
|
|
248
342
|
});
|
|
249
343
|
}
|
|
250
344
|
return {
|
|
251
|
-
|
|
345
|
+
...container,
|
|
252
346
|
children
|
|
253
347
|
};
|
|
254
348
|
};
|
|
@@ -272,31 +366,56 @@ function convertComponent(componentId, dataSource, context, depth, visited) {
|
|
|
272
366
|
const component = node["component"];
|
|
273
367
|
visited.add(componentId);
|
|
274
368
|
try {
|
|
275
|
-
|
|
276
|
-
if (isTemplateChildren(templateChildren)) return convertTemplate(node, templateChildren, dataSource, context, depth, visited);
|
|
277
|
-
if (typeof component !== "string" || !SUPPORTED_COMPONENTS.has(component)) {
|
|
369
|
+
if (typeof component !== "string") {
|
|
278
370
|
context.warnings.push(`Unknown A2UI component "${String(component ?? "")}" was skipped.`);
|
|
279
371
|
return null;
|
|
280
372
|
}
|
|
281
|
-
|
|
373
|
+
const templateChildren = node["children"];
|
|
374
|
+
const hasTemplate = isTemplateChildren(templateChildren);
|
|
375
|
+
if (!SUPPORTED_COMPONENTS.has(component) && !context.keepUnknownComponents && !hasTemplate) {
|
|
376
|
+
context.warnings.push(`Unknown A2UI component "${component}" was skipped.`);
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
282
379
|
const props = {};
|
|
283
380
|
for (const [key, value] of Object.entries(node)) {
|
|
284
|
-
if (key === "id" || key === "component" || key === "children") continue;
|
|
381
|
+
if (key === "id" || key === "component" || key === "children" || key === "child") continue;
|
|
285
382
|
const resolved = materialize(value, dataSource);
|
|
286
383
|
if (resolved !== void 0) setOwnProperty(props, key, resolved);
|
|
287
384
|
}
|
|
288
|
-
const mapped = mappedProps(node, props,
|
|
289
|
-
if (!mapped)
|
|
385
|
+
const mapped = mappedProps(node, props, context);
|
|
386
|
+
if (!mapped && SUPPORTED_COMPONENTS.has(component)) {
|
|
387
|
+
context.warnings.push(`A2UI component "${component}" could not be mapped and was skipped.`);
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
const retained = !mapped && context.keepUnknownComponents ? {
|
|
391
|
+
$type: component,
|
|
392
|
+
...Object.fromEntries(Object.entries(props).filter(([key]) => !key.startsWith("$")))
|
|
393
|
+
} : void 0;
|
|
394
|
+
if (hasTemplate) return convertTemplate(node, templateChildren, dataSource, context, depth, visited, retained, component === "List" ? mapped : void 0);
|
|
395
|
+
if (!reserveNode(context)) return null;
|
|
396
|
+
const converted = mapped ?? retained;
|
|
397
|
+
if (!converted) return null;
|
|
290
398
|
const children = childrenOf(node, dataSource, context, depth, visited);
|
|
399
|
+
if (mapped?.$type === "Button" && mapped["label"] === void 0) {
|
|
400
|
+
const label = textLabel(node, children, context);
|
|
401
|
+
if (label !== void 0) return {
|
|
402
|
+
...mapped,
|
|
403
|
+
label
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
const listChildren = component === "List" && mapped?.$type === "ListView" ? children.map((child) => ({
|
|
407
|
+
$type: "ListViewItem",
|
|
408
|
+
children: child
|
|
409
|
+
})) : children;
|
|
291
410
|
return {
|
|
292
|
-
...
|
|
293
|
-
...
|
|
411
|
+
...converted,
|
|
412
|
+
...listChildren.length > 0 ? { children: listChildren } : {}
|
|
294
413
|
};
|
|
295
414
|
} finally {
|
|
296
415
|
visited.delete(componentId);
|
|
297
416
|
}
|
|
298
417
|
}
|
|
299
|
-
function convertSurfaceToUISpec(surface) {
|
|
418
|
+
function convertSurfaceToUISpec(surface, options = {}) {
|
|
300
419
|
const warnings = [];
|
|
301
420
|
if (!surface.components.has("root")) return {
|
|
302
421
|
spec: null,
|
|
@@ -309,7 +428,8 @@ function convertSurfaceToUISpec(surface) {
|
|
|
309
428
|
emittedNodes: 0,
|
|
310
429
|
depthWarned: false,
|
|
311
430
|
budgetWarned: false,
|
|
312
|
-
templateCapWarned: false
|
|
431
|
+
templateCapWarned: false,
|
|
432
|
+
keepUnknownComponents: options.keepUnknownComponents === true
|
|
313
433
|
};
|
|
314
434
|
try {
|
|
315
435
|
return {
|