getsyntux 0.7.0 → 0.8.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
@@ -10,15 +10,22 @@ You give it a <code>value</code> and it designs the UI to display it.
10
10
 
11
11
  ---
12
12
 
13
- https://github.com/user-attachments/assets/694d4646-c36d-4c19-a111-86e546484101
13
+ https://github.com/user-attachments/assets/c85de55d-21f3-43ff-8bd3-d6ede2171447
14
+
15
+ *syntux* is designed to **display data**. Do not let this fact intimidate you - that is simply a testament to how token-efficient it is.
16
+
17
+ For instance, if you provide an array `value` with 10,000 items, it will cost you the same as one with 10 items. **That is how efficient syntux is**.
18
+
19
+ ### Features
14
20
 
15
21
  - ⚡ **Streamable** - display UI as you generate.
16
22
  - 🎨 **Custom Components** - use your own React components.
17
23
  - 💾 **Cacheable** - reuse generated UIs with new values.
24
+ - 🔄 **Reactive** - update the UI programmatically.
18
25
 
19
26
  **How does it work?** *syntux* generates a JSON-DSL to represent the UI, known as the React Interface Schema. The specifics are in the FAQ [below](#faq).
20
27
 
21
- <h3 align="center" margin="0"><a href="https://github.com/puffinsoft/syntux/wiki">➡️ view documentation</a></h3>
28
+ <h3 align="center" margin="0"><a href="https://docs.getsyntux.com/">➡️ view documentation</a></h3>
22
29
 
23
30
  ---
24
31
 
@@ -45,7 +52,7 @@ const valueToDisplay = {
45
52
  *syntux* takes the `value` into consideration and designs a UI to best display it. `value` can be anything; an object, array or primitive.
46
53
 
47
54
  > [!TIP]
48
- > If you are passing in a **large array** as a value, or an object with untrusted input, use the `skeletonize` property. See [the explanation](https://github.com/puffinsoft/syntux/wiki/FAQ#handling-untrusted-input--large-arrays).
55
+ > If you are passing in a **large array** as a value, or an object with untrusted input, use the `skeletonize` property. See [the explanation](https://docs.getsyntux.com/advanced#skeletonize-property).
49
56
 
50
57
  ### Installation
51
58
 
@@ -90,13 +97,23 @@ export default function Home(){
90
97
  Cache generated UI based on a user ID:
91
98
 
92
99
  ```jsx
93
- const cache: Map<number, string> = new Map();
94
- export default function Home(){
95
- const userID = 10;
96
- const valueToDisplay = { ... };
97
- return <GeneratedUI cached={cache.get(userID)} onGenerate={(result) => {
98
- cache.set(userID, result)
99
- }} model={anthropic("claude-sonnet-4-5")} value={valueToDisplay} />
100
+ const cache: Map<number, string> = new Map(); // user id → UI schema
101
+
102
+ export default function Home() {
103
+ const userID = 10;
104
+ const valueToDisplay = { ... };
105
+
106
+ return (
107
+ <GeneratedUI
108
+ cached={cache.get(userID)}
109
+ onGenerate={(result) => {
110
+ cache.set(userID, result);
111
+ }}
112
+
113
+ model={anthropic("claude-sonnet-4-5")}
114
+ value={valueToDisplay}
115
+ />
116
+ );
100
117
  }
101
118
  ```
102
119
 
@@ -105,64 +122,122 @@ export default function Home(){
105
122
  Use your own components, or someone else's (a library):
106
123
 
107
124
  ```jsx
108
- import { CustomOne, CustomTwo } from '@/my_components'
109
- export default function Home(){
110
- const valueToDisplay = { ... };
111
-
112
- <GeneratedUI components={[
113
- { name: 'Button', props: "{ color: string, text: string }", component: CustomOne },
114
- { name: 'Input', props: "{ initial: string, disabled: boolean }", component: CustomTwo, context: "Creates an input field with an (initial) value. Can be disabled." }
115
- ]} />
125
+ import { CustomOne, CustomTwo } from "@/my_components";
126
+
127
+ export default function Home() {
128
+ const valueToDisplay = { ... };
129
+
130
+ return (
131
+ <GeneratedUI
132
+ components={[{
133
+ name: "Button",
134
+ props: "{ color: string, text: string }",
135
+ component: CustomOne,
136
+ }, {
137
+ name: "Input",
138
+ props: "{ initial: string, disabled: boolean }",
139
+ component: CustomTwo,
140
+ context: "Creates an input field with an (initial) value. Can be disabled.",
141
+ }]}
142
+
143
+ model={anthropic("claude-sonnet-4-5")}
144
+ value={valueToDisplay}
145
+ />
146
+ );
116
147
  }
117
148
  ```
118
149
 
119
150
  <sup>
120
151
 
121
- **Note**: the `components` array above can be generated automatically with `npx getsyntux generate-defs <component.tsx>`. See the [documentation](https://github.com/puffinsoft/syntux/wiki).
152
+ **Note**: the `components` array above can be generated automatically with `npx getsyntux generate-defs <component.tsx>`. See the [documentation](https://docs.getsyntux.com/api#generate-defs).
122
153
 
123
154
  </sup>
124
155
 
125
156
  Make sure components are marked with `"use client"`.
126
157
 
127
- #### Update value (interactivity)
158
+ #### Update value (static)
128
159
 
129
160
  Use the `useSyntux` hook to retrieve and update the `value` inside a custom component:
130
161
 
131
162
  ```jsx
132
163
  "use client";
133
164
 
134
- export default function CustomComponent(){
135
- const { value, setValue } = useSyntux();
136
-
137
- return (
138
- <button onClick={() => {
139
- setValue("new value!")
140
- }}>${value}</button>
141
- );
165
+ export default function CustomComponent() {
166
+ const { value, setValue } = useSyntux();
167
+
168
+ return (
169
+ <button
170
+ onClick={() => {
171
+ const newArr = [...value];
172
+ newArr.push({ ... });
173
+ setValue(newArr);
174
+ }}
175
+ >
176
+ Add value
177
+ </button>
178
+ );
142
179
  }
143
180
  ```
144
181
 
145
- #### Custom actions
182
+ #### Regenerate UI (dynamic)
183
+
184
+ Provide the `rerender` prop a server action.
146
185
 
147
- Perform server actions, attached automatically to component events:
186
+ **The server action is already provided.** However, you will need to configure it (i.e., add an API key etc,.)
148
187
 
149
188
  ```jsx
150
- import { defineTool } from "getsyntux";
189
+ import { rerenderAction } from "@/lib/getsyntux/RerenderHandler"; // preinstalled
151
190
 
152
- export default function Home(){
153
- const valueToDisplay = { ... };
191
+ <GeneratedUI
192
+ model={anthropic("claude-sonnet-4-5")}
193
+ value={valueToDisplay}
194
+ rerender={rerenderAction}
195
+ />
196
+ ```
197
+
198
+ Inside a custom component, use the `useSyntux` hook and provide a hint to regenerate the UI:
154
199
 
155
- <GeneratedUI actions = {{
156
- "delete": defineTool(async (id: string) => { "use server"; /* ... */ }, "id: string", "deletes post with id"),
157
- "refresh": defineTool(async () => { "use server"; /* ... */})
158
- }} />
200
+ ```jsx
201
+ "use client";
202
+
203
+ export default function CustomComponent() {
204
+ const { value, setValue } = useSyntux();
205
+
206
+ return (
207
+ <button
208
+ onClick={() => {
209
+ setValue(value, {
210
+ regenerate: true, // if false, treated as static
211
+ hint: "Change the style to be more..."
212
+ })
213
+ }}
214
+ >
215
+ Update UI!
216
+ </button>
217
+ );
159
218
  }
160
219
  ```
161
- <sup>
162
220
 
163
- **Note**: The name of the action should specify its purpose (it is seen by the LLM). Use `defineTool` to add further context to actions. See the [documentation](https://github.com/puffinsoft/syntux/wiki).
221
+ The new user interface will be streamed.
164
222
 
165
- </sup>
223
+ #### Customize animation
224
+
225
+ By default, new elements fade in from below when mounted.
226
+
227
+ This motion cannot yet be customized. However, the duration and offset can, using the `animate` property:
228
+
229
+ ```jsx
230
+ <GeneratedUI
231
+ model={anthropic("claude-sonnet-4-5")}
232
+ value={valueToDisplay}
233
+ animate={{
234
+ offset: 10, // pixels
235
+ duration: 100 // ms
236
+ }}
237
+ />
238
+ ```
239
+
240
+ In order to disable the animation, set `offset` to 0 or `duration` to 0.
166
241
 
167
242
  ---
168
243
 
@@ -171,7 +246,7 @@ export default function Home(){
171
246
  <details>
172
247
  <summary>How expensive is generation?</summary>
173
248
 
174
- *syntux* is highly optimized to save tokens. See [here](https://github.com/puffinsoft/syntux/wiki/FAQ#how-expensive-is-this) for a cost estimation table and an explanation.
249
+ *syntux* is highly optimized to save tokens. See [here](https://docs.getsyntux.com/advanced#cost-estimation) for a cost estimation table and an explanation.
175
250
  </details>
176
251
 
177
252
  <details>
package/dist/client.d.mts CHANGED
@@ -2,18 +2,19 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { StreamableValue } from '@ai-sdk/rsc';
3
3
  import * as react from 'react';
4
4
  import react__default, { JSX, ComponentType } from 'react';
5
- import { C as ContextfulAction, b as ComponentMap, a as ChildrenMap } from './types-B7z31wIq.mjs';
5
+ import { A as AnimateOptions, R as RerenderContext, a as ComponentMap, C as ChildrenMap, b as RerenderOptions } from './types-0XgxLwqz.mjs';
6
6
 
7
7
  /**
8
8
  * Client wrapper for Renderer that handles streaming and parsing with server.
9
9
  */
10
- declare function GeneratedClient({ value, allowedComponents, inputStream, placeholder, actions, errorFallback }: {
10
+ declare function GeneratedClient({ value, allowedComponents, inputStream, placeholder, errorFallback, animate, rerender }: {
11
11
  value: any;
12
12
  allowedComponents: Record<string, react__default.ComponentType<any> | string>;
13
13
  inputStream: StreamableValue<string>;
14
14
  placeholder?: JSX.Element;
15
- actions?: Record<string, ContextfulAction>;
16
15
  errorFallback?: JSX.Element;
16
+ animate?: AnimateOptions;
17
+ rerender: RerenderContext;
17
18
  }): react_jsx_runtime.JSX.Element;
18
19
 
19
20
  interface RendererProps {
@@ -23,7 +24,7 @@ interface RendererProps {
23
24
  allowedComponents: Record<string, ComponentType<any> | string>;
24
25
  global: any;
25
26
  local: any;
26
- actions: Record<string, ContextfulAction>;
27
+ animate?: AnimateOptions;
27
28
  }
28
29
  /**
29
30
  * Renders a UISchema recursively, in accordance to the spec.
@@ -32,7 +33,7 @@ declare function Renderer(props: RendererProps): react_jsx_runtime.JSX.Element;
32
33
 
33
34
  type SyntuxContextType = {
34
35
  value: any;
35
- setValue: (arg0: any) => void;
36
+ setValue: (value: any, options?: RerenderOptions) => Promise<null> | null;
36
37
  };
37
38
  declare const SyntuxContext: react.Context<SyntuxContextType>;
38
39
  declare function useSyntux(): SyntuxContextType;
package/dist/client.mjs CHANGED
@@ -1,3 +1,3 @@
1
- "use client";import{readStreamableValue as O}from"@ai-sdk/rsc";import{useEffect as j,useMemo as k,useReducer as D,useRef as G,useState as I}from"react";var S=class{buffer="";schema={childrenMap:{},componentMap:{},root:null};addDelta(r){this.buffer+=r;let e=this.buffer.split(`
2
- `);return e.length>1?(e.slice(0,e.length-1).forEach(o=>this.handleLine(o)),this.buffer=e[e.length-1],!0):!1}handleLine(r){try{let e=JSON.parse(r),{childrenMap:o,componentMap:n}=this.schema;n[e.id]=e,e.parentId===null?this.schema.root=e:(o[e.parentId]||(o[e.parentId]=[]),o[e.parentId].push(e.id))}catch{}}finish(){this.handleLine(this.buffer),this.buffer=""}};import{Fragment as U}from"react";import{Fragment as A,jsx as d}from"react/jsx-runtime";import{createElement as X}from"react";var P=(t,r)=>r==="$"?t:r.split(".").reduce((e,o)=>e==null?void 0:e[o],t),b=(t,r,e)=>e.startsWith("$item.")?(e=e.slice(6),P(r,e)):e==="$item"?r:P(t,e),$=new Set(["dangerouslySetInnerHTML"]),T=(t,r,e,o)=>{if(!e)return e;if("$action"in e){let n=o[e.$action];if(!n)return()=>{};let i=e.args.map(s=>s&&typeof s=="object"&&"$bind"in s?b(t,r,s.$bind):s);return s=>{n.fn(...i)}}if("$bind"in e){let n=b(t,r,e.$bind);return Object.keys(n).forEach(i=>{$.has(i)&&delete n[i]}),n}return Object.keys(e).forEach(n=>{if($.has(n)){delete e[n];return}let i=e[n];typeof i=="object"&&(e[n]=T(t,r,i,o))}),e},w=(t,r,e)=>typeof e=="object"?b(t,r,e.$bind):e;function g(t){var f,m;let{id:r,componentMap:e,childrenMap:o,global:n,local:i,allowedComponents:s,actions:M}=t,a=e[r];if(a.type==="TEXT")return d(A,{children:w(n,i,a.content)});let c=(f=a.props)==null?void 0:f.source;if(a.type==="__ForEach__"&&c){let l=b(n,i,c);if(!Array.isArray(l))return null;let p=o[a.id];return d(A,{children:p==null?void 0:p.map((V,N)=>d(U,{children:l.map((J,L)=>X(g,{...t,id:V,local:J,key:L}))},N))})}let h=s[a.type]||a.type,x=T(n,i,a.props,M),u=w(n,i,a.content),R=((m=o[a.id])==null?void 0:m.map((l,p)=>d(g,{...t,id:l},p)))||[],C=[u,...R].filter(l=>l!=null);return C.length>0?d(h,{...x,children:C}):d(h,{...x})}import{createContext as _,useContext as F}from"react";var v=_(null);function Y(){let t=F(v);if(!t)throw new Error("useSyntux must be used inside a GeneratedUI.");return t}import{Fragment as E,jsx as y}from"react/jsx-runtime";function ce({value:t,allowedComponents:r,inputStream:e,placeholder:o,actions:n,errorFallback:i}){var f;let[s,M]=I(t),[,a]=D(m=>m+1,0),c=G(null),[h,x]=I(!1);j(()=>{c.current=new S,(async()=>{for await(let l of O(e))c.current&&l!==void 0&&c.current.addDelta(l)&&a()})().then(()=>{c.current.finish(),a()}).catch(()=>{x(!0)})},[e]);let u=(f=c==null?void 0:c.current)==null?void 0:f.schema,R=k(()=>({value:s,setValue:M}),[s]),C=()=>h&&i?y(E,{children:i}):u!=null&&u.root?y(g,{id:u.root.id,componentMap:u.componentMap,childrenMap:u.childrenMap,allowedComponents:r,global:s,local:s,actions:n||{}}):y(E,{children:o});return y(E,{children:y(v.Provider,{value:R,children:C()})})}export{ce as GeneratedClient,g as Renderer,v as SyntuxContext,Y as useSyntux};
1
+ "use client";import{readStreamableValue as W}from"@ai-sdk/rsc";import{useEffect as J,useMemo as z,useReducer as B,useRef as K,useState as I}from"react";var R=class{buffer="";total="";schema={childrenMap:{},componentMap:{},root:null};addDelta(t){this.total+=t,this.buffer+=t;let e=this.buffer.split(`
2
+ `);return e.length>1?(e.slice(0,e.length-1).forEach(n=>this.handleLine(n)),this.buffer=e[e.length-1],!0):!1}handleLine(t){try{let e=JSON.parse(t),{childrenMap:n,componentMap:a}=this.schema;a[e.id]=e,e.parentId===null?this.schema.root=e:(n[e.parentId]||(n[e.parentId]=[]),n[e.parentId].push(e.id))}catch{}}finish(){this.handleLine(this.buffer),this.buffer=""}};import{Fragment as D,useEffect as G,useState as Y}from"react";import{Fragment as F,jsx as h}from"react/jsx-runtime";import{createElement as j}from"react";var T=(r,t)=>t==="$"?r:t.split(".").reduce((e,n)=>e==null?void 0:e[n],r),E=(r,t,e)=>e.startsWith("$item.")?(e=e.slice(6),T(t,e)):e==="$item"?t:T(r,e),$=new Set(["dangerouslySetInnerHTML"]),U=(r,t,e)=>{if(!e)return e;if("$bind"in e){let n=E(r,t,e.$bind);return Object.keys(n).forEach(a=>{$.has(a)&&delete n[a]}),n}return Object.keys(e).forEach(n=>{if($.has(n)){delete e[n];return}let a=e[n];typeof a=="object"&&(e[n]=U(r,t,a))}),e},N=(r,t,e)=>typeof e=="object"?E(r,t,e.$bind):e;function v(r){var S,u,y;let[t,e]=Y(!1);G(()=>{let o=requestAnimationFrame(()=>e(!0));return()=>cancelAnimationFrame(o)},[]);let{id:n,componentMap:a,childrenMap:b,global:p,local:m,allowedComponents:g,animate:i}=r,s=a[n];if(s.type==="TEXT")return h(F,{children:N(p,m,s.content)});let x=(S=s.props)==null?void 0:S.source;if(s.type==="__ForEach__"&&x){let o=E(p,m,x);if(!Array.isArray(o))return null;let f=b[s.id];return h(F,{children:f==null?void 0:f.map((L,X)=>h(D,{children:o.map((_,k)=>j(v,{...r,id:L,local:_,key:k}))},X))})}let l=g[s.type]||s.type,c={...U(p,m,s.props)};c.style={...c.style||{}};let d=((u=c.style)==null?void 0:u.opacity)??1;c.style.opacity=t?d:0,c.style.transform=t?"translateY(0)":`translateY(${(i==null?void 0:i.offset)??10}px)`,c.style.transition=`opacity ${(i==null?void 0:i.duration)??200}ms ease-out, transform ${(i==null?void 0:i.duration)??200}ms ease-out`,c.style.willChange="opacity, transform";let P=N(p,m,s.content),w=((y=b[s.id])==null?void 0:y.map((o,f)=>h(v,{...r,id:o},f)))||[],M=[P,...w].filter(o=>o!=null);return M.length>0?h(l,{...c,children:M}):h(l,{...c})}import{createContext as q,useContext as H}from"react";var O=q(null);function se(){let r=H(O);if(!r)throw new Error("useSyntux must be used inside a GeneratedUI.");return r}import{Fragment as V,jsx as C}from"react/jsx-runtime";function ye({value:r,allowedComponents:t,inputStream:e,placeholder:n,errorFallback:a,animate:b,rerender:p}){var S;let[m,g]=I(r),[i,s]=I(e),[,x]=B(u=>u+1,0),l=K(null),[A,c]=I(!1);J(()=>{s(e)},[e]),J(()=>{let u=!0;return l.current=new R,(async()=>{var o;try{for await(let f of W(i)){if(!u)break;l.current&&f!==void 0&&l.current.addDelta(f)&&x()}u&&((o=l.current)==null||o.finish(),x())}catch{u&&c(!0)}})(),()=>{u=!1}},[i]);let d=(S=l==null?void 0:l.current)==null?void 0:S.schema,P=()=>A&&a?C(V,{children:a}):d!=null&&d.root?C(v,{id:d.root.id,componentMap:d.componentMap,childrenMap:d.childrenMap,allowedComponents:t,global:m,local:m,animate:b}):C(V,{children:n}),w=async(u,y)=>{if(!y||!y.regenerate)g(u);else if(p.action){if(l.current)return g(u),new Promise(async o=>{let{value:f}=await p.action(p.context,l.current.total,y.hint);s(f),o(null)})}else throw new Error("No rerender server action provided. Use the 'rerender' prop.")},M=z(()=>({value:m,setValue:w}),[m]);return C(V,{children:C(O.Provider,{value:M,children:P()})})}export{ye as GeneratedClient,v as Renderer,O as SyntuxContext,se as useSyntux};
3
3
  //# sourceMappingURL=client.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client/GeneratedClient.tsx","../src/ResponseParser.ts","../src/client/Renderer.tsx","../src/client/SyntuxContext.tsx"],"sourcesContent":["\"use client\";\r\n\r\nimport { StreamableValue, readStreamableValue } from '@ai-sdk/rsc';\r\nimport React, { JSX, useEffect, useMemo, useReducer, useRef, useState } from 'react';\r\nimport { ContextfulAction } from 'src/types';\r\nimport { ResponseParser } from '../ResponseParser';\r\nimport { Renderer } from './Renderer';\r\nimport { SyntuxContext } from './SyntuxContext';\r\n\r\n/**\r\n * Client wrapper for Renderer that handles streaming and parsing with server.\r\n */\r\nexport function GeneratedClient({\r\n value,\r\n allowedComponents,\r\n inputStream,\r\n placeholder,\r\n actions,\r\n errorFallback\r\n}: {\r\n value: any,\r\n allowedComponents: Record<string, React.ComponentType<any> | string>,\r\n inputStream: StreamableValue<string>,\r\n placeholder?: JSX.Element,\r\n actions?: Record<string, ContextfulAction>,\r\n errorFallback?: JSX.Element\r\n}) {\r\n const [statefulValue, setStatefulValue] = useState(value); // stateful because changeable through context\r\n const [, forceUpdate] = useReducer(x => x + 1, 0);\r\n const parser = useRef<ResponseParser | null>(null);\r\n const [errored, setErrored] = useState(false)\r\n\r\n useEffect(() => {\r\n // forcibly create a new one for HMR\r\n parser.current = new ResponseParser();\r\n\r\n const parseStream = async () => {\r\n for await (const delta of readStreamableValue(inputStream)) {\r\n if (parser.current && delta !== undefined) {\r\n if (parser.current.addDelta(delta)) {\r\n forceUpdate();\r\n }\r\n }\r\n }\r\n };\r\n\r\n parseStream().then(() => {\r\n parser.current.finish();\r\n forceUpdate();\r\n }).catch(() => {\r\n setErrored(true)\r\n });\r\n }, [inputStream]);\r\n\r\n const schema = parser?.current?.schema;\r\n\r\n const providerValue = useMemo(() => ({ value: statefulValue, setValue: setStatefulValue }), [statefulValue]);\r\n\r\n const renderContent = () => {\r\n if(errored && errorFallback) return <>{errorFallback}</>\r\n\r\n if(schema?.root){\r\n return <Renderer id={schema.root.id} componentMap={schema.componentMap} childrenMap={schema.childrenMap} allowedComponents={allowedComponents} global={statefulValue} local={statefulValue} actions={actions || {}} /> \r\n } else {\r\n return <>{placeholder}</>\r\n }\r\n }\r\n\r\n return (\r\n <>\r\n <SyntuxContext.Provider value={providerValue}>\r\n {renderContent()}\r\n </SyntuxContext.Provider >\r\n </>\r\n )\r\n}\r\n","import { SchemaNode, UISchema } from \"./types\";\r\n\r\n/**\r\n * Utility class for parsing UISchema from stream.\r\n */\r\nexport class ResponseParser {\r\n buffer = \"\"; // unflushed existing deltas w/o newline\r\n \r\n // schema assembled thus far\r\n schema: UISchema = {\r\n childrenMap: {},\r\n componentMap: {},\r\n root: null\r\n }\r\n\r\n /**\r\n * Update schema with latest data chunk.\r\n * \r\n * Handles multiline input gracefully; can be used to load entire schemas from cache.\r\n * \r\n * @param delta delta from stream.\r\n * @returns true if update is warranted, false otherwise.\r\n */\r\n addDelta(delta: string) {\r\n this.buffer += delta;\r\n const split = this.buffer.split(\"\\n\")\r\n if (split.length > 1) {\r\n split.slice(0, split.length - 1).forEach((line) => this.handleLine(line));\r\n this.buffer = split[split.length - 1];\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Parses a single line (full JSON object) and updates schema.\r\n * Generally should not be used when streaming data.\r\n */\r\n handleLine(line: string) {\r\n try {\r\n const node: SchemaNode = JSON.parse(line);\r\n\r\n const { childrenMap, componentMap } = this.schema;\r\n\r\n componentMap[node.id] = node;\r\n if (node.parentId === null) {\r\n this.schema.root = node;\r\n } else {\r\n if (!childrenMap[node.parentId]) childrenMap[node.parentId] = []\r\n childrenMap[node.parentId].push(node.id)\r\n }\r\n } catch (err) { /* probably markdown or generation inconsistency */ }\r\n }\r\n\r\n /**\r\n * Clears the buffer and handles any remaining information within.\r\n */\r\n finish(){\r\n this.handleLine(this.buffer);\r\n this.buffer = \"\";\r\n }\r\n}","\"use client\";\r\n\r\nimport { ComponentType, Fragment } from 'react'\r\nimport { ChildrenMap, ComponentMap, ContextfulAction, SchemaNode } from '../types';\r\n\r\n/**\r\n * lightweight implementation of lodash.get\r\n */\r\nconst resolvePath = (obj: any, path: string) => {\r\n if (path === '$') return obj;\r\n return path.split('.').reduce((acc, curr) => acc?.[curr], obj)\r\n}\r\n\r\n/**\r\n * parses binding protocol and performs property lookup w/ scope resolution\r\n */\r\nconst get = (global: any, local: any, path: string) => {\r\n if (path.startsWith(\"$item.\")) {\r\n path = path.slice(6)\r\n return resolvePath(local, path);\r\n } else {\r\n if (path === \"$item\") return local;\r\n return resolvePath(global, path);\r\n }\r\n}\r\n\r\n\r\nconst blacklistedProps = new Set([\"dangerouslySetInnerHTML\"])\r\n/**\r\n * recursively parses props for bindings, replacing with true values\r\n */\r\nconst resolveProps = (global: any, local: any, props: any, actions: Record<string, ContextfulAction>) => {\r\n if (!props) return props;\r\n if (\"$action\" in props) {\r\n const action = actions[props.$action];\r\n if (!action) return () => { };\r\n\r\n const resolvedArgs = props.args.map((arg: any) => {\r\n if (arg && typeof arg === \"object\" && \"$bind\" in arg) {\r\n return get(global, local, arg.$bind);\r\n } else {\r\n return arg;\r\n }\r\n })\r\n\r\n return (e: any) => {\r\n action.fn(...resolvedArgs)\r\n }\r\n }\r\n\r\n if (\"$bind\" in props) { // $bind may be falsy value\r\n const resolved = get(global, local, props.$bind);\r\n Object.keys(resolved).forEach((key) => {\r\n if(blacklistedProps.has(key)){\r\n delete resolved[key];\r\n }\r\n })\r\n return resolved;\r\n }\r\n\r\n Object.keys(props).forEach((key) => {\r\n if (blacklistedProps.has(key)) {\r\n delete props[key];\r\n return;\r\n }\r\n\r\n const val = props[key];\r\n if (typeof val === \"object\") {\r\n props[key] = resolveProps(global, local, val, actions);\r\n }\r\n })\r\n return props;\r\n}\r\n\r\n/**\r\n * output node.content, with check for $bind\r\n*/\r\nconst renderContent = (global: any, local: any, content: any) => {\r\n if (typeof content === \"object\") {\r\n return get(global, local, content.$bind);\r\n } else {\r\n return content;\r\n }\r\n}\r\n\r\nexport interface RendererProps {\r\n id: string;\r\n componentMap: ComponentMap;\r\n childrenMap: ChildrenMap;\r\n allowedComponents: Record<string, ComponentType<any> | string>;\r\n global: any;\r\n local: any;\r\n actions: Record<string, ContextfulAction>;\r\n}\r\n\r\n/**\r\n * Renders a UISchema recursively, in accordance to the spec.\r\n */\r\nexport function Renderer(props: RendererProps) {\r\n const {\r\n id, componentMap, childrenMap, global, local, allowedComponents, actions\r\n } = props;\r\n const element = componentMap[id];\r\n\r\n if (element.type === \"TEXT\") return <>{renderContent(global, local, element.content)}</>\r\n\r\n const sourceArrPath = element.props?.source;\r\n if (element.type === '__ForEach__' && sourceArrPath) {\r\n const sourceArr = get(global, local, sourceArrPath)\r\n if (!Array.isArray(sourceArr)) return null;\r\n\r\n const childrenArr = childrenMap[element.id];\r\n return <>{childrenArr?.map((childId: string, index: number) => <Fragment key={index}>\r\n {sourceArr.map((item: any, index1: number) => <Renderer {...props} id={childId} local={item} key={index1} />)}\r\n </Fragment>)}</>\r\n }\r\n\r\n const Component = allowedComponents[element.type] || element.type;\r\n const componentProps = resolveProps(global, local, element.props, actions);\r\n\r\n const contentNode = renderContent(global, local, element.content);\r\n const childNodes = childrenMap[element.id]?.map((childId: string, index: number) => {\r\n return <Renderer\r\n key={index}\r\n {...props}\r\n id={childId}\r\n />\r\n }) || []\r\n\r\n const nodesToRender = [contentNode, ...childNodes].filter(node => node !== null && node !== undefined) // 0 is falsy\r\n\r\n if (nodesToRender.length > 0) {\r\n return <Component {...componentProps}>\r\n {nodesToRender}\r\n </Component>\r\n }\r\n\r\n return <Component {...componentProps} />\r\n}\r\n","import { createContext, useContext } from \"react\";\r\n\r\nexport type SyntuxContextType = {\r\n value: any,\r\n setValue: (arg0: any) => void\r\n}\r\n\r\nexport const SyntuxContext = createContext<SyntuxContextType | null>(null)\r\n\r\nexport function useSyntux(){\r\n const context = useContext(SyntuxContext);\r\n if(!context) throw new Error(\"useSyntux must be used inside a GeneratedUI.\");\r\n return context;\r\n}"],"mappings":"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","names":["readStreamableValue","useEffect","useMemo","useReducer","useRef","useState","ResponseParser","delta","split","line","node","childrenMap","componentMap","Fragment","jsx","createElement","resolvePath","obj","path","acc","curr","get","global","local","blacklistedProps","resolveProps","props","actions","action","resolvedArgs","arg","e","resolved","key","val","renderContent","content","Renderer","_a","_b","id","componentMap","childrenMap","allowedComponents","element","sourceArrPath","sourceArr","childrenArr","childId","index","item","index1","Component","componentProps","contentNode","childNodes","nodesToRender","node","createContext","useContext","SyntuxContext","useSyntux","context","Fragment","jsx","GeneratedClient","value","allowedComponents","inputStream","placeholder","actions","errorFallback","_a","statefulValue","setStatefulValue","useState","forceUpdate","useReducer","x","parser","useRef","errored","setErrored","useEffect","ResponseParser","delta","readStreamableValue","schema","providerValue","useMemo","renderContent","Renderer","SyntuxContext"]}
1
+ {"version":3,"sources":["../src/client/GeneratedClient.tsx","../src/ResponseParser.ts","../src/client/Renderer.tsx","../src/client/SyntuxContext.tsx"],"sourcesContent":["\"use client\";\r\n\r\nimport { StreamableValue, readStreamableValue } from '@ai-sdk/rsc';\r\nimport React, { JSX, useEffect, useMemo, useReducer, useRef, useState } from 'react';\r\nimport { AnimateOptions, RerenderContext, RerenderOptions } from 'src/types';\r\nimport { ResponseParser } from 'src/ResponseParser';\r\nimport { Renderer } from './Renderer';\r\nimport { SyntuxContext } from './SyntuxContext';\r\n\r\n\r\n\r\n/**\r\n * Client wrapper for Renderer that handles streaming and parsing with server.\r\n */\r\nexport function GeneratedClient({\r\n value,\r\n allowedComponents,\r\n inputStream,\r\n placeholder,\r\n errorFallback,\r\n animate,\r\n rerender\r\n}: {\r\n value: any,\r\n allowedComponents: Record<string, React.ComponentType<any> | string>,\r\n inputStream: StreamableValue<string>,\r\n placeholder?: JSX.Element,\r\n errorFallback?: JSX.Element,\r\n animate?: AnimateOptions,\r\n rerender: RerenderContext\r\n}) {\r\n const [statefulValue, setStatefulValue] = useState(value); // stateful because changeable through context\r\n const [statefulInputStream, setStatefulInputStream] = useState(inputStream);\r\n\r\n const [, forceUpdate] = useReducer(x => x + 1, 0);\r\n const parser = useRef<ResponseParser | null>(null);\r\n const [errored, setErrored] = useState(false)\r\n\r\n // HMR support\r\n useEffect(() => {\r\n setStatefulInputStream(inputStream)\r\n }, [inputStream])\r\n\r\n useEffect(() => {\r\n /**\r\n * flag to avoid conflicting streams from mutating UI.\r\n */\r\n let isActive = true;\r\n\r\n // forcibly create a new one for HMR\r\n parser.current = new ResponseParser();\r\n\r\n const parseStream = async () => {\r\n try {\r\n for await (const delta of readStreamableValue(statefulInputStream)) {\r\n if (!isActive) break;\r\n\r\n if (parser.current && delta !== undefined) {\r\n if (parser.current.addDelta(delta)) {\r\n forceUpdate();\r\n }\r\n }\r\n }\r\n\r\n if (isActive) {\r\n parser.current?.finish();\r\n forceUpdate();\r\n }\r\n } catch (err) {\r\n if (isActive) setErrored(true);\r\n }\r\n };\r\n\r\n parseStream();\r\n\r\n return () => {\r\n isActive = false;\r\n }\r\n }, [statefulInputStream]);\r\n\r\n const schema = parser?.current?.schema;\r\n\r\n\r\n const renderContent = () => {\r\n if (errored && errorFallback) return <>{errorFallback}</>\r\n\r\n if (schema?.root) {\r\n return <Renderer id={schema.root.id} componentMap={schema.componentMap} childrenMap={schema.childrenMap} allowedComponents={allowedComponents} global={statefulValue} local={statefulValue} animate={animate} />\r\n } else {\r\n return <>{placeholder}</>\r\n }\r\n }\r\n\r\n const modifyValue = async (value: any, options?: RerenderOptions): Promise<null> | null => {\r\n if (!options || !options.regenerate) {\r\n setStatefulValue(value);\r\n } else {\r\n if (!rerender.action) {\r\n throw new Error(\"No rerender server action provided. Use the 'rerender' prop.\")\r\n } else {\r\n if (parser.current) {\r\n setStatefulValue(value);\r\n return new Promise(async (resolve) => {\r\n const { value } = await rerender.action(rerender.context, parser.current.total, options.hint);\r\n setStatefulInputStream(value);\r\n resolve(null);\r\n })\r\n }\r\n }\r\n }\r\n }\r\n\r\n const providerValue = useMemo(() => ({\r\n value: statefulValue, setValue: modifyValue\r\n }), [statefulValue]);\r\n return (\r\n <>\r\n <SyntuxContext.Provider value={providerValue}>\r\n {renderContent()}\r\n </SyntuxContext.Provider >\r\n </>\r\n )\r\n}\r\n","import { SchemaNode, UISchema } from \"./types\";\r\n\r\n/**\r\n * Utility class for parsing UISchema from stream.\r\n */\r\nexport class ResponseParser {\r\n buffer = \"\"; // unflushed existing deltas w/o newline\r\n total = \"\"; // accumulator\r\n\r\n // schema assembled thus far\r\n schema: UISchema = {\r\n childrenMap: {},\r\n componentMap: {},\r\n root: null\r\n }\r\n\r\n /**\r\n * Update schema with latest data chunk.\r\n * \r\n * Handles multiline input gracefully; can be used to load entire schemas from cache.\r\n * \r\n * @param delta delta from stream.\r\n * @returns true if update is warranted, false otherwise.\r\n */\r\n addDelta(delta: string) {\r\n this.total += delta;\r\n this.buffer += delta;\r\n const split = this.buffer.split(\"\\n\")\r\n if (split.length > 1) {\r\n split.slice(0, split.length - 1).forEach((line) => this.handleLine(line));\r\n this.buffer = split[split.length - 1];\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Parses a single line (full JSON object) and updates schema.\r\n * Generally should not be used when streaming data.\r\n */\r\n handleLine(line: string) {\r\n try {\r\n const node: SchemaNode = JSON.parse(line);\r\n\r\n const { childrenMap, componentMap } = this.schema;\r\n\r\n componentMap[node.id] = node;\r\n if (node.parentId === null) {\r\n this.schema.root = node;\r\n } else {\r\n if (!childrenMap[node.parentId]) childrenMap[node.parentId] = []\r\n childrenMap[node.parentId].push(node.id)\r\n }\r\n } catch (err) { /* probably markdown or generation inconsistency */ }\r\n }\r\n\r\n /**\r\n * Clears the buffer and handles any remaining information within.\r\n */\r\n finish(){\r\n this.handleLine(this.buffer);\r\n this.buffer = \"\";\r\n }\r\n}","\"use client\";\r\n\r\nimport { ComponentType, Fragment, useEffect, useState } from 'react';\r\nimport { AnimateOptions, ChildrenMap, ComponentMap } from '../types';\r\n\r\n/**\r\n * lightweight implementation of lodash.get\r\n */\r\nconst resolvePath = (obj: any, path: string) => {\r\n if (path === '$') return obj;\r\n return path.split('.').reduce((acc, curr) => acc?.[curr], obj)\r\n}\r\n\r\n/**\r\n * parses binding protocol and performs property lookup w/ scope resolution\r\n */\r\nconst get = (global: any, local: any, path: string) => {\r\n if (path.startsWith(\"$item.\")) {\r\n path = path.slice(6)\r\n return resolvePath(local, path);\r\n } else {\r\n if (path === \"$item\") return local;\r\n return resolvePath(global, path);\r\n }\r\n}\r\n\r\n\r\nconst blacklistedProps = new Set([\"dangerouslySetInnerHTML\"])\r\n/**\r\n * recursively parses props for bindings, replacing with true values\r\n */\r\nconst resolveProps = (global: any, local: any, props: any) => {\r\n if (!props) return props;\r\n\r\n if (\"$bind\" in props) { // $bind may be falsy value\r\n const resolved = get(global, local, props.$bind);\r\n Object.keys(resolved).forEach((key) => {\r\n if (blacklistedProps.has(key)) {\r\n delete resolved[key];\r\n }\r\n })\r\n return resolved;\r\n }\r\n\r\n Object.keys(props).forEach((key) => {\r\n if (blacklistedProps.has(key)) {\r\n delete props[key];\r\n return;\r\n }\r\n\r\n const val = props[key];\r\n if (typeof val === \"object\") {\r\n props[key] = resolveProps(global, local, val);\r\n }\r\n })\r\n return props;\r\n}\r\n\r\n/**\r\n * output node.content, with check for $bind\r\n*/\r\nconst renderContent = (global: any, local: any, content: any) => {\r\n if (typeof content === \"object\") {\r\n return get(global, local, content.$bind);\r\n } else {\r\n return content;\r\n }\r\n}\r\n\r\nexport interface RendererProps {\r\n id: string;\r\n componentMap: ComponentMap;\r\n childrenMap: ChildrenMap;\r\n allowedComponents: Record<string, ComponentType<any> | string>;\r\n global: any;\r\n local: any;\r\n animate?: AnimateOptions;\r\n}\r\n\r\n/**\r\n * Renders a UISchema recursively, in accordance to the spec.\r\n */\r\nexport function Renderer(props: RendererProps) {\r\n const [isVisible, setIsVisible] = useState(false);\r\n\r\n useEffect(() => {\r\n const frame = requestAnimationFrame(() => setIsVisible(true));\r\n return () => cancelAnimationFrame(frame)\r\n }, [])\r\n\r\n const {\r\n id, componentMap, childrenMap, global, local, allowedComponents, animate\r\n } = props;\r\n const element = componentMap[id];\r\n\r\n if (element.type === \"TEXT\") return <>{renderContent(global, local, element.content)}</>\r\n\r\n const sourceArrPath = element.props?.source;\r\n if (element.type === '__ForEach__' && sourceArrPath) {\r\n const sourceArr = get(global, local, sourceArrPath)\r\n if (!Array.isArray(sourceArr)) return null;\r\n\r\n const childrenArr = childrenMap[element.id];\r\n return <>{childrenArr?.map((childId: string, index: number) => <Fragment key={index}>\r\n {sourceArr.map((item: any, index1: number) => <Renderer {...props} id={childId} local={item} key={index1} />)}\r\n </Fragment>)}</>\r\n }\r\n\r\n const Component = allowedComponents[element.type] || element.type;\r\n const componentProps = resolveProps(global, local, element.props);\r\n\r\n const animatedProps = {...componentProps}\r\n animatedProps.style = {...(animatedProps.style) || {}}\r\n\r\n const initialOpacity = animatedProps.style?.opacity ?? 1;\r\n animatedProps.style.opacity = isVisible ? initialOpacity : 0;\r\n animatedProps.style.transform = isVisible ? 'translateY(0)' : `translateY(${animate?.offset ?? 10}px)`;\r\n animatedProps.style.transition = `opacity ${animate?.duration ?? 200}ms ease-out, transform ${animate?.duration ?? 200}ms ease-out`;\r\n animatedProps.style.willChange = 'opacity, transform';\r\n\r\n const contentNode = renderContent(global, local, element.content);\r\n const childNodes = childrenMap[element.id]?.map((childId: string, index: number) => {\r\n return <Renderer\r\n key={index}\r\n {...props}\r\n id={childId}\r\n />\r\n }) || []\r\n\r\n const nodesToRender = [contentNode, ...childNodes].filter(node => node !== null && node !== undefined) // 0 is falsy\r\n\r\n if (nodesToRender.length > 0) {\r\n return <Component {...animatedProps}>\r\n {nodesToRender}\r\n </Component>\r\n }\r\n\r\n return <Component {...animatedProps}/>\r\n}\r\n","import { createContext, useContext } from \"react\";\r\nimport { RerenderOptions } from \"src/types\";\r\n\r\nexport type SyntuxContextType = {\r\n value: any,\r\n setValue: (value: any, options?: RerenderOptions) => Promise<null> | null\r\n}\r\n\r\nexport const SyntuxContext = createContext<SyntuxContextType | null>(null)\r\n\r\nexport function useSyntux(){\r\n const context = useContext(SyntuxContext);\r\n if(!context) throw new Error(\"useSyntux must be used inside a GeneratedUI.\");\r\n return context;\r\n}"],"mappings":"aAEA,OAA0B,uBAAAA,MAA2B,cACrD,OAAqB,aAAAC,EAAW,WAAAC,EAAS,cAAAC,EAAY,UAAAC,EAAQ,YAAAC,MAAgB,QCEtE,IAAMC,EAAN,KAAqB,CACxB,OAAS,GACT,MAAQ,GAGR,OAAmB,CACf,YAAa,CAAC,EACd,aAAc,CAAC,EACf,KAAM,IACV,EAUA,SAASC,EAAe,CACpB,KAAK,OAASA,EACd,KAAK,QAAUA,EACf,IAAMC,EAAQ,KAAK,OAAO,MAAM;AAAA,CAAI,EACpC,OAAIA,EAAM,OAAS,GACfA,EAAM,MAAM,EAAGA,EAAM,OAAS,CAAC,EAAE,QAASC,GAAS,KAAK,WAAWA,CAAI,CAAC,EACxE,KAAK,OAASD,EAAMA,EAAM,OAAS,CAAC,EAC7B,IAEJ,EACX,CAMA,WAAWC,EAAc,CACrB,GAAI,CACA,IAAMC,EAAmB,KAAK,MAAMD,CAAI,EAElC,CAAE,YAAAE,EAAa,aAAAC,CAAa,EAAI,KAAK,OAE3CA,EAAaF,EAAK,EAAE,EAAIA,EACpBA,EAAK,WAAa,KAClB,KAAK,OAAO,KAAOA,GAEdC,EAAYD,EAAK,QAAQ,IAAGC,EAAYD,EAAK,QAAQ,EAAI,CAAC,GAC/DC,EAAYD,EAAK,QAAQ,EAAE,KAAKA,EAAK,EAAE,EAE/C,MAAc,CAAsD,CACxE,CAKA,QAAQ,CACJ,KAAK,WAAW,KAAK,MAAM,EAC3B,KAAK,OAAS,EAClB,CACJ,EC7DA,OAAwB,YAAAG,EAAU,aAAAC,EAAW,YAAAC,MAAgB,QA6FrB,mBAAAF,EAAA,OAAAG,MAAA,oBASkB,wBAAAC,MAAA,QAhG1D,IAAMC,EAAc,CAACC,EAAUC,IACvBA,IAAS,IAAYD,EAClBC,EAAK,MAAM,GAAG,EAAE,OAAO,CAACC,EAAKC,IAASD,GAAA,YAAAA,EAAMC,GAAOH,CAAG,EAM3DI,EAAM,CAACC,EAAaC,EAAYL,IAC9BA,EAAK,WAAW,QAAQ,GACxBA,EAAOA,EAAK,MAAM,CAAC,EACZF,EAAYO,EAAOL,CAAI,GAE1BA,IAAS,QAAgBK,EACtBP,EAAYM,EAAQJ,CAAI,EAKjCM,EAAmB,IAAI,IAAI,CAAC,yBAAyB,CAAC,EAItDC,EAAe,CAACH,EAAaC,EAAYG,IAAe,CAC1D,GAAI,CAACA,EAAO,OAAOA,EAEnB,GAAI,UAAWA,EAAO,CAClB,IAAMC,EAAWN,EAAIC,EAAQC,EAAOG,EAAM,KAAK,EAC/C,cAAO,KAAKC,CAAQ,EAAE,QAASC,GAAQ,CAC/BJ,EAAiB,IAAII,CAAG,GACxB,OAAOD,EAASC,CAAG,CAE3B,CAAC,EACMD,CACX,CAEA,cAAO,KAAKD,CAAK,EAAE,QAASE,GAAQ,CAChC,GAAIJ,EAAiB,IAAII,CAAG,EAAG,CAC3B,OAAOF,EAAME,CAAG,EAChB,MACJ,CAEA,IAAMC,EAAMH,EAAME,CAAG,EACjB,OAAOC,GAAQ,WACfH,EAAME,CAAG,EAAIH,EAAaH,EAAQC,EAAOM,CAAG,EAEpD,CAAC,EACMH,CACX,EAKMI,EAAgB,CAACR,EAAaC,EAAYQ,IACxC,OAAOA,GAAY,SACZV,EAAIC,EAAQC,EAAOQ,EAAQ,KAAK,EAEhCA,EAiBR,SAASC,EAASN,EAAsB,CAlF/C,IAAAO,EAAAC,EAAAC,EAmFI,GAAM,CAACC,EAAWC,CAAY,EAAIxB,EAAS,EAAK,EAEhDD,EAAU,IAAM,CACZ,IAAM0B,EAAQ,sBAAsB,IAAMD,EAAa,EAAI,CAAC,EAC5D,MAAO,IAAM,qBAAqBC,CAAK,CAC3C,EAAG,CAAC,CAAC,EAEL,GAAM,CACF,GAAAC,EAAI,aAAAC,EAAc,YAAAC,EAAa,OAAAnB,EAAQ,MAAAC,EAAO,kBAAAmB,EAAmB,QAAAC,CACrE,EAAIjB,EACEkB,EAAUJ,EAAaD,CAAE,EAE/B,GAAIK,EAAQ,OAAS,OAAQ,OAAO9B,EAAAH,EAAA,CAAG,SAAAmB,EAAcR,EAAQC,EAAOqB,EAAQ,OAAO,EAAE,EAErF,IAAMC,GAAgBZ,EAAAW,EAAQ,QAAR,YAAAX,EAAe,OACrC,GAAIW,EAAQ,OAAS,eAAiBC,EAAe,CACjD,IAAMC,EAAYzB,EAAIC,EAAQC,EAAOsB,CAAa,EAClD,GAAI,CAAC,MAAM,QAAQC,CAAS,EAAG,OAAO,KAEtC,IAAMC,EAAcN,EAAYG,EAAQ,EAAE,EAC1C,OAAO9B,EAAAH,EAAA,CAAG,SAAAoC,GAAA,YAAAA,EAAa,IAAI,CAACC,EAAiBC,IAAkBnC,EAACH,EAAA,CAC3D,SAAAmC,EAAU,IAAI,CAACI,EAAWC,IAAmBpC,EAACiB,EAAA,CAAU,GAAGN,EAAO,GAAIsB,EAAS,MAAOE,EAAM,IAAKC,EAAQ,CAAE,GADlCF,CAE9E,GAAa,CACjB,CAEA,IAAMG,EAAYV,EAAkBE,EAAQ,IAAI,GAAKA,EAAQ,KAGvDS,EAAgB,CAAC,GAFA5B,EAAaH,EAAQC,EAAOqB,EAAQ,KAAK,CAExB,EACxCS,EAAc,MAAQ,CAAC,GAAIA,EAAc,OAAU,CAAC,CAAC,EAErD,IAAMC,IAAiBpB,EAAAmB,EAAc,QAAd,YAAAnB,EAAqB,UAAW,EACvDmB,EAAc,MAAM,QAAUjB,EAAYkB,EAAiB,EAC3DD,EAAc,MAAM,UAAYjB,EAAY,gBAAkB,eAAcO,GAAA,YAAAA,EAAS,SAAU,EAAE,MACjGU,EAAc,MAAM,WAAa,YAAWV,GAAA,YAAAA,EAAS,WAAY,GAAG,2BAA0BA,GAAA,YAAAA,EAAS,WAAY,GAAG,cACtHU,EAAc,MAAM,WAAa,qBAEjC,IAAME,EAAczB,EAAcR,EAAQC,EAAOqB,EAAQ,OAAO,EAC1DY,IAAarB,EAAAM,EAAYG,EAAQ,EAAE,IAAtB,YAAAT,EAAyB,IAAI,CAACa,EAAiBC,IACvDnC,EAACkB,EAAA,CAEH,GAAGN,EACJ,GAAIsB,GAFCC,CAGT,KACE,CAAC,EAEDQ,EAAgB,CAACF,EAAa,GAAGC,CAAU,EAAE,OAAOE,GAAQA,GAAS,IAA0B,EAErG,OAAID,EAAc,OAAS,EAChB3C,EAACsC,EAAA,CAAW,GAAGC,EACjB,SAAAI,EACL,EAGG3C,EAACsC,EAAA,CAAW,GAAGC,EAAc,CACxC,CC1IA,OAAS,iBAAAM,EAAe,cAAAC,MAAkB,QAQnC,IAAMC,EAAgBF,EAAwC,IAAI,EAElE,SAASG,IAAW,CACvB,IAAMC,EAAUH,EAAWC,CAAa,EACxC,GAAG,CAACE,EAAS,MAAM,IAAI,MAAM,8CAA8C,EAC3E,OAAOA,CACX,CHsEyC,mBAAAC,EAAA,OAAAC,MAAA,oBAtElC,SAASC,GAAgB,CAC9B,MAAAC,EACA,kBAAAC,EACA,YAAAC,EACA,YAAAC,EACA,cAAAC,EACA,QAAAC,EACA,SAAAC,CACF,EAQG,CA9BH,IAAAC,EA+BE,GAAM,CAACC,EAAeC,CAAgB,EAAIC,EAASV,CAAK,EAClD,CAACW,EAAqBC,CAAsB,EAAIF,EAASR,CAAW,EAEpE,CAAC,CAAEW,CAAW,EAAIC,EAAWC,GAAKA,EAAI,EAAG,CAAC,EAC1CC,EAASC,EAA8B,IAAI,EAC3C,CAACC,EAASC,CAAU,EAAIT,EAAS,EAAK,EAG5CU,EAAU,IAAM,CACdR,EAAuBV,CAAW,CACpC,EAAG,CAACA,CAAW,CAAC,EAEhBkB,EAAU,IAAM,CAId,IAAIC,EAAW,GAGf,OAAAL,EAAO,QAAU,IAAIM,GAED,SAAY,CApDpC,IAAAf,EAqDM,GAAI,CACF,cAAiBgB,KAASC,EAAoBb,CAAmB,EAAG,CAClE,GAAI,CAACU,EAAU,MAEXL,EAAO,SAAWO,IAAU,QAC1BP,EAAO,QAAQ,SAASO,CAAK,GAC/BV,EAAY,CAGlB,CAEIQ,KACFd,EAAAS,EAAO,UAAP,MAAAT,EAAgB,SAChBM,EAAY,EAEhB,MAAc,CACRQ,GAAUF,EAAW,EAAI,CAC/B,CACF,GAEY,EAEL,IAAM,CACXE,EAAW,EACb,CACF,EAAG,CAACV,CAAmB,CAAC,EAExB,IAAMc,GAASlB,EAAAS,GAAA,YAAAA,EAAQ,UAAR,YAAAT,EAAiB,OAG1BmB,EAAgB,IAChBR,GAAWd,EAAsBN,EAAAD,EAAA,CAAG,SAAAO,EAAc,EAElDqB,GAAA,MAAAA,EAAQ,KACH3B,EAAC6B,EAAA,CAAS,GAAIF,EAAO,KAAK,GAAI,aAAcA,EAAO,aAAc,YAAaA,EAAO,YAAa,kBAAmBxB,EAAmB,OAAQO,EAAe,MAAOA,EAAe,QAASH,EAAS,EAEvMP,EAAAD,EAAA,CAAG,SAAAM,EAAY,EAIpByB,EAAc,MAAO5B,EAAY6B,IAAqD,CAC1F,GAAI,CAACA,GAAW,CAACA,EAAQ,WACvBpB,EAAiBT,CAAK,UAEjBM,EAAS,QAGZ,GAAIU,EAAO,QACT,OAAAP,EAAiBT,CAAK,EACf,IAAI,QAAQ,MAAO8B,GAAY,CACpC,GAAM,CAAE,MAAA9B,CAAM,EAAI,MAAMM,EAAS,OAAOA,EAAS,QAASU,EAAO,QAAQ,MAAOa,EAAQ,IAAI,EAC5FjB,EAAuBZ,CAAK,EAC5B8B,EAAQ,IAAI,CACd,CAAC,MARH,OAAM,IAAI,MAAM,8DAA8D,CAYpF,EAEMC,EAAgBC,EAAQ,KAAO,CACnC,MAAOxB,EAAe,SAAUoB,CAClC,GAAI,CAACpB,CAAa,CAAC,EACnB,OACEV,EAAAD,EAAA,CACE,SAAAC,EAACmC,EAAc,SAAd,CAAuB,MAAOF,EAC5B,SAAAL,EAAc,EACjB,EACF,CAEJ","names":["readStreamableValue","useEffect","useMemo","useReducer","useRef","useState","ResponseParser","delta","split","line","node","childrenMap","componentMap","Fragment","useEffect","useState","jsx","createElement","resolvePath","obj","path","acc","curr","get","global","local","blacklistedProps","resolveProps","props","resolved","key","val","renderContent","content","Renderer","_a","_b","_c","isVisible","setIsVisible","frame","id","componentMap","childrenMap","allowedComponents","animate","element","sourceArrPath","sourceArr","childrenArr","childId","index","item","index1","Component","animatedProps","initialOpacity","contentNode","childNodes","nodesToRender","node","createContext","useContext","SyntuxContext","useSyntux","context","Fragment","jsx","GeneratedClient","value","allowedComponents","inputStream","placeholder","errorFallback","animate","rerender","_a","statefulValue","setStatefulValue","useState","statefulInputStream","setStatefulInputStream","forceUpdate","useReducer","x","parser","useRef","errored","setErrored","useEffect","isActive","ResponseParser","delta","readStreamableValue","schema","renderContent","Renderer","modifyValue","options","resolve","providerValue","useMemo","SyntuxContext"]}
package/dist/index.d.mts CHANGED
@@ -1,15 +1,15 @@
1
- import { C as ContextfulAction$1, S as SyntuxComponent$1, U as UISchema } from './types-B7z31wIq.mjs';
2
- export { a as ChildrenMap, b as ComponentMap, c as SchemaNode } from './types-B7z31wIq.mjs';
1
+ import { S as SyntuxComponent$1, U as UISchema } from './types-0XgxLwqz.mjs';
2
+ export { A as AnimateOptions, C as ChildrenMap, a as ComponentMap, R as RerenderContext, b as RerenderOptions, c as SchemaNode } from './types-0XgxLwqz.mjs';
3
3
  import * as react from 'react';
4
4
  import { JSX } from 'react';
5
+ import { StreamableValue } from '@ai-sdk/rsc';
5
6
  import { LanguageModel } from 'ai';
6
- import { SyntuxComponent, ContextfulAction } from 'getsyntux';
7
+ import { SyntuxComponent, AnimateOptions } from 'getsyntux';
7
8
 
8
9
  interface GeneratedContentProps {
9
10
  value: any;
10
11
  model: LanguageModel;
11
12
  components?: (SyntuxComponent | string)[];
12
- actions?: Record<string, ContextfulAction>;
13
13
  hint?: string;
14
14
  placeholder?: JSX.Element;
15
15
  cached?: string;
@@ -17,6 +17,10 @@ interface GeneratedContentProps {
17
17
  skeletonize?: boolean;
18
18
  onError?: (arg0: any) => void;
19
19
  errorFallback?: JSX.Element;
20
+ animate?: AnimateOptions;
21
+ rerender?: (arg0: string, arg1: string, arg2: string) => Promise<{
22
+ value: StreamableValue;
23
+ }>;
20
24
  }
21
25
 
22
26
  /**
@@ -27,27 +31,21 @@ declare function generateComponentMap(allowedComponents: (SyntuxComponent$1 | st
27
31
  /**
28
32
  * Creates LLM input in accordance to the spec
29
33
  */
30
- declare function constructInput({ value, skeletonize, components, hint, actions }: GeneratedContentProps): string;
34
+ declare function constructInput({ value, skeletonize, components, hint }: GeneratedContentProps): string;
31
35
  /**
32
36
  * generates a skeleton of the input value, ideal for large arrays or untrusted input.
33
37
  * see the FAQ for more information: https://github.com/puffinsoft/syntux/wiki/FAQ#handling-untrusted-input--large-arrays.
34
38
  *
35
39
  * *important*: assumes arrays are non-polymorphic
36
40
  */
37
- declare function create_skeleton(input: any): any;
38
- /**
39
- * attaches metadata to callback to allow LLM understanding
40
- * @param fn the action to be binded to an event on the UI
41
- * @param params the parameters the function accepts, in Typescript format (e.g., "id: number, name: string")
42
- * @param context a description of what the function does, for better LLM context
43
- */
44
- declare function defineTool(fn: Function, params?: string, context?: string): ContextfulAction$1;
41
+ declare function createSkeleton(input: any): any;
45
42
 
46
43
  /**
47
44
  * Utility class for parsing UISchema from stream.
48
45
  */
49
46
  declare class ResponseParser {
50
47
  buffer: string;
48
+ total: string;
51
49
  schema: UISchema;
52
50
  /**
53
51
  * Update schema with latest data chunk.
@@ -69,4 +67,4 @@ declare class ResponseParser {
69
67
  finish(): void;
70
68
  }
71
69
 
72
- export { ContextfulAction$1 as ContextfulAction, ResponseParser, SyntuxComponent$1 as SyntuxComponent, UISchema, constructInput, create_skeleton, defineTool, generateComponentMap };
70
+ export { ResponseParser, SyntuxComponent$1 as SyntuxComponent, UISchema, constructInput, createSkeleton, generateComponentMap };
package/dist/index.mjs CHANGED
@@ -1,13 +1,9 @@
1
- function x(e){return e.reduce((n,t)=>typeof t=="string"?(n[t]=t,n):(n[t.name]=t.component,n),{})}function m({value:e,skeletonize:n=!1,components:t,hint:o,actions:i}){let u=(t==null?void 0:t.map(r=>typeof r=="string"?r:r.name).join(","))||"",s=t==null?void 0:t.filter(r=>typeof r!="string"),c=(s==null?void 0:s.map(r=>r.context?`${r.name} [props: ${r.props}, details: ${r.context}]`:`${r.name} [props: ${r.props}]`).join(","))||"",h=o,l="";i&&(l=`
2
- `+Object.keys(i).map(r=>{let f=i[r];return`- ${r}(${f.params}): ${f.context}`}).join(`
3
- `)+`
4
- `);let d=JSON.stringify(n?a(e):e);return`<AllowedComponents>${u}</AllowedComponents>
5
- <ComponentContext>${c}</ComponentContext>
6
- <UserContext>${h||""}</UserContext>
7
- <AvailableActions>${l}</AvailableActions>
8
- <IsSkeleton>${n.toString()}</IsSkeleton>
1
+ function h(n){return n.reduce((t,e)=>typeof e=="string"?(t[e]=e,t):(t[e.name]=e.component,t),{})}function d({value:n,skeletonize:t=!1,components:e,hint:o}){let s=(e==null?void 0:e.map(r=>typeof r=="string"?r:r.name).join(","))||"",i=e==null?void 0:e.filter(r=>typeof r!="string"),l=(i==null?void 0:i.map(r=>r.context?`${r.name} [props: ${r.props}, details: ${r.context}]`:`${r.name} [props: ${r.props}]`).join(","))||"",p=o,u=JSON.stringify(t?a(n):n);return`<AllowedComponents>${s}</AllowedComponents>
2
+ <ComponentContext>${l}</ComponentContext>
3
+ <UserContext>${p||""}</UserContext>
4
+ <IsSkeleton>${t.toString()}</IsSkeleton>
9
5
  <Value>
10
- ${d}
11
- </Value>`}function a(e){return e===null?"null":typeof e!="object"?typeof e:Array.isArray(e)?e.length==0?"null":[a(e[0])]:Object.entries(e).reduce((n,[t,o])=>(n[t]=a(o),n),{})}function C(e,n,t){return{fn:e,params:n||"",context:t||"no context provided"}}var p=class{buffer="";schema={childrenMap:{},componentMap:{},root:null};addDelta(n){this.buffer+=n;let t=this.buffer.split(`
12
- `);return t.length>1?(t.slice(0,t.length-1).forEach(o=>this.handleLine(o)),this.buffer=t[t.length-1],!0):!1}handleLine(n){try{let t=JSON.parse(n),{childrenMap:o,componentMap:i}=this.schema;i[t.id]=t,t.parentId===null?this.schema.root=t:(o[t.parentId]||(o[t.parentId]=[]),o[t.parentId].push(t.id))}catch{}}finish(){this.handleLine(this.buffer),this.buffer=""}};export{p as ResponseParser,m as constructInput,a as create_skeleton,C as defineTool,x as generateComponentMap};
6
+ ${u}
7
+ </Value>`}function a(n){return n===null?"null":typeof n!="object"?typeof n:Array.isArray(n)?n.length==0?"null":[a(n[0])]:Object.entries(n).reduce((t,[e,o])=>(t[e]=a(o),t),{})}var f=class{buffer="";total="";schema={childrenMap:{},componentMap:{},root:null};addDelta(t){this.total+=t,this.buffer+=t;let e=this.buffer.split(`
8
+ `);return e.length>1?(e.slice(0,e.length-1).forEach(o=>this.handleLine(o)),this.buffer=e[e.length-1],!0):!1}handleLine(t){try{let e=JSON.parse(t),{childrenMap:o,componentMap:s}=this.schema;s[e.id]=e,e.parentId===null?this.schema.root=e:(o[e.parentId]||(o[e.parentId]=[]),o[e.parentId].push(e.id))}catch{}}finish(){this.handleLine(this.buffer),this.buffer=""}};export{f as ResponseParser,d as constructInput,a as createSkeleton,h as generateComponentMap};
13
9
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/util.ts","../src/ResponseParser.ts"],"sourcesContent":["import { GeneratedContentProps } from \"./templates/GeneratedUI\";\r\nimport { ContextfulAction, SyntuxComponent } from \"./types\";\r\n\r\n/**\r\n * Converts a list of components into a dictionary for fast-retrieval\r\n * during rendering.\r\n */\r\nexport function generateComponentMap(allowedComponents: (SyntuxComponent | string)[]) {\r\n return allowedComponents.reduce((acc: Record<string, React.ComponentType<any> | string>, curr: SyntuxComponent | string) => {\r\n if (typeof curr === \"string\") {\r\n acc[curr] = curr;\r\n return acc;\r\n }\r\n\r\n acc[curr.name] = curr.component;\r\n return acc;\r\n }, {})\r\n}\r\n\r\n/**\r\n * Creates LLM input in accordance to the spec\r\n */\r\nexport function constructInput({\r\n value, skeletonize = false, components, hint, actions\r\n}: GeneratedContentProps) {\r\n const allowedComponents = components?.map((item: SyntuxComponent | string) => {\r\n if (typeof item === \"string\") return item;\r\n return item.name;\r\n }).join(',') || \"\"\r\n\r\n const customComponents = components?.filter((item): item is SyntuxComponent => typeof item !== \"string\");\r\n const componentContext = customComponents?.map((item) => {\r\n if (!item.context) {\r\n return `${item.name} [props: ${item.props}]`\r\n } else {\r\n return `${item.name} [props: ${item.props}, details: ${item.context}]`\r\n }\r\n }).join(',') || \"\"\r\n\r\n const userContext = hint;\r\n\r\n let availableActions = \"\";\r\n if(actions){\r\n availableActions = \"\\n\" + Object.keys(actions).map((key: string) => {\r\n const action: ContextfulAction = actions[key];\r\n return `- ${key}(${action.params}): ${action.context}`\r\n }).join('\\n') + \"\\n\"\r\n }\r\n\r\n const inputValue = JSON.stringify(skeletonize ? create_skeleton(value) : value)\r\n\r\n return `<AllowedComponents>${allowedComponents}</AllowedComponents>\\n<ComponentContext>${componentContext}</ComponentContext>\\n<UserContext>${userContext || \"\"}</UserContext>\\n<AvailableActions>${availableActions}</AvailableActions>\\n<IsSkeleton>${skeletonize.toString()}</IsSkeleton>\\n<Value>\\n${inputValue}\\n</Value>`\r\n}\r\n\r\n/**\r\n * generates a skeleton of the input value, ideal for large arrays or untrusted input.\r\n * see the FAQ for more information: https://github.com/puffinsoft/syntux/wiki/FAQ#handling-untrusted-input--large-arrays.\r\n * \r\n * *important*: assumes arrays are non-polymorphic\r\n */\r\nexport function create_skeleton(input: any) {\r\n if (input === null) return \"null\";\r\n\r\n if (typeof input !== \"object\") return typeof input;\r\n\r\n if (Array.isArray(input)) {\r\n if (input.length == 0) {\r\n return \"null\"; // ignore this field completely\r\n } else {\r\n return [create_skeleton(input[0])]\r\n }\r\n }\r\n return Object.entries(input).reduce((acc, [key, value]) => {\r\n acc[key] = create_skeleton(value);\r\n return acc;\r\n }, {})\r\n}\r\n\r\n/**\r\n * attaches metadata to callback to allow LLM understanding\r\n * @param fn the action to be binded to an event on the UI\r\n * @param params the parameters the function accepts, in Typescript format (e.g., \"id: number, name: string\")\r\n * @param context a description of what the function does, for better LLM context\r\n */\r\nexport function defineTool(fn: Function, params?: string, context?: string): ContextfulAction {\r\n return {\r\n fn, \r\n params: params || \"\",\r\n context: context || \"no context provided\"\r\n }\r\n}","import { SchemaNode, UISchema } from \"./types\";\r\n\r\n/**\r\n * Utility class for parsing UISchema from stream.\r\n */\r\nexport class ResponseParser {\r\n buffer = \"\"; // unflushed existing deltas w/o newline\r\n \r\n // schema assembled thus far\r\n schema: UISchema = {\r\n childrenMap: {},\r\n componentMap: {},\r\n root: null\r\n }\r\n\r\n /**\r\n * Update schema with latest data chunk.\r\n * \r\n * Handles multiline input gracefully; can be used to load entire schemas from cache.\r\n * \r\n * @param delta delta from stream.\r\n * @returns true if update is warranted, false otherwise.\r\n */\r\n addDelta(delta: string) {\r\n this.buffer += delta;\r\n const split = this.buffer.split(\"\\n\")\r\n if (split.length > 1) {\r\n split.slice(0, split.length - 1).forEach((line) => this.handleLine(line));\r\n this.buffer = split[split.length - 1];\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Parses a single line (full JSON object) and updates schema.\r\n * Generally should not be used when streaming data.\r\n */\r\n handleLine(line: string) {\r\n try {\r\n const node: SchemaNode = JSON.parse(line);\r\n\r\n const { childrenMap, componentMap } = this.schema;\r\n\r\n componentMap[node.id] = node;\r\n if (node.parentId === null) {\r\n this.schema.root = node;\r\n } else {\r\n if (!childrenMap[node.parentId]) childrenMap[node.parentId] = []\r\n childrenMap[node.parentId].push(node.id)\r\n }\r\n } catch (err) { /* probably markdown or generation inconsistency */ }\r\n }\r\n\r\n /**\r\n * Clears the buffer and handles any remaining information within.\r\n */\r\n finish(){\r\n this.handleLine(this.buffer);\r\n this.buffer = \"\";\r\n }\r\n}"],"mappings":"AAOO,SAASA,EAAqBC,EAAiD,CAClF,OAAOA,EAAkB,OAAO,CAACC,EAAwDC,IACjF,OAAOA,GAAS,UAChBD,EAAIC,CAAI,EAAIA,EACLD,IAGXA,EAAIC,EAAK,IAAI,EAAIA,EAAK,UACfD,GACR,CAAC,CAAC,CACT,CAKO,SAASE,EAAe,CAC3B,MAAAC,EAAO,YAAAC,EAAc,GAAO,WAAAC,EAAY,KAAAC,EAAM,QAAAC,CAClD,EAA0B,CACtB,IAAMR,GAAoBM,GAAA,YAAAA,EAAY,IAAKG,GACnC,OAAOA,GAAS,SAAiBA,EAC9BA,EAAK,MACb,KAAK,OAAQ,GAEVC,EAAmBJ,GAAA,YAAAA,EAAY,OAAQG,GAAkC,OAAOA,GAAS,UACzFE,GAAmBD,GAAA,YAAAA,EAAkB,IAAKD,GACvCA,EAAK,QAGC,GAAGA,EAAK,IAAI,YAAYA,EAAK,KAAK,cAAcA,EAAK,OAAO,IAF5D,GAAGA,EAAK,IAAI,YAAYA,EAAK,KAAK,KAI9C,KAAK,OAAQ,GAEVG,EAAcL,EAEhBM,EAAmB,GACpBL,IACCK,EAAmB;AAAA,EAAO,OAAO,KAAKL,CAAO,EAAE,IAAKM,GAAgB,CAChE,IAAMC,EAA2BP,EAAQM,CAAG,EAC5C,MAAO,KAAKA,CAAG,IAAIC,EAAO,MAAM,MAAMA,EAAO,OAAO,EACxD,CAAC,EAAE,KAAK;AAAA,CAAI,EAAI;AAAA,GAGpB,IAAMC,EAAa,KAAK,UAAUX,EAAcY,EAAgBb,CAAK,EAAIA,CAAK,EAE9E,MAAO,sBAAsBJ,CAAiB;AAAA,oBAA2CW,CAAgB;AAAA,eAAqCC,GAAe,EAAE;AAAA,oBAAqCC,CAAgB;AAAA,cAAoCR,EAAY,SAAS,CAAC;AAAA;AAAA,EAA2BW,CAAU;AAAA,SACvT,CAQO,SAASC,EAAgBC,EAAY,CACxC,OAAIA,IAAU,KAAa,OAEvB,OAAOA,GAAU,SAAiB,OAAOA,EAEzC,MAAM,QAAQA,CAAK,EACfA,EAAM,QAAU,EACT,OAEA,CAACD,EAAgBC,EAAM,CAAC,CAAC,CAAC,EAGlC,OAAO,QAAQA,CAAK,EAAE,OAAO,CAACjB,EAAK,CAACa,EAAKV,CAAK,KACjDH,EAAIa,CAAG,EAAIG,EAAgBb,CAAK,EACzBH,GACR,CAAC,CAAC,CACT,CAQO,SAASkB,EAAWC,EAAcC,EAAiBC,EAAoC,CAC1F,MAAO,CACH,GAAAF,EACA,OAAQC,GAAU,GAClB,QAASC,GAAW,qBACxB,CACJ,CCrFO,IAAMC,EAAN,KAAqB,CACxB,OAAS,GAGT,OAAmB,CACf,YAAa,CAAC,EACd,aAAc,CAAC,EACf,KAAM,IACV,EAUA,SAASC,EAAe,CACpB,KAAK,QAAUA,EACf,IAAMC,EAAQ,KAAK,OAAO,MAAM;AAAA,CAAI,EACpC,OAAIA,EAAM,OAAS,GACfA,EAAM,MAAM,EAAGA,EAAM,OAAS,CAAC,EAAE,QAASC,GAAS,KAAK,WAAWA,CAAI,CAAC,EACxE,KAAK,OAASD,EAAMA,EAAM,OAAS,CAAC,EAC7B,IAEJ,EACX,CAMA,WAAWC,EAAc,CACrB,GAAI,CACA,IAAMC,EAAmB,KAAK,MAAMD,CAAI,EAElC,CAAE,YAAAE,EAAa,aAAAC,CAAa,EAAI,KAAK,OAE3CA,EAAaF,EAAK,EAAE,EAAIA,EACpBA,EAAK,WAAa,KAClB,KAAK,OAAO,KAAOA,GAEdC,EAAYD,EAAK,QAAQ,IAAGC,EAAYD,EAAK,QAAQ,EAAI,CAAC,GAC/DC,EAAYD,EAAK,QAAQ,EAAE,KAAKA,EAAK,EAAE,EAE/C,MAAc,CAAsD,CACxE,CAKA,QAAQ,CACJ,KAAK,WAAW,KAAK,MAAM,EAC3B,KAAK,OAAS,EAClB,CACJ","names":["generateComponentMap","allowedComponents","acc","curr","constructInput","value","skeletonize","components","hint","actions","item","customComponents","componentContext","userContext","availableActions","key","action","inputValue","create_skeleton","input","defineTool","fn","params","context","ResponseParser","delta","split","line","node","childrenMap","componentMap"]}
1
+ {"version":3,"sources":["../src/util.ts","../src/ResponseParser.ts"],"sourcesContent":["import { GeneratedContentProps } from \"./templates/GeneratedUI\";\r\nimport { SyntuxComponent } from \"./types\";\r\n\r\n/**\r\n * Converts a list of components into a dictionary for fast-retrieval\r\n * during rendering.\r\n */\r\nexport function generateComponentMap(allowedComponents: (SyntuxComponent | string)[]) {\r\n return allowedComponents.reduce((acc: Record<string, React.ComponentType<any> | string>, curr: SyntuxComponent | string) => {\r\n if (typeof curr === \"string\") {\r\n acc[curr] = curr;\r\n return acc;\r\n }\r\n\r\n acc[curr.name] = curr.component;\r\n return acc;\r\n }, {})\r\n}\r\n\r\n/**\r\n * Creates LLM input in accordance to the spec\r\n */\r\nexport function constructInput({\r\n value, skeletonize = false, components, hint\r\n}: GeneratedContentProps) {\r\n const allowedComponents = components?.map((item: SyntuxComponent | string) => {\r\n if (typeof item === \"string\") return item;\r\n return item.name;\r\n }).join(',') || \"\"\r\n\r\n const customComponents = components?.filter((item): item is SyntuxComponent => typeof item !== \"string\");\r\n const componentContext = customComponents?.map((item) => {\r\n if (!item.context) {\r\n return `${item.name} [props: ${item.props}]`\r\n } else {\r\n return `${item.name} [props: ${item.props}, details: ${item.context}]`\r\n }\r\n }).join(',') || \"\"\r\n\r\n const userContext = hint;\r\n\r\n const inputValue = JSON.stringify(skeletonize ? createSkeleton(value) : value)\r\n\r\n return `<AllowedComponents>${allowedComponents}</AllowedComponents>\\n<ComponentContext>${componentContext}</ComponentContext>\\n<UserContext>${userContext || \"\"}</UserContext>\\n<IsSkeleton>${skeletonize.toString()}</IsSkeleton>\\n<Value>\\n${inputValue}\\n</Value>`\r\n}\r\n\r\n/**\r\n * generates a skeleton of the input value, ideal for large arrays or untrusted input.\r\n * see the FAQ for more information: https://github.com/puffinsoft/syntux/wiki/FAQ#handling-untrusted-input--large-arrays.\r\n * \r\n * *important*: assumes arrays are non-polymorphic\r\n */\r\nexport function createSkeleton(input: any) {\r\n if (input === null) return \"null\";\r\n\r\n if (typeof input !== \"object\") return typeof input;\r\n\r\n if (Array.isArray(input)) {\r\n if (input.length == 0) {\r\n return \"null\"; // ignore this field completely\r\n } else {\r\n return [createSkeleton(input[0])]\r\n }\r\n }\r\n return Object.entries(input).reduce((acc, [key, value]) => {\r\n acc[key] = createSkeleton(value);\r\n return acc;\r\n }, {})\r\n}","import { SchemaNode, UISchema } from \"./types\";\r\n\r\n/**\r\n * Utility class for parsing UISchema from stream.\r\n */\r\nexport class ResponseParser {\r\n buffer = \"\"; // unflushed existing deltas w/o newline\r\n total = \"\"; // accumulator\r\n\r\n // schema assembled thus far\r\n schema: UISchema = {\r\n childrenMap: {},\r\n componentMap: {},\r\n root: null\r\n }\r\n\r\n /**\r\n * Update schema with latest data chunk.\r\n * \r\n * Handles multiline input gracefully; can be used to load entire schemas from cache.\r\n * \r\n * @param delta delta from stream.\r\n * @returns true if update is warranted, false otherwise.\r\n */\r\n addDelta(delta: string) {\r\n this.total += delta;\r\n this.buffer += delta;\r\n const split = this.buffer.split(\"\\n\")\r\n if (split.length > 1) {\r\n split.slice(0, split.length - 1).forEach((line) => this.handleLine(line));\r\n this.buffer = split[split.length - 1];\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Parses a single line (full JSON object) and updates schema.\r\n * Generally should not be used when streaming data.\r\n */\r\n handleLine(line: string) {\r\n try {\r\n const node: SchemaNode = JSON.parse(line);\r\n\r\n const { childrenMap, componentMap } = this.schema;\r\n\r\n componentMap[node.id] = node;\r\n if (node.parentId === null) {\r\n this.schema.root = node;\r\n } else {\r\n if (!childrenMap[node.parentId]) childrenMap[node.parentId] = []\r\n childrenMap[node.parentId].push(node.id)\r\n }\r\n } catch (err) { /* probably markdown or generation inconsistency */ }\r\n }\r\n\r\n /**\r\n * Clears the buffer and handles any remaining information within.\r\n */\r\n finish(){\r\n this.handleLine(this.buffer);\r\n this.buffer = \"\";\r\n }\r\n}"],"mappings":"AAOO,SAASA,EAAqBC,EAAiD,CAClF,OAAOA,EAAkB,OAAO,CAACC,EAAwDC,IACjF,OAAOA,GAAS,UAChBD,EAAIC,CAAI,EAAIA,EACLD,IAGXA,EAAIC,EAAK,IAAI,EAAIA,EAAK,UACfD,GACR,CAAC,CAAC,CACT,CAKO,SAASE,EAAe,CAC3B,MAAAC,EAAO,YAAAC,EAAc,GAAO,WAAAC,EAAY,KAAAC,CAC5C,EAA0B,CACtB,IAAMP,GAAoBM,GAAA,YAAAA,EAAY,IAAKE,GACnC,OAAOA,GAAS,SAAiBA,EAC9BA,EAAK,MACb,KAAK,OAAQ,GAEVC,EAAmBH,GAAA,YAAAA,EAAY,OAAQE,GAAkC,OAAOA,GAAS,UACzFE,GAAmBD,GAAA,YAAAA,EAAkB,IAAKD,GACvCA,EAAK,QAGC,GAAGA,EAAK,IAAI,YAAYA,EAAK,KAAK,cAAcA,EAAK,OAAO,IAF5D,GAAGA,EAAK,IAAI,YAAYA,EAAK,KAAK,KAI9C,KAAK,OAAQ,GAEVG,EAAcJ,EAEdK,EAAa,KAAK,UAAUP,EAAcQ,EAAeT,CAAK,EAAIA,CAAK,EAE7E,MAAO,sBAAsBJ,CAAiB;AAAA,oBAA2CU,CAAgB;AAAA,eAAqCC,GAAe,EAAE;AAAA,cAA+BN,EAAY,SAAS,CAAC;AAAA;AAAA,EAA2BO,CAAU;AAAA,SAC7P,CAQO,SAASC,EAAeC,EAAY,CACvC,OAAIA,IAAU,KAAa,OAEvB,OAAOA,GAAU,SAAiB,OAAOA,EAEzC,MAAM,QAAQA,CAAK,EACfA,EAAM,QAAU,EACT,OAEA,CAACD,EAAeC,EAAM,CAAC,CAAC,CAAC,EAGjC,OAAO,QAAQA,CAAK,EAAE,OAAO,CAACb,EAAK,CAACc,EAAKX,CAAK,KACjDH,EAAIc,CAAG,EAAIF,EAAeT,CAAK,EACxBH,GACR,CAAC,CAAC,CACT,CC/DO,IAAMe,EAAN,KAAqB,CACxB,OAAS,GACT,MAAQ,GAGR,OAAmB,CACf,YAAa,CAAC,EACd,aAAc,CAAC,EACf,KAAM,IACV,EAUA,SAASC,EAAe,CACpB,KAAK,OAASA,EACd,KAAK,QAAUA,EACf,IAAMC,EAAQ,KAAK,OAAO,MAAM;AAAA,CAAI,EACpC,OAAIA,EAAM,OAAS,GACfA,EAAM,MAAM,EAAGA,EAAM,OAAS,CAAC,EAAE,QAASC,GAAS,KAAK,WAAWA,CAAI,CAAC,EACxE,KAAK,OAASD,EAAMA,EAAM,OAAS,CAAC,EAC7B,IAEJ,EACX,CAMA,WAAWC,EAAc,CACrB,GAAI,CACA,IAAMC,EAAmB,KAAK,MAAMD,CAAI,EAElC,CAAE,YAAAE,EAAa,aAAAC,CAAa,EAAI,KAAK,OAE3CA,EAAaF,EAAK,EAAE,EAAIA,EACpBA,EAAK,WAAa,KAClB,KAAK,OAAO,KAAOA,GAEdC,EAAYD,EAAK,QAAQ,IAAGC,EAAYD,EAAK,QAAQ,EAAI,CAAC,GAC/DC,EAAYD,EAAK,QAAQ,EAAE,KAAKA,EAAK,EAAE,EAE/C,MAAc,CAAsD,CACxE,CAKA,QAAQ,CACJ,KAAK,WAAW,KAAK,MAAM,EAC3B,KAAK,OAAS,EAClB,CACJ","names":["generateComponentMap","allowedComponents","acc","curr","constructInput","value","skeletonize","components","hint","item","customComponents","componentContext","userContext","inputValue","createSkeleton","input","key","ResponseParser","delta","split","line","node","childrenMap","componentMap"]}
@@ -1 +1 @@
1
- {"inputs":{"src/types.ts":{"bytes":683,"imports":[],"format":"esm"},"src/util.ts":{"bytes":3487,"imports":[{"path":"./templates/GeneratedUI","kind":"import-statement","external":true},{"path":"./types","kind":"import-statement","external":true}],"format":"esm"},"src/ResponseParser.ts":{"bytes":1865,"imports":[{"path":"./types","kind":"import-statement","external":true}],"format":"esm"},"src/index.ts":{"bytes":84,"imports":[{"path":"src/types.ts","kind":"import-statement","original":"./types"},{"path":"src/util.ts","kind":"import-statement","original":"./util"},{"path":"src/ResponseParser.ts","kind":"import-statement","original":"./ResponseParser"}],"format":"esm"},"src/client/Renderer.tsx":{"bytes":4350,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"../types","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"src/client/SyntuxContext.tsx":{"bytes":407,"imports":[{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"src/client/GeneratedClient.tsx":{"bytes":2373,"imports":[{"path":"@ai-sdk/rsc","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"src/types","kind":"import-statement","external":true},{"path":"src/ResponseParser.ts","kind":"import-statement","original":"../ResponseParser"},{"path":"src/client/Renderer.tsx","kind":"import-statement","original":"./Renderer"},{"path":"src/client/SyntuxContext.tsx","kind":"import-statement","original":"./SyntuxContext"},{"path":"react/jsx-runtime","kind":"import-statement","external":true}],"format":"esm"},"src/client.ts":{"bytes":133,"imports":[{"path":"src/client/GeneratedClient.tsx","kind":"import-statement","original":"./client/GeneratedClient"},{"path":"src/client/Renderer.tsx","kind":"import-statement","original":"./client/Renderer"},{"path":"src/client/SyntuxContext.tsx","kind":"import-statement","original":"./client/SyntuxContext"}],"format":"esm"},"src/bin/cli_util.mjs":{"bytes":115,"imports":[{"path":"chalk","kind":"import-statement","external":true}],"format":"esm"},"src/bin/commands/init.mjs":{"bytes":3700,"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"child_process","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"src/bin/cli_util.mjs","kind":"import-statement","original":"../cli_util.mjs"},{"path":"url","kind":"import-statement","external":true}],"format":"esm"},"src/bin/commands/generate.mjs":{"bytes":2933,"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"react-docgen-typescript","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true},{"path":"src/bin/cli_util.mjs","kind":"import-statement","original":"../cli_util.mjs"}],"format":"esm"},"src/bin/cli.mjs":{"bytes":482,"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"src/bin/commands/init.mjs","kind":"import-statement","original":"./commands/init.mjs"},{"path":"src/bin/commands/generate.mjs","kind":"import-statement","original":"./commands/generate.mjs"}],"format":"esm"}},"outputs":{"dist/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":8268},"dist/index.mjs":{"imports":[],"exports":["ResponseParser","constructInput","create_skeleton","defineTool","generateComponentMap"],"entryPoint":"src/index.ts","inputs":{"src/index.ts":{"bytesInOutput":0},"src/util.ts":{"bytesInOutput":1050},"src/ResponseParser.ts":{"bytesInOutput":485}},"bytes":1647},"dist/client.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":15341},"dist/client.mjs":{"imports":[{"path":"@ai-sdk/rsc","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true}],"exports":["GeneratedClient","Renderer","SyntuxContext","useSyntux"],"entryPoint":"src/client.ts","inputs":{"src/client/GeneratedClient.tsx":{"bytesInOutput":862},"src/ResponseParser.ts":{"bytesInOutput":485},"src/client/Renderer.tsx":{"bytesInOutput":1393},"src/client/SyntuxContext.tsx":{"bytesInOutput":171},"src/client.ts":{"bytesInOutput":0}},"bytes":3003},"dist/bin/cli.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":12417},"dist/bin/cli.mjs":{"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"commander","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"child_process","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"url","kind":"import-statement","external":true},{"path":"commander","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"react-docgen-typescript","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true}],"exports":[],"entryPoint":"src/bin/cli.mjs","inputs":{"src/bin/cli.mjs":{"bytesInOutput":250},"src/bin/commands/init.mjs":{"bytesInOutput":1851},"src/bin/cli_util.mjs":{"bytesInOutput":78},"src/bin/commands/generate.mjs":{"bytesInOutput":1443}},"bytes":3643}}}
1
+ {"inputs":{"src/types.ts":{"bytes":1256,"imports":[{"path":"@ai-sdk/rsc","kind":"import-statement","external":true}],"format":"esm"},"src/util.ts":{"bytes":2558,"imports":[{"path":"./templates/GeneratedUI","kind":"import-statement","external":true},{"path":"./types","kind":"import-statement","external":true}],"format":"esm"},"src/ResponseParser.ts":{"bytes":1923,"imports":[{"path":"./types","kind":"import-statement","external":true}],"format":"esm"},"src/index.ts":{"bytes":84,"imports":[{"path":"src/types.ts","kind":"import-statement","original":"./types"},{"path":"src/util.ts","kind":"import-statement","original":"./util"},{"path":"src/ResponseParser.ts","kind":"import-statement","original":"./ResponseParser"}],"format":"esm"},"src/client/Renderer.tsx":{"bytes":4570,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"../types","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"src/client/SyntuxContext.tsx":{"bytes":497,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"src/types","kind":"import-statement","external":true}],"format":"esm"},"src/client/GeneratedClient.tsx":{"bytes":3579,"imports":[{"path":"@ai-sdk/rsc","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"src/types","kind":"import-statement","external":true},{"path":"src/ResponseParser.ts","kind":"import-statement","original":"src/ResponseParser"},{"path":"src/client/Renderer.tsx","kind":"import-statement","original":"./Renderer"},{"path":"src/client/SyntuxContext.tsx","kind":"import-statement","original":"./SyntuxContext"},{"path":"react/jsx-runtime","kind":"import-statement","external":true}],"format":"esm"},"src/client.ts":{"bytes":133,"imports":[{"path":"src/client/GeneratedClient.tsx","kind":"import-statement","original":"./client/GeneratedClient"},{"path":"src/client/Renderer.tsx","kind":"import-statement","original":"./client/Renderer"},{"path":"src/client/SyntuxContext.tsx","kind":"import-statement","original":"./client/SyntuxContext"}],"format":"esm"},"src/bin/cli_util.mjs":{"bytes":115,"imports":[{"path":"chalk","kind":"import-statement","external":true}],"format":"esm"},"src/bin/commands/init.mjs":{"bytes":3700,"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"child_process","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"src/bin/cli_util.mjs","kind":"import-statement","original":"../cli_util.mjs"},{"path":"url","kind":"import-statement","external":true}],"format":"esm"},"src/bin/commands/generate.mjs":{"bytes":2933,"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"react-docgen-typescript","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true},{"path":"src/bin/cli_util.mjs","kind":"import-statement","original":"../cli_util.mjs"}],"format":"esm"},"src/bin/cli.mjs":{"bytes":482,"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"src/bin/commands/init.mjs","kind":"import-statement","original":"./commands/init.mjs"},{"path":"src/bin/commands/generate.mjs","kind":"import-statement","original":"./commands/generate.mjs"}],"format":"esm"}},"outputs":{"dist/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":6941},"dist/index.mjs":{"imports":[],"exports":["ResponseParser","constructInput","createSkeleton","generateComponentMap"],"entryPoint":"src/index.ts","inputs":{"src/index.ts":{"bytesInOutput":0},"src/util.ts":{"bytesInOutput":809},"src/ResponseParser.ts":{"bytesInOutput":508}},"bytes":1412},"dist/client.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":17974},"dist/client.mjs":{"imports":[{"path":"@ai-sdk/rsc","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true}],"exports":["GeneratedClient","Renderer","SyntuxContext","useSyntux"],"entryPoint":"src/client.ts","inputs":{"src/client/GeneratedClient.tsx":{"bytesInOutput":1220},"src/ResponseParser.ts":{"bytesInOutput":508},"src/client/Renderer.tsx":{"bytesInOutput":1727},"src/client/SyntuxContext.tsx":{"bytesInOutput":172},"src/client.ts":{"bytesInOutput":0}},"bytes":3720},"dist/bin/cli.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":12417},"dist/bin/cli.mjs":{"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"commander","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"child_process","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"url","kind":"import-statement","external":true},{"path":"commander","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"react-docgen-typescript","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true}],"exports":[],"entryPoint":"src/bin/cli.mjs","inputs":{"src/bin/cli.mjs":{"bytesInOutput":250},"src/bin/commands/init.mjs":{"bytesInOutput":1851},"src/bin/cli_util.mjs":{"bytesInOutput":78},"src/bin/commands/generate.mjs":{"bytesInOutput":1443}},"bytes":3643}}}
@@ -1,10 +1,10 @@
1
1
  import { JSX } from 'react';
2
2
 
3
- import { createStreamableValue } from '@ai-sdk/rsc';
3
+ import { createStreamableValue, StreamableValue } from '@ai-sdk/rsc';
4
4
  import { LanguageModel, streamText } from 'ai';
5
5
 
6
+ import { AnimateOptions, constructInput, generateComponentMap, ResponseParser, SyntuxComponent, UISchema } from "getsyntux";
6
7
  import { GeneratedClient, Renderer } from 'getsyntux/client';
7
- import { ContextfulAction, ResponseParser, SyntuxComponent, UISchema, constructInput, generateComponentMap } from "getsyntux";
8
8
 
9
9
  import spec from './spec';
10
10
 
@@ -12,7 +12,6 @@ export interface GeneratedContentProps {
12
12
  value: any;
13
13
  model: LanguageModel;
14
14
  components?: (SyntuxComponent | string)[];
15
- actions?: Record<string, ContextfulAction>;
16
15
  hint?: string;
17
16
  placeholder?: JSX.Element;
18
17
  cached?: string;
@@ -26,6 +25,9 @@ export interface GeneratedContentProps {
26
25
 
27
26
  onError?: (arg0: any) => void;
28
27
  errorFallback?: JSX.Element;
28
+ animate?: AnimateOptions
29
+
30
+ rerender?: (arg0: string, arg1: string, arg2: string) => Promise<{ value: StreamableValue }>
29
31
  }
30
32
 
31
33
  /**
@@ -33,72 +35,58 @@ export interface GeneratedContentProps {
33
35
  * @param values The values (object, primitive, or array) to be displayed.
34
36
  * @param model The LanguageModel (as provided from AI SDK) to use. Must support streaming
35
37
  * @param components List of allowed components that LLM can use.
36
- * @param actions Map of callbacks that can be attached to events (e.g., onClick, onMouseOver) by LLM.
37
38
  * @param hint Additional custom instructions for the LLM.
38
39
  * @param placeholder A placeholder to show while awaiting streaming (NOT during streaming)
39
40
  * @param cached Schema returned from onGenerate, used for caching UI
40
41
  * @param onGenerate Callback which accepts a string, to be passed to `cached` to reuse same UI
41
- * @param skeletonize Compresses value for large inputs (arrays) or untrusted input
42
- * @param onError Callback which accepts an error, invoked when necessary. If not provided, runtime error occurs.
43
- * @param errorFallback An element fallback to show if an error occurs during generation.
44
42
  */
45
43
  export async function GeneratedUI(props: GeneratedContentProps) {
46
44
  const input = constructInput(props);
45
+ const rerenderContext = input.split('\n').slice(0, 2);
47
46
 
48
- const { value, model, components, placeholder, cached, onGenerate, actions, onError, errorFallback } = props;
49
-
47
+ const { value, model, components, placeholder, cached, onGenerate, rerender } = props;
48
+
50
49
  const allowedComponents = generateComponentMap(components || []);
51
50
 
52
51
  // prerender if cached
53
- if (cached) {
52
+ if(cached){
54
53
  const parser = new ResponseParser();
55
54
  parser.addDelta(cached);
56
55
  parser.finish();
57
56
 
58
57
  const schema: UISchema = parser.schema;
59
58
 
60
- if (schema.root) {
59
+ if(schema.root){
61
60
  return <Renderer id={schema.root.id} componentMap={schema.componentMap} childrenMap={schema.childrenMap}
62
- allowedComponents={allowedComponents} global={value} local={value} actions={actions || {}} />
61
+ allowedComponents={allowedComponents} global={value} local={value} />
63
62
  } else {
64
63
  return <></>;
65
64
  }
66
65
  }
67
66
 
68
67
  const stream = createStreamableValue('');
68
+
69
69
  (async () => {
70
70
  let total = "";
71
- let errored = false;
72
71
 
73
72
  const { textStream } = await streamText({
74
73
  model,
75
74
  system: spec,
76
- prompt: input,
77
- onError: (err) => {
78
- stream.error(err)
79
- errored = true;
80
-
81
- if (!onError) {
82
- if (!errorFallback) {
83
- throw err;
84
- }
85
- } else {
86
- onError(err)
87
- }
88
- }
75
+ prompt: input
89
76
  })
90
77
 
91
- for await (const delta of textStream) {
78
+ for await(const delta of textStream){
92
79
  stream.update(delta);
93
80
  total += delta;
94
81
  }
95
82
 
96
- if (!errored) {
97
- stream.done();
98
- }
83
+ stream.done();
99
84
 
100
- if (onGenerate) onGenerate(total);
85
+ if(onGenerate) onGenerate(total);
101
86
  })()
102
87
 
103
- return <GeneratedClient value={value} allowedComponents={allowedComponents} inputStream={stream.value} placeholder={placeholder} actions={actions} errorFallback={errorFallback} />
88
+ return <GeneratedClient value={value} allowedComponents={allowedComponents} inputStream={stream.value} placeholder={placeholder} rerender={{
89
+ context: rerenderContext.join('\n'),
90
+ action: rerender
91
+ }} />
104
92
  }
@@ -0,0 +1,54 @@
1
+ "use server";
2
+
3
+ /**
4
+ * this file is optional!
5
+ * you can delete it if you do not need rerender functionality.
6
+ *
7
+ * run "npm i @ai-sdk/anthropic" if you want to use Claude.
8
+ */
9
+ import { createAnthropic } from "@ai-sdk/anthropic";
10
+ import { createStreamableValue } from "@ai-sdk/rsc";
11
+ import { streamText } from "ai";
12
+
13
+ import spec from "./spec";
14
+
15
+ /**
16
+ * IMPORTANT: replace the below with your own model.
17
+ */
18
+ const anthropic = createAnthropic({
19
+ apiKey: "..."
20
+ })
21
+ const model = anthropic("claude-haiku-4-5");
22
+
23
+ /**
24
+ * The server action for rerendering the UI.
25
+ * This is an UNSECURED ENDPOINT. Please modify it to perform your own authentication etc,.
26
+ *
27
+ * @param context information about allowed components, component context etc,.
28
+ * @param existing the current UI schema.
29
+ * @param hint the update request.
30
+ */
31
+ export async function rerenderAction(context: string, existing: string, hint: string) {
32
+ const stream = createStreamableValue('');
33
+ (async () => {
34
+ let total = "";
35
+ let errored = false;
36
+
37
+ const { textStream } = await streamText({
38
+ model,
39
+ system: spec,
40
+ prompt: `${context}\n<Existing>${existing}</Existing>\n<UserContext>${hint}</UserContext>`,
41
+ })
42
+
43
+ for await (const delta of textStream) {
44
+ stream.update(delta);
45
+ total += delta;
46
+ }
47
+
48
+ if (!errored) {
49
+ stream.done();
50
+ }
51
+ })()
52
+
53
+ return { value: stream.value }
54
+ }
@@ -32,24 +32,6 @@ Use "$bind" in `content` or `props` to link data.
32
32
  Use "$bind": "$" to reference the global object itself, useful when the value itself is an array and you need to loop through it.
33
33
  </binding_rules>
34
34
 
35
- <action_rules>
36
- In the props, to attach event handlers (like onClick), use the "$action" schema.
37
- Format: { "$action": "actionName", "args": [arg1, arg2, ...] }
38
-
39
- Argument Rules:
40
- - Hardcoded value: Pass the literal value directly (e.g., "dark_mode", 15, true).
41
- - Dynamic value: Use a binding object (e.g., { "$bind": "$item.id" }).
42
-
43
- Example:
44
- "props": {
45
- "onClick": {
46
- "$action": "addToCart",
47
- "args": [ { "$bind": "$item.id" }, 1 ]
48
- }
49
- }
50
- This calls the `addToCart` action with the item's ID and the number 1.
51
- </action_rules>
52
-
53
35
  <iteration>
54
36
  To render arrays, use the `__ForEach__` component.
55
37
  To define a loop:
@@ -68,13 +50,13 @@ In the example above, card_1 is the template that repeats for every author. It s
68
50
  * `AllowedComponents` is a comma-separated list, lowercase for Native HTML tags, Uppercase for Custom React Components. If none are provided, you can use any HTML tag. If they are, only use them to the best of your ability.
69
51
  * `ComponentContext` defines the Typescript interface for custom components. Components are separated by a comma, in the format `ComponentName [props: { ... }, details: "..."]`. The `props` indicate what `props` it must accept, in Typescript format. The `details` is an optional field, and describes what the component does. DO NOT hallucinate props. Use the details to better your understanding of how to generate the UI.
70
52
  2. Parse Context: Read `UserContext` for specific design requests.
71
- 3. Parse Actions: Read `AvailableActions`.
72
- - This list contains functions you can attach to events (onClick, onHover, etc.).
73
- - The format is `actionName(params): description`.
74
- - ONLY use actions listed here. Do not invent function names.
75
- - Pay close attention to the `params` signature to ensure you pass the correct data types in the `args` array.
76
- 4. Parse Data: Analyze `Value` to determine structure.
77
- 5. Check Skeleton: Read `IsSkeleton`. If it is `true`, that means all the property values have been replaced by the *type* of the value. If it is `false`, then you are seeing the raw values of each property.
53
+ 3. Parse Data: Analyze `Value` to determine structure.
54
+ 4. Check Skeleton: Read `IsSkeleton`. If it is `true`, that means all the property values have been replaced by the *type* of the value. If it is `false`, then you are seeing the raw values of each property.
55
+ 5. Check Existing: If `Existing` exists, then your job is to update the existing UI.
56
+ * Existing is the schema for the existing UI
57
+ * Read UserContext: it contains a request to update the UI
58
+ * Output the same, full UI, updated with the request. For instance, if UserContext says to remove something, generate the same UI, but with the thing removed.
59
+ * Ensure the new UI is semantically valid.
78
60
  </input_processing_rules>
79
61
 
80
62
  <output_formatting>
@@ -84,7 +66,6 @@ Input:
84
66
  <AllowedComponents>...</AllowedComponents>
85
67
  <ComponentContext>...</ComponentContext>
86
68
  <UserContext>...</UserContext>
87
- <AvailableActions>...</AvailableActions>
88
69
  <IsSkeleton>...</IsSkeleton>
89
70
  <Value>...</Value>
90
71
 
@@ -101,4 +82,5 @@ Output:
101
82
 
102
83
  <IMPORTANT>
103
84
  Do NOT output anything EXCEPT the list of JSON.
85
+ Do NOT add event listeners.
104
86
  </IMPORTANT>
@@ -38,24 +38,6 @@ Use "$bind" in \`content\` or \`props\` to link data.
38
38
  Use "$bind": "$" to reference the global object itself, useful when the value itself is an array and you need to loop through it.
39
39
  </binding_rules>
40
40
 
41
- <action_rules>
42
- In the props, to attach event handlers (like onClick), use the "$action" schema.
43
- Format: { "$action": "actionName", "args": [arg1, arg2, ...] }
44
-
45
- Argument Rules:
46
- - Hardcoded value: Pass the literal value directly (e.g., "dark_mode", 15, true).
47
- - Dynamic value: Use a binding object (e.g., { "$bind": "$item.id" }).
48
-
49
- Example:
50
- "props": {
51
- "onClick": {
52
- "$action": "addToCart",
53
- "args": [ { "$bind": "$item.id" }, 1 ]
54
- }
55
- }
56
- This calls the \`addToCart\` action with the item's ID and the number 1.
57
- </action_rules>
58
-
59
41
  <iteration>
60
42
  To render arrays, use the \`__ForEach__\` component.
61
43
  To define a loop:
@@ -74,13 +56,13 @@ In the example above, card_1 is the template that repeats for every author. It s
74
56
  * \`AllowedComponents\` is a comma-separated list, lowercase for Native HTML tags, Uppercase for Custom React Components. If none are provided, you can use any HTML tag. If they are, only use them to the best of your ability.
75
57
  * \`ComponentContext\` defines the Typescript interface for custom components. Components are separated by a comma, in the format \`ComponentName [props: { ... }, details: "..."]\`. The \`props\` indicate what \`props\` it must accept, in Typescript format. The \`details\` is an optional field, and describes what the component does. DO NOT hallucinate props. Use the details to better your understanding of how to generate the UI.
76
58
  2. Parse Context: Read \`UserContext\` for specific design requests.
77
- 3. Parse Actions: Read \`AvailableActions\`.
78
- - This list contains functions you can attach to events (onClick, onHover, etc.).
79
- - The format is \`actionName(params): description\`.
80
- - ONLY use actions listed here. Do not invent function names.
81
- - Pay close attention to the \`params\` signature to ensure you pass the correct data types in the \`args\` array.
82
- 4. Parse Data: Analyze \`Value\` to determine structure.
83
- 5. Check Skeleton: Read \`IsSkeleton\`. If it is \`true\`, that means all the property values have been replaced by the *type* of the value. If it is \`false\`, then you are seeing the raw values of each property.
59
+ 3. Parse Data: Analyze \`Value\` to determine structure.
60
+ 4. Check Skeleton: Read \`IsSkeleton\`. If it is \`true\`, that means all the property values have been replaced by the *type* of the value. If it is \`false\`, then you are seeing the raw values of each property.
61
+ 5. Check Existing: If \`Existing\` exists, then your job is to update the existing UI.
62
+ * Existing is the schema for the existing UI
63
+ * Read UserContext: it contains a request to update the UI
64
+ * Output the same, full UI, updated with the request. For instance, if UserContext says to remove something, generate the same UI, but with the thing removed.
65
+ * Ensure the new UI is semantically valid.
84
66
  </input_processing_rules>
85
67
 
86
68
  <output_formatting>
@@ -90,13 +72,23 @@ Input:
90
72
  <AllowedComponents>...</AllowedComponents>
91
73
  <ComponentContext>...</ComponentContext>
92
74
  <UserContext>...</UserContext>
93
- <AvailableActions>...</AvailableActions>
94
75
  <IsSkeleton>...</IsSkeleton>
95
76
  <Value>...</Value>
96
77
 
97
78
  Output:
98
79
  { ... }
99
80
  ... more lines
81
+
82
+ Or for an existing UI:
83
+
84
+ <AllowedComponents>...</AllowedComponents>
85
+ <ComponentContext>...</ComponentContext>
86
+ <UserContext>...</UserContext>
87
+ <Existing>...</Existing>
88
+
89
+ Output:
90
+ { ... }
91
+ ... more lines
100
92
  </output_formatting>
101
93
 
102
94
  <reasoning_requirements>
@@ -107,6 +99,7 @@ Output:
107
99
 
108
100
  <IMPORTANT>
109
101
  Do NOT output anything EXCEPT the list of JSON.
102
+ Do NOT add event listeners.
110
103
  </IMPORTANT>`;
111
104
 
112
105
  export default spec;
@@ -0,0 +1,45 @@
1
+ import { StreamableValue } from '@ai-sdk/rsc';
2
+
3
+ type SchemaNode = {
4
+ id: string;
5
+ parentId: string | null;
6
+ type: string;
7
+ props?: Record<string, any>;
8
+ content?: any | {
9
+ "$bind": string;
10
+ };
11
+ };
12
+ type ComponentMap = Record<string, SchemaNode>;
13
+ type ChildrenMap = Record<string, string[]>;
14
+ type UISchema = {
15
+ componentMap: ComponentMap;
16
+ childrenMap: ChildrenMap;
17
+ root: SchemaNode | null;
18
+ };
19
+ type SyntuxComponent = {
20
+ name: string;
21
+ props: string;
22
+ component: React.ComponentType<any>;
23
+ context?: string;
24
+ };
25
+ type AnimateOptions = {
26
+ offset: number;
27
+ duration: number;
28
+ };
29
+ /**
30
+ * setValue will not send a request if regenerate is false.
31
+ * however, the value will still be updated (statically).
32
+ * as opposed to a falsy options existence check, this is more robust for DX.
33
+ */
34
+ type RerenderOptions = {
35
+ regenerate: boolean;
36
+ hint: string;
37
+ };
38
+ type RerenderContext = {
39
+ context: string;
40
+ action?: (arg0: string, arg1: string, arg2: string) => Promise<{
41
+ value: StreamableValue;
42
+ }>;
43
+ };
44
+
45
+ export type { AnimateOptions as A, ChildrenMap as C, RerenderContext as R, SyntuxComponent as S, UISchema as U, ComponentMap as a, RerenderOptions as b, SchemaNode as c };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "getsyntux",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Build generative UIs for the web.",
5
5
  "exports": {
6
6
  ".": {
@@ -1,29 +0,0 @@
1
- type SchemaNode = {
2
- id: string;
3
- parentId: string | null;
4
- type: string;
5
- props?: Record<string, any>;
6
- content?: any | {
7
- "$bind": string;
8
- };
9
- };
10
- type ComponentMap = Record<string, SchemaNode>;
11
- type ChildrenMap = Record<string, string[]>;
12
- type UISchema = {
13
- componentMap: ComponentMap;
14
- childrenMap: ChildrenMap;
15
- root: SchemaNode | null;
16
- };
17
- type SyntuxComponent = {
18
- name: string;
19
- props: string;
20
- component: React.ComponentType<any>;
21
- context?: string;
22
- };
23
- type ContextfulAction = {
24
- fn: Function;
25
- params: string;
26
- context: string;
27
- };
28
-
29
- export type { ContextfulAction as C, SyntuxComponent as S, UISchema as U, ChildrenMap as a, ComponentMap as b, SchemaNode as c };