autoui-react 0.0.4-alpha → 0.1.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 +6 -52
- package/dist/index.css +0 -10
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +70 -103
- package/dist/index.d.ts +70 -103
- package/dist/index.js +418 -1155
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +412 -1141
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -44
package/dist/index.mjs
CHANGED
|
@@ -1,105 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { twMerge } from 'tailwind-merge';
|
|
3
|
-
import { Slot } from '@radix-ui/react-slot';
|
|
4
|
-
import { cva } from 'class-variance-authority';
|
|
5
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
|
-
import React, { useState, useEffect, useRef, useCallback, useReducer } from 'react';
|
|
7
|
-
import { createOpenAI } from '@ai-sdk/openai';
|
|
8
|
-
import { generateObject } from 'ai';
|
|
1
|
+
import { useState, useEffect, useRef, useCallback, useReducer } from 'react';
|
|
9
2
|
import { z } from 'zod';
|
|
10
|
-
|
|
11
|
-
var __defProp = Object.defineProperty;
|
|
12
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
-
var __esm = (fn, res) => function __init() {
|
|
14
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
15
|
-
};
|
|
16
|
-
var __export = (target, all) => {
|
|
17
|
-
for (var name in all)
|
|
18
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
19
|
-
};
|
|
20
|
-
function cn(...inputs) {
|
|
21
|
-
return twMerge(clsx(inputs));
|
|
22
|
-
}
|
|
23
|
-
var init_utils = __esm({
|
|
24
|
-
"src/lib/utils.ts"() {
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// components/ui/button.tsx
|
|
29
|
-
var button_exports = {};
|
|
30
|
-
__export(button_exports, {
|
|
31
|
-
Button: () => Button2,
|
|
32
|
-
buttonVariants: () => buttonVariants
|
|
33
|
-
});
|
|
34
|
-
function Button2({
|
|
35
|
-
className,
|
|
36
|
-
variant,
|
|
37
|
-
size,
|
|
38
|
-
asChild = false,
|
|
39
|
-
...props
|
|
40
|
-
}) {
|
|
41
|
-
const Comp = asChild ? Slot : "button";
|
|
42
|
-
return /* @__PURE__ */ jsx(
|
|
43
|
-
Comp,
|
|
44
|
-
{
|
|
45
|
-
"data-slot": "button",
|
|
46
|
-
className: cn(buttonVariants({ variant, size, className })),
|
|
47
|
-
...props
|
|
48
|
-
}
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
var buttonVariants;
|
|
52
|
-
var init_button = __esm({
|
|
53
|
-
"components/ui/button.tsx"() {
|
|
54
|
-
init_utils();
|
|
55
|
-
buttonVariants = cva(
|
|
56
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
57
|
-
{
|
|
58
|
-
variants: {
|
|
59
|
-
variant: {
|
|
60
|
-
default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
|
61
|
-
destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
62
|
-
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
|
63
|
-
secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
|
64
|
-
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
65
|
-
link: "text-primary underline-offset-4 hover:underline"
|
|
66
|
-
},
|
|
67
|
-
size: {
|
|
68
|
-
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
69
|
-
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
70
|
-
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
71
|
-
icon: "size-9"
|
|
72
|
-
}
|
|
73
|
-
},
|
|
74
|
-
defaultVariants: {
|
|
75
|
-
variant: "default",
|
|
76
|
-
size: "default"
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
3
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
82
4
|
|
|
83
5
|
// src/core/reducer.ts
|
|
84
6
|
function cloneNode(node) {
|
|
85
7
|
return {
|
|
86
8
|
...node,
|
|
87
|
-
props: node.props ? { ...node.props } :
|
|
88
|
-
bindings: node.bindings ? { ...node.bindings } :
|
|
89
|
-
events: node.events ? { ...node.events } :
|
|
90
|
-
children: node.children
|
|
9
|
+
props: node.props ? { ...node.props } : void 0,
|
|
10
|
+
bindings: node.bindings ? { ...node.bindings } : void 0,
|
|
11
|
+
events: node.events ? { ...node.events } : void 0,
|
|
12
|
+
children: node.children?.map((child) => cloneNode(child))
|
|
91
13
|
};
|
|
92
14
|
}
|
|
93
15
|
function findNodeById(tree, nodeId) {
|
|
94
|
-
if (!tree)
|
|
95
|
-
|
|
96
|
-
if (tree.id === nodeId)
|
|
97
|
-
return tree;
|
|
16
|
+
if (!tree) return void 0;
|
|
17
|
+
if (tree.id === nodeId) return tree;
|
|
98
18
|
if (tree.children) {
|
|
99
19
|
for (const child of tree.children) {
|
|
100
20
|
const found = findNodeById(child, nodeId);
|
|
101
|
-
if (found)
|
|
102
|
-
return found;
|
|
21
|
+
if (found) return found;
|
|
103
22
|
}
|
|
104
23
|
}
|
|
105
24
|
return void 0;
|
|
@@ -114,15 +33,13 @@ function updateNodeById(tree, nodeId, updater) {
|
|
|
114
33
|
if (node.children) {
|
|
115
34
|
for (const child of node.children) {
|
|
116
35
|
const path2 = findPath(child, id, newPath);
|
|
117
|
-
if (path2)
|
|
118
|
-
return path2;
|
|
36
|
+
if (path2) return path2;
|
|
119
37
|
}
|
|
120
38
|
}
|
|
121
39
|
return null;
|
|
122
40
|
}
|
|
123
41
|
const path = findPath(result, nodeId);
|
|
124
|
-
if (!path)
|
|
125
|
-
return result;
|
|
42
|
+
if (!path) return result;
|
|
126
43
|
const nodeToUpdate = path[path.length - 1];
|
|
127
44
|
const updatedNode = updater(nodeToUpdate);
|
|
128
45
|
if (path.length === 1) {
|
|
@@ -131,14 +48,18 @@ function updateNodeById(tree, nodeId, updater) {
|
|
|
131
48
|
const parent = path[path.length - 2];
|
|
132
49
|
const updatedParent = {
|
|
133
50
|
...parent,
|
|
134
|
-
children: parent.children
|
|
51
|
+
children: parent.children?.map(
|
|
135
52
|
(child) => child.id === nodeId ? updatedNode : child
|
|
136
|
-
)
|
|
53
|
+
)
|
|
137
54
|
};
|
|
138
55
|
if (path.length === 2) {
|
|
139
56
|
return updatedParent;
|
|
140
57
|
}
|
|
141
|
-
return updateNodeById(
|
|
58
|
+
return updateNodeById(
|
|
59
|
+
result,
|
|
60
|
+
parent.id,
|
|
61
|
+
() => updatedParent
|
|
62
|
+
);
|
|
142
63
|
}
|
|
143
64
|
function replaceNodeById(tree, nodeId, newNode) {
|
|
144
65
|
return updateNodeById(tree, nodeId, () => newNode);
|
|
@@ -165,8 +86,7 @@ function removeNodeById(tree, nodeId) {
|
|
|
165
86
|
}
|
|
166
87
|
for (const child of node.children) {
|
|
167
88
|
const parent2 = findParent(child, id);
|
|
168
|
-
if (parent2)
|
|
169
|
-
return parent2;
|
|
89
|
+
if (parent2) return parent2;
|
|
170
90
|
}
|
|
171
91
|
}
|
|
172
92
|
return null;
|
|
@@ -176,11 +96,10 @@ function removeNodeById(tree, nodeId) {
|
|
|
176
96
|
throw new Error("Cannot remove root node");
|
|
177
97
|
}
|
|
178
98
|
const parent = findParent(result, nodeId);
|
|
179
|
-
if (!parent)
|
|
180
|
-
return result;
|
|
99
|
+
if (!parent) return result;
|
|
181
100
|
return updateNodeById(result, parent.id, (node) => ({
|
|
182
101
|
...node,
|
|
183
|
-
children: node.children
|
|
102
|
+
children: node.children?.filter((child) => child.id !== nodeId)
|
|
184
103
|
}));
|
|
185
104
|
}
|
|
186
105
|
function uiReducer(state, action) {
|
|
@@ -197,7 +116,7 @@ function uiReducer(state, action) {
|
|
|
197
116
|
...state,
|
|
198
117
|
layout: action.node,
|
|
199
118
|
loading: false,
|
|
200
|
-
error:
|
|
119
|
+
error: void 0
|
|
201
120
|
};
|
|
202
121
|
}
|
|
203
122
|
case "PARTIAL_UPDATE": {
|
|
@@ -206,7 +125,7 @@ function uiReducer(state, action) {
|
|
|
206
125
|
...state,
|
|
207
126
|
layout: action.node,
|
|
208
127
|
loading: false,
|
|
209
|
-
error:
|
|
128
|
+
error: void 0
|
|
210
129
|
};
|
|
211
130
|
}
|
|
212
131
|
if (action.nodeId === "root" || action.nodeId === state.layout.id) {
|
|
@@ -214,23 +133,19 @@ function uiReducer(state, action) {
|
|
|
214
133
|
...state,
|
|
215
134
|
layout: action.node,
|
|
216
135
|
loading: false,
|
|
217
|
-
error:
|
|
136
|
+
error: void 0
|
|
218
137
|
};
|
|
219
138
|
}
|
|
220
139
|
return {
|
|
221
140
|
...state,
|
|
222
141
|
layout: replaceNodeById(state.layout, action.nodeId, action.node),
|
|
223
142
|
loading: false,
|
|
224
|
-
error:
|
|
143
|
+
error: void 0
|
|
225
144
|
};
|
|
226
145
|
}
|
|
227
146
|
case "ADD_NODE": {
|
|
228
147
|
if (!state.layout) {
|
|
229
|
-
return
|
|
230
|
-
...state,
|
|
231
|
-
error: "Cannot add node: Layout is empty.",
|
|
232
|
-
loading: false
|
|
233
|
-
};
|
|
148
|
+
return state;
|
|
234
149
|
}
|
|
235
150
|
return {
|
|
236
151
|
...state,
|
|
@@ -238,41 +153,21 @@ function uiReducer(state, action) {
|
|
|
238
153
|
state.layout,
|
|
239
154
|
action.parentId,
|
|
240
155
|
action.node,
|
|
241
|
-
action.index
|
|
156
|
+
action.index
|
|
242
157
|
),
|
|
243
158
|
loading: false,
|
|
244
|
-
error:
|
|
159
|
+
error: void 0
|
|
245
160
|
};
|
|
246
161
|
}
|
|
247
162
|
case "REMOVE_NODE": {
|
|
248
163
|
if (!state.layout) {
|
|
249
|
-
return
|
|
250
|
-
...state,
|
|
251
|
-
error: "Cannot remove node: Layout is empty.",
|
|
252
|
-
loading: false
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
try {
|
|
256
|
-
return {
|
|
257
|
-
...state,
|
|
258
|
-
layout: removeNodeById(state.layout, action.nodeId),
|
|
259
|
-
loading: false,
|
|
260
|
-
error: null
|
|
261
|
-
};
|
|
262
|
-
} catch (e) {
|
|
263
|
-
const errorMessage = e instanceof Error ? e.message : "Failed to remove node.";
|
|
264
|
-
return {
|
|
265
|
-
...state,
|
|
266
|
-
error: errorMessage,
|
|
267
|
-
loading: false
|
|
268
|
-
};
|
|
164
|
+
return state;
|
|
269
165
|
}
|
|
270
|
-
}
|
|
271
|
-
case "ERROR": {
|
|
272
166
|
return {
|
|
273
167
|
...state,
|
|
274
|
-
|
|
275
|
-
loading: false
|
|
168
|
+
layout: removeNodeById(state.layout, action.nodeId),
|
|
169
|
+
loading: false,
|
|
170
|
+
error: void 0
|
|
276
171
|
};
|
|
277
172
|
}
|
|
278
173
|
case "LOADING": {
|
|
@@ -281,15 +176,20 @@ function uiReducer(state, action) {
|
|
|
281
176
|
loading: action.isLoading
|
|
282
177
|
};
|
|
283
178
|
}
|
|
179
|
+
case "ERROR": {
|
|
180
|
+
return {
|
|
181
|
+
...state,
|
|
182
|
+
error: action.message,
|
|
183
|
+
loading: false
|
|
184
|
+
};
|
|
185
|
+
}
|
|
284
186
|
default:
|
|
285
187
|
return state;
|
|
286
188
|
}
|
|
287
189
|
}
|
|
288
190
|
var initialState = {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
history: [],
|
|
292
|
-
error: null
|
|
191
|
+
loading: true,
|
|
192
|
+
history: []
|
|
293
193
|
};
|
|
294
194
|
|
|
295
195
|
// src/core/action-router.ts
|
|
@@ -336,7 +236,7 @@ var ActionRouter = class {
|
|
|
336
236
|
schema,
|
|
337
237
|
goal,
|
|
338
238
|
history: [event],
|
|
339
|
-
userContext
|
|
239
|
+
userContext
|
|
340
240
|
},
|
|
341
241
|
prompt: `Generate a new UI for the goal: "${goal}". The user just triggered: ${event.type} on node ${event.nodeId}`
|
|
342
242
|
};
|
|
@@ -385,20 +285,16 @@ var ActionRouter = class {
|
|
|
385
285
|
...additionalContext
|
|
386
286
|
}
|
|
387
287
|
};
|
|
388
|
-
const templateValues = {
|
|
389
|
-
goal,
|
|
390
|
-
eventType: event.type,
|
|
391
|
-
nodeId: event.nodeId,
|
|
392
|
-
targetNodeId,
|
|
393
|
-
actionType: matchingRoute.actionType,
|
|
394
|
-
...userContext || {},
|
|
395
|
-
// Spread the original userContext (passed to resolveRoute)
|
|
396
|
-
...additionalContext
|
|
397
|
-
// Spread additionalContext afterwards (can override userContext keys)
|
|
398
|
-
};
|
|
399
288
|
const prompt = this.processTemplate(
|
|
400
289
|
matchingRoute.promptTemplate,
|
|
401
|
-
|
|
290
|
+
{
|
|
291
|
+
goal,
|
|
292
|
+
eventType: event.type,
|
|
293
|
+
nodeId: event.nodeId,
|
|
294
|
+
targetNodeId,
|
|
295
|
+
actionType: matchingRoute.actionType,
|
|
296
|
+
...additionalContext
|
|
297
|
+
}
|
|
402
298
|
);
|
|
403
299
|
return {
|
|
404
300
|
actionType: matchingRoute.actionType,
|
|
@@ -466,58 +362,27 @@ var uiEventType = z.enum([
|
|
|
466
362
|
var uiEvent = z.object({
|
|
467
363
|
type: uiEventType,
|
|
468
364
|
nodeId: z.string(),
|
|
469
|
-
timestamp: z.number().
|
|
470
|
-
payload: z.record(z.
|
|
471
|
-
});
|
|
472
|
-
z.enum(["AI_RESPONSE", "ERROR"]);
|
|
473
|
-
var runtimeRecord = z.record(z.any()).nullable();
|
|
474
|
-
var openAISimplifiedValue = z.string().nullable();
|
|
475
|
-
var openAIRecordSimplifiedNullable = z.record(openAISimplifiedValue).nullable();
|
|
476
|
-
var openAIEventPayloadSimplifiedNullable = z.record(openAISimplifiedValue).nullable();
|
|
477
|
-
var openAIBaseNode = z.object({
|
|
478
|
-
id: z.string(),
|
|
479
|
-
node_type: z.string(),
|
|
480
|
-
props: openAIRecordSimplifiedNullable,
|
|
481
|
-
// Nullable record
|
|
482
|
-
bindings: openAIRecordSimplifiedNullable,
|
|
483
|
-
// Nullable record
|
|
484
|
-
events: z.record(
|
|
485
|
-
z.string(),
|
|
486
|
-
z.object({
|
|
487
|
-
action: z.string(),
|
|
488
|
-
target: z.string(),
|
|
489
|
-
payload: openAIEventPayloadSimplifiedNullable
|
|
490
|
-
})
|
|
491
|
-
).nullable(),
|
|
492
|
-
// Entire events object is nullable
|
|
493
|
-
children: z.null()
|
|
494
|
-
// Base children are null. When extended, it will be an array or null.
|
|
365
|
+
timestamp: z.number().optional(),
|
|
366
|
+
payload: z.record(z.any()).optional()
|
|
495
367
|
});
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
var
|
|
501
|
-
children: z.array(openAINodeL3).nullable()
|
|
502
|
-
});
|
|
503
|
-
var openAIUISpec = openAIBaseNode.extend({
|
|
504
|
-
children: z.array(openAINodeL2).nullable()
|
|
505
|
-
});
|
|
506
|
-
var uiSpecNode = z.object({
|
|
368
|
+
z.enum([
|
|
369
|
+
"AI_RESPONSE",
|
|
370
|
+
"ERROR"
|
|
371
|
+
]);
|
|
372
|
+
var uiSpecNode = z.lazy(() => z.object({
|
|
507
373
|
id: z.string(),
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
).
|
|
519
|
-
|
|
520
|
-
});
|
|
374
|
+
type: z.string(),
|
|
375
|
+
// e.g., "ListView", "Button", "TextField"
|
|
376
|
+
props: z.record(z.any()).optional(),
|
|
377
|
+
bindings: z.record(z.any()).optional(),
|
|
378
|
+
// Data bindings
|
|
379
|
+
events: z.record(z.string(), z.object({
|
|
380
|
+
action: z.string(),
|
|
381
|
+
target: z.string().optional(),
|
|
382
|
+
payload: z.record(z.any()).optional()
|
|
383
|
+
})).optional(),
|
|
384
|
+
children: z.array(uiSpecNode).optional()
|
|
385
|
+
}));
|
|
521
386
|
z.discriminatedUnion("type", [
|
|
522
387
|
z.object({
|
|
523
388
|
type: z.literal("UI_EVENT"),
|
|
@@ -536,7 +401,7 @@ z.discriminatedUnion("type", [
|
|
|
536
401
|
type: z.literal("ADD_NODE"),
|
|
537
402
|
parentId: z.string(),
|
|
538
403
|
node: uiSpecNode,
|
|
539
|
-
index: z.number().
|
|
404
|
+
index: z.number().optional()
|
|
540
405
|
}),
|
|
541
406
|
z.object({
|
|
542
407
|
type: z.literal("REMOVE_NODE"),
|
|
@@ -552,16 +417,16 @@ z.discriminatedUnion("type", [
|
|
|
552
417
|
})
|
|
553
418
|
]);
|
|
554
419
|
z.object({
|
|
555
|
-
layout: uiSpecNode.
|
|
420
|
+
layout: uiSpecNode.optional(),
|
|
556
421
|
loading: z.boolean(),
|
|
557
422
|
history: z.array(uiEvent),
|
|
558
|
-
error: z.string().
|
|
423
|
+
error: z.string().optional()
|
|
559
424
|
});
|
|
560
425
|
z.object({
|
|
561
426
|
schema: z.record(z.unknown()),
|
|
562
427
|
goal: z.string(),
|
|
563
|
-
history: z.array(uiEvent).
|
|
564
|
-
userContext: z.record(z.unknown()).
|
|
428
|
+
history: z.array(uiEvent).optional(),
|
|
429
|
+
userContext: z.record(z.unknown()).optional()
|
|
565
430
|
});
|
|
566
431
|
|
|
567
432
|
// src/core/system-events.ts
|
|
@@ -587,7 +452,7 @@ var SystemEventManager = class {
|
|
|
587
452
|
}
|
|
588
453
|
/**
|
|
589
454
|
* Register a listener for a specific system event type
|
|
590
|
-
*
|
|
455
|
+
*
|
|
591
456
|
* @param eventType - The system event type to listen for
|
|
592
457
|
* @param listener - The listener function
|
|
593
458
|
* @returns Function to unregister the listener
|
|
@@ -607,7 +472,7 @@ var SystemEventManager = class {
|
|
|
607
472
|
}
|
|
608
473
|
/**
|
|
609
474
|
* Emit a system event to all registered listeners
|
|
610
|
-
*
|
|
475
|
+
*
|
|
611
476
|
* @param event - The system event to emit
|
|
612
477
|
*/
|
|
613
478
|
async emit(event) {
|
|
@@ -627,22 +492,14 @@ function createSystemEvent(type, data) {
|
|
|
627
492
|
}
|
|
628
493
|
|
|
629
494
|
// src/env.ts
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
NODE_ENV: process.env.VITE_NODE_ENV || "development",
|
|
636
|
-
// Simplified NODE_ENV assignment
|
|
637
|
-
OPENAI_API_KEY: rawApiKeyFromEnv === void 0 ? defaultApiKeyLiteral : rawApiKeyFromEnv
|
|
638
|
-
};
|
|
495
|
+
({
|
|
496
|
+
MOCK_PLANNER: import.meta.env?.VITE_MOCK_PLANNER || "1",
|
|
497
|
+
NODE_ENV: import.meta.env?.MODE || "development"
|
|
498
|
+
// Add other environment variables as needed
|
|
499
|
+
});
|
|
639
500
|
|
|
640
501
|
// src/core/planner.ts
|
|
641
|
-
|
|
642
|
-
compatibility: "strict"
|
|
643
|
-
// Required for structured outputs with OpenAI API
|
|
644
|
-
});
|
|
645
|
-
function buildPrompt(input, customPrompt) {
|
|
502
|
+
function buildPrompt(input, targetNodeId, customPrompt) {
|
|
646
503
|
const { schema, goal, history, userContext } = input;
|
|
647
504
|
const schemaInfo = Object.entries(schema).map(([tableName, tableSchema]) => {
|
|
648
505
|
return `Table: ${tableName}
|
|
@@ -655,9 +512,6 @@ Schema: ${JSON.stringify(tableSchema)}`;
|
|
|
655
512
|
|
|
656
513
|
User Context:
|
|
657
514
|
${JSON.stringify(userContext)}` : "";
|
|
658
|
-
if (customPrompt) {
|
|
659
|
-
return customPrompt;
|
|
660
|
-
}
|
|
661
515
|
return `
|
|
662
516
|
You are an expert UI generator.
|
|
663
517
|
Create a user interface that achieves the following goal: "${goal}"
|
|
@@ -671,10 +525,10 @@ ${recentEvents}${userContextSection}
|
|
|
671
525
|
Generate a complete UI specification in JSON format that matches the following TypeScript type:
|
|
672
526
|
type UISpecNode = {
|
|
673
527
|
id: string;
|
|
674
|
-
|
|
675
|
-
props?: Record<string,
|
|
676
|
-
bindings?: Record<string,
|
|
677
|
-
events?: Record<string, { action: string; target
|
|
528
|
+
type: string;
|
|
529
|
+
props?: Record<string, any>;
|
|
530
|
+
bindings?: Record<string, any>;
|
|
531
|
+
events?: Record<string, { action: string; target?: string; payload?: Record<string, any>; }>;
|
|
678
532
|
children?: UISpecNode[];
|
|
679
533
|
};
|
|
680
534
|
|
|
@@ -684,419 +538,211 @@ UI Guidance:
|
|
|
684
538
|
3. Include navigation between related views when needed
|
|
685
539
|
4. Keep the interface simple and intuitive
|
|
686
540
|
5. Bind to schema data where appropriate
|
|
687
|
-
6. Provide event handlers for user interactions
|
|
541
|
+
6. Provide event handlers for user interactions
|
|
688
542
|
|
|
689
543
|
Respond ONLY with the JSON UI specification and no other text.
|
|
690
544
|
`;
|
|
691
545
|
}
|
|
692
546
|
function mockPlanner(input, targetNodeId, customPrompt) {
|
|
693
|
-
if (customPrompt) {
|
|
694
|
-
console.log("mockPlanner received customPrompt:", customPrompt);
|
|
695
|
-
}
|
|
696
|
-
const taskSchema = input.schema.tasks;
|
|
697
|
-
const taskData = taskSchema?.sampleData || [
|
|
698
|
-
{
|
|
699
|
-
id: "1",
|
|
700
|
-
title: "Example Task 1",
|
|
701
|
-
description: "This is a sample task",
|
|
702
|
-
status: "pending",
|
|
703
|
-
priority: "medium"
|
|
704
|
-
},
|
|
705
|
-
{
|
|
706
|
-
id: "2",
|
|
707
|
-
title: "Example Task 2",
|
|
708
|
-
description: "Another sample task",
|
|
709
|
-
status: "completed",
|
|
710
|
-
priority: "high"
|
|
711
|
-
}
|
|
712
|
-
];
|
|
713
547
|
const mockNode = {
|
|
714
548
|
id: targetNodeId || "root",
|
|
715
|
-
|
|
716
|
-
props: {
|
|
717
|
-
className: "p-4 space-y-6"
|
|
718
|
-
},
|
|
719
|
-
bindings: null,
|
|
720
|
-
events: null,
|
|
549
|
+
type: "Container",
|
|
550
|
+
props: { title: "Mock UI" },
|
|
721
551
|
children: [
|
|
722
552
|
{
|
|
723
|
-
id: "
|
|
724
|
-
|
|
725
|
-
props: {
|
|
726
|
-
title: "Task Management Dashboard",
|
|
727
|
-
className: "mb-4"
|
|
728
|
-
},
|
|
729
|
-
bindings: null,
|
|
730
|
-
events: null,
|
|
731
|
-
children: null
|
|
732
|
-
},
|
|
733
|
-
{
|
|
734
|
-
id: "main-content",
|
|
735
|
-
node_type: "Container",
|
|
736
|
-
props: {
|
|
737
|
-
className: "grid grid-cols-1 gap-6 md:grid-cols-3"
|
|
738
|
-
},
|
|
739
|
-
bindings: null,
|
|
740
|
-
events: null,
|
|
741
|
-
children: [
|
|
742
|
-
{
|
|
743
|
-
id: "tasks-container",
|
|
744
|
-
node_type: "Container",
|
|
745
|
-
props: {
|
|
746
|
-
className: "md:col-span-2"
|
|
747
|
-
},
|
|
748
|
-
bindings: null,
|
|
749
|
-
events: null,
|
|
750
|
-
children: [
|
|
751
|
-
{
|
|
752
|
-
id: "list-heading",
|
|
753
|
-
node_type: "Container",
|
|
754
|
-
props: {
|
|
755
|
-
className: "flex justify-between items-center mb-4"
|
|
756
|
-
},
|
|
757
|
-
bindings: null,
|
|
758
|
-
events: null,
|
|
759
|
-
children: [
|
|
760
|
-
{
|
|
761
|
-
id: "list-title",
|
|
762
|
-
node_type: "Header",
|
|
763
|
-
props: {
|
|
764
|
-
title: "Tasks",
|
|
765
|
-
className: "border-none p-0 m-0"
|
|
766
|
-
},
|
|
767
|
-
bindings: null,
|
|
768
|
-
events: null,
|
|
769
|
-
children: null
|
|
770
|
-
},
|
|
771
|
-
{
|
|
772
|
-
id: "add-task-button",
|
|
773
|
-
node_type: "Button",
|
|
774
|
-
props: {
|
|
775
|
-
label: "Add Task",
|
|
776
|
-
variant: "default"
|
|
777
|
-
},
|
|
778
|
-
bindings: null,
|
|
779
|
-
events: {
|
|
780
|
-
onClick: {
|
|
781
|
-
action: "ADD_TASK",
|
|
782
|
-
target: "tasks-container",
|
|
783
|
-
payload: {}
|
|
784
|
-
}
|
|
785
|
-
},
|
|
786
|
-
children: null
|
|
787
|
-
}
|
|
788
|
-
]
|
|
789
|
-
},
|
|
790
|
-
{
|
|
791
|
-
id: "task-list",
|
|
792
|
-
node_type: "ListView",
|
|
793
|
-
props: {
|
|
794
|
-
selectable: "true"
|
|
795
|
-
},
|
|
796
|
-
bindings: {
|
|
797
|
-
items: JSON.stringify(taskData),
|
|
798
|
-
fields: JSON.stringify([
|
|
799
|
-
{ key: "id", label: "ID" },
|
|
800
|
-
{ key: "title", label: "Title" },
|
|
801
|
-
{ key: "status", label: "Status" },
|
|
802
|
-
{ key: "priority", label: "Priority" }
|
|
803
|
-
])
|
|
804
|
-
},
|
|
805
|
-
events: {
|
|
806
|
-
onSelect: {
|
|
807
|
-
action: "SELECT_TASK",
|
|
808
|
-
target: "task-detail",
|
|
809
|
-
payload: {
|
|
810
|
-
source: "task-list"
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
},
|
|
814
|
-
children: null
|
|
815
|
-
}
|
|
816
|
-
]
|
|
817
|
-
},
|
|
818
|
-
{
|
|
819
|
-
id: "task-detail",
|
|
820
|
-
node_type: "Detail",
|
|
821
|
-
props: {
|
|
822
|
-
title: "Task Details",
|
|
823
|
-
visible: "true"
|
|
824
|
-
},
|
|
825
|
-
bindings: {
|
|
826
|
-
data: JSON.stringify(taskData[0]),
|
|
827
|
-
fields: JSON.stringify([
|
|
828
|
-
{ key: "title", label: "Title", type: "heading" },
|
|
829
|
-
{ key: "description", label: "Description", type: "content" },
|
|
830
|
-
{ key: "status", label: "Status" },
|
|
831
|
-
{ key: "priority", label: "Priority" },
|
|
832
|
-
{ key: "dueDate", label: "Due Date" }
|
|
833
|
-
])
|
|
834
|
-
},
|
|
835
|
-
events: {
|
|
836
|
-
onBack: {
|
|
837
|
-
action: "CLOSE_DETAIL",
|
|
838
|
-
target: "task-detail",
|
|
839
|
-
payload: {}
|
|
840
|
-
}
|
|
841
|
-
},
|
|
842
|
-
children: null
|
|
843
|
-
}
|
|
844
|
-
]
|
|
553
|
+
id: "text-1",
|
|
554
|
+
type: "Text",
|
|
555
|
+
props: { text: "This is a mock UI for testing" }
|
|
845
556
|
}
|
|
846
557
|
]
|
|
847
558
|
};
|
|
848
559
|
return mockNode;
|
|
849
560
|
}
|
|
850
|
-
async function callPlannerLLM(input, routeResolution) {
|
|
851
|
-
await systemEvents.emit(
|
|
852
|
-
createSystemEvent("PLAN_START" /* PLAN_START */, { plannerInput: input })
|
|
853
|
-
);
|
|
854
|
-
if (env.MOCK_PLANNER === "1" || !env.OPENAI_API_KEY) {
|
|
855
|
-
console.warn(
|
|
856
|
-
"Using mock planner because MOCK_PLANNER is enabled or OPENAI_API_KEY is not available"
|
|
857
|
-
);
|
|
858
|
-
return mockPlanner(input);
|
|
859
|
-
}
|
|
860
|
-
const startTime = Date.now();
|
|
861
|
-
const prompt = routeResolution?.prompt || buildPrompt(input);
|
|
862
|
-
await systemEvents.emit(
|
|
863
|
-
createSystemEvent("PLAN_PROMPT_CREATED" /* PLAN_PROMPT_CREATED */, { prompt })
|
|
864
|
-
);
|
|
865
|
-
try {
|
|
866
|
-
const { object: uiSpec } = await generateObject({
|
|
867
|
-
model: strictOpenAI("gpt-4o", { structuredOutputs: true }),
|
|
868
|
-
schema: openAIUISpec,
|
|
869
|
-
messages: [{ role: "user", content: prompt }],
|
|
870
|
-
temperature: 0.2,
|
|
871
|
-
maxTokens: 4e3
|
|
872
|
-
});
|
|
873
|
-
await systemEvents.emit(
|
|
874
|
-
createSystemEvent("PLAN_COMPLETE" /* PLAN_COMPLETE */, {
|
|
875
|
-
layout: uiSpec,
|
|
876
|
-
executionTimeMs: Date.now() - startTime
|
|
877
|
-
})
|
|
878
|
-
);
|
|
879
|
-
return uiSpec;
|
|
880
|
-
} catch (error) {
|
|
881
|
-
console.error("Error calling LLM planner:", error);
|
|
882
|
-
await systemEvents.emit(
|
|
883
|
-
createSystemEvent("PLAN_ERROR" /* PLAN_ERROR */, {
|
|
884
|
-
error: error instanceof Error ? error : new Error(String(error))
|
|
885
|
-
})
|
|
886
|
-
);
|
|
887
|
-
throw error;
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
async function processEvent(event, router, schema, layout, dataContext, goal, userContext) {
|
|
891
|
-
const routeResolution = await router.resolveRoute(
|
|
892
|
-
event,
|
|
893
|
-
schema,
|
|
894
|
-
layout || null,
|
|
895
|
-
dataContext,
|
|
896
|
-
goal,
|
|
897
|
-
userContext
|
|
898
|
-
);
|
|
899
|
-
if (!routeResolution) {
|
|
900
|
-
throw new Error(
|
|
901
|
-
`No route found for event type: ${event.type}, node: ${event.nodeId}`
|
|
902
|
-
);
|
|
903
|
-
}
|
|
904
|
-
if (routeResolution.actionType.toString() === "NoOp") {
|
|
905
|
-
if (!layout)
|
|
906
|
-
throw new Error("Layout is undefined and action is NoOp");
|
|
907
|
-
return layout;
|
|
908
|
-
}
|
|
909
|
-
const plannerInputForLLM = routeResolution.plannerInput;
|
|
910
|
-
const newLayout = await callPlannerLLM(plannerInputForLLM, routeResolution);
|
|
911
|
-
return newLayout;
|
|
912
|
-
}
|
|
913
561
|
|
|
914
562
|
// src/core/state.ts
|
|
563
|
+
var useChat = (config) => ({
|
|
564
|
+
append: async (message) => {
|
|
565
|
+
},
|
|
566
|
+
data: { content: "{}" },
|
|
567
|
+
isLoading: false,
|
|
568
|
+
error: null,
|
|
569
|
+
stop: () => {
|
|
570
|
+
}
|
|
571
|
+
});
|
|
915
572
|
function useUIStateEngine({
|
|
916
573
|
schema,
|
|
917
574
|
goal,
|
|
918
575
|
userContext,
|
|
919
576
|
mockMode = false,
|
|
920
|
-
planningConfig,
|
|
577
|
+
planningConfig = {},
|
|
921
578
|
router = createDefaultRouter(),
|
|
922
579
|
dataContext = {},
|
|
923
580
|
enablePartialUpdates = false
|
|
924
581
|
}) {
|
|
925
|
-
if (userContext === null) {
|
|
926
|
-
console.warn(
|
|
927
|
-
"useUIStateEngine: userContext was explicitly set to null. This is an allowed but discouraged value. Consider using undefined if you intend to omit the user context."
|
|
928
|
-
);
|
|
929
|
-
}
|
|
930
582
|
const [state, dispatch] = useReducer(uiReducer, initialState);
|
|
931
|
-
const
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
goal,
|
|
946
|
-
userContext
|
|
947
|
-
);
|
|
948
|
-
if (route) {
|
|
949
|
-
console.log("Resolved route:", route);
|
|
950
|
-
actionTypeForDispatch = route.actionType;
|
|
951
|
-
targetNodeIdForDispatch = route.targetNodeId;
|
|
952
|
-
systemEvents.emit(
|
|
953
|
-
createSystemEvent("PLAN_START" /* PLAN_START */, {
|
|
954
|
-
plannerInput: route.plannerInput
|
|
955
|
-
})
|
|
956
|
-
);
|
|
957
|
-
if (mockMode) {
|
|
958
|
-
resolvedNode = mockPlanner(
|
|
959
|
-
route.plannerInput,
|
|
960
|
-
route.targetNodeId,
|
|
961
|
-
route.prompt
|
|
962
|
-
);
|
|
963
|
-
} else {
|
|
964
|
-
resolvedNode = await callPlannerLLM(route.plannerInput, route);
|
|
965
|
-
}
|
|
966
|
-
} else {
|
|
967
|
-
const input = {
|
|
968
|
-
schema,
|
|
969
|
-
goal,
|
|
970
|
-
history: [...state.history, event],
|
|
971
|
-
userContext
|
|
972
|
-
};
|
|
973
|
-
if (mockMode) {
|
|
974
|
-
resolvedNode = mockPlanner(input);
|
|
975
|
-
} else {
|
|
976
|
-
resolvedNode = await callPlannerLLM(input);
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
} else {
|
|
980
|
-
const input = {
|
|
981
|
-
schema,
|
|
982
|
-
goal,
|
|
983
|
-
history: [...state.history, event],
|
|
984
|
-
// event is already in history from UI_EVENT dispatch
|
|
985
|
-
userContext
|
|
986
|
-
};
|
|
987
|
-
if (mockMode) {
|
|
988
|
-
resolvedNode = mockPlanner(input);
|
|
989
|
-
} else {
|
|
990
|
-
resolvedNode = await callPlannerLLM(input);
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
switch (actionTypeForDispatch) {
|
|
994
|
-
case "UPDATE_NODE" /* UPDATE_NODE */:
|
|
995
|
-
case "SHOW_DETAIL" /* SHOW_DETAIL */:
|
|
996
|
-
case "HIDE_DETAIL" /* HIDE_DETAIL */:
|
|
997
|
-
case "TOGGLE_STATE" /* TOGGLE_STATE */:
|
|
998
|
-
case "ADD_DROPDOWN" /* ADD_DROPDOWN */:
|
|
999
|
-
case "UPDATE_FORM" /* UPDATE_FORM */:
|
|
1000
|
-
case "NAVIGATE" /* NAVIGATE */:
|
|
1001
|
-
dispatch({
|
|
1002
|
-
type: "PARTIAL_UPDATE",
|
|
1003
|
-
nodeId: targetNodeIdForDispatch,
|
|
1004
|
-
node: resolvedNode
|
|
1005
|
-
});
|
|
1006
|
-
break;
|
|
1007
|
-
case "FULL_REFRESH" /* FULL_REFRESH */:
|
|
1008
|
-
default:
|
|
1009
|
-
dispatch({ type: "AI_RESPONSE", node: resolvedNode });
|
|
1010
|
-
break;
|
|
1011
|
-
}
|
|
1012
|
-
} catch (e) {
|
|
1013
|
-
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
1014
|
-
dispatch({ type: "ERROR", message: errorMessage });
|
|
583
|
+
const { append, data, isLoading, error, stop } = useChat();
|
|
584
|
+
const handleEvent = useCallback((event) => {
|
|
585
|
+
dispatch({ type: "UI_EVENT", event });
|
|
586
|
+
if (enablePartialUpdates) {
|
|
587
|
+
const route = router.resolveRoute(
|
|
588
|
+
event,
|
|
589
|
+
schema,
|
|
590
|
+
state.layout,
|
|
591
|
+
dataContext,
|
|
592
|
+
goal,
|
|
593
|
+
userContext
|
|
594
|
+
);
|
|
595
|
+
if (route) {
|
|
596
|
+
console.log("Resolved route:", route);
|
|
1015
597
|
systemEvents.emit(
|
|
1016
|
-
createSystemEvent("
|
|
1017
|
-
|
|
598
|
+
createSystemEvent("PLAN_START" /* PLAN_START */, {
|
|
599
|
+
plannerInput: route.plannerInput
|
|
1018
600
|
})
|
|
1019
601
|
);
|
|
1020
|
-
|
|
1021
|
-
|
|
602
|
+
if (mockMode) {
|
|
603
|
+
const node = mockPlanner(route.plannerInput, route.targetNodeId, route.prompt);
|
|
604
|
+
switch (route.actionType) {
|
|
605
|
+
case "FULL_REFRESH" /* FULL_REFRESH */:
|
|
606
|
+
dispatch({ type: "AI_RESPONSE", node });
|
|
607
|
+
break;
|
|
608
|
+
case "UPDATE_NODE" /* UPDATE_NODE */:
|
|
609
|
+
case "SHOW_DETAIL" /* SHOW_DETAIL */:
|
|
610
|
+
case "HIDE_DETAIL" /* HIDE_DETAIL */:
|
|
611
|
+
case "TOGGLE_STATE" /* TOGGLE_STATE */:
|
|
612
|
+
case "ADD_DROPDOWN" /* ADD_DROPDOWN */:
|
|
613
|
+
case "UPDATE_FORM" /* UPDATE_FORM */:
|
|
614
|
+
case "NAVIGATE" /* NAVIGATE */:
|
|
615
|
+
dispatch({
|
|
616
|
+
type: "PARTIAL_UPDATE",
|
|
617
|
+
nodeId: route.targetNodeId,
|
|
618
|
+
node
|
|
619
|
+
});
|
|
620
|
+
break;
|
|
621
|
+
}
|
|
622
|
+
} else {
|
|
623
|
+
const prompt = route.prompt;
|
|
624
|
+
systemEvents.emit(
|
|
625
|
+
createSystemEvent("PLAN_PROMPT_CREATED" /* PLAN_PROMPT_CREATED */, { prompt })
|
|
626
|
+
);
|
|
627
|
+
append({
|
|
628
|
+
content: prompt,
|
|
629
|
+
role: "user"
|
|
630
|
+
});
|
|
631
|
+
sessionStorage.setItem("currentRoute", JSON.stringify({
|
|
632
|
+
actionType: route.actionType,
|
|
633
|
+
targetNodeId: route.targetNodeId
|
|
634
|
+
}));
|
|
635
|
+
}
|
|
636
|
+
return;
|
|
1022
637
|
}
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
// append, // REMOVE
|
|
1026
|
-
goal,
|
|
638
|
+
}
|
|
639
|
+
const input = {
|
|
1027
640
|
schema,
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
641
|
+
goal,
|
|
642
|
+
history: [...state.history, event],
|
|
643
|
+
userContext
|
|
644
|
+
};
|
|
645
|
+
if (mockMode) {
|
|
646
|
+
const node = mockPlanner();
|
|
647
|
+
dispatch({ type: "AI_RESPONSE", node });
|
|
648
|
+
} else {
|
|
649
|
+
const prompt = buildPrompt(input);
|
|
650
|
+
append({
|
|
651
|
+
content: prompt,
|
|
652
|
+
role: "user"
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
}, [append, goal, schema, state.history, state.layout, stop, userContext, router, mockMode, dataContext, enablePartialUpdates]);
|
|
1041
656
|
useEffect(() => {
|
|
1042
|
-
|
|
1043
|
-
dispatch({ type: "LOADING", isLoading: true });
|
|
657
|
+
{
|
|
1044
658
|
try {
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
659
|
+
systemEvents.emit(
|
|
660
|
+
createSystemEvent("PLAN_RESPONSE_CHUNK" /* PLAN_RESPONSE_CHUNK */, {
|
|
661
|
+
chunk: data.content,
|
|
662
|
+
isComplete: true
|
|
663
|
+
})
|
|
664
|
+
);
|
|
665
|
+
const jsonMatch = data.content.match(/```(?:json)?\s*([\s\S]*?)\s*```/) || [null, data.content];
|
|
666
|
+
const jsonStr = jsonMatch[1].trim();
|
|
667
|
+
const parsedJson = JSON.parse(jsonStr);
|
|
668
|
+
const validatedNode = uiSpecNode.parse(parsedJson);
|
|
669
|
+
const routeInfoStr = sessionStorage.getItem("currentRoute");
|
|
670
|
+
if (routeInfoStr && enablePartialUpdates) {
|
|
671
|
+
try {
|
|
672
|
+
const routeInfo = JSON.parse(routeInfoStr);
|
|
673
|
+
switch (routeInfo.actionType) {
|
|
674
|
+
case "FULL_REFRESH" /* FULL_REFRESH */:
|
|
675
|
+
dispatch({ type: "AI_RESPONSE", node: validatedNode });
|
|
676
|
+
break;
|
|
677
|
+
case "UPDATE_NODE" /* UPDATE_NODE */:
|
|
678
|
+
case "SHOW_DETAIL" /* SHOW_DETAIL */:
|
|
679
|
+
case "HIDE_DETAIL" /* HIDE_DETAIL */:
|
|
680
|
+
case "TOGGLE_STATE" /* TOGGLE_STATE */:
|
|
681
|
+
case "ADD_DROPDOWN" /* ADD_DROPDOWN */:
|
|
682
|
+
case "UPDATE_FORM" /* UPDATE_FORM */:
|
|
683
|
+
case "NAVIGATE" /* NAVIGATE */:
|
|
684
|
+
dispatch({
|
|
685
|
+
type: "PARTIAL_UPDATE",
|
|
686
|
+
nodeId: routeInfo.targetNodeId,
|
|
687
|
+
node: validatedNode
|
|
688
|
+
});
|
|
689
|
+
break;
|
|
690
|
+
default:
|
|
691
|
+
dispatch({ type: "AI_RESPONSE", node: validatedNode });
|
|
692
|
+
}
|
|
693
|
+
sessionStorage.removeItem("currentRoute");
|
|
694
|
+
} catch (e) {
|
|
695
|
+
console.error("Error parsing route info:", e);
|
|
696
|
+
dispatch({ type: "AI_RESPONSE", node: validatedNode });
|
|
697
|
+
}
|
|
1054
698
|
} else {
|
|
1055
|
-
node
|
|
699
|
+
dispatch({ type: "AI_RESPONSE", node: validatedNode });
|
|
1056
700
|
}
|
|
1057
|
-
dispatch({ type: "AI_RESPONSE", node });
|
|
1058
|
-
} catch (e) {
|
|
1059
|
-
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
1060
|
-
dispatch({ type: "ERROR", message: errorMessage });
|
|
1061
701
|
systemEvents.emit(
|
|
1062
|
-
|
|
702
|
+
createSystemEvent("PLAN_COMPLETE" /* PLAN_COMPLETE */, {
|
|
703
|
+
layout: validatedNode,
|
|
704
|
+
executionTimeMs: 0
|
|
705
|
+
// Not available here
|
|
706
|
+
})
|
|
707
|
+
);
|
|
708
|
+
} catch (parseError) {
|
|
709
|
+
console.error("Failed to parse LLM response:", parseError);
|
|
710
|
+
dispatch({
|
|
711
|
+
type: "ERROR",
|
|
712
|
+
message: "Failed to parse LLM response"
|
|
713
|
+
});
|
|
714
|
+
systemEvents.emit(
|
|
1063
715
|
createSystemEvent("PLAN_ERROR" /* PLAN_ERROR */, {
|
|
1064
|
-
error:
|
|
716
|
+
error: parseError instanceof Error ? parseError : new Error("Parse error")
|
|
1065
717
|
})
|
|
1066
718
|
);
|
|
1067
|
-
} finally {
|
|
1068
|
-
dispatch({ type: "LOADING", isLoading: false });
|
|
1069
719
|
}
|
|
720
|
+
}
|
|
721
|
+
}, [data.content, error, isLoading, enablePartialUpdates]);
|
|
722
|
+
useEffect(() => {
|
|
723
|
+
const input = {
|
|
724
|
+
schema,
|
|
725
|
+
goal,
|
|
726
|
+
history: [],
|
|
727
|
+
userContext
|
|
1070
728
|
};
|
|
1071
|
-
|
|
1072
|
-
|
|
729
|
+
if (mockMode) {
|
|
730
|
+
const node = mockPlanner();
|
|
731
|
+
dispatch({ type: "AI_RESPONSE", node });
|
|
732
|
+
} else {
|
|
733
|
+
const prompt = buildPrompt(input);
|
|
734
|
+
append({
|
|
735
|
+
content: prompt,
|
|
736
|
+
role: "user"
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
}, [append, goal, schema, userContext, mockMode]);
|
|
1073
740
|
return {
|
|
1074
741
|
state,
|
|
1075
742
|
dispatch,
|
|
1076
743
|
handleEvent
|
|
1077
744
|
};
|
|
1078
745
|
}
|
|
1079
|
-
z.enum([
|
|
1080
|
-
// Layout components
|
|
1081
|
-
"Container",
|
|
1082
|
-
"Card",
|
|
1083
|
-
"Header",
|
|
1084
|
-
// Input components
|
|
1085
|
-
"Button",
|
|
1086
|
-
"Input",
|
|
1087
|
-
"Select",
|
|
1088
|
-
"Textarea",
|
|
1089
|
-
"Checkbox",
|
|
1090
|
-
"RadioGroup",
|
|
1091
|
-
// Data display components
|
|
1092
|
-
"ListView",
|
|
1093
|
-
"Detail",
|
|
1094
|
-
"Tabs",
|
|
1095
|
-
"Dialog",
|
|
1096
|
-
// Typography
|
|
1097
|
-
"Heading",
|
|
1098
|
-
"Text"
|
|
1099
|
-
]);
|
|
1100
746
|
var ShimmerBlock = () => /* @__PURE__ */ jsx("div", { className: "w-full h-8 bg-gray-200 animate-pulse rounded" });
|
|
1101
747
|
var ShimmerTable = ({ rows = 3 }) => /* @__PURE__ */ jsxs("div", { className: "w-full space-y-2", children: [
|
|
1102
748
|
/* @__PURE__ */ jsx("div", { className: "w-full h-10 bg-gray-200 animate-pulse rounded" }),
|
|
@@ -1110,259 +756,117 @@ var ShimmerCard = () => /* @__PURE__ */ jsxs("div", { className: "w-full p-4 spa
|
|
|
1110
756
|
/* @__PURE__ */ jsx("div", { className: "w-5/6 h-4 bg-gray-200 animate-pulse rounded" })
|
|
1111
757
|
] })
|
|
1112
758
|
] });
|
|
1113
|
-
var Container = (props) => /* @__PURE__ */ jsx("div", { className: `
|
|
1114
|
-
var Header = ({
|
|
1115
|
-
title,
|
|
1116
|
-
className
|
|
1117
|
-
}) => /* @__PURE__ */ jsx(
|
|
1118
|
-
"header",
|
|
1119
|
-
{
|
|
1120
|
-
className: `py-4 px-6 border-b border-gray-300 mb-4 bg-gray-50 dark:bg-gray-800 ${className || ""}`,
|
|
1121
|
-
children: /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-gray-800 dark:text-white", children: title })
|
|
1122
|
-
}
|
|
1123
|
-
);
|
|
759
|
+
var Container = (props) => /* @__PURE__ */ jsx("div", { className: `w-full ${props.className || ""}`, style: props.style, children: props.children });
|
|
760
|
+
var Header = ({ title }) => /* @__PURE__ */ jsx("header", { className: "py-4 px-6 border-b mb-4", children: /* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold", children: title }) });
|
|
1124
761
|
var Button = ({ onClick, children, variant = "default" }) => /* @__PURE__ */ jsx(
|
|
1125
762
|
"button",
|
|
1126
763
|
{
|
|
1127
|
-
className: `px-4 py-2 rounded
|
|
764
|
+
className: `px-4 py-2 rounded font-medium ${variant === "default" ? "bg-blue-600 text-white" : variant === "outline" ? "border border-gray-300 text-gray-700" : "bg-red-600 text-white"}`,
|
|
1128
765
|
onClick,
|
|
1129
766
|
children
|
|
1130
767
|
}
|
|
1131
768
|
);
|
|
1132
|
-
var Table = ({ items = [], fields = [], onSelect, selectable }) => /* @__PURE__ */ jsx("div", { className: "w-full border
|
|
1133
|
-
/* @__PURE__ */ jsx("thead", { className: "bg-gray-
|
|
1134
|
-
|
|
1135
|
-
{
|
|
1136
|
-
className: "px-6 py-3 text-left text-xs font-medium text-gray-700 dark:text-gray-300 uppercase tracking-wider",
|
|
1137
|
-
children: field.label
|
|
1138
|
-
},
|
|
1139
|
-
field.key
|
|
1140
|
-
)) }) }),
|
|
1141
|
-
/* @__PURE__ */ jsx("tbody", { className: "bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-700", children: items.map((item, index) => /* @__PURE__ */ jsx(
|
|
769
|
+
var Table = ({ items = [], fields = [], onSelect, selectable }) => /* @__PURE__ */ jsx("div", { className: "w-full border rounded-lg overflow-hidden", children: /* @__PURE__ */ jsxs("table", { className: "w-full", children: [
|
|
770
|
+
/* @__PURE__ */ jsx("thead", { className: "bg-gray-50", children: /* @__PURE__ */ jsx("tr", { children: fields.map((field) => /* @__PURE__ */ jsx("th", { className: "px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider", children: field.label }, field.key)) }) }),
|
|
771
|
+
/* @__PURE__ */ jsx("tbody", { className: "bg-white divide-y divide-gray-200", children: items.map((item, index) => /* @__PURE__ */ jsx(
|
|
1142
772
|
"tr",
|
|
1143
773
|
{
|
|
1144
774
|
onClick: () => selectable && onSelect && onSelect(item),
|
|
1145
|
-
className: selectable ? "cursor-pointer hover:bg-gray-
|
|
1146
|
-
children: fields.map((field) => /* @__PURE__ */ jsx(
|
|
1147
|
-
"td",
|
|
1148
|
-
{
|
|
1149
|
-
className: "px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-gray-300",
|
|
1150
|
-
children: item[field.key] ?? ""
|
|
1151
|
-
},
|
|
1152
|
-
field.key
|
|
1153
|
-
))
|
|
775
|
+
className: selectable ? "cursor-pointer hover:bg-gray-50" : "",
|
|
776
|
+
children: fields.map((field) => /* @__PURE__ */ jsx("td", { className: "px-6 py-4 whitespace-nowrap text-sm text-gray-500", children: item[field.key] }, field.key))
|
|
1154
777
|
},
|
|
1155
778
|
index
|
|
1156
779
|
)) })
|
|
1157
780
|
] }) });
|
|
1158
781
|
var Detail = ({ data, fields = [], title, visible = true, onBack }) => {
|
|
1159
|
-
if (!visible)
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
title && /* @__PURE__ */ jsx("h2", { className: "text-lg font-medium text-gray-800 dark:text-white", children: title }),
|
|
782
|
+
if (!visible) return null;
|
|
783
|
+
return /* @__PURE__ */ jsxs("div", { className: "w-full border rounded-lg p-6 space-y-4", children: [
|
|
784
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center", children: [
|
|
785
|
+
title && /* @__PURE__ */ jsx("h2", { className: "text-lg font-medium", children: title }),
|
|
1164
786
|
onBack && /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: onBack, children: "Back" })
|
|
1165
787
|
] }),
|
|
1166
788
|
/* @__PURE__ */ jsx("div", { className: "space-y-4", children: fields.map((field) => {
|
|
1167
789
|
if (field.type === "heading") {
|
|
1168
|
-
return /* @__PURE__ */ jsx(
|
|
1169
|
-
"h3",
|
|
1170
|
-
{
|
|
1171
|
-
className: "text-xl font-semibold text-gray-800 dark:text-white",
|
|
1172
|
-
children: data?.[field.key] ?? ""
|
|
1173
|
-
},
|
|
1174
|
-
field.key
|
|
1175
|
-
);
|
|
790
|
+
return /* @__PURE__ */ jsx("h3", { className: "text-xl font-semibold", children: data?.[field.key] }, field.key);
|
|
1176
791
|
}
|
|
1177
792
|
if (field.type === "content") {
|
|
1178
|
-
return /* @__PURE__ */ jsx(
|
|
1179
|
-
"div",
|
|
1180
|
-
{
|
|
1181
|
-
className: "text-sm text-gray-700 dark:text-gray-300",
|
|
1182
|
-
children: data?.[field.key] ?? ""
|
|
1183
|
-
},
|
|
1184
|
-
field.key
|
|
1185
|
-
);
|
|
793
|
+
return /* @__PURE__ */ jsx("div", { className: "text-sm text-gray-700", children: data?.[field.key] }, field.key);
|
|
1186
794
|
}
|
|
1187
|
-
return /* @__PURE__ */ jsxs(
|
|
1188
|
-
"
|
|
1189
|
-
{
|
|
1190
|
-
|
|
1191
|
-
children: [
|
|
1192
|
-
field.label && /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-600 dark:text-gray-400 font-medium", children: field.label }),
|
|
1193
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm text-gray-800 dark:text-gray-200", children: data?.[field.key] ?? "" })
|
|
1194
|
-
]
|
|
1195
|
-
},
|
|
1196
|
-
field.key
|
|
1197
|
-
);
|
|
795
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
|
|
796
|
+
field.label && /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-500", children: field.label }),
|
|
797
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm", children: data?.[field.key] })
|
|
798
|
+
] }, field.key);
|
|
1198
799
|
}) })
|
|
1199
800
|
] });
|
|
1200
801
|
};
|
|
1201
|
-
var
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
};
|
|
1210
|
-
var isObject = (value) => typeof value === "object" && value !== null;
|
|
1211
|
-
var isString = (value) => typeof value === "string";
|
|
1212
|
-
var isBoolean = (value) => typeof value === "boolean";
|
|
1213
|
-
var isCSSProperties = (value) => isObject(value);
|
|
1214
|
-
var isButtonVariant = (value) => isString(value) && ["default", "outline", "destructive"].includes(value);
|
|
1215
|
-
var getSafeBinding = (bindings, key, validator, defaultValue) => {
|
|
1216
|
-
if (bindings && typeof bindings === "object" && key in bindings) {
|
|
1217
|
-
const value = bindings[key];
|
|
1218
|
-
if (validator(value)) {
|
|
1219
|
-
return value;
|
|
1220
|
-
}
|
|
1221
|
-
}
|
|
1222
|
-
return defaultValue;
|
|
1223
|
-
};
|
|
1224
|
-
var isArrayOf = (itemValidator) => (arr) => Array.isArray(arr) && arr.every(itemValidator);
|
|
1225
|
-
var isReactNode = (value) => {
|
|
1226
|
-
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null || typeof value === "undefined" || typeof value === "object" && value !== null && "$$typeof" in value;
|
|
1227
|
-
};
|
|
1228
|
-
var isRecordWithReactNodeValues = (value) => isObject(value) && Object.values(value).every(isReactNode);
|
|
1229
|
-
var isFieldObject = (item) => isObject(item) && isString(item.key) && isString(item.label);
|
|
1230
|
-
var isDetailFieldObject = (item) => isObject(item) && isString(item.key) && isString(item.label) && (item.type === void 0 || isString(item.type));
|
|
1231
|
-
var createEventHandler = (node, eventName, uiEventType2, processEvent2) => {
|
|
1232
|
-
const eventConfig = node.events?.[uiEventType2];
|
|
1233
|
-
if (!processEvent2 || !eventConfig)
|
|
1234
|
-
return void 0;
|
|
1235
|
-
return (eventPayload) => {
|
|
1236
|
-
const fullEvent = {
|
|
1237
|
-
type: uiEventType2,
|
|
1238
|
-
nodeId: node.id,
|
|
1239
|
-
timestamp: Date.now(),
|
|
1240
|
-
payload: {
|
|
1241
|
-
...eventConfig.payload || {},
|
|
1242
|
-
...eventPayload || {}
|
|
1243
|
-
}
|
|
1244
|
-
};
|
|
1245
|
-
processEvent2(fullEvent);
|
|
802
|
+
var createEventHandler = (node, eventName) => {
|
|
803
|
+
const eventConfig = node.events?.[eventName];
|
|
804
|
+
if (!eventConfig) return void 0;
|
|
805
|
+
return () => {
|
|
806
|
+
console.log(`Event triggered: ${eventName} on node ${node.id}`, {
|
|
807
|
+
action: eventConfig.action,
|
|
808
|
+
target: eventConfig.target,
|
|
809
|
+
payload: eventConfig.payload
|
|
810
|
+
});
|
|
1246
811
|
};
|
|
1247
812
|
};
|
|
1248
813
|
var adapterMap = {
|
|
1249
|
-
Container: (node
|
|
1250
|
-
|
|
814
|
+
Container: (node) => /* @__PURE__ */ jsx(Container, { style: node.props?.style, className: node.props?.className, children: node.children?.map((child) => renderNode(child)) }),
|
|
815
|
+
Header: (node) => /* @__PURE__ */ jsx(Header, { title: node.props?.title || "Untitled" }),
|
|
816
|
+
Button: (node) => /* @__PURE__ */ jsx(
|
|
817
|
+
Button,
|
|
1251
818
|
{
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
children: node.
|
|
819
|
+
variant: node.props?.variant,
|
|
820
|
+
onClick: createEventHandler(node, "onClick"),
|
|
821
|
+
children: node.props?.label || "Button"
|
|
1255
822
|
}
|
|
1256
823
|
),
|
|
1257
|
-
|
|
1258
|
-
|
|
824
|
+
ListView: (node) => /* @__PURE__ */ jsx(
|
|
825
|
+
Table,
|
|
1259
826
|
{
|
|
1260
|
-
|
|
1261
|
-
|
|
827
|
+
items: node.bindings?.items || [],
|
|
828
|
+
fields: node.bindings?.fields || [],
|
|
829
|
+
selectable: node.props?.selectable,
|
|
830
|
+
onSelect: createEventHandler(node, "onSelect")
|
|
1262
831
|
}
|
|
1263
832
|
),
|
|
1264
|
-
|
|
1265
|
-
|
|
833
|
+
Detail: (node) => /* @__PURE__ */ jsx(
|
|
834
|
+
Detail,
|
|
1266
835
|
{
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
836
|
+
data: node.bindings?.data,
|
|
837
|
+
fields: node.bindings?.fields || [],
|
|
838
|
+
title: node.props?.title,
|
|
839
|
+
visible: node.props?.visible !== false,
|
|
840
|
+
onBack: createEventHandler(node, "onBack")
|
|
1270
841
|
}
|
|
1271
|
-
)
|
|
1272
|
-
ListView: (node, processEvent2) => {
|
|
1273
|
-
const items = getSafeBinding(
|
|
1274
|
-
node.bindings,
|
|
1275
|
-
"items",
|
|
1276
|
-
isArrayOf(isRecordWithReactNodeValues),
|
|
1277
|
-
[]
|
|
1278
|
-
);
|
|
1279
|
-
const fields = getSafeBinding(
|
|
1280
|
-
node.bindings,
|
|
1281
|
-
"fields",
|
|
1282
|
-
isArrayOf(isFieldObject),
|
|
1283
|
-
[]
|
|
1284
|
-
);
|
|
1285
|
-
const selectable = getSafeProp(node.props, "selectable", isBoolean, false);
|
|
1286
|
-
return /* @__PURE__ */ jsx(
|
|
1287
|
-
Table,
|
|
1288
|
-
{
|
|
1289
|
-
items,
|
|
1290
|
-
fields,
|
|
1291
|
-
selectable,
|
|
1292
|
-
onSelect: (item) => {
|
|
1293
|
-
const handler = createEventHandler(
|
|
1294
|
-
node,
|
|
1295
|
-
"onSelect",
|
|
1296
|
-
"CLICK",
|
|
1297
|
-
processEvent2
|
|
1298
|
-
);
|
|
1299
|
-
if (handler) {
|
|
1300
|
-
handler({ selectedItem: item });
|
|
1301
|
-
}
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
);
|
|
1305
|
-
},
|
|
1306
|
-
Detail: (node, processEvent2) => {
|
|
1307
|
-
const data = getSafeBinding(
|
|
1308
|
-
node.bindings,
|
|
1309
|
-
"data",
|
|
1310
|
-
isRecordWithReactNodeValues,
|
|
1311
|
-
{}
|
|
1312
|
-
);
|
|
1313
|
-
const fields = getSafeBinding(
|
|
1314
|
-
node.bindings,
|
|
1315
|
-
"fields",
|
|
1316
|
-
isArrayOf(isDetailFieldObject),
|
|
1317
|
-
[]
|
|
1318
|
-
);
|
|
1319
|
-
const title = getSafeProp(node.props, "title", isString, "");
|
|
1320
|
-
const visible = getSafeProp(node.props, "visible", isBoolean, true);
|
|
1321
|
-
return /* @__PURE__ */ jsx(
|
|
1322
|
-
Detail,
|
|
1323
|
-
{
|
|
1324
|
-
data,
|
|
1325
|
-
fields,
|
|
1326
|
-
title,
|
|
1327
|
-
visible,
|
|
1328
|
-
onBack: createEventHandler(node, "onBack", "CLICK", processEvent2)
|
|
1329
|
-
}
|
|
1330
|
-
);
|
|
1331
|
-
}
|
|
842
|
+
)
|
|
1332
843
|
};
|
|
1333
|
-
function renderNode(node
|
|
1334
|
-
const
|
|
1335
|
-
if (
|
|
1336
|
-
return
|
|
844
|
+
function renderNode(node) {
|
|
845
|
+
const Component = adapterMap[node.type];
|
|
846
|
+
if (Component) {
|
|
847
|
+
return Component(node);
|
|
1337
848
|
}
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
849
|
+
return /* @__PURE__ */ jsxs("div", { className: "p-2 border border-red-300 rounded", children: [
|
|
850
|
+
/* @__PURE__ */ jsxs("p", { className: "text-sm text-red-500", children: [
|
|
851
|
+
"Unsupported component: ",
|
|
852
|
+
node.type
|
|
853
|
+
] }),
|
|
854
|
+
node.children?.map((child) => renderNode(child))
|
|
855
|
+
] });
|
|
1344
856
|
}
|
|
1345
|
-
|
|
1346
|
-
var MAX_CACHE_SIZE = 10;
|
|
1347
|
-
var CACHE_TTL = 5e3;
|
|
1348
|
-
async function renderNode2(node, adapter = "shadcn", processEvent2) {
|
|
857
|
+
async function renderNode2(node, adapter = "shadcn") {
|
|
1349
858
|
const startTime = Date.now();
|
|
1350
|
-
const nodeId = node.id;
|
|
1351
|
-
const cachedItem = renderedNodesCache.get(nodeId);
|
|
1352
|
-
if (cachedItem && startTime - cachedItem.timestamp < CACHE_TTL) {
|
|
1353
|
-
return cachedItem.element;
|
|
1354
|
-
}
|
|
1355
859
|
await systemEvents.emit(
|
|
1356
860
|
createSystemEvent("RENDER_START" /* RENDER_START */, { layout: node })
|
|
1357
861
|
);
|
|
1358
862
|
let result;
|
|
1359
863
|
switch (adapter) {
|
|
1360
864
|
case "shadcn":
|
|
1361
|
-
result = renderNode(node
|
|
865
|
+
result = renderNode(node);
|
|
1362
866
|
break;
|
|
1363
867
|
default:
|
|
1364
868
|
console.warn(`Unsupported adapter: ${adapter}, falling back to shadcn`);
|
|
1365
|
-
result = renderNode(node
|
|
869
|
+
result = renderNode(node);
|
|
1366
870
|
}
|
|
1367
871
|
await systemEvents.emit(
|
|
1368
872
|
createSystemEvent("RENDER_COMPLETE" /* RENDER_COMPLETE */, {
|
|
@@ -1370,23 +874,13 @@ async function renderNode2(node, adapter = "shadcn", processEvent2) {
|
|
|
1370
874
|
renderTimeMs: Date.now() - startTime
|
|
1371
875
|
})
|
|
1372
876
|
);
|
|
1373
|
-
renderedNodesCache.set(nodeId, {
|
|
1374
|
-
element: result,
|
|
1375
|
-
timestamp: startTime
|
|
1376
|
-
});
|
|
1377
|
-
if (renderedNodesCache.size > MAX_CACHE_SIZE) {
|
|
1378
|
-
const oldestKey = [...renderedNodesCache.entries()].sort(
|
|
1379
|
-
([, a], [, b]) => a.timestamp - b.timestamp
|
|
1380
|
-
)[0][0];
|
|
1381
|
-
renderedNodesCache.delete(oldestKey);
|
|
1382
|
-
}
|
|
1383
877
|
return result;
|
|
1384
878
|
}
|
|
1385
879
|
function renderShimmer(node, adapter = "shadcn") {
|
|
1386
880
|
if (!node) {
|
|
1387
881
|
return /* @__PURE__ */ jsx(ShimmerBlock, {});
|
|
1388
882
|
}
|
|
1389
|
-
switch (node.
|
|
883
|
+
switch (node.type) {
|
|
1390
884
|
case "ListView":
|
|
1391
885
|
return /* @__PURE__ */ jsx(ShimmerTable, { rows: 3 });
|
|
1392
886
|
case "Detail":
|
|
@@ -1399,16 +893,6 @@ function renderShimmer(node, adapter = "shadcn") {
|
|
|
1399
893
|
}
|
|
1400
894
|
|
|
1401
895
|
// src/core/bindings.ts
|
|
1402
|
-
var bindingsCache = /* @__PURE__ */ new Map();
|
|
1403
|
-
var MAX_CACHE_SIZE2 = 50;
|
|
1404
|
-
var CACHE_TTL2 = 2e3;
|
|
1405
|
-
var nodeCacheTimestamps = /* @__PURE__ */ new Map();
|
|
1406
|
-
function hashDataContext(context) {
|
|
1407
|
-
return JSON.stringify(context);
|
|
1408
|
-
}
|
|
1409
|
-
function createCacheKey(nodeId, context) {
|
|
1410
|
-
return `${nodeId}:${hashDataContext(context)}`;
|
|
1411
|
-
}
|
|
1412
896
|
function getValueByPath(context, path) {
|
|
1413
897
|
const parts = path.split(".");
|
|
1414
898
|
let current = context;
|
|
@@ -1426,32 +910,19 @@ function getValueByPath(context, path) {
|
|
|
1426
910
|
function setValueByPath(context, path, value) {
|
|
1427
911
|
const result = { ...context };
|
|
1428
912
|
const parts = path.split(".");
|
|
1429
|
-
if (parts.length === 0)
|
|
1430
|
-
return result;
|
|
1431
913
|
let current = result;
|
|
1432
914
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
1433
915
|
const part = parts[i];
|
|
1434
|
-
if (
|
|
1435
|
-
|
|
1436
|
-
return context;
|
|
916
|
+
if (!(part in current) || current[part] === null || current[part] === void 0) {
|
|
917
|
+
current[part] = {};
|
|
1437
918
|
}
|
|
1438
|
-
|
|
1439
|
-
if (
|
|
1440
|
-
|
|
919
|
+
current = current[part];
|
|
920
|
+
if (typeof current !== "object") {
|
|
921
|
+
current = {};
|
|
1441
922
|
}
|
|
1442
|
-
current = currentAsObject[part];
|
|
1443
923
|
}
|
|
1444
924
|
const lastPart = parts[parts.length - 1];
|
|
1445
|
-
|
|
1446
|
-
current[lastPart] = value;
|
|
1447
|
-
} else if (parts.length === 1 && typeof result === "object" && result !== null) {
|
|
1448
|
-
result[lastPart] = value;
|
|
1449
|
-
} else {
|
|
1450
|
-
console.warn(
|
|
1451
|
-
`setValueByPath: Could not set value for path "${path}". Final segment location is not an object.`
|
|
1452
|
-
);
|
|
1453
|
-
return context;
|
|
1454
|
-
}
|
|
925
|
+
current[lastPart] = value;
|
|
1455
926
|
return result;
|
|
1456
927
|
}
|
|
1457
928
|
function processBinding(binding, context) {
|
|
@@ -1471,27 +942,18 @@ function processBinding(binding, context) {
|
|
|
1471
942
|
return binding;
|
|
1472
943
|
}
|
|
1473
944
|
async function resolveBindings(node, context) {
|
|
1474
|
-
const currentTime = Date.now();
|
|
1475
|
-
const cacheKey = createCacheKey(node.id, context);
|
|
1476
|
-
const cachedNode = bindingsCache.get(cacheKey);
|
|
1477
|
-
const cachedTimestamp = nodeCacheTimestamps.get(cacheKey);
|
|
1478
|
-
if (cachedNode && cachedTimestamp && currentTime - cachedTimestamp < CACHE_TTL2) {
|
|
1479
|
-
return cachedNode;
|
|
1480
|
-
}
|
|
1481
945
|
await systemEvents.emit(
|
|
1482
|
-
createSystemEvent("BINDING_RESOLUTION_START" /* BINDING_RESOLUTION_START */, {
|
|
1483
|
-
layout: node
|
|
1484
|
-
})
|
|
946
|
+
createSystemEvent("BINDING_RESOLUTION_START" /* BINDING_RESOLUTION_START */, { layout: node })
|
|
1485
947
|
);
|
|
1486
948
|
const result = {
|
|
1487
949
|
...node,
|
|
1488
|
-
props: node.props ? { ...node.props } :
|
|
1489
|
-
events: node.events ? { ...node.events } :
|
|
950
|
+
props: node.props ? { ...node.props } : void 0,
|
|
951
|
+
events: node.events ? { ...node.events } : void 0
|
|
1490
952
|
};
|
|
1491
953
|
if (node.bindings) {
|
|
1492
954
|
for (const [key, binding] of Object.entries(node.bindings)) {
|
|
1493
955
|
const value = processBinding(binding, context);
|
|
1494
|
-
if (value !== void 0
|
|
956
|
+
if (value !== void 0) {
|
|
1495
957
|
if (!result.props) {
|
|
1496
958
|
result.props = {};
|
|
1497
959
|
}
|
|
@@ -1500,9 +962,7 @@ async function resolveBindings(node, context) {
|
|
|
1500
962
|
}
|
|
1501
963
|
}
|
|
1502
964
|
if (node.children) {
|
|
1503
|
-
result.children = await Promise.all(
|
|
1504
|
-
node.children.map((child) => resolveBindings(child, context))
|
|
1505
|
-
);
|
|
965
|
+
result.children = await Promise.all(node.children.map((child) => resolveBindings(child, context)));
|
|
1506
966
|
}
|
|
1507
967
|
await systemEvents.emit(
|
|
1508
968
|
createSystemEvent("BINDING_RESOLUTION_COMPLETE" /* BINDING_RESOLUTION_COMPLETE */, {
|
|
@@ -1510,17 +970,6 @@ async function resolveBindings(node, context) {
|
|
|
1510
970
|
resolvedLayout: result
|
|
1511
971
|
})
|
|
1512
972
|
);
|
|
1513
|
-
bindingsCache.set(cacheKey, result);
|
|
1514
|
-
nodeCacheTimestamps.set(cacheKey, currentTime);
|
|
1515
|
-
if (bindingsCache.size > MAX_CACHE_SIZE2) {
|
|
1516
|
-
const entries = [...nodeCacheTimestamps.entries()];
|
|
1517
|
-
if (entries.length > 0) {
|
|
1518
|
-
entries.sort((a, b) => a[1] - b[1]);
|
|
1519
|
-
const oldestKey = entries[0][0];
|
|
1520
|
-
bindingsCache.delete(oldestKey);
|
|
1521
|
-
nodeCacheTimestamps.delete(oldestKey);
|
|
1522
|
-
}
|
|
1523
|
-
}
|
|
1524
973
|
return result;
|
|
1525
974
|
}
|
|
1526
975
|
function executeAction(action, targetId, payload, context = {}, layoutTree) {
|
|
@@ -1543,6 +992,7 @@ function executeAction(action, targetId, payload, context = {}, layoutTree) {
|
|
|
1543
992
|
}
|
|
1544
993
|
break;
|
|
1545
994
|
}
|
|
995
|
+
// Add more actions as needed
|
|
1546
996
|
default:
|
|
1547
997
|
console.warn(`Unknown action: ${action}`);
|
|
1548
998
|
}
|
|
@@ -1556,7 +1006,7 @@ var EventManager = class {
|
|
|
1556
1006
|
}
|
|
1557
1007
|
/**
|
|
1558
1008
|
* Register a hook for specific event types
|
|
1559
|
-
*
|
|
1009
|
+
*
|
|
1560
1010
|
* @param eventTypes - Event types to register for, or 'all' for all events
|
|
1561
1011
|
* @param hook - Hook function to execute
|
|
1562
1012
|
* @returns Unregister function
|
|
@@ -1589,7 +1039,7 @@ var EventManager = class {
|
|
|
1589
1039
|
}
|
|
1590
1040
|
/**
|
|
1591
1041
|
* Process an event through all registered hooks
|
|
1592
|
-
*
|
|
1042
|
+
*
|
|
1593
1043
|
* @param event - The UI event to process
|
|
1594
1044
|
* @returns Whether the default action should proceed
|
|
1595
1045
|
*/
|
|
@@ -1610,15 +1060,13 @@ var EventManager = class {
|
|
|
1610
1060
|
if (this.hooks.all) {
|
|
1611
1061
|
for (const hook of this.hooks.all) {
|
|
1612
1062
|
await hook(context);
|
|
1613
|
-
if (propagationStopped)
|
|
1614
|
-
break;
|
|
1063
|
+
if (propagationStopped) break;
|
|
1615
1064
|
}
|
|
1616
1065
|
}
|
|
1617
1066
|
if (!propagationStopped && this.hooks[event.type]) {
|
|
1618
1067
|
for (const hook of this.hooks[event.type] || []) {
|
|
1619
1068
|
await hook(context);
|
|
1620
|
-
if (propagationStopped)
|
|
1621
|
-
break;
|
|
1069
|
+
if (propagationStopped) break;
|
|
1622
1070
|
}
|
|
1623
1071
|
}
|
|
1624
1072
|
return !defaultPrevented;
|
|
@@ -1635,20 +1083,6 @@ function createEventHook(eventTypes, hook, options) {
|
|
|
1635
1083
|
}
|
|
1636
1084
|
};
|
|
1637
1085
|
}
|
|
1638
|
-
|
|
1639
|
-
// src/core/component-detection.ts
|
|
1640
|
-
function areShadcnComponentsAvailable() {
|
|
1641
|
-
try {
|
|
1642
|
-
init_button();
|
|
1643
|
-
return true;
|
|
1644
|
-
} catch (error) {
|
|
1645
|
-
return false;
|
|
1646
|
-
}
|
|
1647
|
-
}
|
|
1648
|
-
function getMissingComponentsMessage() {
|
|
1649
|
-
return `Missing required shadcn components. Please run:
|
|
1650
|
-
> npm run setup-shadcn`;
|
|
1651
|
-
}
|
|
1652
1086
|
var AutoUI = ({
|
|
1653
1087
|
schema,
|
|
1654
1088
|
goal,
|
|
@@ -1659,32 +1093,23 @@ var AutoUI = ({
|
|
|
1659
1093
|
systemEventHooks,
|
|
1660
1094
|
debugMode = false,
|
|
1661
1095
|
mockMode = true,
|
|
1096
|
+
databaseConfig,
|
|
1662
1097
|
planningConfig,
|
|
1663
1098
|
integration = {},
|
|
1664
1099
|
scope = {},
|
|
1665
1100
|
enablePartialUpdates = false
|
|
1666
1101
|
}) => {
|
|
1667
|
-
const [schemaAdapterInstance] = useState(null);
|
|
1102
|
+
const [schemaAdapterInstance, setSchemaAdapterInstance] = useState(null);
|
|
1668
1103
|
const [dataContext, setDataContext] = useState({});
|
|
1669
|
-
const [componentsAvailable, setComponentsAvailable] = useState(true);
|
|
1670
1104
|
const effectiveSchema = schema;
|
|
1671
1105
|
const scopedGoal = goal;
|
|
1672
|
-
useEffect(() => {
|
|
1673
|
-
if (componentAdapter === "shadcn") {
|
|
1674
|
-
setComponentsAvailable(areShadcnComponentsAvailable());
|
|
1675
|
-
}
|
|
1676
|
-
}, [componentAdapter]);
|
|
1677
1106
|
useEffect(() => {
|
|
1678
1107
|
const unregisters = [];
|
|
1679
1108
|
if (systemEventHooks) {
|
|
1680
1109
|
Object.entries(systemEventHooks).forEach(([eventType, hooks]) => {
|
|
1681
|
-
if (!hooks)
|
|
1682
|
-
return;
|
|
1110
|
+
if (!hooks) return;
|
|
1683
1111
|
hooks.forEach((hook) => {
|
|
1684
|
-
const unregister = systemEvents.on(
|
|
1685
|
-
eventType,
|
|
1686
|
-
hook
|
|
1687
|
-
);
|
|
1112
|
+
const unregister = systemEvents.on(eventType, hook);
|
|
1688
1113
|
unregisters.push(unregister);
|
|
1689
1114
|
});
|
|
1690
1115
|
});
|
|
@@ -1693,9 +1118,7 @@ var AutoUI = ({
|
|
|
1693
1118
|
const debugHook = (event) => {
|
|
1694
1119
|
console.debug(`[AutoUI Debug] System Event:`, event);
|
|
1695
1120
|
};
|
|
1696
|
-
Object.values(SystemEventType).
|
|
1697
|
-
(eventType) => eventType !== "RENDER_START" /* RENDER_START */ && eventType !== "BINDING_RESOLUTION_START" /* BINDING_RESOLUTION_START */
|
|
1698
|
-
).forEach((eventType) => {
|
|
1121
|
+
Object.values(SystemEventType).forEach((eventType) => {
|
|
1699
1122
|
const unregister = systemEvents.on(eventType, debugHook);
|
|
1700
1123
|
unregisters.push(unregister);
|
|
1701
1124
|
});
|
|
@@ -1738,141 +1161,84 @@ var AutoUI = ({
|
|
|
1738
1161
|
});
|
|
1739
1162
|
const eventManagerRef = useRef(new EventManager());
|
|
1740
1163
|
useEffect(() => {
|
|
1741
|
-
if (!eventHooks)
|
|
1742
|
-
return;
|
|
1164
|
+
if (!eventHooks) return;
|
|
1743
1165
|
const unregisters = [];
|
|
1744
1166
|
if (eventHooks.all) {
|
|
1745
|
-
const unregister = eventManagerRef.current.register(
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
await hook(ctx);
|
|
1750
|
-
if (ctx.isPropagationStopped())
|
|
1751
|
-
break;
|
|
1752
|
-
}
|
|
1167
|
+
const unregister = eventManagerRef.current.register("all", async (ctx) => {
|
|
1168
|
+
for (const hook of eventHooks.all || []) {
|
|
1169
|
+
await hook(ctx);
|
|
1170
|
+
if (ctx.isPropagationStopped()) break;
|
|
1753
1171
|
}
|
|
1754
|
-
);
|
|
1172
|
+
});
|
|
1755
1173
|
unregisters.push(unregister);
|
|
1756
1174
|
}
|
|
1757
1175
|
Object.entries(eventHooks).forEach(([type, hooks]) => {
|
|
1758
|
-
if (type === "all" || !hooks)
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
for (const hook of hooks) {
|
|
1764
|
-
await hook(ctx);
|
|
1765
|
-
if (ctx.isPropagationStopped())
|
|
1766
|
-
break;
|
|
1767
|
-
}
|
|
1176
|
+
if (type === "all" || !hooks) return;
|
|
1177
|
+
const unregister = eventManagerRef.current.register([type], async (ctx) => {
|
|
1178
|
+
for (const hook of hooks) {
|
|
1179
|
+
await hook(ctx);
|
|
1180
|
+
if (ctx.isPropagationStopped()) break;
|
|
1768
1181
|
}
|
|
1769
|
-
);
|
|
1182
|
+
});
|
|
1770
1183
|
unregisters.push(unregister);
|
|
1771
1184
|
});
|
|
1772
1185
|
return () => {
|
|
1773
1186
|
unregisters.forEach((unregister) => unregister());
|
|
1774
1187
|
};
|
|
1775
1188
|
}, [eventHooks]);
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
for (const child of node.children) {
|
|
1793
|
-
const found = findNodeById2(child, id);
|
|
1794
|
-
if (found)
|
|
1795
|
-
return found;
|
|
1796
|
-
}
|
|
1189
|
+
useCallback(async (event) => {
|
|
1190
|
+
const shouldProceed = await eventManagerRef.current.processEvent(event);
|
|
1191
|
+
if (onEvent) {
|
|
1192
|
+
onEvent(event);
|
|
1193
|
+
}
|
|
1194
|
+
if (!shouldProceed) {
|
|
1195
|
+
console.info("Event processing was prevented by hooks", event);
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
const findNodeById2 = (node, id) => {
|
|
1199
|
+
if (!node) return void 0;
|
|
1200
|
+
if (node.id === id) return node;
|
|
1201
|
+
if (node.children) {
|
|
1202
|
+
for (const child of node.children) {
|
|
1203
|
+
const found = findNodeById2(child, id);
|
|
1204
|
+
if (found) return found;
|
|
1797
1205
|
}
|
|
1798
|
-
return void 0;
|
|
1799
|
-
};
|
|
1800
|
-
const sourceNode = findNodeById2(state.layout, event.nodeId);
|
|
1801
|
-
if (!sourceNode) {
|
|
1802
|
-
console.warn(`Node not found for event: ${event.nodeId}`);
|
|
1803
|
-
handleEvent(event);
|
|
1804
|
-
return;
|
|
1805
1206
|
}
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
handleEvent(event);
|
|
1812
|
-
return;
|
|
1813
|
-
}
|
|
1814
|
-
const newContext = executeAction(
|
|
1815
|
-
eventConfig.action,
|
|
1816
|
-
eventConfig.target || "",
|
|
1817
|
-
// Provide empty string as fallback if target is null
|
|
1818
|
-
{
|
|
1819
|
-
...eventConfig.payload,
|
|
1820
|
-
...event.payload
|
|
1821
|
-
},
|
|
1822
|
-
dataContext,
|
|
1823
|
-
state.layout || void 0
|
|
1824
|
-
);
|
|
1825
|
-
setDataContext(newContext);
|
|
1207
|
+
return void 0;
|
|
1208
|
+
};
|
|
1209
|
+
const sourceNode = findNodeById2(state.layout, event.nodeId);
|
|
1210
|
+
if (!sourceNode) {
|
|
1211
|
+
console.warn(`Node not found for event: ${event.nodeId}`);
|
|
1826
1212
|
handleEvent(event);
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
const eventConfig = sourceNode.events?.[event.type];
|
|
1216
|
+
if (!eventConfig) {
|
|
1217
|
+
console.warn(`No event config found for ${event.type} on node ${event.nodeId}`);
|
|
1218
|
+
handleEvent(event);
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
const newContext = executeAction(
|
|
1222
|
+
eventConfig.action,
|
|
1223
|
+
eventConfig.target,
|
|
1224
|
+
{
|
|
1225
|
+
...eventConfig.payload,
|
|
1226
|
+
...event.payload
|
|
1227
|
+
},
|
|
1228
|
+
dataContext,
|
|
1229
|
+
state.layout
|
|
1230
|
+
);
|
|
1231
|
+
setDataContext(newContext);
|
|
1232
|
+
handleEvent(event);
|
|
1233
|
+
}, [dataContext, handleEvent, onEvent, state.layout]);
|
|
1234
|
+
const [resolvedLayout, setResolvedLayout] = useState(void 0);
|
|
1235
|
+
useEffect(() => {
|
|
1837
1236
|
if (state.layout) {
|
|
1838
|
-
|
|
1839
|
-
const resolved = await resolveBindings(state.layout, dataContext);
|
|
1840
|
-
setResolvedLayout(resolved);
|
|
1841
|
-
} catch (err) {
|
|
1842
|
-
console.error("Error resolving bindings:", err);
|
|
1843
|
-
}
|
|
1237
|
+
resolveBindings(state.layout, dataContext).then((resolved) => setResolvedLayout(resolved)).catch((err) => console.error("Error resolving bindings:", err));
|
|
1844
1238
|
} else {
|
|
1845
1239
|
setResolvedLayout(void 0);
|
|
1846
1240
|
}
|
|
1847
1241
|
}, [state.layout, dataContext]);
|
|
1848
|
-
useEffect(() => {
|
|
1849
|
-
resolveLayoutBindings();
|
|
1850
|
-
}, [resolveLayoutBindings]);
|
|
1851
|
-
const renderResolvedLayout = useCallback(async () => {
|
|
1852
|
-
if (resolvedLayout) {
|
|
1853
|
-
try {
|
|
1854
|
-
const rendered = await renderNode2(
|
|
1855
|
-
resolvedLayout,
|
|
1856
|
-
componentAdapter,
|
|
1857
|
-
processEvent2
|
|
1858
|
-
);
|
|
1859
|
-
setRenderedNode(rendered);
|
|
1860
|
-
} catch (err) {
|
|
1861
|
-
console.error("Error rendering node:", err);
|
|
1862
|
-
}
|
|
1863
|
-
} else {
|
|
1864
|
-
setRenderedNode(null);
|
|
1865
|
-
}
|
|
1866
|
-
}, [resolvedLayout, componentAdapter, processEvent2]);
|
|
1867
|
-
useEffect(() => {
|
|
1868
|
-
renderResolvedLayout();
|
|
1869
|
-
}, [renderResolvedLayout]);
|
|
1870
|
-
if (!componentsAvailable) {
|
|
1871
|
-
return /* @__PURE__ */ jsxs("div", { className: "autoui-error p-4 border border-red-300 bg-red-50 text-red-700 rounded", children: [
|
|
1872
|
-
/* @__PURE__ */ jsx("p", { className: "font-medium", children: "Component Library Not Found" }),
|
|
1873
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm whitespace-pre-line", children: getMissingComponentsMessage() })
|
|
1874
|
-
] });
|
|
1875
|
-
}
|
|
1876
1242
|
return /* @__PURE__ */ jsxs(
|
|
1877
1243
|
"div",
|
|
1878
1244
|
{
|
|
@@ -1889,24 +1255,11 @@ var AutoUI = ({
|
|
|
1889
1255
|
] }) })
|
|
1890
1256
|
) : (
|
|
1891
1257
|
// Render the resolved layout
|
|
1892
|
-
/* @__PURE__ */ jsx("div", { className: "autoui-content", children:
|
|
1258
|
+
/* @__PURE__ */ jsx("div", { className: "autoui-content", children: renderNode2(resolvedLayout, componentAdapter) })
|
|
1893
1259
|
),
|
|
1894
|
-
state.error && /* @__PURE__ */ jsxs("div", { className: "autoui-error
|
|
1895
|
-
/* @__PURE__ */ jsx("p", { className: "autoui-error-title
|
|
1896
|
-
/* @__PURE__ */ jsx("p", { className: "autoui-error-message
|
|
1897
|
-
!mockMode && /* @__PURE__ */ jsxs("div", { className: "mt-4 text-sm text-red-600 dark:text-red-300", children: [
|
|
1898
|
-
/* @__PURE__ */ jsx("p", { children: "This could be because:" }),
|
|
1899
|
-
/* @__PURE__ */ jsxs("ul", { className: "list-disc pl-5 mt-2", children: [
|
|
1900
|
-
/* @__PURE__ */ jsx("li", { children: "Your OpenAI API key is missing or invalid" }),
|
|
1901
|
-
/* @__PURE__ */ jsx("li", { children: "The OpenAI service is experiencing issues" }),
|
|
1902
|
-
/* @__PURE__ */ jsx("li", { children: "Your API rate limit has been exceeded" })
|
|
1903
|
-
] }),
|
|
1904
|
-
/* @__PURE__ */ jsxs("p", { className: "mt-2", children: [
|
|
1905
|
-
"Try setting ",
|
|
1906
|
-
/* @__PURE__ */ jsx("code", { children: "mockMode=true" }),
|
|
1907
|
-
" to use sample data instead."
|
|
1908
|
-
] })
|
|
1909
|
-
] })
|
|
1260
|
+
state.error && /* @__PURE__ */ jsxs("div", { className: "autoui-error", children: [
|
|
1261
|
+
/* @__PURE__ */ jsx("p", { className: "autoui-error-title", children: "Error generating UI" }),
|
|
1262
|
+
/* @__PURE__ */ jsx("p", { className: "autoui-error-message", children: state.error })
|
|
1910
1263
|
] })
|
|
1911
1264
|
]
|
|
1912
1265
|
}
|
|
@@ -1959,26 +1312,26 @@ var DrizzleAdapter = class {
|
|
|
1959
1312
|
*/
|
|
1960
1313
|
mapDataType(drizzleType) {
|
|
1961
1314
|
const typeMap = {
|
|
1962
|
-
serial: "integer",
|
|
1963
|
-
integer: "integer",
|
|
1964
|
-
int: "integer",
|
|
1965
|
-
bigint: "integer",
|
|
1966
|
-
text: "string",
|
|
1967
|
-
varchar: "string",
|
|
1968
|
-
char: "string",
|
|
1969
|
-
boolean: "boolean",
|
|
1970
|
-
bool: "boolean",
|
|
1971
|
-
timestamp: "datetime",
|
|
1972
|
-
timestamptz: "datetime",
|
|
1973
|
-
date: "date",
|
|
1974
|
-
time: "time",
|
|
1975
|
-
json: "object",
|
|
1976
|
-
jsonb: "object",
|
|
1977
|
-
real: "number",
|
|
1978
|
-
float: "number",
|
|
1979
|
-
double: "number",
|
|
1980
|
-
numeric: "number",
|
|
1981
|
-
decimal: "number"
|
|
1315
|
+
"serial": "integer",
|
|
1316
|
+
"integer": "integer",
|
|
1317
|
+
"int": "integer",
|
|
1318
|
+
"bigint": "integer",
|
|
1319
|
+
"text": "string",
|
|
1320
|
+
"varchar": "string",
|
|
1321
|
+
"char": "string",
|
|
1322
|
+
"boolean": "boolean",
|
|
1323
|
+
"bool": "boolean",
|
|
1324
|
+
"timestamp": "datetime",
|
|
1325
|
+
"timestamptz": "datetime",
|
|
1326
|
+
"date": "date",
|
|
1327
|
+
"time": "time",
|
|
1328
|
+
"json": "object",
|
|
1329
|
+
"jsonb": "object",
|
|
1330
|
+
"real": "number",
|
|
1331
|
+
"float": "number",
|
|
1332
|
+
"double": "number",
|
|
1333
|
+
"numeric": "number",
|
|
1334
|
+
"decimal": "number"
|
|
1982
1335
|
};
|
|
1983
1336
|
return typeMap[drizzleType.toLowerCase()] || "string";
|
|
1984
1337
|
}
|
|
@@ -2021,92 +1374,10 @@ function createSchemaAdapter(options) {
|
|
|
2021
1374
|
case "custom":
|
|
2022
1375
|
return options.adapter;
|
|
2023
1376
|
default:
|
|
2024
|
-
throw new Error(
|
|
2025
|
-
`Unsupported schema adapter type: ${options.type}`
|
|
2026
|
-
);
|
|
1377
|
+
throw new Error(`Unsupported schema adapter type: ${options.type}`);
|
|
2027
1378
|
}
|
|
2028
1379
|
}
|
|
2029
1380
|
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
console.warn(
|
|
2033
|
-
"generateComponent is a placeholder and will be implemented in a future version"
|
|
2034
|
-
);
|
|
2035
|
-
return `<div>Generated Component for: ${prompt}</div>`;
|
|
2036
|
-
};
|
|
2037
|
-
var generateUIDescription = async (prompt) => {
|
|
2038
|
-
console.warn(
|
|
2039
|
-
"generateUIDescription is a placeholder and will be implemented in a future version"
|
|
2040
|
-
);
|
|
2041
|
-
return `Description for ${prompt}`;
|
|
2042
|
-
};
|
|
2043
|
-
var generateUIComponent = async (prompt) => {
|
|
2044
|
-
console.warn(
|
|
2045
|
-
"generateUIComponent is a placeholder and will be implemented in a future version"
|
|
2046
|
-
);
|
|
2047
|
-
return `<div>Generated UI Component for: ${prompt}</div>`;
|
|
2048
|
-
};
|
|
2049
|
-
function usePlanner(options) {
|
|
2050
|
-
const { goal, schema, userContext, router: customRouter } = options;
|
|
2051
|
-
const [layout, setLayout] = useState(void 0);
|
|
2052
|
-
const [loading, setLoading] = useState(false);
|
|
2053
|
-
const [error, setError] = useState(null);
|
|
2054
|
-
const router = customRouter || createDefaultRouter();
|
|
2055
|
-
const dataContext = {};
|
|
2056
|
-
const generateInitialLayout = useCallback(async () => {
|
|
2057
|
-
setLoading(true);
|
|
2058
|
-
setError(null);
|
|
2059
|
-
try {
|
|
2060
|
-
const plannerInput2 = {
|
|
2061
|
-
schema,
|
|
2062
|
-
goal,
|
|
2063
|
-
userContext: userContext || null,
|
|
2064
|
-
history: null
|
|
2065
|
-
};
|
|
2066
|
-
const generatedLayout = await callPlannerLLM(plannerInput2);
|
|
2067
|
-
setLayout(generatedLayout);
|
|
2068
|
-
} catch (err) {
|
|
2069
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
2070
|
-
} finally {
|
|
2071
|
-
setLoading(false);
|
|
2072
|
-
}
|
|
2073
|
-
}, [schema, goal, userContext]);
|
|
2074
|
-
const handleEvent = useCallback(
|
|
2075
|
-
async (event) => {
|
|
2076
|
-
if (!layout) {
|
|
2077
|
-
setError(new Error("Cannot handle event - no layout exists"));
|
|
2078
|
-
return;
|
|
2079
|
-
}
|
|
2080
|
-
setLoading(true);
|
|
2081
|
-
setError(null);
|
|
2082
|
-
try {
|
|
2083
|
-
const updatedLayout = await processEvent(
|
|
2084
|
-
event,
|
|
2085
|
-
router,
|
|
2086
|
-
schema,
|
|
2087
|
-
layout,
|
|
2088
|
-
dataContext,
|
|
2089
|
-
goal,
|
|
2090
|
-
userContext
|
|
2091
|
-
);
|
|
2092
|
-
setLayout(updatedLayout);
|
|
2093
|
-
} catch (err) {
|
|
2094
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
2095
|
-
} finally {
|
|
2096
|
-
setLoading(false);
|
|
2097
|
-
}
|
|
2098
|
-
},
|
|
2099
|
-
[layout, router, schema, dataContext, goal, userContext]
|
|
2100
|
-
);
|
|
2101
|
-
return {
|
|
2102
|
-
layout,
|
|
2103
|
-
loading,
|
|
2104
|
-
error,
|
|
2105
|
-
handleEvent,
|
|
2106
|
-
generateInitialLayout
|
|
2107
|
-
};
|
|
2108
|
-
}
|
|
2109
|
-
|
|
2110
|
-
export { ActionRouter, ActionType, AutoUI, DrizzleAdapter, SystemEventType, createDefaultRouter, createEventHook, createSchemaAdapter, createSystemEvent, generateComponent, generateUIComponent, generateUIDescription, systemEvents, uiEvent, uiEventType, uiSpecNode, usePlanner };
|
|
2111
|
-
//# sourceMappingURL=out.js.map
|
|
1381
|
+
export { ActionRouter, ActionType, AutoUI, DrizzleAdapter, SystemEventType, createDefaultRouter, createEventHook, createSchemaAdapter, createSystemEvent, systemEvents, uiEvent, uiEventType, uiSpecNode };
|
|
1382
|
+
//# sourceMappingURL=index.mjs.map
|
|
2112
1383
|
//# sourceMappingURL=index.mjs.map
|