@assistant-ui/react-generative-ui 0.0.6 → 0.0.7
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 +4 -1
- package/dist/JSONGenerativeUI.client.d.ts.map +1 -1
- package/dist/JSONGenerativeUI.client.js +9 -2
- package/dist/JSONGenerativeUI.client.js.map +1 -1
- package/dist/JSONGenerativeUI.shared.d.ts +8 -0
- package/dist/JSONGenerativeUI.shared.d.ts.map +1 -1
- package/dist/JSONGenerativeUI.shared.js.map +1 -1
- package/dist/actionRegistry.d.ts +41 -0
- package/dist/actionRegistry.d.ts.map +1 -0
- package/dist/actionRegistry.js +41 -0
- package/dist/actionRegistry.js.map +1 -0
- package/dist/buildPresentParameters.js +10 -1
- package/dist/buildPresentParameters.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.js +5 -2
- package/dist/index.server.d.ts +12 -0
- package/dist/index.server.js +10 -0
- package/dist/index.shared.d.ts +11 -0
- package/dist/index.shared.js +9 -0
- package/dist/ir.d.ts +115 -0
- package/dist/ir.d.ts.map +1 -0
- package/dist/ir.js +149 -0
- package/dist/ir.js.map +1 -0
- package/dist/renderGenerativeUI.d.ts +5 -4
- package/dist/renderGenerativeUI.d.ts.map +1 -1
- package/dist/renderGenerativeUI.js +18 -45
- package/dist/renderGenerativeUI.js.map +1 -1
- package/dist/types.d.ts +34 -30
- package/dist/types.d.ts.map +1 -1
- package/dist/vocabulary/alert.d.ts +34 -0
- package/dist/vocabulary/alert.d.ts.map +1 -0
- package/dist/vocabulary/alert.js +49 -0
- package/dist/vocabulary/alert.js.map +1 -0
- package/dist/vocabulary/data.d.ts +53 -0
- package/dist/vocabulary/data.d.ts.map +1 -0
- package/dist/vocabulary/data.js +63 -0
- package/dist/vocabulary/data.js.map +1 -0
- package/dist/vocabulary/fact.d.ts +20 -0
- package/dist/vocabulary/fact.d.ts.map +1 -0
- package/dist/vocabulary/fact.js +24 -0
- package/dist/vocabulary/fact.js.map +1 -0
- package/dist/vocabulary/index.d.ts +16 -0
- package/dist/vocabulary/index.d.ts.map +1 -0
- package/dist/vocabulary/index.js +30 -0
- package/dist/vocabulary/index.js.map +1 -0
- package/dist/vocabulary/interactive.d.ts +81 -0
- package/dist/vocabulary/interactive.d.ts.map +1 -0
- package/dist/vocabulary/interactive.js +123 -0
- package/dist/vocabulary/interactive.js.map +1 -0
- package/dist/vocabulary/layout.d.ts +78 -0
- package/dist/vocabulary/layout.d.ts.map +1 -0
- package/dist/vocabulary/layout.js +72 -0
- package/dist/vocabulary/layout.js.map +1 -0
- package/dist/vocabulary/media.d.ts +34 -0
- package/dist/vocabulary/media.d.ts.map +1 -0
- package/dist/vocabulary/media.js +32 -0
- package/dist/vocabulary/media.js.map +1 -0
- package/dist/vocabulary/text.d.ts +74 -0
- package/dist/vocabulary/text.d.ts.map +1 -0
- package/dist/vocabulary/text.js +48 -0
- package/dist/vocabulary/text.js.map +1 -0
- package/package.json +12 -12
- package/src/JSONGenerativeUI.client.tsx +10 -2
- package/src/JSONGenerativeUI.shared.ts +8 -0
- package/src/actionRegistry.test.ts +90 -0
- package/src/actionRegistry.ts +96 -0
- package/src/buildPresentParameters.ts +23 -7
- package/src/index.server.ts +2 -0
- package/src/index.shared.ts +58 -0
- package/src/index.ts +2 -26
- package/src/ir.test.ts +203 -0
- package/src/ir.ts +253 -0
- package/src/renderGenerativeUI.test.tsx +53 -0
- package/src/renderGenerativeUI.tsx +49 -82
- package/src/types.ts +57 -42
- package/src/vocabulary/alert.test.tsx +66 -0
- package/src/vocabulary/alert.tsx +47 -0
- package/src/vocabulary/data.test.tsx +67 -0
- package/src/vocabulary/data.tsx +86 -0
- package/src/vocabulary/fact.test.tsx +15 -0
- package/src/vocabulary/fact.tsx +22 -0
- package/src/vocabulary/index.test.ts +56 -0
- package/src/vocabulary/index.ts +27 -0
- package/src/vocabulary/interactive.dispatch.test.tsx +110 -0
- package/src/vocabulary/interactive.test.tsx +108 -0
- package/src/vocabulary/interactive.tsx +165 -0
- package/src/vocabulary/layout.test.tsx +61 -0
- package/src/vocabulary/layout.tsx +76 -0
- package/src/vocabulary/media.test.tsx +53 -0
- package/src/vocabulary/media.tsx +37 -0
- package/src/vocabulary/text.test.tsx +73 -0
- package/src/vocabulary/text.tsx +59 -0
|
@@ -8,11 +8,14 @@ import { JSONGenerativeUIOptions, PresentTool, PresentToolOptions, PromptUserToo
|
|
|
8
8
|
* `present` is a frontend tool that renders the model's `{ $type, ...props }`
|
|
9
9
|
* tree against the library and resolves immediately. `prompt_user` is a
|
|
10
10
|
* human-in-the-loop tool: the model pauses and the rendered UI supplies the
|
|
11
|
-
* result. Both draw the tree the same way, so they share one `render`.
|
|
11
|
+
* result. Both draw the tree the same way, so they share one `render`. The
|
|
12
|
+
* `actions` registry (if provided) is threaded into the render context so
|
|
13
|
+
* interactive components can fire `$action` through `$dispatch`.
|
|
12
14
|
*/
|
|
13
15
|
declare class JSONGenerativeUI {
|
|
14
16
|
private readonly library;
|
|
15
17
|
private readonly parameters;
|
|
18
|
+
private readonly actions;
|
|
16
19
|
constructor(options: JSONGenerativeUIOptions);
|
|
17
20
|
private readonly render;
|
|
18
21
|
present(options?: PresentToolOptions): PresentTool;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSONGenerativeUI.client.d.ts","names":[],"sources":["../src/JSONGenerativeUI.client.tsx"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"JSONGenerativeUI.client.d.ts","names":[],"sources":["../src/JSONGenerativeUI.client.tsx"],"mappings":";;;;;AAkCA;;;;;;;;;cAAa,gBAAA;EAAA,iBACM,OAAA;EAAA,iBACA,UAAA;EAAA,iBACA,OAAA;cAEL,OAAA,EAAS,uBAAA;EAAA,iBAMJ,MAAA;EAYjB,OAAA,CAAQ,OAAA,GAAU,kBAAA,GAAqB,WAAA;EASvC,UAAA,IAAc,cAAA;AAAA"}
|
|
@@ -16,16 +16,23 @@ function uiStatus(status) {
|
|
|
16
16
|
* `present` is a frontend tool that renders the model's `{ $type, ...props }`
|
|
17
17
|
* tree against the library and resolves immediately. `prompt_user` is a
|
|
18
18
|
* human-in-the-loop tool: the model pauses and the rendered UI supplies the
|
|
19
|
-
* result. Both draw the tree the same way, so they share one `render`.
|
|
19
|
+
* result. Both draw the tree the same way, so they share one `render`. The
|
|
20
|
+
* `actions` registry (if provided) is threaded into the render context so
|
|
21
|
+
* interactive components can fire `$action` through `$dispatch`.
|
|
20
22
|
*/
|
|
21
23
|
var JSONGenerativeUI = class {
|
|
22
24
|
library;
|
|
23
25
|
parameters;
|
|
26
|
+
actions;
|
|
24
27
|
constructor(options) {
|
|
25
28
|
this.library = options.library;
|
|
26
29
|
this.parameters = buildPresentParameters(options.library);
|
|
30
|
+
this.actions = options.actions;
|
|
27
31
|
}
|
|
28
|
-
render = ({ args, status }) => renderGenerativeUI(args, this.library, {
|
|
32
|
+
render = ({ args, status }) => renderGenerativeUI(args, this.library, {
|
|
33
|
+
status: uiStatus(status),
|
|
34
|
+
...this.actions ? { dispatch: this.actions.dispatch } : {}
|
|
35
|
+
});
|
|
29
36
|
present(options) {
|
|
30
37
|
return {
|
|
31
38
|
...presentToolBase(this.parameters, options),
|
|
@@ -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 { 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`.\n */\nexport class JSONGenerativeUI {\n private readonly library: GenerativeUILibrary;\n private readonly parameters: PresentParameters;\n\n constructor(options: JSONGenerativeUIOptions) {\n this.library = options.library;\n this.parameters = buildPresentParameters(options.library);\n }\n\n private readonly render = ({\n args,\n status,\n }: {\n args: unknown;\n status: { type: string };\n }): ReactNode =>\n renderGenerativeUI(args, this.library, {
|
|
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 private readonly render = ({\n args,\n status,\n }: {\n args: unknown;\n status: { type: string };\n }): ReactNode =>\n renderGenerativeUI(args, this.library, {\n status: uiStatus(status),\n ...(this.actions ? { dispatch: this.actions.dispatch } : {}),\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: this.render,\n };\n }\n}\n"],"mappings":";;;;;;;;AAmBA,SAAS,SAAS,QAA8C;CAC9D,OAAO,OAAO,SAAS,aAAa,SAAS;AAC/C;;;;;;;;;;;;AAaA,IAAa,mBAAb,MAA8B;CAC5B;CACA;CACA;CAEA,YAAY,SAAkC;EAC5C,KAAK,UAAU,QAAQ;EACvB,KAAK,aAAa,uBAAuB,QAAQ,OAAO;EACxD,KAAK,UAAU,QAAQ;CACzB;CAEA,UAA2B,EACzB,MACA,aAKA,mBAAmB,MAAM,KAAK,SAAS;EACrC,QAAQ,SAAS,MAAM;EACvB,GAAI,KAAK,UAAU,EAAE,UAAU,KAAK,QAAQ,SAAS,IAAI,CAAC;CAC5D,CAAC;CAEH,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,QAAQ,KAAK;EACf;CACF;AACF"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { JSONSchema7 } from "./node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.js";
|
|
2
|
+
import { ActionRegistry } from "./actionRegistry.js";
|
|
2
3
|
import { GenerativeUILibrary } from "./types.js";
|
|
3
4
|
import { ToolDefinition } from "@assistant-ui/react";
|
|
4
5
|
|
|
@@ -11,6 +12,13 @@ type JSONGenerativeUIOptions = {
|
|
|
11
12
|
* `"use generative"` build can split each `render` from its `properties`.
|
|
12
13
|
*/
|
|
13
14
|
library: GenerativeUILibrary;
|
|
15
|
+
/**
|
|
16
|
+
* Host-provided map from `$action.type` to its handler. Interactive
|
|
17
|
+
* components (`Button`/`Select`/`Input`/`DatePicker`) call `$dispatch($action)`
|
|
18
|
+
* on their event, which resolves through this registry. Omit it for a
|
|
19
|
+
* read-only render where model-emitted actions degrade to a no-op.
|
|
20
|
+
*/
|
|
21
|
+
actions?: ActionRegistry;
|
|
14
22
|
};
|
|
15
23
|
/** Options for {@link JSONGenerativeUI.present}. */
|
|
16
24
|
type PresentToolOptions = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSONGenerativeUI.shared.d.ts","names":[],"sources":["../src/JSONGenerativeUI.shared.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"JSONGenerativeUI.shared.d.ts","names":[],"sources":["../src/JSONGenerativeUI.shared.ts"],"mappings":";;;;;;;KAMY,uBAAA;EAAA;;;;;EAMV,OAAA,EAAS,mBAAA;EAOT;;;AAAwB;AAI1B;;EAJE,OAAA,GAAU,cAAc;AAAA;AAWjB;AAAA,KAPG,kBAAA;EAUe;;;AAEb;AAKd;;EAVE,OAAO;AAAA;AAAA,KAGJ,sBAAA;EACH,uBAAA;IACE,UAAU;EAAA;AAAA;;KAKF,WAAA,GAAc,cAAA,CACxB,MAAA,mBACA,MAAA,mBAEA,sBAAA;;KAGU,cAAA,GAAiB,cAAA,CAAe,MAAA,8BAC1C,sBAAA;;KAYU,iBAAA,GAAoB,WAAW;AAb3C;;;;;AAAA,iBAoBgB,eAAA,CACd,UAAA,EAAY,iBAAA,EACZ,OAAA,GAAU,kBAAA;;;;;;;AArBY;AAYxB;;iBAuBgB,kBAAA,CAAmB,UAAA,EAAY,iBAAA;;;cAAA,WAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSONGenerativeUI.shared.js","names":[],"sources":["../src/JSONGenerativeUI.shared.ts"],"sourcesContent":["import type { ToolDefinition } from \"@assistant-ui/react\";\nimport type { JSONSchema7 } from \"json-schema\";\nimport type { GenerativeUILibrary } from \"./types\";\n\n/** Options for {@link JSONGenerativeUI}. */\nexport type JSONGenerativeUIOptions = {\n /**\n * The components the model is allowed to render, keyed by the `$type` it\n * selects them with. Author it with `defineGenerativeComponents({ ... })` so a\n * `\"use generative\"` build can split each `render` from its `properties`.\n */\n library: GenerativeUILibrary;\n};\n\n/** Options for {@link JSONGenerativeUI.present}. */\nexport type PresentToolOptions = {\n /**\n * Set `\"standalone\"` to render the component on its own surface (outside the\n * chain-of-thought trace), e.g. a full-bleed artifact like a card. Omit it for\n * the default inline rendering — there is no `\"inline\"` value because that is\n * already the default.\n */\n display?: \"standalone\";\n};\n\ntype BackendDefaultMetadata = {\n unstable_backendDefault?: {\n parameters?: boolean;\n };\n};\n\n/** The `present` tool, as the model sees it (no client `render`/`execute`). */\nexport type PresentTool = ToolDefinition<\n Record<string, unknown>,\n Record<string, never>\n> &\n BackendDefaultMetadata;\n\n/** The `prompt_user` tool, as the model sees it (no client `render`). */\nexport type PromptUserTool = ToolDefinition<Record<string, unknown>, unknown> &\n BackendDefaultMetadata;\n\nconst PRESENT_DESCRIPTION =\n \"Present a UI component to the user. Select a component with `$type` and \" +\n \"provide its props inline; nest components with `children`.\";\n\nconst PROMPT_USER_DESCRIPTION =\n \"Present a UI component to the user and wait for their response. Select a \" +\n \"component with `$type` and provide its props inline; nest components with \" +\n \"`children`. The user interacts with it and the result is returned to you.\";\n\n/** The tool `parameters` schema, built once per instance (see `buildPresentParameters`). */\nexport type PresentParameters = JSONSchema7;\n\n/**\n * The schema-only half of the `present` tool, shared by both builds. The server\n * build returns exactly this; the client build adds `execute` and `render`.\n * Takes the already-built `parameters` so it isn't recomputed per tool.\n */\nexport function presentToolBase(\n parameters: PresentParameters,\n options?: PresentToolOptions,\n) {\n return {\n type: \"frontend\" as const,\n description: PRESENT_DESCRIPTION,\n parameters,\n ...(options?.display !== undefined ? { display: options.display } : {}),\n };\n}\n\n/**\n * The schema-only half of the `prompt_user` tool, shared by both builds. The\n * server build returns exactly this; the client build adds `render`.\n */\nexport function promptUserToolBase(parameters: PresentParameters) {\n return {\n type: \"human\" as const,\n description: PROMPT_USER_DESCRIPTION,\n parameters,\n };\n}\n"],"mappings":";
|
|
1
|
+
{"version":3,"file":"JSONGenerativeUI.shared.js","names":[],"sources":["../src/JSONGenerativeUI.shared.ts"],"sourcesContent":["import type { ToolDefinition } from \"@assistant-ui/react\";\nimport type { JSONSchema7 } from \"json-schema\";\nimport type { ActionRegistry } from \"./actionRegistry\";\nimport type { GenerativeUILibrary } from \"./types\";\n\n/** Options for {@link JSONGenerativeUI}. */\nexport type JSONGenerativeUIOptions = {\n /**\n * The components the model is allowed to render, keyed by the `$type` it\n * selects them with. Author it with `defineGenerativeComponents({ ... })` so a\n * `\"use generative\"` build can split each `render` from its `properties`.\n */\n library: GenerativeUILibrary;\n /**\n * Host-provided map from `$action.type` to its handler. Interactive\n * components (`Button`/`Select`/`Input`/`DatePicker`) call `$dispatch($action)`\n * on their event, which resolves through this registry. Omit it for a\n * read-only render where model-emitted actions degrade to a no-op.\n */\n actions?: ActionRegistry;\n};\n\n/** Options for {@link JSONGenerativeUI.present}. */\nexport type PresentToolOptions = {\n /**\n * Set `\"standalone\"` to render the component on its own surface (outside the\n * chain-of-thought trace), e.g. a full-bleed artifact like a card. Omit it for\n * the default inline rendering — there is no `\"inline\"` value because that is\n * already the default.\n */\n display?: \"standalone\";\n};\n\ntype BackendDefaultMetadata = {\n unstable_backendDefault?: {\n parameters?: boolean;\n };\n};\n\n/** The `present` tool, as the model sees it (no client `render`/`execute`). */\nexport type PresentTool = ToolDefinition<\n Record<string, unknown>,\n Record<string, never>\n> &\n BackendDefaultMetadata;\n\n/** The `prompt_user` tool, as the model sees it (no client `render`). */\nexport type PromptUserTool = ToolDefinition<Record<string, unknown>, unknown> &\n BackendDefaultMetadata;\n\nconst PRESENT_DESCRIPTION =\n \"Present a UI component to the user. Select a component with `$type` and \" +\n \"provide its props inline; nest components with `children`.\";\n\nconst PROMPT_USER_DESCRIPTION =\n \"Present a UI component to the user and wait for their response. Select a \" +\n \"component with `$type` and provide its props inline; nest components with \" +\n \"`children`. The user interacts with it and the result is returned to you.\";\n\n/** The tool `parameters` schema, built once per instance (see `buildPresentParameters`). */\nexport type PresentParameters = JSONSchema7;\n\n/**\n * The schema-only half of the `present` tool, shared by both builds. The server\n * build returns exactly this; the client build adds `execute` and `render`.\n * Takes the already-built `parameters` so it isn't recomputed per tool.\n */\nexport function presentToolBase(\n parameters: PresentParameters,\n options?: PresentToolOptions,\n) {\n return {\n type: \"frontend\" as const,\n description: PRESENT_DESCRIPTION,\n parameters,\n ...(options?.display !== undefined ? { display: options.display } : {}),\n };\n}\n\n/**\n * The schema-only half of the `prompt_user` tool, shared by both builds. The\n * server build returns exactly this; the client build adds `render`.\n */\nexport function promptUserToolBase(parameters: PresentParameters) {\n return {\n type: \"human\" as const,\n description: PROMPT_USER_DESCRIPTION,\n parameters,\n };\n}\n"],"mappings":";AAkDA,MAAM,sBACJ;AAGF,MAAM,0BACJ;;;;;;AAYF,SAAgB,gBACd,YACA,SACA;CACA,OAAO;EACL,MAAM;EACN,aAAa;EACb;EACA,GAAI,SAAS,YAAY,KAAA,IAAY,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;CACvE;AACF;;;;;AAMA,SAAgB,mBAAmB,YAA+B;CAChE,OAAO;EACL,MAAM;EACN,aAAa;EACb;CACF;AACF"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Action } from "./ir.js";
|
|
2
|
+
|
|
3
|
+
//#region src/actionRegistry.d.ts
|
|
4
|
+
/** Context handed to an {@link ActionHandler} when an `$action` fires. */
|
|
5
|
+
type ActionDispatchContext = {
|
|
6
|
+
/**
|
|
7
|
+
* The action payload. For fire-and-forget actions this is the `$action` as
|
|
8
|
+
* the model emitted it. For interactive components (`Select`/`Input`/
|
|
9
|
+
* `DatePicker`) the user's runtime input is merged in under the reserved
|
|
10
|
+
* `$input` key, so the handler sees both the model payload and what the user
|
|
11
|
+
* did; a model-supplied `value` field is never clobbered.
|
|
12
|
+
*/
|
|
13
|
+
readonly payload: Action;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Resolves a single `$action.type`. Fire-and-forget actions return `void` or a
|
|
17
|
+
* promise that resolves to it; human-in-the-loop actions return a value the
|
|
18
|
+
* runtime uses to resume the run (see IR doc Open question #2 — the resume
|
|
19
|
+
* value is left as `unknown` and documented per-action). The return value is
|
|
20
|
+
* handed back to `dispatch`'s caller as `unknown`.
|
|
21
|
+
*/
|
|
22
|
+
type ActionHandler = (ctx: ActionDispatchContext) => unknown | Promise<unknown>;
|
|
23
|
+
/**
|
|
24
|
+
* The host-provided map from `$action.type` to {@link ActionHandler}. This is
|
|
25
|
+
* the single dispatch target for `$action` on web, shared by the model
|
|
26
|
+
* `present` renderer, the synthetic `present` produced from A2A/A2UI, and the
|
|
27
|
+
* decoded `block_actions` from Slack. Construct it with
|
|
28
|
+
* {@link createActionRegistry} and pass it to `JSONGenerativeUI`.
|
|
29
|
+
*/
|
|
30
|
+
type ActionRegistry = {
|
|
31
|
+
dispatch(action: Action): unknown;
|
|
32
|
+
has(type: string): boolean;
|
|
33
|
+
};
|
|
34
|
+
declare function createActionRegistry(handlers: Readonly<Record<string, ActionHandler>>): ActionRegistry;
|
|
35
|
+
/** A no-op registry used when no handlers are provided. Dispatch resolves to
|
|
36
|
+
* `undefined` and logs a warning in dev for unknown types, so a model-emitted
|
|
37
|
+
* action with no handler degrades to "does nothing" rather than throwing. */
|
|
38
|
+
declare const emptyActionRegistry: ActionRegistry;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { ActionDispatchContext, ActionHandler, ActionRegistry, createActionRegistry, emptyActionRegistry };
|
|
41
|
+
//# sourceMappingURL=actionRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actionRegistry.d.ts","names":[],"sources":["../src/actionRegistry.ts"],"mappings":";;;;KAGY,qBAAA;EAAA;;;;AAQc;AAU1B;;EAlBY,SAQD,OAAA,EAAS,MAAM;AAAA;;;;;AAYJ;AAStB;;KAXY,aAAA,IACV,GAAA,EAAK,qBAAA,eACQ,OAAO;;;;;;;;KASV,cAAA;EACV,QAAA,CAAS,MAAA,EAAQ,MAAM;EACvB,GAAA,CAAI,IAAA;AAAA;AAAA,iBAGU,oBAAA,CACd,QAAA,EAAU,QAAA,CAAS,MAAA,SAAe,aAAA,KACjC,cAAA;;;;cA0CU,mBAAA,EAAqB,cAAyC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region src/actionRegistry.ts
|
|
2
|
+
function createActionRegistry(handlers) {
|
|
3
|
+
const map = new Map(Object.entries(handlers));
|
|
4
|
+
return {
|
|
5
|
+
dispatch(action) {
|
|
6
|
+
if (typeof action?.type !== "string") {
|
|
7
|
+
if (process.env["NODE_ENV"] !== "production") console.warn(`[@assistant-ui/react-generative-ui] Skipping malformed action; \`\$action.type\` must be a string. Received ${formatReceivedType(action?.type)}. Update the emitted \`\$action\` payload.`);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
const handler = map.get(action.type);
|
|
11
|
+
if (!handler) {
|
|
12
|
+
if (process.env["NODE_ENV"] !== "production") {
|
|
13
|
+
const actionTypes = [...map.keys()];
|
|
14
|
+
console.warn(`[@assistant-ui/react-generative-ui] Action "${action.type}" has no registered handler. ${formatRegisteredActions(actionTypes)} Register it with createActionRegistry(...) or update the emitted \`\$action.type\`.`);
|
|
15
|
+
}
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
return handler({ payload: action });
|
|
19
|
+
},
|
|
20
|
+
has(type) {
|
|
21
|
+
return map.has(type);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** A no-op registry used when no handlers are provided. Dispatch resolves to
|
|
26
|
+
* `undefined` and logs a warning in dev for unknown types, so a model-emitted
|
|
27
|
+
* action with no handler degrades to "does nothing" rather than throwing. */
|
|
28
|
+
const emptyActionRegistry = createActionRegistry({});
|
|
29
|
+
function formatRegisteredActions(actionTypes) {
|
|
30
|
+
if (actionTypes.length === 0) return "No actions are registered.";
|
|
31
|
+
return `Registered actions: ${actionTypes.map((type) => `"${type}"`).join(", ")}.`;
|
|
32
|
+
}
|
|
33
|
+
function formatReceivedType(value) {
|
|
34
|
+
if (value === null) return "null";
|
|
35
|
+
if (Array.isArray(value)) return "array";
|
|
36
|
+
return typeof value;
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { createActionRegistry, emptyActionRegistry };
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=actionRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actionRegistry.js","names":[],"sources":["../src/actionRegistry.ts"],"sourcesContent":["import type { Action } from \"./ir\";\n\n/** Context handed to an {@link ActionHandler} when an `$action` fires. */\nexport type ActionDispatchContext = {\n /**\n * The action payload. For fire-and-forget actions this is the `$action` as\n * the model emitted it. For interactive components (`Select`/`Input`/\n * `DatePicker`) the user's runtime input is merged in under the reserved\n * `$input` key, so the handler sees both the model payload and what the user\n * did; a model-supplied `value` field is never clobbered.\n */\n readonly payload: Action;\n};\n\n/**\n * Resolves a single `$action.type`. Fire-and-forget actions return `void` or a\n * promise that resolves to it; human-in-the-loop actions return a value the\n * runtime uses to resume the run (see IR doc Open question #2 — the resume\n * value is left as `unknown` and documented per-action). The return value is\n * handed back to `dispatch`'s caller as `unknown`.\n */\nexport type ActionHandler = (\n ctx: ActionDispatchContext,\n) => unknown | Promise<unknown>;\n\n/**\n * The host-provided map from `$action.type` to {@link ActionHandler}. This is\n * the single dispatch target for `$action` on web, shared by the model\n * `present` renderer, the synthetic `present` produced from A2A/A2UI, and the\n * decoded `block_actions` from Slack. Construct it with\n * {@link createActionRegistry} and pass it to `JSONGenerativeUI`.\n */\nexport type ActionRegistry = {\n dispatch(action: Action): unknown;\n has(type: string): boolean;\n};\n\nexport function createActionRegistry(\n handlers: Readonly<Record<string, ActionHandler>>,\n): ActionRegistry {\n const map = new Map(Object.entries(handlers));\n return {\n dispatch(action) {\n if (typeof action?.type !== \"string\") {\n if (process.env[\"NODE_ENV\"] !== \"production\") {\n // eslint-disable-next-line no-console\n console.warn(\n \"[@assistant-ui/react-generative-ui] Skipping malformed action; \" +\n \"`$action.type` must be a string. \" +\n `Received ${formatReceivedType(action?.type)}. Update the emitted ` +\n \"`$action` payload.\",\n );\n }\n return undefined;\n }\n\n const handler = map.get(action.type);\n if (!handler) {\n if (process.env[\"NODE_ENV\"] !== \"production\") {\n const actionTypes = [...map.keys()];\n // eslint-disable-next-line no-console\n console.warn(\n `[@assistant-ui/react-generative-ui] Action \"${action.type}\" has ` +\n `no registered handler. ${formatRegisteredActions(actionTypes)} ` +\n \"Register it with createActionRegistry(...) or update the emitted \" +\n \"`$action.type`.\",\n );\n }\n return undefined;\n }\n return handler({ payload: action });\n },\n has(type) {\n return map.has(type);\n },\n };\n}\n\n/** A no-op registry used when no handlers are provided. Dispatch resolves to\n * `undefined` and logs a warning in dev for unknown types, so a model-emitted\n * action with no handler degrades to \"does nothing\" rather than throwing. */\nexport const emptyActionRegistry: ActionRegistry = createActionRegistry({});\n\nfunction formatRegisteredActions(actionTypes: string[]) {\n if (actionTypes.length === 0) return \"No actions are registered.\";\n\n return `Registered actions: ${actionTypes\n .map((type) => `\"${type}\"`)\n .join(\", \")}.`;\n}\n\nfunction formatReceivedType(value: unknown) {\n if (value === null) return \"null\";\n if (Array.isArray(value)) return \"array\";\n return typeof value;\n}\n"],"mappings":";AAqCA,SAAgB,qBACd,UACgB;CAChB,MAAM,MAAM,IAAI,IAAI,OAAO,QAAQ,QAAQ,CAAC;CAC5C,OAAO;EACL,SAAS,QAAQ;GACf,IAAI,OAAO,QAAQ,SAAS,UAAU;IACpC,IAAI,QAAQ,IAAI,gBAAgB,cAE9B,QAAQ,KACN,+GAEc,mBAAmB,QAAQ,IAAI,EAAE,2CAEjD;IAEF;GACF;GAEA,MAAM,UAAU,IAAI,IAAI,OAAO,IAAI;GACnC,IAAI,CAAC,SAAS;IACZ,IAAI,QAAQ,IAAI,gBAAgB,cAAc;KAC5C,MAAM,cAAc,CAAC,GAAG,IAAI,KAAK,CAAC;KAElC,QAAQ,KACN,+CAA+C,OAAO,KAAK,+BAC/B,wBAAwB,WAAW,EAAE,qFAGnE;IACF;IACA;GACF;GACA,OAAO,QAAQ,EAAE,SAAS,OAAO,CAAC;EACpC;EACA,IAAI,MAAM;GACR,OAAO,IAAI,IAAI,IAAI;EACrB;CACF;AACF;;;;AAKA,MAAa,sBAAsC,qBAAqB,CAAC,CAAC;AAE1E,SAAS,wBAAwB,aAAuB;CACtD,IAAI,YAAY,WAAW,GAAG,OAAO;CAErC,OAAO,uBAAuB,YAC3B,KAAK,SAAS,IAAI,KAAK,EAAE,CAAC,CAC1B,KAAK,IAAI,EAAE;AAChB;AAEA,SAAS,mBAAmB,OAAgB;CAC1C,IAAI,UAAU,MAAM,OAAO;CAC3B,IAAI,MAAM,QAAQ,KAAK,GAAG,OAAO;CACjC,OAAO,OAAO;AAChB"}
|
|
@@ -20,15 +20,20 @@ import { toJSONSchema } from "assistant-stream";
|
|
|
20
20
|
function buildPresentParameters(library) {
|
|
21
21
|
const names = Object.keys(library);
|
|
22
22
|
const props = {};
|
|
23
|
+
const propOwners = /* @__PURE__ */ new Map();
|
|
23
24
|
for (const name of names) {
|
|
24
25
|
const propsSchema = toJSONSchema(library[name].properties);
|
|
25
26
|
if (propsSchema.type !== "object") throw new Error(`[@assistant-ui/react-generative-ui] Component "${name}": \`properties\` must be an object schema (e.g. \`z.object({ ... })\`).`);
|
|
26
27
|
for (const [key, schema] of Object.entries(propsSchema.properties ?? {})) {
|
|
27
28
|
if (key === "$type" || key === "children") continue;
|
|
28
29
|
if (!(key in props)) props[key] = schema;
|
|
29
|
-
|
|
30
|
+
propOwners.set(key, [...propOwners.get(key) ?? [], name]);
|
|
30
31
|
}
|
|
31
32
|
}
|
|
33
|
+
if (process.env["NODE_ENV"] !== "production") for (const [key, owners] of propOwners) {
|
|
34
|
+
if (owners.length < 2) continue;
|
|
35
|
+
console.warn(`[@assistant-ui/react-generative-ui] Prop "${key}" is declared by ${formatComponentList(owners)}; keeping "${owners[0]}"'s schema. Rename or align the prop type to avoid an ambiguous schema.`);
|
|
36
|
+
}
|
|
32
37
|
const typeDescription = names.length > 0 ? `The component to render. ${names.map((name) => `"${name}": ${library[name].description}`).join("; ")}` : "The component to render.";
|
|
33
38
|
const node = {
|
|
34
39
|
type: "object",
|
|
@@ -62,6 +67,10 @@ function buildPresentParameters(library) {
|
|
|
62
67
|
}
|
|
63
68
|
};
|
|
64
69
|
}
|
|
70
|
+
function formatComponentList(names) {
|
|
71
|
+
if (names.length <= 2) return names.map((name) => `"${name}"`).join(" and ");
|
|
72
|
+
return `${names.slice(0, -1).map((name) => `"${name}"`).join(", ")}, and "${names[names.length - 1]}"`;
|
|
73
|
+
}
|
|
65
74
|
//#endregion
|
|
66
75
|
export { buildPresentParameters };
|
|
67
76
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buildPresentParameters.js","names":[],"sources":["../src/buildPresentParameters.ts"],"sourcesContent":["import { toJSONSchema } from \"assistant-stream\";\nimport type { JSONSchema7, JSONSchema7Definition } from \"json-schema\";\nimport { TYPE_KEY } from \"./constants\";\nimport type { GenerativeUILibrary } from \"./types\";\n\n/**\n * Builds the JSON schema for the `present` tool from a {@link GenerativeUILibrary}.\n *\n * The model produces a node `{ $type, ...props }` where `$type` selects a\n * component and the rest are its props. The schema is a flat object: `$type` is\n * an enum of the component names, every component's props are merged into one\n * optional bag, and `children` recurses via `$defs` so the tree can nest.\n *\n * It is intentionally flat rather than a per-`$type` discriminated union. Tool /\n * function-call schemas (OpenAI and others) require the top-level parameters to\n * be a plain object and reject a top-level `oneOf`/`anyOf`/`enum`. So props can't\n * be refined per `$type` at the root; the model is guided instead by `$type`'s\n * description (which lists each component) and each prop's own description. The\n * renderer validates nothing here — an unknown `$type` or stray prop is handled\n * at render time — so a looser schema only costs the model a hint, not safety.\n */\nexport function buildPresentParameters(\n library: GenerativeUILibrary,\n): JSONSchema7 {\n const names = Object.keys(library);\n\n // Merge every component's props into one optional bag. `$type`/`children` are\n // framework-reserved, so drop any author-declared copies. On a name clash the\n // first component's schema wins — props are an advisory hint here, not a\n // strict per-component contract.\n const props: Record<string, JSONSchema7Definition> = {};\n for (const name of names) {\n const propsSchema = toJSONSchema(library[name]!.properties);\n if (propsSchema.type !== \"object\") {\n throw new Error(\n `[@assistant-ui/react-generative-ui] Component \"${name}\": ` +\n \"`properties` must be an object schema (e.g. `z.object({ ... })`).\",\n );\n }\n for (const [key, schema] of Object.entries(propsSchema.properties ?? {})) {\n if (key === TYPE_KEY || key === \"children\") continue;\n if (!(key in props)) {\n props[key] = schema;\n }
|
|
1
|
+
{"version":3,"file":"buildPresentParameters.js","names":[],"sources":["../src/buildPresentParameters.ts"],"sourcesContent":["import { toJSONSchema } from \"assistant-stream\";\nimport type { JSONSchema7, JSONSchema7Definition } from \"json-schema\";\nimport { TYPE_KEY } from \"./constants\";\nimport type { GenerativeUILibrary } from \"./types\";\n\n/**\n * Builds the JSON schema for the `present` tool from a {@link GenerativeUILibrary}.\n *\n * The model produces a node `{ $type, ...props }` where `$type` selects a\n * component and the rest are its props. The schema is a flat object: `$type` is\n * an enum of the component names, every component's props are merged into one\n * optional bag, and `children` recurses via `$defs` so the tree can nest.\n *\n * It is intentionally flat rather than a per-`$type` discriminated union. Tool /\n * function-call schemas (OpenAI and others) require the top-level parameters to\n * be a plain object and reject a top-level `oneOf`/`anyOf`/`enum`. So props can't\n * be refined per `$type` at the root; the model is guided instead by `$type`'s\n * description (which lists each component) and each prop's own description. The\n * renderer validates nothing here — an unknown `$type` or stray prop is handled\n * at render time — so a looser schema only costs the model a hint, not safety.\n */\nexport function buildPresentParameters(\n library: GenerativeUILibrary,\n): JSONSchema7 {\n const names = Object.keys(library);\n\n // Merge every component's props into one optional bag. `$type`/`children` are\n // framework-reserved, so drop any author-declared copies. On a name clash the\n // first component's schema wins — props are an advisory hint here, not a\n // strict per-component contract.\n const props: Record<string, JSONSchema7Definition> = {};\n const propOwners = new Map<string, string[]>();\n for (const name of names) {\n const propsSchema = toJSONSchema(library[name]!.properties);\n if (propsSchema.type !== \"object\") {\n throw new Error(\n `[@assistant-ui/react-generative-ui] Component \"${name}\": ` +\n \"`properties` must be an object schema (e.g. `z.object({ ... })`).\",\n );\n }\n for (const [key, schema] of Object.entries(propsSchema.properties ?? {})) {\n if (key === TYPE_KEY || key === \"children\") continue;\n if (!(key in props)) {\n props[key] = schema;\n }\n propOwners.set(key, [...(propOwners.get(key) ?? []), name]);\n }\n }\n\n if (process.env[\"NODE_ENV\"] !== \"production\") {\n for (const [key, owners] of propOwners) {\n if (owners.length < 2) continue;\n // eslint-disable-next-line no-console\n console.warn(\n `[@assistant-ui/react-generative-ui] Prop \"${key}\" is declared by ` +\n `${formatComponentList(owners)}; keeping \"${owners[0]}\"'s schema. ` +\n \"Rename or align the prop type to avoid an ambiguous schema.\",\n );\n }\n }\n\n // Carry each component's description on the `$type` enum, since there are no\n // per-branch schemas to hang them on anymore.\n const typeDescription =\n names.length > 0\n ? `The component to render. ${names\n .map((name) => `\"${name}\": ${library[name]!.description}`)\n .join(\"; \")}`\n : \"The component to render.\";\n\n const node: JSONSchema7 = {\n type: \"object\",\n properties: {\n [TYPE_KEY]: { type: \"string\", enum: names, description: typeDescription },\n ...props,\n children: { $ref: \"#/$defs/children\" },\n },\n required: [TYPE_KEY],\n };\n\n const children: JSONSchema7 = {\n description: \"Nested generative UI rendered inside this component.\",\n anyOf: [\n { type: \"string\" },\n { $ref: \"#/$defs/node\" },\n {\n type: \"array\",\n items: { anyOf: [{ type: \"string\" }, { $ref: \"#/$defs/node\" }] },\n },\n ],\n };\n\n return {\n ...node,\n $defs: { node, children },\n };\n}\n\nfunction formatComponentList(names: string[]) {\n if (names.length <= 2) return names.map((name) => `\"${name}\"`).join(\" and \");\n\n return `${names\n .slice(0, -1)\n .map((name) => `\"${name}\"`)\n .join(\", \")}, and \"${names[names.length - 1]}\"`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,uBACd,SACa;CACb,MAAM,QAAQ,OAAO,KAAK,OAAO;CAMjC,MAAM,QAA+C,CAAC;CACtD,MAAM,6BAAa,IAAI,IAAsB;CAC7C,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,cAAc,aAAa,QAAQ,KAAK,CAAE,UAAU;EAC1D,IAAI,YAAY,SAAS,UACvB,MAAM,IAAI,MACR,kDAAkD,KAAK,yEAEzD;EAEF,KAAK,MAAM,CAAC,KAAK,WAAW,OAAO,QAAQ,YAAY,cAAc,CAAC,CAAC,GAAG;GACxE,IAAI,QAAA,WAAoB,QAAQ,YAAY;GAC5C,IAAI,EAAE,OAAO,QACX,MAAM,OAAO;GAEf,WAAW,IAAI,KAAK,CAAC,GAAI,WAAW,IAAI,GAAG,KAAK,CAAC,GAAI,IAAI,CAAC;EAC5D;CACF;CAEA,IAAI,QAAQ,IAAI,gBAAgB,cAC9B,KAAK,MAAM,CAAC,KAAK,WAAW,YAAY;EACtC,IAAI,OAAO,SAAS,GAAG;EAEvB,QAAQ,KACN,6CAA6C,IAAI,mBAC5C,oBAAoB,MAAM,EAAE,aAAa,OAAO,GAAG,wEAE1D;CACF;CAKF,MAAM,kBACJ,MAAM,SAAS,IACX,4BAA4B,MACzB,KAAK,SAAS,IAAI,KAAK,KAAK,QAAQ,KAAK,CAAE,aAAa,CAAC,CACzD,KAAK,IAAI,MACZ;CAEN,MAAM,OAAoB;EACxB,MAAM;EACN,YAAY;IACT,WAAW;IAAE,MAAM;IAAU,MAAM;IAAO,aAAa;GAAgB;GACxE,GAAG;GACH,UAAU,EAAE,MAAM,mBAAmB;EACvC;EACA,UAAU,CAAC,QAAQ;CACrB;CAEA,MAAM,WAAwB;EAC5B,aAAa;EACb,OAAO;GACL,EAAE,MAAM,SAAS;GACjB,EAAE,MAAM,eAAe;GACvB;IACE,MAAM;IACN,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,SAAS,GAAG,EAAE,MAAM,eAAe,CAAC,EAAE;GACjE;EACF;CACF;CAEA,OAAO;EACL,GAAG;EACH,OAAO;GAAE;GAAM;EAAS;CAC1B;AACF;AAEA,SAAS,oBAAoB,OAAiB;CAC5C,IAAI,MAAM,UAAU,GAAG,OAAO,MAAM,KAAK,SAAS,IAAI,KAAK,EAAE,CAAC,CAAC,KAAK,OAAO;CAE3E,OAAO,GAAG,MACP,MAAM,GAAG,EAAE,CAAC,CACZ,KAAK,SAAS,IAAI,KAAK,EAAE,CAAC,CAC1B,KAAK,IAAI,EAAE,SAAS,MAAM,MAAM,SAAS,GAAG;AACjD"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ALERT_TONES, ALIGNS, Action, AlertTone, Align, BUTTON_STYLES, ButtonStyle, COLORS, Color, IMAGE_SIZE_TOKENS, ImageSize, JUSTIFIES, Justify, LegacyComponentNode, NormalizedUIElement, NormalizedUINode, TEXT_SIZES, TextSize, UIChildren, UIElement, UINode, UISpec, WEIGHTS, Weight, normalizeSpec, normalizeUINode } from "./ir.js";
|
|
2
|
+
import { ActionDispatchContext, ActionHandler, ActionRegistry, createActionRegistry, emptyActionRegistry } from "./actionRegistry.js";
|
|
3
|
+
import { GenerativeUIAction, GenerativeUIComponent, GenerativeUIDispatch, GenerativeUIElement, GenerativeUILibrary, GenerativeUINode, GenerativeUIProps, GenerativeUIRenderContext, GenerativeUIStatus } from "./types.js";
|
|
2
4
|
import { JSONGenerativeUIOptions, PresentTool, PresentToolOptions, PromptUserTool } from "./JSONGenerativeUI.shared.js";
|
|
5
|
+
import { JSONGenerativeUI } from "./JSONGenerativeUI.client.js";
|
|
3
6
|
import { buildPresentParameters } from "./buildPresentParameters.js";
|
|
4
7
|
import { TYPE_KEY } from "./constants.js";
|
|
5
8
|
import { defineGenerativeComponents } from "./defineGenerativeComponents.js";
|
|
6
9
|
import { generativeUIToJSX } from "./generativeUIToJSX.js";
|
|
7
10
|
import { renderGenerativeUI } from "./renderGenerativeUI.js";
|
|
8
|
-
import {
|
|
9
|
-
export { type GenerativeUIComponent, type GenerativeUIElement, type GenerativeUILibrary, type GenerativeUINode, type GenerativeUIProps, type GenerativeUIRenderContext, type GenerativeUIStatus, JSONGenerativeUI, type JSONGenerativeUIOptions, type PresentTool, type PresentToolOptions, type PromptUserTool, TYPE_KEY, buildPresentParameters, defineGenerativeComponents, generativeUIToJSX, renderGenerativeUI };
|
|
11
|
+
import { defaultGenerativeUILibrary } from "./vocabulary/index.js";
|
|
12
|
+
export { ALERT_TONES, ALIGNS, type Action, type ActionDispatchContext, type ActionHandler, type ActionRegistry, type AlertTone, type Align, BUTTON_STYLES, type ButtonStyle, COLORS, type Color, type GenerativeUIAction, type GenerativeUIComponent, type GenerativeUIDispatch, type GenerativeUIElement, type GenerativeUILibrary, type GenerativeUINode, type GenerativeUIProps, type GenerativeUIRenderContext, type GenerativeUIStatus, IMAGE_SIZE_TOKENS, type ImageSize, JSONGenerativeUI, type JSONGenerativeUIOptions, JUSTIFIES, type Justify, type LegacyComponentNode, type NormalizedUIElement, type NormalizedUINode, type PresentTool, type PresentToolOptions, type PromptUserTool, TEXT_SIZES, TYPE_KEY, type TextSize, type UIChildren, type UIElement, type UINode, type UISpec, WEIGHTS, type Weight, buildPresentParameters, createActionRegistry, defaultGenerativeUILibrary, defineGenerativeComponents, emptyActionRegistry, generativeUIToJSX, normalizeSpec, normalizeUINode, renderGenerativeUI };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { TYPE_KEY } from "./constants.js";
|
|
2
2
|
import { buildPresentParameters } from "./buildPresentParameters.js";
|
|
3
|
+
import { ALERT_TONES, ALIGNS, BUTTON_STYLES, COLORS, IMAGE_SIZE_TOKENS, JUSTIFIES, TEXT_SIZES, WEIGHTS, normalizeSpec, normalizeUINode } from "./ir.js";
|
|
3
4
|
import { renderGenerativeUI } from "./renderGenerativeUI.js";
|
|
5
|
+
import { JSONGenerativeUI } from "./JSONGenerativeUI.client.js";
|
|
6
|
+
import { createActionRegistry, emptyActionRegistry } from "./actionRegistry.js";
|
|
4
7
|
import { defineGenerativeComponents } from "./defineGenerativeComponents.js";
|
|
5
8
|
import { generativeUIToJSX } from "./generativeUIToJSX.js";
|
|
6
|
-
import {
|
|
7
|
-
export { JSONGenerativeUI, TYPE_KEY, buildPresentParameters, defineGenerativeComponents, generativeUIToJSX, renderGenerativeUI };
|
|
9
|
+
import { defaultGenerativeUILibrary } from "./vocabulary/index.js";
|
|
10
|
+
export { ALERT_TONES, ALIGNS, BUTTON_STYLES, COLORS, IMAGE_SIZE_TOKENS, JSONGenerativeUI, JUSTIFIES, TEXT_SIZES, TYPE_KEY, WEIGHTS, buildPresentParameters, createActionRegistry, defaultGenerativeUILibrary, defineGenerativeComponents, emptyActionRegistry, generativeUIToJSX, normalizeSpec, normalizeUINode, renderGenerativeUI };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ALERT_TONES, ALIGNS, Action, AlertTone, Align, BUTTON_STYLES, ButtonStyle, COLORS, Color, IMAGE_SIZE_TOKENS, ImageSize, JUSTIFIES, Justify, LegacyComponentNode, NormalizedUIElement, NormalizedUINode, TEXT_SIZES, TextSize, UIChildren, UIElement, UINode, UISpec, WEIGHTS, Weight, normalizeSpec, normalizeUINode } from "./ir.js";
|
|
2
|
+
import { ActionDispatchContext, ActionHandler, ActionRegistry, createActionRegistry, emptyActionRegistry } from "./actionRegistry.js";
|
|
3
|
+
import { GenerativeUIAction, GenerativeUIComponent, GenerativeUIDispatch, GenerativeUIElement, GenerativeUILibrary, GenerativeUINode, GenerativeUIProps, GenerativeUIRenderContext, GenerativeUIStatus } from "./types.js";
|
|
4
|
+
import { JSONGenerativeUIOptions, PresentTool, PresentToolOptions, PromptUserTool } from "./JSONGenerativeUI.shared.js";
|
|
5
|
+
import { JSONGenerativeUI } from "./JSONGenerativeUI.server.js";
|
|
6
|
+
import { buildPresentParameters } from "./buildPresentParameters.js";
|
|
7
|
+
import { TYPE_KEY } from "./constants.js";
|
|
8
|
+
import { defineGenerativeComponents } from "./defineGenerativeComponents.js";
|
|
9
|
+
import { generativeUIToJSX } from "./generativeUIToJSX.js";
|
|
10
|
+
import { renderGenerativeUI } from "./renderGenerativeUI.js";
|
|
11
|
+
import { defaultGenerativeUILibrary } from "./vocabulary/index.js";
|
|
12
|
+
export { ALERT_TONES, ALIGNS, type Action, type ActionDispatchContext, type ActionHandler, type ActionRegistry, type AlertTone, type Align, BUTTON_STYLES, type ButtonStyle, COLORS, type Color, type GenerativeUIAction, type GenerativeUIComponent, type GenerativeUIDispatch, type GenerativeUIElement, type GenerativeUILibrary, type GenerativeUINode, type GenerativeUIProps, type GenerativeUIRenderContext, type GenerativeUIStatus, IMAGE_SIZE_TOKENS, type ImageSize, JSONGenerativeUI, type JSONGenerativeUIOptions, JUSTIFIES, type Justify, type LegacyComponentNode, type NormalizedUIElement, type NormalizedUINode, type PresentTool, type PresentToolOptions, type PromptUserTool, TEXT_SIZES, TYPE_KEY, type TextSize, type UIChildren, type UIElement, type UINode, type UISpec, WEIGHTS, type Weight, buildPresentParameters, createActionRegistry, defaultGenerativeUILibrary, defineGenerativeComponents, emptyActionRegistry, generativeUIToJSX, normalizeSpec, normalizeUINode, renderGenerativeUI };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { TYPE_KEY } from "./constants.js";
|
|
2
|
+
import { buildPresentParameters } from "./buildPresentParameters.js";
|
|
3
|
+
import { ALERT_TONES, ALIGNS, BUTTON_STYLES, COLORS, IMAGE_SIZE_TOKENS, JUSTIFIES, TEXT_SIZES, WEIGHTS, normalizeSpec, normalizeUINode } from "./ir.js";
|
|
4
|
+
import { renderGenerativeUI } from "./renderGenerativeUI.js";
|
|
5
|
+
import { JSONGenerativeUI } from "./JSONGenerativeUI.server.js";
|
|
6
|
+
import { createActionRegistry, emptyActionRegistry } from "./actionRegistry.js";
|
|
7
|
+
import { defineGenerativeComponents } from "./defineGenerativeComponents.js";
|
|
8
|
+
import { generativeUIToJSX } from "./generativeUIToJSX.js";
|
|
9
|
+
import { defaultGenerativeUILibrary } from "./vocabulary/index.js";
|
|
10
|
+
export { ALERT_TONES, ALIGNS, BUTTON_STYLES, COLORS, IMAGE_SIZE_TOKENS, JSONGenerativeUI, JUSTIFIES, TEXT_SIZES, TYPE_KEY, WEIGHTS, buildPresentParameters, createActionRegistry, defaultGenerativeUILibrary, defineGenerativeComponents, emptyActionRegistry, generativeUIToJSX, normalizeSpec, normalizeUINode, renderGenerativeUI };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ALERT_TONES, ALIGNS, Action, AlertTone, Align, BUTTON_STYLES, ButtonStyle, COLORS, Color, IMAGE_SIZE_TOKENS, ImageSize, JUSTIFIES, Justify, LegacyComponentNode, NormalizedUIElement, NormalizedUINode, TEXT_SIZES, TextSize, UIChildren, UIElement, UINode, UISpec, WEIGHTS, Weight, normalizeSpec, normalizeUINode } from "./ir.js";
|
|
2
|
+
import { ActionDispatchContext, ActionHandler, ActionRegistry, createActionRegistry, emptyActionRegistry } from "./actionRegistry.js";
|
|
3
|
+
import { GenerativeUIAction, GenerativeUIComponent, GenerativeUIDispatch, GenerativeUIElement, GenerativeUILibrary, GenerativeUINode, GenerativeUIProps, GenerativeUIRenderContext, GenerativeUIStatus } from "./types.js";
|
|
4
|
+
import { JSONGenerativeUIOptions, PresentTool, PresentToolOptions, PromptUserTool } from "./JSONGenerativeUI.shared.js";
|
|
5
|
+
import { buildPresentParameters } from "./buildPresentParameters.js";
|
|
6
|
+
import { TYPE_KEY } from "./constants.js";
|
|
7
|
+
import { defineGenerativeComponents } from "./defineGenerativeComponents.js";
|
|
8
|
+
import { generativeUIToJSX } from "./generativeUIToJSX.js";
|
|
9
|
+
import { renderGenerativeUI } from "./renderGenerativeUI.js";
|
|
10
|
+
import { defaultGenerativeUILibrary } from "./vocabulary/index.js";
|
|
11
|
+
export { ALERT_TONES, ALIGNS, type Action, type ActionDispatchContext, type ActionHandler, type ActionRegistry, type AlertTone, type Align, BUTTON_STYLES, type ButtonStyle, COLORS, type Color, type GenerativeUIAction, type GenerativeUIComponent, type GenerativeUIDispatch, type GenerativeUIElement, type GenerativeUILibrary, type GenerativeUINode, type GenerativeUIProps, type GenerativeUIRenderContext, type GenerativeUIStatus, IMAGE_SIZE_TOKENS, type ImageSize, type JSONGenerativeUIOptions, JUSTIFIES, type Justify, type LegacyComponentNode, type NormalizedUIElement, type NormalizedUINode, type PresentTool, type PresentToolOptions, type PromptUserTool, TEXT_SIZES, TYPE_KEY, type TextSize, type UIChildren, type UIElement, type UINode, type UISpec, WEIGHTS, type Weight, buildPresentParameters, createActionRegistry, defaultGenerativeUILibrary, defineGenerativeComponents, emptyActionRegistry, generativeUIToJSX, normalizeSpec, normalizeUINode, renderGenerativeUI };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { TYPE_KEY } from "./constants.js";
|
|
2
|
+
import { buildPresentParameters } from "./buildPresentParameters.js";
|
|
3
|
+
import { ALERT_TONES, ALIGNS, BUTTON_STYLES, COLORS, IMAGE_SIZE_TOKENS, JUSTIFIES, TEXT_SIZES, WEIGHTS, normalizeSpec, normalizeUINode } from "./ir.js";
|
|
4
|
+
import { renderGenerativeUI } from "./renderGenerativeUI.js";
|
|
5
|
+
import { createActionRegistry, emptyActionRegistry } from "./actionRegistry.js";
|
|
6
|
+
import { defineGenerativeComponents } from "./defineGenerativeComponents.js";
|
|
7
|
+
import { generativeUIToJSX } from "./generativeUIToJSX.js";
|
|
8
|
+
import { defaultGenerativeUILibrary } from "./vocabulary/index.js";
|
|
9
|
+
export { ALERT_TONES, ALIGNS, BUTTON_STYLES, COLORS, IMAGE_SIZE_TOKENS, JUSTIFIES, TEXT_SIZES, TYPE_KEY, WEIGHTS, buildPresentParameters, createActionRegistry, defaultGenerativeUILibrary, defineGenerativeComponents, emptyActionRegistry, generativeUIToJSX, normalizeSpec, normalizeUINode, renderGenerativeUI };
|
package/dist/ir.d.ts
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
//#region src/ir.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The generative-ui intermediate representation: a model-emitted, cross-platform
|
|
4
|
+
* UI tree. React-free, so converters and non-web runtimes consume it without
|
|
5
|
+
* pulling React. The flat `$type` shape is the canonical form; the legacy
|
|
6
|
+
* `component` shape is accepted as a backward-compatible alias.
|
|
7
|
+
*
|
|
8
|
+
* Reserved keys are partitioned off from component props so the component prop
|
|
9
|
+
* namespace stays fully free:
|
|
10
|
+
*
|
|
11
|
+
* - `$`-prefixed keys are framework-reserved (`$type`, `$key`, `$action`,
|
|
12
|
+
* `$status`). Components never declare `$`-prefixed props, so a component
|
|
13
|
+
* can use `type`, `status`, `variant`, etc. as ordinary props without
|
|
14
|
+
* colliding with the framework.
|
|
15
|
+
* - `children` is additionally reserved (the JSX convention).
|
|
16
|
+
* - every other key is an inline prop passed straight to the component.
|
|
17
|
+
*/
|
|
18
|
+
declare const TEXT_SIZES: readonly ["sm", "md", "lg", "xl", "2xl", "3xl"];
|
|
19
|
+
type TextSize = (typeof TEXT_SIZES)[number];
|
|
20
|
+
declare const IMAGE_SIZE_TOKENS: readonly ["sm", "md", "lg"];
|
|
21
|
+
type ImageSize = (typeof IMAGE_SIZE_TOKENS)[number] | number;
|
|
22
|
+
declare const WEIGHTS: readonly ["normal", "medium", "semibold", "bold"];
|
|
23
|
+
type Weight = (typeof WEIGHTS)[number];
|
|
24
|
+
declare const COLORS: readonly ["emphasis", "secondary", "alpha-70", "white", "white-70", "white-50"];
|
|
25
|
+
type Color = (typeof COLORS)[number];
|
|
26
|
+
declare const ALIGNS: readonly ["start", "center", "end"];
|
|
27
|
+
type Align = (typeof ALIGNS)[number];
|
|
28
|
+
declare const JUSTIFIES: readonly ["start", "center", "end", "between"];
|
|
29
|
+
type Justify = (typeof JUSTIFIES)[number];
|
|
30
|
+
declare const BUTTON_STYLES: readonly ["primary", "secondary", "outline", "ghost", "danger"];
|
|
31
|
+
type ButtonStyle = (typeof BUTTON_STYLES)[number];
|
|
32
|
+
declare const ALERT_TONES: readonly ["info", "success", "warning", "danger"];
|
|
33
|
+
/** Maps to ChatKit `alert` severity levels. */
|
|
34
|
+
type AlertTone = (typeof ALERT_TONES)[number];
|
|
35
|
+
/**
|
|
36
|
+
* Behavior payload carried by an interactive node. `type` is resolved by the
|
|
37
|
+
* host's action registry, not the renderer; keeping behavior as data keeps the
|
|
38
|
+
* tree serializable so the same node renders on web and converts to a native
|
|
39
|
+
* action id on Slack.
|
|
40
|
+
*/
|
|
41
|
+
interface Action {
|
|
42
|
+
readonly type: string;
|
|
43
|
+
readonly [payload: string]: unknown;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Anything renderable as generative UI, as the model emits it. The renderer
|
|
47
|
+
* also accepts `number`, `boolean`, `null`, `undefined`, and arrays at the
|
|
48
|
+
* input boundary (numbers render as text, falsy/boolean as nothing, arrays as
|
|
49
|
+
* lists); {@link normalizeUINode} accepts that full range.
|
|
50
|
+
*/
|
|
51
|
+
type UINode = string | number | UIElement | LegacyComponentNode;
|
|
52
|
+
type UIChildren = UINode | readonly UINode[];
|
|
53
|
+
/** The flat node shape: inline props keep the tree compact and natural for a
|
|
54
|
+
* model to emit, instead of a nested `{ type, props }` bag. Reserved keys are
|
|
55
|
+
* stripped before props reach the component (see the module header). */
|
|
56
|
+
interface UIElement {
|
|
57
|
+
readonly $type: string;
|
|
58
|
+
readonly $key?: string | number;
|
|
59
|
+
readonly children?: UIChildren;
|
|
60
|
+
readonly $action?: Action;
|
|
61
|
+
readonly [prop: string]: unknown;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The legacy node shape: a `component` name plus a nested `props` bag. Kept
|
|
65
|
+
* for backward compatibility. New code authors the flat {@link UIElement}
|
|
66
|
+
* shape instead.
|
|
67
|
+
*/
|
|
68
|
+
interface LegacyComponentNode {
|
|
69
|
+
readonly component: string;
|
|
70
|
+
readonly props?: Record<string, unknown>;
|
|
71
|
+
readonly children?: UIChildren;
|
|
72
|
+
readonly key?: string;
|
|
73
|
+
}
|
|
74
|
+
type UISpec = UINode | readonly UINode[];
|
|
75
|
+
/**
|
|
76
|
+
* A node normalized to a single canonical shape: a `type` string, an inline
|
|
77
|
+
* `props` bag, recursive `children`, an optional `key`, and an optional
|
|
78
|
+
* `action`. Renderers and platform converters consume this form, so they never
|
|
79
|
+
* branch on whether the model emitted the flat `$type` shape or the legacy
|
|
80
|
+
* `component` shape, and they never see the reserved `$`-prefixed keys leak
|
|
81
|
+
* into component props.
|
|
82
|
+
*/
|
|
83
|
+
interface NormalizedUIElement {
|
|
84
|
+
readonly type: string;
|
|
85
|
+
readonly props: Readonly<Record<string, unknown>>;
|
|
86
|
+
readonly children?: NormalizedUINode | undefined;
|
|
87
|
+
readonly key?: string | number | undefined;
|
|
88
|
+
readonly action?: Action | undefined;
|
|
89
|
+
}
|
|
90
|
+
type NormalizedUINode = string | number | readonly NormalizedUINode[] | NormalizedUIElement | null;
|
|
91
|
+
/**
|
|
92
|
+
* Normalizes a generative-ui input to {@link NormalizedUINode}. The flat
|
|
93
|
+
* `$type` shape and the legacy `component` shape both map to the same canonical
|
|
94
|
+
* element, with reserved keys (`$type`, `$key`, `$action`, `children`) stripped
|
|
95
|
+
* from the prop bag. A node that carries neither a `$type` nor a `component`
|
|
96
|
+
* string is not renderable and resolves to `null` rather than throwing, so a
|
|
97
|
+
* partially-streamed or malformed node degrades to "render nothing".
|
|
98
|
+
*
|
|
99
|
+
* `partialPath` carries streaming state from the tool-args parse meta: a node
|
|
100
|
+
* whose `$type` is still mid-arrival is held back (resolves to `null`) until it
|
|
101
|
+
* completes, and the path is threaded into `children` so a nested streaming
|
|
102
|
+
* node is held back while completed siblings render. Omit it for a
|
|
103
|
+
* non-streaming (converter) normalize.
|
|
104
|
+
*/
|
|
105
|
+
declare function normalizeUINode(node: unknown, partialPath?: readonly string[] | undefined, depth?: number): NormalizedUINode;
|
|
106
|
+
/**
|
|
107
|
+
* Normalizes the root of a {@link UISpec}, preserving whether the root was a
|
|
108
|
+
* single node or a list.
|
|
109
|
+
*/
|
|
110
|
+
declare function normalizeSpec(spec: UISpec): {
|
|
111
|
+
readonly root: NormalizedUINode | readonly NormalizedUINode[];
|
|
112
|
+
};
|
|
113
|
+
//#endregion
|
|
114
|
+
export { ALERT_TONES, ALIGNS, Action, AlertTone, Align, BUTTON_STYLES, ButtonStyle, COLORS, Color, IMAGE_SIZE_TOKENS, ImageSize, JUSTIFIES, Justify, LegacyComponentNode, NormalizedUIElement, NormalizedUINode, TEXT_SIZES, TextSize, UIChildren, UIElement, UINode, UISpec, WEIGHTS, Weight, normalizeSpec, normalizeUINode };
|
|
115
|
+
//# sourceMappingURL=ir.d.ts.map
|
package/dist/ir.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ir.d.ts","names":[],"sources":["../src/ir.ts"],"mappings":";;AAmBA;;;;AAAyE;AACzE;;;;AAAyC;AAEzC;;;;AAA4D;cAH/C,UAAA;AAAA,KACD,QAAA,WAAmB,UAAU;AAAA,cAE5B,iBAAA;AAAA,KACD,SAAA,WAAoB,iBAAiB;AAAA,cAEpC,OAAA;AAAA,KACD,MAAA,WAAiB,OAAO;AAAA,cAEvB,MAAA;AAAA,KAQD,KAAA,WAAgB,MAAM;AAAA,cAErB,MAAA;AAAA,KACD,KAAA,WAAgB,MAAM;AAAA,cAErB,SAAA;AAAA,KACD,OAAA,WAAkB,SAAS;AAAA,cAE1B,aAAA;AAAA,KAOD,WAAA,WAAsB,aAAa;AAAA,cAElC,WAAA;AAzBb;AAAA,KA2BY,SAAA,WAAoB,WAAW;;;AApBjC;AACV;;;UA2BiB,MAAA;EAAA,SACN,IAAA;EAAA,UACC,OAAe;AAAA;;;AA3B8B;AACzD;;;KAmCY,MAAA,qBAA2B,SAAA,GAAY,mBAAmB;AAAA,KAE1D,UAAA,GAAa,MAAA,YAAkB,MAAM;AAnCjD;;;AAAA,UAwCiB,SAAA;EAAA,SACN,KAAA;EAAA,SACA,IAAA;EAAA,SACA,QAAA,GAAW,UAAA;EAAA,SACX,OAAA,GAAU,MAAM;EAAA,UACf,IAAA;AAAA;AA1CZ;;;;AAMU;AANV,UAkDiB,mBAAA;EAAA,SACN,SAAA;EAAA,SACA,KAAA,GAAQ,MAAA;EAAA,SACR,QAAA,GAAW,UAAU;EAAA,SACrB,GAAA;AAAA;AAAA,KAGC,MAAA,GAAS,MAAA,YAAkB,MAAM;;;AAhD+B;AAE5E;;;;AAA2C;UAwD1B,mBAAA;EAAA,SACN,IAAA;EAAA,SACA,KAAA,EAAO,QAAA,CAAS,MAAA;EAAA,SAChB,QAAA,GAAW,gBAAA;EAAA,SACX,GAAA;EAAA,SACA,MAAA,GAAS,MAAA;AAAA;AAAA,KAGR,gBAAA,8BAGC,gBAAA,KACT,mBAAmB;;AAjD+C;AAEtE;;;;AAAiD;AAKjD;;;;;;;iBAuFgB,eAAA,CACd,IAAA,WACA,WAAA,kCACA,KAAA,YACC,gBAAgB;;;;;iBAuEH,aAAA,CAAc,IAAA,EAAM,MAAA;EAAA,SACzB,IAAA,EAAM,gBAAA,YAA4B,gBAAA;AAAA"}
|