@assistant-ui/react-generative-ui 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/JSONGenerativeUI.client.d.ts +4 -2
- 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.server.d.ts +0 -1
- package/dist/JSONGenerativeUI.server.d.ts.map +1 -1
- package/dist/JSONGenerativeUI.shared.d.ts +8 -1
- package/dist/JSONGenerativeUI.shared.d.ts.map +1 -1
- package/dist/JSONGenerativeUI.shared.js.map +1 -1
- package/dist/actionRegistry.d.ts +32 -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.d.ts +5 -5
- package/dist/buildPresentParameters.d.ts.map +1 -1
- package/dist/buildPresentParameters.js +20 -6
- package/dist/buildPresentParameters.js.map +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/defineGenerativeComponents.d.ts +0 -1
- package/dist/defineGenerativeComponents.d.ts.map +1 -1
- package/dist/generativeUIToJSX.d.ts +15 -10
- package/dist/generativeUIToJSX.d.ts.map +1 -1
- package/dist/generativeUIToJSX.js +47 -17
- package/dist/generativeUIToJSX.js.map +1 -1
- package/dist/index.d.ts +8 -4
- package/dist/index.js +5 -2
- package/dist/index.server.d.ts +13 -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 +175 -0
- package/dist/ir.js.map +1 -0
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts +3 -3
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts.map +1 -1
- package/dist/renderGenerativeUI.d.ts +5 -5
- package/dist/renderGenerativeUI.d.ts.map +1 -1
- package/dist/renderGenerativeUI.js +18 -45
- package/dist/renderGenerativeUI.js.map +1 -1
- package/dist/slack/constants.d.ts +111 -0
- package/dist/slack/constants.d.ts.map +1 -0
- package/dist/slack/constants.js +168 -0
- package/dist/slack/constants.js.map +1 -0
- package/dist/slack/decodeBlockAction.d.ts +11 -0
- package/dist/slack/decodeBlockAction.d.ts.map +1 -0
- package/dist/slack/decodeBlockAction.js +40 -0
- package/dist/slack/decodeBlockAction.js.map +1 -0
- package/dist/slack/fromSlackBlocks.d.ts +30 -0
- package/dist/slack/fromSlackBlocks.d.ts.map +1 -0
- package/dist/slack/fromSlackBlocks.js +447 -0
- package/dist/slack/fromSlackBlocks.js.map +1 -0
- package/dist/slack/toSlackBlocks.d.ts +7 -0
- package/dist/slack/toSlackBlocks.d.ts.map +1 -0
- package/dist/slack/toSlackBlocks.js +649 -0
- package/dist/slack/toSlackBlocks.js.map +1 -0
- package/dist/slack/types.d.ts +178 -0
- package/dist/slack/types.d.ts.map +1 -0
- package/dist/slack/types.js +0 -0
- package/dist/slack.d.ts +5 -0
- package/dist/slack.js +4 -0
- package/dist/teams/boundSpec.d.ts +20 -0
- package/dist/teams/boundSpec.d.ts.map +1 -0
- package/dist/teams/boundSpec.js +67 -0
- package/dist/teams/boundSpec.js.map +1 -0
- package/dist/teams/constants.d.ts +57 -0
- package/dist/teams/constants.d.ts.map +1 -0
- package/dist/teams/constants.js +92 -0
- package/dist/teams/constants.js.map +1 -0
- package/dist/teams/decodeSubmitData.d.ts +25 -0
- package/dist/teams/decodeSubmitData.d.ts.map +1 -0
- package/dist/teams/decodeSubmitData.js +44 -0
- package/dist/teams/decodeSubmitData.js.map +1 -0
- package/dist/teams/toAdaptiveCard.d.ts +39 -0
- package/dist/teams/toAdaptiveCard.d.ts.map +1 -0
- package/dist/teams/toAdaptiveCard.js +496 -0
- package/dist/teams/toAdaptiveCard.js.map +1 -0
- package/dist/teams/toTeamsAttachments.d.ts +13 -0
- package/dist/teams/toTeamsAttachments.d.ts.map +1 -0
- package/dist/teams/toTeamsAttachments.js +95 -0
- package/dist/teams/toTeamsAttachments.js.map +1 -0
- package/dist/teams/types.d.ts +196 -0
- package/dist/teams/types.d.ts.map +1 -0
- package/dist/teams/types.js +0 -0
- package/dist/teams.d.ts +5 -0
- package/dist/teams.js +4 -0
- package/dist/types.d.ts +41 -34
- package/dist/types.d.ts.map +1 -1
- package/dist/vocabulary/alert.d.ts +28 -0
- package/dist/vocabulary/alert.d.ts.map +1 -0
- package/dist/vocabulary/alert.js +58 -0
- package/dist/vocabulary/alert.js.map +1 -0
- package/dist/vocabulary/collectFormValues.d.ts +23 -0
- package/dist/vocabulary/collectFormValues.d.ts.map +1 -0
- package/dist/vocabulary/collectFormValues.js +32 -0
- package/dist/vocabulary/collectFormValues.js.map +1 -0
- package/dist/vocabulary/data.d.ts +52 -0
- package/dist/vocabulary/data.d.ts.map +1 -0
- package/dist/vocabulary/data.js +294 -0
- package/dist/vocabulary/data.js.map +1 -0
- package/dist/vocabulary/dispatch.d.ts +11 -0
- package/dist/vocabulary/dispatch.d.ts.map +1 -0
- package/dist/vocabulary/dispatch.js +21 -0
- package/dist/vocabulary/dispatch.js.map +1 -0
- package/dist/vocabulary/fact.d.ts +15 -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/form.d.ts +14 -0
- package/dist/vocabulary/form.d.ts.map +1 -0
- package/dist/vocabulary/form.js +23 -0
- package/dist/vocabulary/form.js.map +1 -0
- package/dist/vocabulary/icon.d.ts +44 -0
- package/dist/vocabulary/icon.d.ts.map +1 -0
- package/dist/vocabulary/icon.js +272 -0
- package/dist/vocabulary/icon.js.map +1 -0
- package/dist/vocabulary/index.d.ts +15 -0
- package/dist/vocabulary/index.d.ts.map +1 -0
- package/dist/vocabulary/index.js +36 -0
- package/dist/vocabulary/index.js.map +1 -0
- package/dist/vocabulary/interactive.d.ts +93 -0
- package/dist/vocabulary/interactive.d.ts.map +1 -0
- package/dist/vocabulary/interactive.js +172 -0
- package/dist/vocabulary/interactive.js.map +1 -0
- package/dist/vocabulary/layout.d.ts +82 -0
- package/dist/vocabulary/layout.d.ts.map +1 -0
- package/dist/vocabulary/layout.js +136 -0
- package/dist/vocabulary/layout.js.map +1 -0
- package/dist/vocabulary/list.d.ts +17 -0
- package/dist/vocabulary/list.d.ts.map +1 -0
- package/dist/vocabulary/list.js +48 -0
- package/dist/vocabulary/list.js.map +1 -0
- package/dist/vocabulary/media.d.ts +28 -0
- package/dist/vocabulary/media.d.ts.map +1 -0
- package/dist/vocabulary/media.js +42 -0
- package/dist/vocabulary/media.js.map +1 -0
- package/dist/vocabulary/text.d.ts +60 -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 +21 -13
- 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 +88 -0
- package/src/buildPresentParameters.ts +38 -16
- package/src/generativeUIToJSX.test.ts +186 -0
- package/src/generativeUIToJSX.ts +112 -21
- package/src/index.server.ts +2 -0
- package/src/index.shared.ts +61 -0
- package/src/index.ts +2 -26
- package/src/ir.test.ts +203 -0
- package/src/ir.ts +279 -0
- package/src/renderGenerativeUI.test.tsx +69 -2
- package/src/renderGenerativeUI.tsx +49 -82
- package/src/slack/constants.ts +217 -0
- package/src/slack/decodeBlockAction.test.ts +135 -0
- package/src/slack/decodeBlockAction.ts +66 -0
- package/src/slack/fromSlackBlocks.test.ts +1145 -0
- package/src/slack/fromSlackBlocks.ts +709 -0
- package/src/slack/toSlackBlocks.test.ts +1936 -0
- package/src/slack/toSlackBlocks.ts +1319 -0
- package/src/slack/types.ts +230 -0
- package/src/slack.ts +37 -0
- package/src/teams/boundSpec.ts +102 -0
- package/src/teams/constants.ts +127 -0
- package/src/teams/decodeSubmitData.test.ts +148 -0
- package/src/teams/decodeSubmitData.ts +57 -0
- package/src/teams/toAdaptiveCard.test.ts +1410 -0
- package/src/teams/toAdaptiveCard.ts +762 -0
- package/src/teams/toTeamsAttachments.test.ts +29 -0
- package/src/teams/toTeamsAttachments.ts +137 -0
- package/src/teams/types.ts +237 -0
- package/src/teams.ts +34 -0
- package/src/types.ts +57 -42
- package/src/vocabulary/alert.test.tsx +136 -0
- package/src/vocabulary/alert.tsx +66 -0
- package/src/vocabulary/collectFormValues.test.ts +127 -0
- package/src/vocabulary/collectFormValues.ts +58 -0
- package/src/vocabulary/data.test.tsx +567 -0
- package/src/vocabulary/data.tsx +494 -0
- package/src/vocabulary/dispatch.ts +22 -0
- package/src/vocabulary/fact.test.tsx +15 -0
- package/src/vocabulary/fact.tsx +22 -0
- package/src/vocabulary/form.test.tsx +112 -0
- package/src/vocabulary/form.tsx +34 -0
- package/src/vocabulary/icon.test.tsx +64 -0
- package/src/vocabulary/icon.tsx +174 -0
- package/src/vocabulary/index.test.ts +63 -0
- package/src/vocabulary/index.ts +33 -0
- package/src/vocabulary/interactive.dispatch.test.tsx +352 -0
- package/src/vocabulary/interactive.test.tsx +248 -0
- package/src/vocabulary/interactive.tsx +269 -0
- package/src/vocabulary/layout.test.tsx +289 -0
- package/src/vocabulary/layout.tsx +229 -0
- package/src/vocabulary/list.test.tsx +195 -0
- package/src/vocabulary/list.tsx +48 -0
- package/src/vocabulary/media.test.tsx +85 -0
- package/src/vocabulary/media.tsx +56 -0
- package/src/vocabulary/text.test.tsx +73 -0
- package/src/vocabulary/text.tsx +59 -0
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { JSONGenerativeUIOptions, PresentTool, PresentToolOptions, PromptUserTool } from "./JSONGenerativeUI.shared.js";
|
|
2
|
-
|
|
3
2
|
//#region src/JSONGenerativeUI.client.d.ts
|
|
4
3
|
/**
|
|
5
4
|
* Client build of {@link JSONGenerativeUI}, resolved through the package's
|
|
@@ -8,11 +7,14 @@ import { JSONGenerativeUIOptions, PresentTool, PresentToolOptions, PromptUserToo
|
|
|
8
7
|
* `present` is a frontend tool that renders the model's `{ $type, ...props }`
|
|
9
8
|
* tree against the library and resolves immediately. `prompt_user` is a
|
|
10
9
|
* 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`.
|
|
10
|
+
* result. Both draw the tree the same way, so they share one `render`. The
|
|
11
|
+
* `actions` registry (if provided) is threaded into the render context so
|
|
12
|
+
* interactive components can fire `$action` through `$dispatch`.
|
|
12
13
|
*/
|
|
13
14
|
declare class JSONGenerativeUI {
|
|
14
15
|
private readonly library;
|
|
15
16
|
private readonly parameters;
|
|
17
|
+
private readonly actions;
|
|
16
18
|
constructor(options: JSONGenerativeUIOptions);
|
|
17
19
|
private readonly render;
|
|
18
20
|
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":";;;;;;;;;;;;;cAkCa;mBACM;mBACA;mBACA;cAEL,SAAS;mBAMJ;EAYjB,QAAQ,UAAU,qBAAqB;EASvC,cAAc"}
|
|
@@ -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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSONGenerativeUI.server.d.ts","names":[],"sources":["../src/JSONGenerativeUI.server.tsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"JSONGenerativeUI.server.d.ts","names":[],"sources":["../src/JSONGenerativeUI.server.tsx"],"mappings":";;;;;;;;;;;;;;;cAwBa;mBACM;cAEL,SAAS;EAIrB,QAAQ,UAAU,qBAAqB;EAIvC,cAAc"}
|
|
@@ -1,7 +1,7 @@
|
|
|
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
5
|
//#region src/JSONGenerativeUI.shared.d.ts
|
|
6
6
|
/** Options for {@link JSONGenerativeUI}. */
|
|
7
7
|
type JSONGenerativeUIOptions = {
|
|
@@ -11,6 +11,13 @@ type JSONGenerativeUIOptions = {
|
|
|
11
11
|
* `"use generative"` build can split each `render` from its `properties`.
|
|
12
12
|
*/
|
|
13
13
|
library: GenerativeUILibrary;
|
|
14
|
+
/**
|
|
15
|
+
* Host-provided map from `$action.type` to its handler. Interactive
|
|
16
|
+
* components (`Button`/`Select`/`Input`/`DatePicker`) call `$dispatch($action)`
|
|
17
|
+
* on their event, which resolves through this registry. Omit it for a
|
|
18
|
+
* read-only render where model-emitted actions degrade to a no-op.
|
|
19
|
+
*/
|
|
20
|
+
actions?: ActionRegistry;
|
|
14
21
|
};
|
|
15
22
|
/** Options for {@link JSONGenerativeUI.present}. */
|
|
16
23
|
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;;;;;;EAMV,SAAS;;;;;;;EAOT,UAAU;;;KAIA;;;;;;;EAOV;;KAGG;EACH;IACE;;;;KAKQ,cAAc,eACxB,yBACA,yBAEA;;KAGU,iBAAiB,eAAe,oCAC1C;;KAYU,oBAAoB;;;;;;iBAOhB,gBACd,YAAY,mBACZ,UAAU;;;;;;;;;;iBAcI,mBAAmB,YAAY;;;cAAA"}
|
|
@@ -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,32 @@
|
|
|
1
|
+
import { Action } from "./ir.js";
|
|
2
|
+
//#region src/actionRegistry.d.ts
|
|
3
|
+
/** Context handed to an {@link ActionHandler} when an `$action` fires. */
|
|
4
|
+
type ActionDispatchContext = {
|
|
5
|
+
/**
|
|
6
|
+
* The action payload. For fire-and-forget actions this is the `$action` as the model emitted it. For an interactive component the user's runtime input is merged in under the reserved `$input` key: a single value for a standalone control's dispatch, or an object keyed by each field's `name` for a `Form` or a `Card` with `asForm` set. A model-supplied `value` field is never clobbered.
|
|
7
|
+
*/
|
|
8
|
+
readonly payload: Action;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Resolves a single `$action.type`. Fire-and-forget actions return `void` or a
|
|
12
|
+
* promise that resolves to it; human-in-the-loop actions return a value the
|
|
13
|
+
* runtime uses to resume the run (see IR doc Open question #2 — the resume
|
|
14
|
+
* value is left as `unknown` and documented per-action). The return value is
|
|
15
|
+
* handed back to `dispatch`'s caller as `unknown`.
|
|
16
|
+
*/
|
|
17
|
+
type ActionHandler = (ctx: ActionDispatchContext) => unknown | Promise<unknown>;
|
|
18
|
+
/**
|
|
19
|
+
* The host-provided map from `$action.type` to {@link ActionHandler}. This is the single dispatch target for rendered generative UI: every interactive component fires its `$action` here through the injected `$dispatch` (a submit Button defers to its ancestor form's dispatch instead). The payload's `$input` takes one of two shapes: a single value for a standalone control's dispatch (`Select`, `Input`, `DatePicker`, `Checkbox`, `RadioGroup`), or an object keyed by field `name` for a `Form` or a `Card` with `asForm` set. Construct it with {@link createActionRegistry} and pass it to `JSONGenerativeUI`.
|
|
20
|
+
*/
|
|
21
|
+
type ActionRegistry = {
|
|
22
|
+
dispatch(action: Action): unknown;
|
|
23
|
+
has(type: string): boolean;
|
|
24
|
+
};
|
|
25
|
+
declare function createActionRegistry(handlers: Readonly<Record<string, ActionHandler>>): ActionRegistry;
|
|
26
|
+
/** A no-op registry used when no handlers are provided. Dispatch resolves to
|
|
27
|
+
* `undefined` and logs a warning in dev for unknown types, so a model-emitted
|
|
28
|
+
* action with no handler degrades to "does nothing" rather than throwing. */
|
|
29
|
+
declare const emptyActionRegistry: ActionRegistry;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { ActionDispatchContext, ActionHandler, ActionRegistry, createActionRegistry, emptyActionRegistry };
|
|
32
|
+
//# sourceMappingURL=actionRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actionRegistry.d.ts","names":[],"sources":["../src/actionRegistry.ts"],"mappings":";;;KAGY;;;;WAID,SAAS;;;;;;;;;KAUR,iBACV,KAAK,oCACQ;;;;KAKH;EACV,SAAS,QAAQ;EACjB,IAAI;;iBAGU,qBACd,UAAU,SAAS,eAAe,kBACjC;;;;cA0CU,qBAAqB"}
|
|
@@ -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 the model emitted it. For an interactive component the user's runtime input is merged in under the reserved `$input` key: a single value for a standalone control's dispatch, or an object keyed by each field's `name` for a `Form` or a `Card` with `asForm` set. 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 the single dispatch target for rendered generative UI: every interactive component fires its `$action` here through the injected `$dispatch` (a submit Button defers to its ancestor form's dispatch instead). The payload's `$input` takes one of two shapes: a single value for a standalone control's dispatch (`Select`, `Input`, `DatePicker`, `Checkbox`, `RadioGroup`), or an object keyed by field `name` for a `Form` or a `Card` with `asForm` set. Construct it with {@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":";AA6BA,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"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { JSONSchema7 } from "./node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.js";
|
|
2
2
|
import { GenerativeUILibrary } from "./types.js";
|
|
3
|
-
|
|
4
3
|
//#region src/buildPresentParameters.d.ts
|
|
5
4
|
/**
|
|
6
5
|
* Builds the JSON schema for the `present` tool from a {@link GenerativeUILibrary}.
|
|
7
6
|
*
|
|
8
|
-
* The model produces a node `{ $type, ...props }` where `$type` selects
|
|
9
|
-
* component
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
* The model produces a node `{ $type, $key?, ...props }` where `$type` selects
|
|
8
|
+
* a component, the optional `$key` pins a stable identity for list items that
|
|
9
|
+
* may reorder, and the rest are its props. The schema is a flat object: `$type`
|
|
10
|
+
* is an enum of the component names, every component's props are merged into
|
|
11
|
+
* one optional bag, and `children` recurses via `$defs` so the tree can nest.
|
|
12
12
|
*
|
|
13
13
|
* It is intentionally flat rather than a per-`$type` discriminated union. Tool /
|
|
14
14
|
* function-call schemas (OpenAI and others) require the top-level parameters to
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buildPresentParameters.d.ts","names":[],"sources":["../src/buildPresentParameters.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"buildPresentParameters.d.ts","names":[],"sources":["../src/buildPresentParameters.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;iBAsBgB,uBACd,SAAS,sBACR"}
|
|
@@ -4,10 +4,11 @@ import { toJSONSchema } from "assistant-stream";
|
|
|
4
4
|
/**
|
|
5
5
|
* Builds the JSON schema for the `present` tool from a {@link GenerativeUILibrary}.
|
|
6
6
|
*
|
|
7
|
-
* The model produces a node `{ $type, ...props }` where `$type` selects
|
|
8
|
-
* component
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* The model produces a node `{ $type, $key?, ...props }` where `$type` selects
|
|
8
|
+
* a component, the optional `$key` pins a stable identity for list items that
|
|
9
|
+
* may reorder, and the rest are its props. The schema is a flat object: `$type`
|
|
10
|
+
* is an enum of the component names, every component's props are merged into
|
|
11
|
+
* one optional bag, and `children` recurses via `$defs` so the tree can nest.
|
|
11
12
|
*
|
|
12
13
|
* It is intentionally flat rather than a per-`$type` discriminated union. Tool /
|
|
13
14
|
* function-call schemas (OpenAI and others) require the top-level parameters to
|
|
@@ -20,15 +21,20 @@ import { toJSONSchema } from "assistant-stream";
|
|
|
20
21
|
function buildPresentParameters(library) {
|
|
21
22
|
const names = Object.keys(library);
|
|
22
23
|
const props = {};
|
|
24
|
+
const propOwners = /* @__PURE__ */ new Map();
|
|
23
25
|
for (const name of names) {
|
|
24
26
|
const propsSchema = toJSONSchema(library[name].properties);
|
|
25
27
|
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
28
|
for (const [key, schema] of Object.entries(propsSchema.properties ?? {})) {
|
|
27
|
-
if (key
|
|
29
|
+
if (key.startsWith("$") || key === "children") continue;
|
|
28
30
|
if (!(key in props)) props[key] = schema;
|
|
29
|
-
|
|
31
|
+
propOwners.set(key, [...propOwners.get(key) ?? [], name]);
|
|
30
32
|
}
|
|
31
33
|
}
|
|
34
|
+
if (process.env["NODE_ENV"] !== "production") for (const [key, owners] of propOwners) {
|
|
35
|
+
if (owners.length < 2) continue;
|
|
36
|
+
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.`);
|
|
37
|
+
}
|
|
32
38
|
const typeDescription = names.length > 0 ? `The component to render. ${names.map((name) => `"${name}": ${library[name].description}`).join("; ")}` : "The component to render.";
|
|
33
39
|
const node = {
|
|
34
40
|
type: "object",
|
|
@@ -38,6 +44,10 @@ function buildPresentParameters(library) {
|
|
|
38
44
|
enum: names,
|
|
39
45
|
description: typeDescription
|
|
40
46
|
},
|
|
47
|
+
$key: {
|
|
48
|
+
description: "Stable identity for this UI node. Use it for list items that may reorder.",
|
|
49
|
+
anyOf: [{ type: "string" }, { type: "number" }]
|
|
50
|
+
},
|
|
41
51
|
...props,
|
|
42
52
|
children: { $ref: "#/$defs/children" }
|
|
43
53
|
},
|
|
@@ -62,6 +72,10 @@ function buildPresentParameters(library) {
|
|
|
62
72
|
}
|
|
63
73
|
};
|
|
64
74
|
}
|
|
75
|
+
function formatComponentList(names) {
|
|
76
|
+
if (names.length <= 2) return names.map((name) => `"${name}"`).join(" and ");
|
|
77
|
+
return `${names.slice(0, -1).map((name) => `"${name}"`).join(", ")}, and "${names[names.length - 1]}"`;
|
|
78
|
+
}
|
|
65
79
|
//#endregion
|
|
66
80
|
export { buildPresentParameters };
|
|
67
81
|
|
|
@@ -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 *
|
|
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, $key?, ...props }` where `$type` selects\n * a component, the optional `$key` pins a stable identity for list items that\n * may reorder, and the rest are its props. The schema is a flat object: `$type`\n * is an enum of the component names, every component's props are merged into\n * one 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. `$`-prefixed keys and\n // `children` are framework-reserved (see ir.ts), so drop any author-declared\n // copies. On a name clash the first component's schema wins — props are an\n // advisory hint here, not a 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.startsWith(\"$\") || 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 $key: {\n description:\n \"Stable identity for this UI node. Use it for list items that may reorder.\",\n anyOf: [{ type: \"string\" }, { type: \"number\" }],\n },\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":";;;;;;;;;;;;;;;;;;;;AAsBA,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,IAAI,WAAW,GAAG,KAAK,QAAQ,YAAY;GAC/C,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,MAAM;IACJ,aACE;IACF,OAAO,CAAC,EAAE,MAAM,SAAS,GAAG,EAAE,MAAM,SAAS,CAAC;GAChD;GACA,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/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","names":[],"sources":["../src/constants.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"constants.d.ts","names":[],"sources":["../src/constants.ts"],"mappings":";;;;;;;;;;cASa"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defineGenerativeComponents.d.ts","names":[],"sources":["../src/defineGenerativeComponents.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"defineGenerativeComponents.d.ts","names":[],"sources":["../src/defineGenerativeComponents.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4BgB,2BACd,UAAU,sBACT"}
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
//#region src/generativeUIToJSX.d.ts
|
|
2
|
+
/** Options for {@link generativeUIToJSX}. */
|
|
3
|
+
interface GenerativeUIToJSXOptions {
|
|
4
|
+
/** Escape string children so the output is safe to paste back into a JSX file. Defaults to `false`. */
|
|
5
|
+
escape?: boolean;
|
|
6
|
+
/** Pretty-print nested element trees with two-space indentation. Defaults to `false`. */
|
|
7
|
+
pretty?: boolean;
|
|
8
|
+
}
|
|
2
9
|
/**
|
|
3
|
-
* Serializes a generative-UI node to a JSX-like string for display
|
|
4
|
-
* "view source" of a model-produced tree. The wire form
|
|
5
|
-
* `{ $type: "Weather", id: "x" }` becomes `<Weather id="x" />`, and nested
|
|
6
|
-
* `children` render between tags: `<Card title="Hi"><Text>hello</Text></Card>`.
|
|
10
|
+
* Serializes a generative-UI node to a JSX-like string for display: the "view source" of a model-produced tree. The wire form `{ $type: "Weather", id: "x" }` becomes `<Weather id="x" />`, and nested `children` render between tags: `<Card title="Hi"><Text>hello</Text></Card>`. A model-provided `$key` becomes the JSX `key` attribute.
|
|
7
11
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
+
* By default this is a faithful textual rendering, not a parser: text children are emitted verbatim (not HTML/JSX-escaped), so the result is meant to be shown, not re-parsed. Returns `""` for nodes that aren't renderable (no `$type` yet, `null`, booleans).
|
|
13
|
+
*
|
|
14
|
+
* Pass `{ escape: true }` to make the output safe to paste back into JSX: any string child containing `<`, `>`, `&`, `{`, or `}` is emitted as a JSON-stringified expression (`{JSON.stringify(child)}`) instead of verbatim, while a string child with none of those characters still renders verbatim.
|
|
15
|
+
*
|
|
16
|
+
* Pass `{ pretty: true }` to pretty-print nested element trees with two-space indentation, while pure text children stay on one line.
|
|
12
17
|
*/
|
|
13
|
-
declare function generativeUIToJSX(node: unknown): string;
|
|
18
|
+
declare function generativeUIToJSX(node: unknown, options?: GenerativeUIToJSXOptions): string;
|
|
14
19
|
//#endregion
|
|
15
|
-
export { generativeUIToJSX };
|
|
20
|
+
export { GenerativeUIToJSXOptions, generativeUIToJSX };
|
|
16
21
|
//# sourceMappingURL=generativeUIToJSX.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generativeUIToJSX.d.ts","names":[],"sources":["../src/generativeUIToJSX.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"generativeUIToJSX.d.ts","names":[],"sources":["../src/generativeUIToJSX.ts"],"mappings":";;UAGiB;;EAEf;;EAEA;;;;;;;;;;;iBAYc,kBACd,eACA,UAAU"}
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import { TYPE_KEY } from "./constants.js";
|
|
2
2
|
//#region src/generativeUIToJSX.ts
|
|
3
3
|
/**
|
|
4
|
-
* Serializes a generative-UI node to a JSX-like string for display
|
|
5
|
-
* "view source" of a model-produced tree. The wire form
|
|
6
|
-
* `{ $type: "Weather", id: "x" }` becomes `<Weather id="x" />`, and nested
|
|
7
|
-
* `children` render between tags: `<Card title="Hi"><Text>hello</Text></Card>`.
|
|
4
|
+
* Serializes a generative-UI node to a JSX-like string for display: the "view source" of a model-produced tree. The wire form `{ $type: "Weather", id: "x" }` becomes `<Weather id="x" />`, and nested `children` render between tags: `<Card title="Hi"><Text>hello</Text></Card>`. A model-provided `$key` becomes the JSX `key` attribute.
|
|
8
5
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
6
|
+
* By default this is a faithful textual rendering, not a parser: text children are emitted verbatim (not HTML/JSX-escaped), so the result is meant to be shown, not re-parsed. Returns `""` for nodes that aren't renderable (no `$type` yet, `null`, booleans).
|
|
7
|
+
*
|
|
8
|
+
* Pass `{ escape: true }` to make the output safe to paste back into JSX: any string child containing `<`, `>`, `&`, `{`, or `}` is emitted as a JSON-stringified expression (`{JSON.stringify(child)}`) instead of verbatim, while a string child with none of those characters still renders verbatim.
|
|
9
|
+
*
|
|
10
|
+
* Pass `{ pretty: true }` to pretty-print nested element trees with two-space indentation, while pure text children stay on one line.
|
|
13
11
|
*/
|
|
14
|
-
function generativeUIToJSX(node) {
|
|
15
|
-
return toJSX(node, 0);
|
|
12
|
+
function generativeUIToJSX(node, options) {
|
|
13
|
+
return toJSX(node, 0, options?.escape ?? false, options?.pretty ?? false, 0);
|
|
16
14
|
}
|
|
17
15
|
/**
|
|
18
16
|
* The deepest tree we serialize. Input is model-produced, so a runaway/
|
|
@@ -20,18 +18,50 @@ function generativeUIToJSX(node) {
|
|
|
20
18
|
* this depth (far beyond any real UI) we stop. Mirrors the renderer's bound.
|
|
21
19
|
*/
|
|
22
20
|
const MAX_DEPTH = 64;
|
|
23
|
-
|
|
21
|
+
/** Characters that would break JSX if emitted verbatim inside a text child. */
|
|
22
|
+
const UNSAFE_CHILD_CHARS = /[<>&{}]/;
|
|
23
|
+
function toJSX(node, depth, escape, pretty, indent) {
|
|
24
24
|
if (depth > MAX_DEPTH) return "";
|
|
25
25
|
if (node == null || typeof node === "boolean") return "";
|
|
26
|
-
if (typeof node === "string") return node;
|
|
26
|
+
if (typeof node === "string") return formatChildText(node, escape);
|
|
27
27
|
if (typeof node === "number") return String(node);
|
|
28
|
-
if (Array.isArray(node))
|
|
28
|
+
if (Array.isArray(node)) {
|
|
29
|
+
if (pretty) return collectBlockLines(node, depth, escape, indent).join("\n");
|
|
30
|
+
return node.map((child) => toJSX(child, depth + 1, escape, false, 0)).join("");
|
|
31
|
+
}
|
|
29
32
|
if (typeof node !== "object") return "";
|
|
30
|
-
const { [TYPE_KEY]: type, children, ...props } = node;
|
|
33
|
+
const { [TYPE_KEY]: type, $key, children, ...props } = node;
|
|
31
34
|
if (typeof type !== "string") return "";
|
|
32
|
-
const attrs = Object.entries(props).map(([key, value]) => formatAttr(key, value)).join("");
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
const attrs = formatAttr("key", $key) + Object.entries(props).map(([key, value]) => formatAttr(key, value)).join("");
|
|
36
|
+
if (!pretty) {
|
|
37
|
+
const inner = children === void 0 ? "" : toJSX(children, depth + 1, escape, false, 0);
|
|
38
|
+
return inner === "" ? `<${type}${attrs} />` : `<${type}${attrs}>${inner}</${type}>`;
|
|
39
|
+
}
|
|
40
|
+
const pad = " ".repeat(indent);
|
|
41
|
+
if (children === void 0 || !hasElementChild(children)) {
|
|
42
|
+
const inner = children === void 0 ? "" : toJSX(children, depth + 1, escape, false, 0);
|
|
43
|
+
return inner === "" ? `${pad}<${type}${attrs} />` : `${pad}<${type}${attrs}>${inner}</${type}>`;
|
|
44
|
+
}
|
|
45
|
+
const lines = collectBlockLines(children, depth + 1, escape, indent + 1);
|
|
46
|
+
if (lines.length === 0) return `${pad}<${type}${attrs} />`;
|
|
47
|
+
return `${pad}<${type}${attrs}>\n${lines.join("\n")}\n${pad}</${type}>`;
|
|
48
|
+
}
|
|
49
|
+
function hasElementChild(node, depth = 0) {
|
|
50
|
+
if (depth > MAX_DEPTH) return false;
|
|
51
|
+
if (Array.isArray(node)) return node.some((child) => hasElementChild(child, depth + 1));
|
|
52
|
+
return node != null && typeof node === "object" && typeof node["$type"] === "string";
|
|
53
|
+
}
|
|
54
|
+
function collectBlockLines(node, depth, escape, indent) {
|
|
55
|
+
if (depth > MAX_DEPTH) return [];
|
|
56
|
+
if (node == null || typeof node === "boolean") return [];
|
|
57
|
+
if (Array.isArray(node)) return node.flatMap((child) => collectBlockLines(child, depth + 1, escape, indent));
|
|
58
|
+
if (typeof node === "string") return [`${" ".repeat(indent)}${formatChildText(node, escape)}`];
|
|
59
|
+
if (typeof node === "number") return [`${" ".repeat(indent)}${String(node)}`];
|
|
60
|
+
const rendered = toJSX(node, depth, escape, true, indent);
|
|
61
|
+
return rendered === "" ? [] : [rendered];
|
|
62
|
+
}
|
|
63
|
+
function formatChildText(value, escape) {
|
|
64
|
+
return escape && UNSAFE_CHILD_CHARS.test(value) ? `{${JSON.stringify(value)}}` : value;
|
|
35
65
|
}
|
|
36
66
|
/** Formats one prop as a JSX attribute (`id="x"`, `count={3}`, `open`, …). */
|
|
37
67
|
function formatAttr(key, value) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generativeUIToJSX.js","names":[],"sources":["../src/generativeUIToJSX.ts"],"sourcesContent":["import { TYPE_KEY } from \"./constants\";\n\n/**\n * Serializes a generative-UI node to a JSX-like string for display
|
|
1
|
+
{"version":3,"file":"generativeUIToJSX.js","names":[],"sources":["../src/generativeUIToJSX.ts"],"sourcesContent":["import { TYPE_KEY } from \"./constants\";\n\n/** Options for {@link generativeUIToJSX}. */\nexport interface GenerativeUIToJSXOptions {\n /** Escape string children so the output is safe to paste back into a JSX file. Defaults to `false`. */\n escape?: boolean;\n /** Pretty-print nested element trees with two-space indentation. Defaults to `false`. */\n pretty?: boolean;\n}\n\n/**\n * Serializes a generative-UI node to a JSX-like string for display: the \"view source\" of a model-produced tree. The wire form `{ $type: \"Weather\", id: \"x\" }` becomes `<Weather id=\"x\" />`, and nested `children` render between tags: `<Card title=\"Hi\"><Text>hello</Text></Card>`. A model-provided `$key` becomes the JSX `key` attribute.\n *\n * By default this is a faithful textual rendering, not a parser: text children are emitted verbatim (not HTML/JSX-escaped), so the result is meant to be shown, not re-parsed. Returns `\"\"` for nodes that aren't renderable (no `$type` yet, `null`, booleans).\n *\n * Pass `{ escape: true }` to make the output safe to paste back into JSX: any string child containing `<`, `>`, `&`, `{`, or `}` is emitted as a JSON-stringified expression (`{JSON.stringify(child)}`) instead of verbatim, while a string child with none of those characters still renders verbatim.\n *\n * Pass `{ pretty: true }` to pretty-print nested element trees with two-space indentation, while pure text children stay on one line.\n */\nexport function generativeUIToJSX(\n node: unknown,\n options?: GenerativeUIToJSXOptions,\n): string {\n return toJSX(node, 0, options?.escape ?? false, options?.pretty ?? false, 0);\n}\n\n/**\n * The deepest tree we serialize. Input is model-produced, so a runaway/\n * adversarial response could nest arbitrarily deep and overflow the stack — past\n * this depth (far beyond any real UI) we stop. Mirrors the renderer's bound.\n */\nconst MAX_DEPTH = 64;\n\n/** Characters that would break JSX if emitted verbatim inside a text child. */\nconst UNSAFE_CHILD_CHARS = /[<>&{}]/;\n\nfunction toJSX(\n node: unknown,\n depth: number,\n escape: boolean,\n pretty: boolean,\n indent: number,\n): string {\n if (depth > MAX_DEPTH) return \"\";\n if (node == null || typeof node === \"boolean\") return \"\";\n if (typeof node === \"string\") return formatChildText(node, escape);\n if (typeof node === \"number\") return String(node);\n if (Array.isArray(node)) {\n if (pretty) {\n return collectBlockLines(node, depth, escape, indent).join(\"\\n\");\n }\n return node\n .map((child) => toJSX(child, depth + 1, escape, false, 0))\n .join(\"\");\n }\n if (typeof node !== \"object\") return \"\";\n\n const {\n [TYPE_KEY]: type,\n $key,\n children,\n ...props\n } = node as Record<string, unknown>;\n if (typeof type !== \"string\") return \"\";\n\n const attrs =\n formatAttr(\"key\", $key) +\n Object.entries(props)\n .map(([key, value]) => formatAttr(key, value))\n .join(\"\");\n\n if (!pretty) {\n const inner =\n children === undefined\n ? \"\"\n : toJSX(children, depth + 1, escape, false, 0);\n\n return inner === \"\"\n ? `<${type}${attrs} />`\n : `<${type}${attrs}>${inner}</${type}>`;\n }\n\n const pad = \" \".repeat(indent);\n\n if (children === undefined || !hasElementChild(children)) {\n const inner =\n children === undefined\n ? \"\"\n : toJSX(children, depth + 1, escape, false, 0);\n return inner === \"\"\n ? `${pad}<${type}${attrs} />`\n : `${pad}<${type}${attrs}>${inner}</${type}>`;\n }\n\n const lines = collectBlockLines(children, depth + 1, escape, indent + 1);\n if (lines.length === 0) {\n return `${pad}<${type}${attrs} />`;\n }\n return `${pad}<${type}${attrs}>\\n${lines.join(\"\\n\")}\\n${pad}</${type}>`;\n}\n\nfunction hasElementChild(node: unknown, depth = 0): boolean {\n if (depth > MAX_DEPTH) return false;\n if (Array.isArray(node))\n return node.some((child) => hasElementChild(child, depth + 1));\n return (\n node != null &&\n typeof node === \"object\" &&\n typeof (node as Record<string, unknown>)[TYPE_KEY] === \"string\"\n );\n}\n\nfunction collectBlockLines(\n node: unknown,\n depth: number,\n escape: boolean,\n indent: number,\n): string[] {\n if (depth > MAX_DEPTH) return [];\n if (node == null || typeof node === \"boolean\") return [];\n if (Array.isArray(node)) {\n return node.flatMap((child) =>\n collectBlockLines(child, depth + 1, escape, indent),\n );\n }\n if (typeof node === \"string\") {\n return [`${\" \".repeat(indent)}${formatChildText(node, escape)}`];\n }\n if (typeof node === \"number\") {\n return [`${\" \".repeat(indent)}${String(node)}`];\n }\n const rendered = toJSX(node, depth, escape, true, indent);\n return rendered === \"\" ? [] : [rendered];\n}\n\nfunction formatChildText(value: string, escape: boolean): string {\n return escape && UNSAFE_CHILD_CHARS.test(value)\n ? `{${JSON.stringify(value)}}`\n : value;\n}\n\n/** Formats one prop as a JSX attribute (`id=\"x\"`, `count={3}`, `open`, …). */\nfunction formatAttr(key: string, value: unknown): string {\n if (value === undefined) return \"\";\n if (value === true) return ` ${key}`;\n if (typeof value === \"string\") {\n // Plain double-quoted form when safe; expression form when a quote or\n // newline would break the attribute.\n return /[\"\\n]/.test(value)\n ? ` ${key}={${JSON.stringify(value)}}`\n : ` ${key}=\"${value}\"`;\n }\n return ` ${key}={${JSON.stringify(value)}}`;\n}\n"],"mappings":";;;;;;;;;;;AAmBA,SAAgB,kBACd,MACA,SACQ;CACR,OAAO,MAAM,MAAM,GAAG,SAAS,UAAU,OAAO,SAAS,UAAU,OAAO,CAAC;AAC7E;;;;;;AAOA,MAAM,YAAY;;AAGlB,MAAM,qBAAqB;AAE3B,SAAS,MACP,MACA,OACA,QACA,QACA,QACQ;CACR,IAAI,QAAQ,WAAW,OAAO;CAC9B,IAAI,QAAQ,QAAQ,OAAO,SAAS,WAAW,OAAO;CACtD,IAAI,OAAO,SAAS,UAAU,OAAO,gBAAgB,MAAM,MAAM;CACjE,IAAI,OAAO,SAAS,UAAU,OAAO,OAAO,IAAI;CAChD,IAAI,MAAM,QAAQ,IAAI,GAAG;EACvB,IAAI,QACF,OAAO,kBAAkB,MAAM,OAAO,QAAQ,MAAM,CAAC,CAAC,KAAK,IAAI;EAEjE,OAAO,KACJ,KAAK,UAAU,MAAM,OAAO,QAAQ,GAAG,QAAQ,OAAO,CAAC,CAAC,CAAC,CACzD,KAAK,EAAE;CACZ;CACA,IAAI,OAAO,SAAS,UAAU,OAAO;CAErC,MAAM,GACH,WAAW,MACZ,MACA,UACA,GAAG,UACD;CACJ,IAAI,OAAO,SAAS,UAAU,OAAO;CAErC,MAAM,QACJ,WAAW,OAAO,IAAI,IACtB,OAAO,QAAQ,KAAK,CAAC,CAClB,KAAK,CAAC,KAAK,WAAW,WAAW,KAAK,KAAK,CAAC,CAAC,CAC7C,KAAK,EAAE;CAEZ,IAAI,CAAC,QAAQ;EACX,MAAM,QACJ,aAAa,KAAA,IACT,KACA,MAAM,UAAU,QAAQ,GAAG,QAAQ,OAAO,CAAC;EAEjD,OAAO,UAAU,KACb,IAAI,OAAO,MAAM,OACjB,IAAI,OAAO,MAAM,GAAG,MAAM,IAAI,KAAK;CACzC;CAEA,MAAM,MAAM,KAAK,OAAO,MAAM;CAE9B,IAAI,aAAa,KAAA,KAAa,CAAC,gBAAgB,QAAQ,GAAG;EACxD,MAAM,QACJ,aAAa,KAAA,IACT,KACA,MAAM,UAAU,QAAQ,GAAG,QAAQ,OAAO,CAAC;EACjD,OAAO,UAAU,KACb,GAAG,IAAI,GAAG,OAAO,MAAM,OACvB,GAAG,IAAI,GAAG,OAAO,MAAM,GAAG,MAAM,IAAI,KAAK;CAC/C;CAEA,MAAM,QAAQ,kBAAkB,UAAU,QAAQ,GAAG,QAAQ,SAAS,CAAC;CACvE,IAAI,MAAM,WAAW,GACnB,OAAO,GAAG,IAAI,GAAG,OAAO,MAAM;CAEhC,OAAO,GAAG,IAAI,GAAG,OAAO,MAAM,KAAK,MAAM,KAAK,IAAI,EAAE,IAAI,IAAI,IAAI,KAAK;AACvE;AAEA,SAAS,gBAAgB,MAAe,QAAQ,GAAY;CAC1D,IAAI,QAAQ,WAAW,OAAO;CAC9B,IAAI,MAAM,QAAQ,IAAI,GACpB,OAAO,KAAK,MAAM,UAAU,gBAAgB,OAAO,QAAQ,CAAC,CAAC;CAC/D,OACE,QAAQ,QACR,OAAO,SAAS,YAChB,OAAQ,KAAA,aAA+C;AAE3D;AAEA,SAAS,kBACP,MACA,OACA,QACA,QACU;CACV,IAAI,QAAQ,WAAW,OAAO,CAAC;CAC/B,IAAI,QAAQ,QAAQ,OAAO,SAAS,WAAW,OAAO,CAAC;CACvD,IAAI,MAAM,QAAQ,IAAI,GACpB,OAAO,KAAK,SAAS,UACnB,kBAAkB,OAAO,QAAQ,GAAG,QAAQ,MAAM,CACpD;CAEF,IAAI,OAAO,SAAS,UAClB,OAAO,CAAC,GAAG,KAAK,OAAO,MAAM,IAAI,gBAAgB,MAAM,MAAM,GAAG;CAElE,IAAI,OAAO,SAAS,UAClB,OAAO,CAAC,GAAG,KAAK,OAAO,MAAM,IAAI,OAAO,IAAI,GAAG;CAEjD,MAAM,WAAW,MAAM,MAAM,OAAO,QAAQ,MAAM,MAAM;CACxD,OAAO,aAAa,KAAK,CAAC,IAAI,CAAC,QAAQ;AACzC;AAEA,SAAS,gBAAgB,OAAe,QAAyB;CAC/D,OAAO,UAAU,mBAAmB,KAAK,KAAK,IAC1C,IAAI,KAAK,UAAU,KAAK,EAAE,KAC1B;AACN;;AAGA,SAAS,WAAW,KAAa,OAAwB;CACvD,IAAI,UAAU,KAAA,GAAW,OAAO;CAChC,IAAI,UAAU,MAAM,OAAO,IAAI;CAC/B,IAAI,OAAO,UAAU,UAGnB,OAAO,QAAQ,KAAK,KAAK,IACrB,IAAI,IAAI,IAAI,KAAK,UAAU,KAAK,EAAE,KAClC,IAAI,IAAI,IAAI,MAAM;CAExB,OAAO,IAAI,IAAI,IAAI,KAAK,UAAU,KAAK,EAAE;AAC3C"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ALERT_TONES, ALIGNS, Action, AlertTone, Align, BUTTON_STYLES, ButtonStyle, COLORS, Color, ICON_NAMES, IMAGE_SIZE_TOKENS, IconName, 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
|
-
import { generativeUIToJSX } from "./generativeUIToJSX.js";
|
|
9
|
+
import { GenerativeUIToJSXOptions, generativeUIToJSX } from "./generativeUIToJSX.js";
|
|
7
10
|
import { renderGenerativeUI } from "./renderGenerativeUI.js";
|
|
8
|
-
import {
|
|
9
|
-
|
|
11
|
+
import { defaultGenerativeUILibrary } from "./vocabulary/index.js";
|
|
12
|
+
import "./index.shared.js";
|
|
13
|
+
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, type GenerativeUIToJSXOptions, ICON_NAMES, IMAGE_SIZE_TOKENS, type IconName, 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, ICON_NAMES, 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, ICON_NAMES, IMAGE_SIZE_TOKENS, JSONGenerativeUI, JUSTIFIES, TEXT_SIZES, TYPE_KEY, WEIGHTS, buildPresentParameters, createActionRegistry, defaultGenerativeUILibrary, defineGenerativeComponents, emptyActionRegistry, generativeUIToJSX, normalizeSpec, normalizeUINode, renderGenerativeUI };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ALERT_TONES, ALIGNS, Action, AlertTone, Align, BUTTON_STYLES, ButtonStyle, COLORS, Color, ICON_NAMES, IMAGE_SIZE_TOKENS, IconName, 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 { GenerativeUIToJSXOptions, generativeUIToJSX } from "./generativeUIToJSX.js";
|
|
10
|
+
import { renderGenerativeUI } from "./renderGenerativeUI.js";
|
|
11
|
+
import { defaultGenerativeUILibrary } from "./vocabulary/index.js";
|
|
12
|
+
import "./index.shared.js";
|
|
13
|
+
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, type GenerativeUIToJSXOptions, ICON_NAMES, IMAGE_SIZE_TOKENS, type IconName, 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, ICON_NAMES, 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, ICON_NAMES, IMAGE_SIZE_TOKENS, JSONGenerativeUI, JUSTIFIES, TEXT_SIZES, TYPE_KEY, WEIGHTS, buildPresentParameters, createActionRegistry, defaultGenerativeUILibrary, defineGenerativeComponents, emptyActionRegistry, generativeUIToJSX, normalizeSpec, normalizeUINode, renderGenerativeUI };
|