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