@dudousxd/nestjs-agent-react 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -111,7 +111,7 @@ function Chat() {
111
111
  | On the instance | What it is |
112
112
  |---|---|
113
113
  | `items` | The mounted window, oldest first. Each item carries `blocks`, `text`, `usage`, `timestamp`, `isStreaming`, `isLastAssistant`, and its action machines. |
114
- | `items[i].blocks` | `{ kind: 'text' \| 'reasoning' \| 'tools' \| 'sources' \| 'elicitation' \| 'ui' }`. A `ui` block is a component the server pushed (`{ id, component, props, version }`) — look `component` up in your own registry. A `tools` block is a run of CONSECUTIVE tool parts — any other part between two calls (including a `step-start` marker) ends the run. A `reasoning` block carries `isOpen`/`toggle`, open while it streams. A `sources` block appears only under `sources: true`, an `elicitation` block only under `onAnswer` — see below. |
114
+ | `items[i].blocks` | `{ kind: 'text' \| 'reasoning' \| 'tools' \| 'sources' \| 'elicitation' \| 'ui' }`. A `ui` block is a component the server pushed (`{ id, component, props, version, toolCallId }`) — draw it with `<GenerativeUI>` (below) or look `component` up in your own registry. A `tools` block is a run of CONSECUTIVE tool parts — any other part between two calls (including a `step-start` marker) ends the run. A `reasoning` block carries `isOpen`/`toggle`, open while it streams. A `sources` block appears only under `sources: true`, an `elicitation` block only under `onAnswer` — see below. |
115
115
  | `items[i].blocks[n]` (`tools`) | Also carries `calls`: the same parts, each with `{ toolCallId, name, toolKind, parentId, children, approval, isAwaitingApproval, approve, reject, error }`, and `roots`: the same calls as a tree (a call nested under another by the stream's `parentId` sits in its parent's `children`). `approval` is `{ approver, expiresAt, reason, status, remember, decidedBy, decidedVia, decisionReason }` when the runner said who has to decide, else `null` — `status` is `pending` / `approved` / `rejected` / `expired`. |
116
116
  | `items[i].copy` | `{ available, copied, copy() }` — `copied` flashes for `copyResetMs` (default 1500). |
117
117
  | `items[i].edit` | `{ available, isEditing, draft, canSave, start(), cancel(), setDraft(), save(), getTextareaProps() }`. The prop-getter focuses with the caret at the end, saves on Enter, cancels on Escape. |
@@ -348,6 +348,51 @@ type-ahead narrows the list it received; it never re-derives which skills apply.
348
348
  The shadcn `ChatComposer` wires all of this for you: pass `autocompleteSources` and it renders the
349
349
  menu (`ChatCommandPalette`, grown into the combobox's listbox) above the composer card.
350
350
 
351
+ ### Generative UI (`/genui`)
352
+
353
+ `@dudousxd/nestjs-agent-react/genui` draws server-pushed components (`ui` frames, persisted `ui[]`)
354
+ with YOUR renderers. Headless: it adds no element and no style — only what your registry renders.
355
+
356
+ ```tsx
357
+ import { GenerativeUI, type GenuiRegistry } from '@dudousxd/nestjs-agent-react/genui';
358
+ import { catalog } from './catalog'; // optional: a @dudousxd/nestjs-agent-genui catalog
359
+
360
+ const registry: GenuiRegistry = { DataTable: MyTable, Chart: MyChart, Card: MyCard, Text: MyText };
361
+
362
+ <MessageItem
363
+ message={message}
364
+ renderUi={(block) => (
365
+ <GenerativeUI
366
+ part={block}
367
+ registry={registry}
368
+ catalog={catalog}
369
+ resolveComponent={(name, version) => loadTenantComponent(name, version)}
370
+ fallback={({ reason, item }) => <UnknownComponent name={item.component} reason={reason} />}
371
+ loading={<Skeleton />}
372
+ />
373
+ )}
374
+ />;
375
+ ```
376
+
377
+ | Prop | |
378
+ |---|---|
379
+ | `part` | A transcript `ui` block, a `data-ui` message part, or a stored `{ id, component, props, version? }`. |
380
+ | `registry` | Component name → your renderer. It receives the props spread (and `children` as a tree layout node). |
381
+ | `catalog?` | Validate props before drawing (`catalog.validateSync` when it can, so no placeholder flashes). Components the catalog does not know render unvalidated. |
382
+ | `resolveComponent?(name, version)` | For components the registry lacks, e.g. a tenant's own, at the exact version a message was rendered with. Sync or async, cached per resolver/name/version. |
383
+ | `fallback?` | A node, or `({ reason: 'unknown' \| 'invalid' \| 'error', item, issues?, error? }) => node`. Default: nothing. |
384
+ | `loading?`, `onError?` | While a resolver or async validation is pending; a renderer threw (each item has its own error boundary). |
385
+
386
+ A `genui:tree` frame (tree mode) is drawn node by node through the same registry, catalog and
387
+ fallbacks, each node in its own boundary; put a `genui:tree` entry in the registry to take over.
388
+ `useGenerativeUI(part, options)` returns the state (`ready` with `Component`/`props`, `loading`,
389
+ `problem`) for your own chrome; wrap it in `<GenerativeUIScope>` when it may draw a tree.
390
+
391
+ **json-render** (optional peer `@json-render/react` >= 0.21):
392
+ `@dudousxd/nestjs-agent-react/genui/json-render` renders tree frames through json-render's
393
+ `Renderer` — `registry[GENUI_TREE_COMPONENT] = jsonRenderTree(toJsonRenderRegistry(registry))` —
394
+ plus `JsonRenderTree` and `treeToJsonRenderSpec`.
395
+
351
396
  ### Designed components, as copy-in source
352
397
 
353
398
  `MessageList`/`MessageItem`/`ChatInput` are deliberately minimal. For a styled, accessible chat
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/genui/json-render.tsx
22
+ var json_render_exports = {};
23
+ __export(json_render_exports, {
24
+ JsonRenderTree: () => JsonRenderTree,
25
+ jsonRenderTree: () => jsonRenderTree,
26
+ toJsonRenderRegistry: () => toJsonRenderRegistry,
27
+ treeToJsonRenderSpec: () => treeToJsonRenderSpec
28
+ });
29
+ module.exports = __toCommonJS(json_render_exports);
30
+ var import_react = require("@json-render/react");
31
+ var import_react2 = require("react");
32
+ function treeToJsonRenderSpec(root) {
33
+ const elements = {};
34
+ let next = 0;
35
+ const visit = /* @__PURE__ */ __name((node) => {
36
+ const id = `el-${next++}`;
37
+ const entry = {
38
+ type: node.type,
39
+ props: node.props ?? {},
40
+ children: []
41
+ };
42
+ elements[id] = entry;
43
+ for (const child of node.children ?? []) entry.children.push(visit(child));
44
+ return id;
45
+ }, "visit");
46
+ return {
47
+ root: visit(root),
48
+ elements
49
+ };
50
+ }
51
+ __name(treeToJsonRenderSpec, "treeToJsonRenderSpec");
52
+ function toJsonRenderRegistry(registry) {
53
+ return Object.fromEntries(Object.entries(registry).map(([name, Renderer2]) => [
54
+ name,
55
+ ({ element, children }) => /* @__PURE__ */ React.createElement(Renderer2, element.props ?? {}, children)
56
+ ]));
57
+ }
58
+ __name(toJsonRenderRegistry, "toJsonRenderRegistry");
59
+ function JsonRenderTree({ root, registry, initialState }) {
60
+ const spec = (0, import_react2.useMemo)(() => root === void 0 ? null : treeToJsonRenderSpec(root), [
61
+ root
62
+ ]);
63
+ if (spec === null) return null;
64
+ return /* @__PURE__ */ React.createElement(import_react.JSONUIProvider, {
65
+ registry,
66
+ ...initialState !== void 0 ? {
67
+ initialState
68
+ } : {}
69
+ }, /* @__PURE__ */ React.createElement(import_react.Renderer, {
70
+ spec,
71
+ registry
72
+ }));
73
+ }
74
+ __name(JsonRenderTree, "JsonRenderTree");
75
+ function jsonRenderTree(registry) {
76
+ return /* @__PURE__ */ __name(function JsonRenderTreeFrame({ root }) {
77
+ return /* @__PURE__ */ React.createElement(JsonRenderTree, {
78
+ registry,
79
+ ...root !== void 0 ? {
80
+ root
81
+ } : {}
82
+ });
83
+ }, "JsonRenderTreeFrame");
84
+ }
85
+ __name(jsonRenderTree, "jsonRenderTree");
86
+ // Annotate the CommonJS export names for ESM import in node:
87
+ 0 && (module.exports = {
88
+ JsonRenderTree,
89
+ jsonRenderTree,
90
+ toJsonRenderRegistry,
91
+ treeToJsonRenderSpec
92
+ });
93
+ //# sourceMappingURL=genui-json-render.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/genui/json-render.tsx"],"sourcesContent":["/**\n * Optional json-render adapter for tree frames (`@dudousxd/nestjs-agent-react/genui/json-render`).\n * Needs the optional peer `@json-render/react` (>= 0.21). Use it when your app already renders\n * json-render specs and wants tree frames to go through the same `Renderer` (its state, actions and\n * visibility machinery); otherwise `<GenerativeUI>` renders trees natively.\n *\n * ```tsx\n * const registry = { ...myComponents, [GENUI_TREE_COMPONENT]: jsonRenderTree(myJsonRenderRegistry) };\n * ```\n */\nimport { type ComponentRegistry, JSONUIProvider, Renderer } from '@json-render/react';\nimport { type ReactNode, useMemo } from 'react';\nimport type { GenerativeUIElement, GenuiRegistry, GenuiRenderer } from './types.js';\n\n/** A json-render flat spec: `{ root, elements: { [id]: { type, props, children } } }`. */\nexport interface JsonRenderFlatSpec {\n root: string;\n elements: Record<string, { type: string; props: Record<string, unknown>; children: string[] }>;\n}\n\n/** A tree frame's `root` as a json-render flat spec (ids `el-0`, `el-1`, … depth first). */\nexport function treeToJsonRenderSpec(root: GenerativeUIElement): JsonRenderFlatSpec {\n const elements: JsonRenderFlatSpec['elements'] = {};\n let next = 0;\n const visit = (node: GenerativeUIElement): string => {\n const id = `el-${next++}`;\n const entry = { type: node.type, props: node.props ?? {}, children: [] as string[] };\n elements[id] = entry;\n for (const child of node.children ?? []) entry.children.push(visit(child));\n return id;\n };\n return { root: visit(root), elements };\n}\n\n/**\n * Adapt a genui registry (renderers taking props + `children`) to a json-render registry (renderers\n * taking `{ element, children }`), so one set of components serves both.\n */\nexport function toJsonRenderRegistry(registry: GenuiRegistry): ComponentRegistry {\n return Object.fromEntries(\n Object.entries(registry).map(([name, Renderer]) => [\n name,\n ({ element, children }: { element: { props?: unknown }; children?: ReactNode }) => (\n <Renderer {...((element.props ?? {}) as Record<string, unknown>)}>{children}</Renderer>\n ),\n ]),\n );\n}\n\nexport interface JsonRenderTreeProps {\n root?: GenerativeUIElement;\n registry: ComponentRegistry;\n /** json-render state the spec's `$state` expressions read. */\n initialState?: Record<string, unknown>;\n}\n\n/** Render a tree frame's `root` with json-render. */\nexport function JsonRenderTree({ root, registry, initialState }: JsonRenderTreeProps) {\n const spec = useMemo(() => (root === undefined ? null : treeToJsonRenderSpec(root)), [root]);\n if (spec === null) return null;\n return (\n <JSONUIProvider registry={registry} {...(initialState !== undefined ? { initialState } : {})}>\n <Renderer spec={spec as never} registry={registry} />\n </JSONUIProvider>\n );\n}\n\n/** A registry entry for `genui:tree` that renders through json-render with `registry`. */\nexport function jsonRenderTree(registry: ComponentRegistry): GenuiRenderer<{\n root?: GenerativeUIElement;\n}> {\n return function JsonRenderTreeFrame({ root }: { root?: GenerativeUIElement }) {\n return <JsonRenderTree registry={registry} {...(root !== undefined ? { root } : {})} />;\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;AAUA,mBAAiE;AACjE,IAAAA,gBAAwC;AAUjC,SAASC,qBAAqBC,MAAyB;AAC5D,QAAMC,WAA2C,CAAC;AAClD,MAAIC,OAAO;AACX,QAAMC,QAAQ,wBAACC,SAAAA;AACb,UAAMC,KAAK,MAAMH,MAAAA;AACjB,UAAMI,QAAQ;MAAEC,MAAMH,KAAKG;MAAMC,OAAOJ,KAAKI,SAAS,CAAC;MAAGC,UAAU,CAAA;IAAe;AACnFR,aAASI,EAAAA,IAAMC;AACf,eAAWI,SAASN,KAAKK,YAAY,CAAA,EAAIH,OAAMG,SAASE,KAAKR,MAAMO,KAAAA,CAAAA;AACnE,WAAOL;EACT,GANc;AAOd,SAAO;IAAEL,MAAMG,MAAMH,IAAAA;IAAOC;EAAS;AACvC;AAXgBF;AAiBT,SAASa,qBAAqBC,UAAuB;AAC1D,SAAOC,OAAOC,YACZD,OAAOE,QAAQH,QAAAA,EAAUI,IAAI,CAAC,CAACC,MAAMC,SAAAA,MAAc;IACjDD;IACA,CAAC,EAAEE,SAASX,SAAQ,MAClB,sBAAA,cAACU,WAAeC,QAAQZ,SAAS,CAAC,GAAiCC,QAAAA;GAEtE,CAAA;AAEL;AATgBG;AAmBT,SAASS,eAAe,EAAErB,MAAMa,UAAUS,aAAY,GAAuB;AAClF,QAAMC,WAAOC,uBAAQ,MAAOxB,SAASyB,SAAY,OAAO1B,qBAAqBC,IAAAA,GAAQ;IAACA;GAAK;AAC3F,MAAIuB,SAAS,KAAM,QAAO;AAC1B,SACE,sBAAA,cAACG,6BAAAA;IAAeb;IAAqB,GAAIS,iBAAiBG,SAAY;MAAEH;IAAa,IAAI,CAAC;KACxF,sBAAA,cAACH,uBAAAA;IAASI;IAAqBV;;AAGrC;AARgBQ;AAWT,SAASM,eAAed,UAA2B;AAGxD,SAAO,gCAASe,oBAAoB,EAAE5B,KAAI,GAAkC;AAC1E,WAAO,sBAAA,cAACqB,gBAAAA;MAAeR;MAAqB,GAAIb,SAASyB,SAAY;QAAEzB;MAAK,IAAI,CAAC;;EACnF,GAFO;AAGT;AANgB2B;","names":["import_react","treeToJsonRenderSpec","root","elements","next","visit","node","id","entry","type","props","children","child","push","toJsonRenderRegistry","registry","Object","fromEntries","entries","map","name","Renderer","element","JsonRenderTree","initialState","spec","useMemo","undefined","JSONUIProvider","jsonRenderTree","JsonRenderTreeFrame"]}
@@ -0,0 +1,34 @@
1
+ import * as React from 'react';
2
+ import { ComponentRegistry } from '@json-render/react';
3
+ import { c as GenerativeUIElement, i as GenuiRenderer, h as GenuiRegistry } from './types-DFD-soWU.cjs';
4
+
5
+ /** A json-render flat spec: `{ root, elements: { [id]: { type, props, children } } }`. */
6
+ interface JsonRenderFlatSpec {
7
+ root: string;
8
+ elements: Record<string, {
9
+ type: string;
10
+ props: Record<string, unknown>;
11
+ children: string[];
12
+ }>;
13
+ }
14
+ /** A tree frame's `root` as a json-render flat spec (ids `el-0`, `el-1`, … depth first). */
15
+ declare function treeToJsonRenderSpec(root: GenerativeUIElement): JsonRenderFlatSpec;
16
+ /**
17
+ * Adapt a genui registry (renderers taking props + `children`) to a json-render registry (renderers
18
+ * taking `{ element, children }`), so one set of components serves both.
19
+ */
20
+ declare function toJsonRenderRegistry(registry: GenuiRegistry): ComponentRegistry;
21
+ interface JsonRenderTreeProps {
22
+ root?: GenerativeUIElement;
23
+ registry: ComponentRegistry;
24
+ /** json-render state the spec's `$state` expressions read. */
25
+ initialState?: Record<string, unknown>;
26
+ }
27
+ /** Render a tree frame's `root` with json-render. */
28
+ declare function JsonRenderTree({ root, registry, initialState }: JsonRenderTreeProps): React.JSX.Element | null;
29
+ /** A registry entry for `genui:tree` that renders through json-render with `registry`. */
30
+ declare function jsonRenderTree(registry: ComponentRegistry): GenuiRenderer<{
31
+ root?: GenerativeUIElement;
32
+ }>;
33
+
34
+ export { type JsonRenderFlatSpec, JsonRenderTree, type JsonRenderTreeProps, jsonRenderTree, toJsonRenderRegistry, treeToJsonRenderSpec };
@@ -0,0 +1,34 @@
1
+ import * as React from 'react';
2
+ import { ComponentRegistry } from '@json-render/react';
3
+ import { c as GenerativeUIElement, i as GenuiRenderer, h as GenuiRegistry } from './types-DFD-soWU.js';
4
+
5
+ /** A json-render flat spec: `{ root, elements: { [id]: { type, props, children } } }`. */
6
+ interface JsonRenderFlatSpec {
7
+ root: string;
8
+ elements: Record<string, {
9
+ type: string;
10
+ props: Record<string, unknown>;
11
+ children: string[];
12
+ }>;
13
+ }
14
+ /** A tree frame's `root` as a json-render flat spec (ids `el-0`, `el-1`, … depth first). */
15
+ declare function treeToJsonRenderSpec(root: GenerativeUIElement): JsonRenderFlatSpec;
16
+ /**
17
+ * Adapt a genui registry (renderers taking props + `children`) to a json-render registry (renderers
18
+ * taking `{ element, children }`), so one set of components serves both.
19
+ */
20
+ declare function toJsonRenderRegistry(registry: GenuiRegistry): ComponentRegistry;
21
+ interface JsonRenderTreeProps {
22
+ root?: GenerativeUIElement;
23
+ registry: ComponentRegistry;
24
+ /** json-render state the spec's `$state` expressions read. */
25
+ initialState?: Record<string, unknown>;
26
+ }
27
+ /** Render a tree frame's `root` with json-render. */
28
+ declare function JsonRenderTree({ root, registry, initialState }: JsonRenderTreeProps): React.JSX.Element | null;
29
+ /** A registry entry for `genui:tree` that renders through json-render with `registry`. */
30
+ declare function jsonRenderTree(registry: ComponentRegistry): GenuiRenderer<{
31
+ root?: GenerativeUIElement;
32
+ }>;
33
+
34
+ export { type JsonRenderFlatSpec, JsonRenderTree, type JsonRenderTreeProps, jsonRenderTree, toJsonRenderRegistry, treeToJsonRenderSpec };
@@ -0,0 +1,67 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
4
+ // src/genui/json-render.tsx
5
+ import { JSONUIProvider, Renderer } from "@json-render/react";
6
+ import { useMemo } from "react";
7
+ function treeToJsonRenderSpec(root) {
8
+ const elements = {};
9
+ let next = 0;
10
+ const visit = /* @__PURE__ */ __name((node) => {
11
+ const id = `el-${next++}`;
12
+ const entry = {
13
+ type: node.type,
14
+ props: node.props ?? {},
15
+ children: []
16
+ };
17
+ elements[id] = entry;
18
+ for (const child of node.children ?? []) entry.children.push(visit(child));
19
+ return id;
20
+ }, "visit");
21
+ return {
22
+ root: visit(root),
23
+ elements
24
+ };
25
+ }
26
+ __name(treeToJsonRenderSpec, "treeToJsonRenderSpec");
27
+ function toJsonRenderRegistry(registry) {
28
+ return Object.fromEntries(Object.entries(registry).map(([name, Renderer2]) => [
29
+ name,
30
+ ({ element, children }) => /* @__PURE__ */ React.createElement(Renderer2, element.props ?? {}, children)
31
+ ]));
32
+ }
33
+ __name(toJsonRenderRegistry, "toJsonRenderRegistry");
34
+ function JsonRenderTree({ root, registry, initialState }) {
35
+ const spec = useMemo(() => root === void 0 ? null : treeToJsonRenderSpec(root), [
36
+ root
37
+ ]);
38
+ if (spec === null) return null;
39
+ return /* @__PURE__ */ React.createElement(JSONUIProvider, {
40
+ registry,
41
+ ...initialState !== void 0 ? {
42
+ initialState
43
+ } : {}
44
+ }, /* @__PURE__ */ React.createElement(Renderer, {
45
+ spec,
46
+ registry
47
+ }));
48
+ }
49
+ __name(JsonRenderTree, "JsonRenderTree");
50
+ function jsonRenderTree(registry) {
51
+ return /* @__PURE__ */ __name(function JsonRenderTreeFrame({ root }) {
52
+ return /* @__PURE__ */ React.createElement(JsonRenderTree, {
53
+ registry,
54
+ ...root !== void 0 ? {
55
+ root
56
+ } : {}
57
+ });
58
+ }, "JsonRenderTreeFrame");
59
+ }
60
+ __name(jsonRenderTree, "jsonRenderTree");
61
+ export {
62
+ JsonRenderTree,
63
+ jsonRenderTree,
64
+ toJsonRenderRegistry,
65
+ treeToJsonRenderSpec
66
+ };
67
+ //# sourceMappingURL=genui-json-render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/genui/json-render.tsx"],"sourcesContent":["/**\n * Optional json-render adapter for tree frames (`@dudousxd/nestjs-agent-react/genui/json-render`).\n * Needs the optional peer `@json-render/react` (>= 0.21). Use it when your app already renders\n * json-render specs and wants tree frames to go through the same `Renderer` (its state, actions and\n * visibility machinery); otherwise `<GenerativeUI>` renders trees natively.\n *\n * ```tsx\n * const registry = { ...myComponents, [GENUI_TREE_COMPONENT]: jsonRenderTree(myJsonRenderRegistry) };\n * ```\n */\nimport { type ComponentRegistry, JSONUIProvider, Renderer } from '@json-render/react';\nimport { type ReactNode, useMemo } from 'react';\nimport type { GenerativeUIElement, GenuiRegistry, GenuiRenderer } from './types.js';\n\n/** A json-render flat spec: `{ root, elements: { [id]: { type, props, children } } }`. */\nexport interface JsonRenderFlatSpec {\n root: string;\n elements: Record<string, { type: string; props: Record<string, unknown>; children: string[] }>;\n}\n\n/** A tree frame's `root` as a json-render flat spec (ids `el-0`, `el-1`, … depth first). */\nexport function treeToJsonRenderSpec(root: GenerativeUIElement): JsonRenderFlatSpec {\n const elements: JsonRenderFlatSpec['elements'] = {};\n let next = 0;\n const visit = (node: GenerativeUIElement): string => {\n const id = `el-${next++}`;\n const entry = { type: node.type, props: node.props ?? {}, children: [] as string[] };\n elements[id] = entry;\n for (const child of node.children ?? []) entry.children.push(visit(child));\n return id;\n };\n return { root: visit(root), elements };\n}\n\n/**\n * Adapt a genui registry (renderers taking props + `children`) to a json-render registry (renderers\n * taking `{ element, children }`), so one set of components serves both.\n */\nexport function toJsonRenderRegistry(registry: GenuiRegistry): ComponentRegistry {\n return Object.fromEntries(\n Object.entries(registry).map(([name, Renderer]) => [\n name,\n ({ element, children }: { element: { props?: unknown }; children?: ReactNode }) => (\n <Renderer {...((element.props ?? {}) as Record<string, unknown>)}>{children}</Renderer>\n ),\n ]),\n );\n}\n\nexport interface JsonRenderTreeProps {\n root?: GenerativeUIElement;\n registry: ComponentRegistry;\n /** json-render state the spec's `$state` expressions read. */\n initialState?: Record<string, unknown>;\n}\n\n/** Render a tree frame's `root` with json-render. */\nexport function JsonRenderTree({ root, registry, initialState }: JsonRenderTreeProps) {\n const spec = useMemo(() => (root === undefined ? null : treeToJsonRenderSpec(root)), [root]);\n if (spec === null) return null;\n return (\n <JSONUIProvider registry={registry} {...(initialState !== undefined ? { initialState } : {})}>\n <Renderer spec={spec as never} registry={registry} />\n </JSONUIProvider>\n );\n}\n\n/** A registry entry for `genui:tree` that renders through json-render with `registry`. */\nexport function jsonRenderTree(registry: ComponentRegistry): GenuiRenderer<{\n root?: GenerativeUIElement;\n}> {\n return function JsonRenderTreeFrame({ root }: { root?: GenerativeUIElement }) {\n return <JsonRenderTree registry={registry} {...(root !== undefined ? { root } : {})} />;\n };\n}\n"],"mappings":";;;;AAUA,SAAiCA,gBAAgBC,gBAAgB;AACjE,SAAyBC,eAAe;AAUjC,SAASC,qBAAqBC,MAAyB;AAC5D,QAAMC,WAA2C,CAAC;AAClD,MAAIC,OAAO;AACX,QAAMC,QAAQ,wBAACC,SAAAA;AACb,UAAMC,KAAK,MAAMH,MAAAA;AACjB,UAAMI,QAAQ;MAAEC,MAAMH,KAAKG;MAAMC,OAAOJ,KAAKI,SAAS,CAAC;MAAGC,UAAU,CAAA;IAAe;AACnFR,aAASI,EAAAA,IAAMC;AACf,eAAWI,SAASN,KAAKK,YAAY,CAAA,EAAIH,OAAMG,SAASE,KAAKR,MAAMO,KAAAA,CAAAA;AACnE,WAAOL;EACT,GANc;AAOd,SAAO;IAAEL,MAAMG,MAAMH,IAAAA;IAAOC;EAAS;AACvC;AAXgBF;AAiBT,SAASa,qBAAqBC,UAAuB;AAC1D,SAAOC,OAAOC,YACZD,OAAOE,QAAQH,QAAAA,EAAUI,IAAI,CAAC,CAACC,MAAMC,SAAAA,MAAc;IACjDD;IACA,CAAC,EAAEE,SAASX,SAAQ,MAClB,sBAAA,cAACU,WAAeC,QAAQZ,SAAS,CAAC,GAAiCC,QAAAA;GAEtE,CAAA;AAEL;AATgBG;AAmBT,SAASS,eAAe,EAAErB,MAAMa,UAAUS,aAAY,GAAuB;AAClF,QAAMC,OAAOC,QAAQ,MAAOxB,SAASyB,SAAY,OAAO1B,qBAAqBC,IAAAA,GAAQ;IAACA;GAAK;AAC3F,MAAIuB,SAAS,KAAM,QAAO;AAC1B,SACE,sBAAA,cAACG,gBAAAA;IAAeb;IAAqB,GAAIS,iBAAiBG,SAAY;MAAEH;IAAa,IAAI,CAAC;KACxF,sBAAA,cAACH,UAAAA;IAASI;IAAqBV;;AAGrC;AARgBQ;AAWT,SAASM,eAAed,UAA2B;AAGxD,SAAO,gCAASe,oBAAoB,EAAE5B,KAAI,GAAkC;AAC1E,WAAO,sBAAA,cAACqB,gBAAAA;MAAeR;MAAqB,GAAIb,SAASyB,SAAY;QAAEzB;MAAK,IAAI,CAAC;;EACnF,GAFO;AAGT;AANgB2B;","names":["JSONUIProvider","Renderer","useMemo","treeToJsonRenderSpec","root","elements","next","visit","node","id","entry","type","props","children","child","push","toJsonRenderRegistry","registry","Object","fromEntries","entries","map","name","Renderer","element","JsonRenderTree","initialState","spec","useMemo","undefined","JSONUIProvider","jsonRenderTree","JsonRenderTreeFrame"]}