@mcp-b/char 0.0.0-beta-20260124143827
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/LICENSE +23 -0
- package/README.md +367 -0
- package/dist/FormToolUI-04m9zI5r.js +619 -0
- package/dist/FormToolUI-04m9zI5r.js.map +1 -0
- package/dist/FormToolUI-CmH2J4Nm.js +3 -0
- package/dist/index.d.ts +103 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11207 -0
- package/dist/index.js.map +1 -0
- package/dist/jsx.d.ts +253 -0
- package/dist/styles/globals.css +2 -0
- package/dist/styles.d.ts +2 -0
- package/dist/web-component-standalone.css +37 -0
- package/dist/web-component.d.ts +108 -0
- package/dist/web-component.d.ts.map +1 -0
- package/dist/web-component.js +11362 -0
- package/dist/web-component.js.map +1 -0
- package/package.json +142 -0
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
import { c } from "react-compiler-runtime";
|
|
2
|
+
import { createContext, useContext, useEffect, useRef, useState } from "react";
|
|
3
|
+
import { AlertCircle, Check, ChevronDownIcon, ChevronUpIcon, FileText } from "lucide-react";
|
|
4
|
+
import { makeAssistantToolUI } from "@assistant-ui/react";
|
|
5
|
+
import { clsx } from "clsx";
|
|
6
|
+
import { twMerge } from "tailwind-merge";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
9
|
+
import { cva } from "class-variance-authority";
|
|
10
|
+
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
|
|
11
|
+
import Ajv from "ajv";
|
|
12
|
+
import { withTheme } from "@rjsf/core";
|
|
13
|
+
import { Theme } from "@rjsf/shadcn";
|
|
14
|
+
import validator from "@rjsf/validator-ajv8";
|
|
15
|
+
|
|
16
|
+
//#region src/utils/cn.ts
|
|
17
|
+
/**
|
|
18
|
+
* Merges Tailwind CSS classes with proper precedence handling.
|
|
19
|
+
* Combines clsx for conditional classes and tailwind-merge for deduplication.
|
|
20
|
+
*/
|
|
21
|
+
function cn(...inputs) {
|
|
22
|
+
return twMerge(clsx(inputs));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/components/ui/button.tsx
|
|
27
|
+
const buttonVariants = cva("inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md font-medium text-sm outline-none transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", {
|
|
28
|
+
variants: {
|
|
29
|
+
variant: {
|
|
30
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
31
|
+
destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
|
|
32
|
+
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
|
|
33
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
34
|
+
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
35
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
36
|
+
},
|
|
37
|
+
size: {
|
|
38
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
39
|
+
sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
|
|
40
|
+
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
41
|
+
icon: "size-9",
|
|
42
|
+
"icon-sm": "size-8",
|
|
43
|
+
"icon-lg": "size-10"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
defaultVariants: {
|
|
47
|
+
variant: "default",
|
|
48
|
+
size: "default"
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
function Button(t0) {
|
|
52
|
+
const $ = c(16);
|
|
53
|
+
let className;
|
|
54
|
+
let props;
|
|
55
|
+
let t1;
|
|
56
|
+
let t2;
|
|
57
|
+
let t3;
|
|
58
|
+
if ($[0] !== t0) {
|
|
59
|
+
({className, variant: t1, size: t2, asChild: t3, ...props} = t0);
|
|
60
|
+
$[0] = t0;
|
|
61
|
+
$[1] = className;
|
|
62
|
+
$[2] = props;
|
|
63
|
+
$[3] = t1;
|
|
64
|
+
$[4] = t2;
|
|
65
|
+
$[5] = t3;
|
|
66
|
+
} else {
|
|
67
|
+
className = $[1];
|
|
68
|
+
props = $[2];
|
|
69
|
+
t1 = $[3];
|
|
70
|
+
t2 = $[4];
|
|
71
|
+
t3 = $[5];
|
|
72
|
+
}
|
|
73
|
+
const variant = t1 === void 0 ? "default" : t1;
|
|
74
|
+
const size = t2 === void 0 ? "default" : t2;
|
|
75
|
+
const Comp = (t3 === void 0 ? false : t3) ? Slot : "button";
|
|
76
|
+
let t4;
|
|
77
|
+
if ($[6] !== className || $[7] !== size || $[8] !== variant) {
|
|
78
|
+
t4 = cn(buttonVariants({
|
|
79
|
+
variant,
|
|
80
|
+
size,
|
|
81
|
+
className
|
|
82
|
+
}));
|
|
83
|
+
$[6] = className;
|
|
84
|
+
$[7] = size;
|
|
85
|
+
$[8] = variant;
|
|
86
|
+
$[9] = t4;
|
|
87
|
+
} else t4 = $[9];
|
|
88
|
+
let t5;
|
|
89
|
+
if ($[10] !== Comp || $[11] !== props || $[12] !== size || $[13] !== t4 || $[14] !== variant) {
|
|
90
|
+
t5 = /* @__PURE__ */ jsx(Comp, {
|
|
91
|
+
"data-slot": "button",
|
|
92
|
+
"data-variant": variant,
|
|
93
|
+
"data-size": size,
|
|
94
|
+
className: t4,
|
|
95
|
+
...props
|
|
96
|
+
});
|
|
97
|
+
$[10] = Comp;
|
|
98
|
+
$[11] = props;
|
|
99
|
+
$[12] = size;
|
|
100
|
+
$[13] = t4;
|
|
101
|
+
$[14] = variant;
|
|
102
|
+
$[15] = t5;
|
|
103
|
+
} else t5 = $[15];
|
|
104
|
+
return t5;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
//#endregion
|
|
108
|
+
//#region src/components/ui/collapsible.tsx
|
|
109
|
+
function Collapsible(t0) {
|
|
110
|
+
const $ = c(4);
|
|
111
|
+
let props;
|
|
112
|
+
if ($[0] !== t0) {
|
|
113
|
+
({...props} = t0);
|
|
114
|
+
$[0] = t0;
|
|
115
|
+
$[1] = props;
|
|
116
|
+
} else props = $[1];
|
|
117
|
+
let t1;
|
|
118
|
+
if ($[2] !== props) {
|
|
119
|
+
t1 = /* @__PURE__ */ jsx(CollapsiblePrimitive.Root, {
|
|
120
|
+
"data-slot": "collapsible",
|
|
121
|
+
...props
|
|
122
|
+
});
|
|
123
|
+
$[2] = props;
|
|
124
|
+
$[3] = t1;
|
|
125
|
+
} else t1 = $[3];
|
|
126
|
+
return t1;
|
|
127
|
+
}
|
|
128
|
+
function CollapsibleTrigger(t0) {
|
|
129
|
+
const $ = c(4);
|
|
130
|
+
let props;
|
|
131
|
+
if ($[0] !== t0) {
|
|
132
|
+
({...props} = t0);
|
|
133
|
+
$[0] = t0;
|
|
134
|
+
$[1] = props;
|
|
135
|
+
} else props = $[1];
|
|
136
|
+
let t1;
|
|
137
|
+
if ($[2] !== props) {
|
|
138
|
+
t1 = /* @__PURE__ */ jsx(CollapsiblePrimitive.CollapsibleTrigger, {
|
|
139
|
+
"data-slot": "collapsible-trigger",
|
|
140
|
+
...props
|
|
141
|
+
});
|
|
142
|
+
$[2] = props;
|
|
143
|
+
$[3] = t1;
|
|
144
|
+
} else t1 = $[3];
|
|
145
|
+
return t1;
|
|
146
|
+
}
|
|
147
|
+
function CollapsibleContent(t0) {
|
|
148
|
+
const $ = c(4);
|
|
149
|
+
let props;
|
|
150
|
+
if ($[0] !== t0) {
|
|
151
|
+
({...props} = t0);
|
|
152
|
+
$[0] = t0;
|
|
153
|
+
$[1] = props;
|
|
154
|
+
} else props = $[1];
|
|
155
|
+
let t1;
|
|
156
|
+
if ($[2] !== props) {
|
|
157
|
+
t1 = /* @__PURE__ */ jsx(CollapsiblePrimitive.CollapsibleContent, {
|
|
158
|
+
"data-slot": "collapsible-content",
|
|
159
|
+
...props
|
|
160
|
+
});
|
|
161
|
+
$[2] = props;
|
|
162
|
+
$[3] = t1;
|
|
163
|
+
} else t1 = $[3];
|
|
164
|
+
return t1;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
//#endregion
|
|
168
|
+
//#region src/providers/ToolExecutionProvider.tsx
|
|
169
|
+
const ToolExecutionContext = createContext(null);
|
|
170
|
+
const ToolExecutionProvider = (t0) => {
|
|
171
|
+
const $ = c(3);
|
|
172
|
+
const { value, children } = t0;
|
|
173
|
+
let t1;
|
|
174
|
+
if ($[0] !== children || $[1] !== value) {
|
|
175
|
+
t1 = /* @__PURE__ */ jsx(ToolExecutionContext.Provider, {
|
|
176
|
+
value,
|
|
177
|
+
children
|
|
178
|
+
});
|
|
179
|
+
$[0] = children;
|
|
180
|
+
$[1] = value;
|
|
181
|
+
$[2] = t1;
|
|
182
|
+
} else t1 = $[2];
|
|
183
|
+
return t1;
|
|
184
|
+
};
|
|
185
|
+
function useOptionalToolExecution() {
|
|
186
|
+
return useContext(ToolExecutionContext);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
//#endregion
|
|
190
|
+
//#region src/tools/FormToolUI.tsx
|
|
191
|
+
const Form = withTheme(Theme);
|
|
192
|
+
const ajv = new Ajv();
|
|
193
|
+
/**
|
|
194
|
+
* Normalize a JSON Schema to handle common model mistakes.
|
|
195
|
+
* - Converts uppercase types (Gemini format) to lowercase (JSON Schema format)
|
|
196
|
+
* - Recursively processes nested schemas
|
|
197
|
+
*/
|
|
198
|
+
function normalizeSchema(schema) {
|
|
199
|
+
if (!schema || typeof schema !== "object") return schema;
|
|
200
|
+
const obj = { ...schema };
|
|
201
|
+
if (typeof obj.type === "string") obj.type = obj.type.toLowerCase();
|
|
202
|
+
if (obj.properties && typeof obj.properties === "object") obj.properties = Object.fromEntries(Object.entries(obj.properties).map(([key, value]) => [key, normalizeSchema(value)]));
|
|
203
|
+
if (obj.items) if (Array.isArray(obj.items)) obj.items = obj.items.map(normalizeSchema);
|
|
204
|
+
else obj.items = normalizeSchema(obj.items);
|
|
205
|
+
if (obj.additionalProperties && typeof obj.additionalProperties === "object") obj.additionalProperties = normalizeSchema(obj.additionalProperties);
|
|
206
|
+
for (const keyword of [
|
|
207
|
+
"allOf",
|
|
208
|
+
"anyOf",
|
|
209
|
+
"oneOf"
|
|
210
|
+
]) if (Array.isArray(obj[keyword])) obj[keyword] = obj[keyword].map(normalizeSchema);
|
|
211
|
+
if (obj.not && typeof obj.not === "object") obj.not = normalizeSchema(obj.not);
|
|
212
|
+
return obj;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Validate a JSON Schema using AJV's meta-schema validation.
|
|
216
|
+
* Returns null if valid, or an error message string if invalid.
|
|
217
|
+
*/
|
|
218
|
+
function validateSchema(schema) {
|
|
219
|
+
if (ajv.validateSchema(schema)) return null;
|
|
220
|
+
return [
|
|
221
|
+
"Invalid JSON Schema:",
|
|
222
|
+
...(ajv.errors ?? []).map((err) => {
|
|
223
|
+
return `- ${err.instancePath || "root"}: ${err.message}`;
|
|
224
|
+
}),
|
|
225
|
+
"",
|
|
226
|
+
"Please fix the schema and try again."
|
|
227
|
+
].join("\n");
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Display component for schema validation errors
|
|
231
|
+
*/
|
|
232
|
+
function SchemaErrorDisplay(t0) {
|
|
233
|
+
const $ = c(16);
|
|
234
|
+
const { title, error } = t0;
|
|
235
|
+
const [isOpen, setIsOpen] = useState(true);
|
|
236
|
+
let t1;
|
|
237
|
+
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
238
|
+
t1 = /* @__PURE__ */ jsxs("div", {
|
|
239
|
+
className: "relative",
|
|
240
|
+
children: [/* @__PURE__ */ jsx(FileText, { className: "h-3.5 w-3.5 text-destructive" }), /* @__PURE__ */ jsx(AlertCircle, { className: "absolute -bottom-0.5 -right-0.5 h-2 w-2 text-destructive" })]
|
|
241
|
+
});
|
|
242
|
+
$[0] = t1;
|
|
243
|
+
} else t1 = $[0];
|
|
244
|
+
let t2;
|
|
245
|
+
if ($[1] !== title) {
|
|
246
|
+
t2 = /* @__PURE__ */ jsxs("span", {
|
|
247
|
+
className: "flex-grow text-xs font-medium text-destructive",
|
|
248
|
+
children: [title, " - Invalid Schema"]
|
|
249
|
+
});
|
|
250
|
+
$[1] = title;
|
|
251
|
+
$[2] = t2;
|
|
252
|
+
} else t2 = $[2];
|
|
253
|
+
let t3;
|
|
254
|
+
if ($[3] !== isOpen) {
|
|
255
|
+
t3 = /* @__PURE__ */ jsx("span", {
|
|
256
|
+
className: "inline-flex h-5 w-5 items-center justify-center p-0",
|
|
257
|
+
children: isOpen ? /* @__PURE__ */ jsx(ChevronUpIcon, { className: "h-3 w-3 text-destructive/70" }) : /* @__PURE__ */ jsx(ChevronDownIcon, { className: "h-3 w-3 text-destructive/70" })
|
|
258
|
+
});
|
|
259
|
+
$[3] = isOpen;
|
|
260
|
+
$[4] = t3;
|
|
261
|
+
} else t3 = $[4];
|
|
262
|
+
let t4;
|
|
263
|
+
if ($[5] !== t2 || $[6] !== t3) {
|
|
264
|
+
t4 = /* @__PURE__ */ jsx(CollapsibleTrigger, {
|
|
265
|
+
asChild: true,
|
|
266
|
+
children: /* @__PURE__ */ jsxs("button", {
|
|
267
|
+
type: "button",
|
|
268
|
+
className: "flex w-full items-center gap-1.5 px-2 py-1.5 text-left transition-colors hover:bg-destructive/15",
|
|
269
|
+
children: [
|
|
270
|
+
t1,
|
|
271
|
+
t2,
|
|
272
|
+
t3
|
|
273
|
+
]
|
|
274
|
+
})
|
|
275
|
+
});
|
|
276
|
+
$[5] = t2;
|
|
277
|
+
$[6] = t3;
|
|
278
|
+
$[7] = t4;
|
|
279
|
+
} else t4 = $[7];
|
|
280
|
+
let t5;
|
|
281
|
+
if ($[8] !== error) {
|
|
282
|
+
t5 = /* @__PURE__ */ jsx(CollapsibleContent, { children: /* @__PURE__ */ jsx("div", {
|
|
283
|
+
className: "border-t border-destructive/20 px-2 py-1.5",
|
|
284
|
+
children: /* @__PURE__ */ jsx("pre", {
|
|
285
|
+
className: "whitespace-pre-wrap text-[11px] text-foreground/70",
|
|
286
|
+
children: error
|
|
287
|
+
})
|
|
288
|
+
}) });
|
|
289
|
+
$[8] = error;
|
|
290
|
+
$[9] = t5;
|
|
291
|
+
} else t5 = $[9];
|
|
292
|
+
let t6;
|
|
293
|
+
if ($[10] !== t4 || $[11] !== t5) {
|
|
294
|
+
t6 = /* @__PURE__ */ jsxs("div", {
|
|
295
|
+
className: "my-1 overflow-hidden rounded-lg bg-destructive/10 border border-destructive/20",
|
|
296
|
+
children: [t4, t5]
|
|
297
|
+
});
|
|
298
|
+
$[10] = t4;
|
|
299
|
+
$[11] = t5;
|
|
300
|
+
$[12] = t6;
|
|
301
|
+
} else t6 = $[12];
|
|
302
|
+
let t7;
|
|
303
|
+
if ($[13] !== isOpen || $[14] !== t6) {
|
|
304
|
+
t7 = /* @__PURE__ */ jsx(Collapsible, {
|
|
305
|
+
open: isOpen,
|
|
306
|
+
onOpenChange: setIsOpen,
|
|
307
|
+
children: t6
|
|
308
|
+
});
|
|
309
|
+
$[13] = isOpen;
|
|
310
|
+
$[14] = t6;
|
|
311
|
+
$[15] = t7;
|
|
312
|
+
} else t7 = $[15];
|
|
313
|
+
return t7;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Parse form result data, handling cases where it may be stringified
|
|
317
|
+
*/
|
|
318
|
+
function parseFormData(data) {
|
|
319
|
+
if (typeof data === "object" && data !== null) {
|
|
320
|
+
if (Object.keys(data).some((key) => isNaN(Number(key)))) return data;
|
|
321
|
+
}
|
|
322
|
+
if (typeof data === "string") try {
|
|
323
|
+
const parsed = JSON.parse(data);
|
|
324
|
+
if (typeof parsed === "object" && parsed !== null) return parsed;
|
|
325
|
+
} catch (error) {
|
|
326
|
+
console.warn("[FormToolUI] Failed to parse form data as JSON:", {
|
|
327
|
+
data: data.substring(0, 100),
|
|
328
|
+
error: error instanceof Error ? error.message : "Unknown parse error"
|
|
329
|
+
});
|
|
330
|
+
return { value: data };
|
|
331
|
+
}
|
|
332
|
+
return typeof data === "object" && data !== null ? data : { value: String(data) };
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Format a value for display
|
|
336
|
+
*/
|
|
337
|
+
function formatValue(value) {
|
|
338
|
+
if (value === null || value === void 0) return "—";
|
|
339
|
+
if (typeof value === "boolean") return value ? "Yes" : "No";
|
|
340
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
341
|
+
return String(value);
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Display component for submitted form data - matches UnifiedToolFallback pattern
|
|
345
|
+
*/
|
|
346
|
+
function FormResultDisplay(t0) {
|
|
347
|
+
const $ = c(41);
|
|
348
|
+
const { title, data } = t0;
|
|
349
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
350
|
+
let T0;
|
|
351
|
+
let T1;
|
|
352
|
+
let t1;
|
|
353
|
+
let t2;
|
|
354
|
+
let t3;
|
|
355
|
+
let t4;
|
|
356
|
+
let t5;
|
|
357
|
+
let t6;
|
|
358
|
+
let t7;
|
|
359
|
+
let t8;
|
|
360
|
+
if ($[0] !== data || $[1] !== isOpen || $[2] !== title) {
|
|
361
|
+
const parsedData = parseFormData(data);
|
|
362
|
+
const entries = Object.entries(parsedData);
|
|
363
|
+
T1 = Collapsible;
|
|
364
|
+
t7 = isOpen;
|
|
365
|
+
t8 = setIsOpen;
|
|
366
|
+
t5 = "my-1 overflow-hidden rounded-lg bg-muted/50";
|
|
367
|
+
let t9$1;
|
|
368
|
+
if ($[13] === Symbol.for("react.memo_cache_sentinel")) {
|
|
369
|
+
t9$1 = /* @__PURE__ */ jsxs("div", {
|
|
370
|
+
className: "relative",
|
|
371
|
+
children: [/* @__PURE__ */ jsx(FileText, { className: "h-3.5 w-3.5 text-muted-foreground" }), /* @__PURE__ */ jsx(Check, { className: "absolute -bottom-0.5 -right-0.5 h-2 w-2 text-muted-foreground" })]
|
|
372
|
+
});
|
|
373
|
+
$[13] = t9$1;
|
|
374
|
+
} else t9$1 = $[13];
|
|
375
|
+
let t10$1;
|
|
376
|
+
if ($[14] !== title) {
|
|
377
|
+
t10$1 = /* @__PURE__ */ jsx("span", {
|
|
378
|
+
className: "flex-grow text-xs font-medium text-foreground/80",
|
|
379
|
+
children: title
|
|
380
|
+
});
|
|
381
|
+
$[14] = title;
|
|
382
|
+
$[15] = t10$1;
|
|
383
|
+
} else t10$1 = $[15];
|
|
384
|
+
let t11$1;
|
|
385
|
+
if ($[16] !== isOpen) {
|
|
386
|
+
t11$1 = /* @__PURE__ */ jsx("span", {
|
|
387
|
+
className: "inline-flex h-5 w-5 items-center justify-center p-0",
|
|
388
|
+
children: isOpen ? /* @__PURE__ */ jsx(ChevronUpIcon, { className: "h-3 w-3 text-muted-foreground/70" }) : /* @__PURE__ */ jsx(ChevronDownIcon, { className: "h-3 w-3 text-muted-foreground/70" })
|
|
389
|
+
});
|
|
390
|
+
$[16] = isOpen;
|
|
391
|
+
$[17] = t11$1;
|
|
392
|
+
} else t11$1 = $[17];
|
|
393
|
+
if ($[18] !== t10$1 || $[19] !== t11$1) {
|
|
394
|
+
t6 = /* @__PURE__ */ jsx(CollapsibleTrigger, {
|
|
395
|
+
asChild: true,
|
|
396
|
+
children: /* @__PURE__ */ jsxs("button", {
|
|
397
|
+
type: "button",
|
|
398
|
+
className: "flex w-full items-center gap-1.5 px-2 py-1.5 text-left transition-colors hover:bg-muted/70",
|
|
399
|
+
children: [
|
|
400
|
+
t9$1,
|
|
401
|
+
t10$1,
|
|
402
|
+
t11$1
|
|
403
|
+
]
|
|
404
|
+
})
|
|
405
|
+
});
|
|
406
|
+
$[18] = t10$1;
|
|
407
|
+
$[19] = t11$1;
|
|
408
|
+
$[20] = t6;
|
|
409
|
+
} else t6 = $[20];
|
|
410
|
+
T0 = CollapsibleContent;
|
|
411
|
+
t3 = "border-t border-border px-2 py-1.5";
|
|
412
|
+
if ($[21] === Symbol.for("react.memo_cache_sentinel")) {
|
|
413
|
+
t4 = /* @__PURE__ */ jsx("div", {
|
|
414
|
+
className: "mb-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground/70",
|
|
415
|
+
children: "Submitted data"
|
|
416
|
+
});
|
|
417
|
+
$[21] = t4;
|
|
418
|
+
} else t4 = $[21];
|
|
419
|
+
t1 = "rounded bg-muted/50 p-1.5 space-y-0.5";
|
|
420
|
+
t2 = entries.map(_temp);
|
|
421
|
+
$[0] = data;
|
|
422
|
+
$[1] = isOpen;
|
|
423
|
+
$[2] = title;
|
|
424
|
+
$[3] = T0;
|
|
425
|
+
$[4] = T1;
|
|
426
|
+
$[5] = t1;
|
|
427
|
+
$[6] = t2;
|
|
428
|
+
$[7] = t3;
|
|
429
|
+
$[8] = t4;
|
|
430
|
+
$[9] = t5;
|
|
431
|
+
$[10] = t6;
|
|
432
|
+
$[11] = t7;
|
|
433
|
+
$[12] = t8;
|
|
434
|
+
} else {
|
|
435
|
+
T0 = $[3];
|
|
436
|
+
T1 = $[4];
|
|
437
|
+
t1 = $[5];
|
|
438
|
+
t2 = $[6];
|
|
439
|
+
t3 = $[7];
|
|
440
|
+
t4 = $[8];
|
|
441
|
+
t5 = $[9];
|
|
442
|
+
t6 = $[10];
|
|
443
|
+
t7 = $[11];
|
|
444
|
+
t8 = $[12];
|
|
445
|
+
}
|
|
446
|
+
let t9;
|
|
447
|
+
if ($[22] !== t1 || $[23] !== t2) {
|
|
448
|
+
t9 = /* @__PURE__ */ jsx("div", {
|
|
449
|
+
className: t1,
|
|
450
|
+
children: t2
|
|
451
|
+
});
|
|
452
|
+
$[22] = t1;
|
|
453
|
+
$[23] = t2;
|
|
454
|
+
$[24] = t9;
|
|
455
|
+
} else t9 = $[24];
|
|
456
|
+
let t10;
|
|
457
|
+
if ($[25] !== t3 || $[26] !== t4 || $[27] !== t9) {
|
|
458
|
+
t10 = /* @__PURE__ */ jsxs("div", {
|
|
459
|
+
className: t3,
|
|
460
|
+
children: [t4, t9]
|
|
461
|
+
});
|
|
462
|
+
$[25] = t3;
|
|
463
|
+
$[26] = t4;
|
|
464
|
+
$[27] = t9;
|
|
465
|
+
$[28] = t10;
|
|
466
|
+
} else t10 = $[28];
|
|
467
|
+
let t11;
|
|
468
|
+
if ($[29] !== T0 || $[30] !== t10) {
|
|
469
|
+
t11 = /* @__PURE__ */ jsx(T0, { children: t10 });
|
|
470
|
+
$[29] = T0;
|
|
471
|
+
$[30] = t10;
|
|
472
|
+
$[31] = t11;
|
|
473
|
+
} else t11 = $[31];
|
|
474
|
+
let t12;
|
|
475
|
+
if ($[32] !== t11 || $[33] !== t5 || $[34] !== t6) {
|
|
476
|
+
t12 = /* @__PURE__ */ jsxs("div", {
|
|
477
|
+
className: t5,
|
|
478
|
+
children: [t6, t11]
|
|
479
|
+
});
|
|
480
|
+
$[32] = t11;
|
|
481
|
+
$[33] = t5;
|
|
482
|
+
$[34] = t6;
|
|
483
|
+
$[35] = t12;
|
|
484
|
+
} else t12 = $[35];
|
|
485
|
+
let t13;
|
|
486
|
+
if ($[36] !== T1 || $[37] !== t12 || $[38] !== t7 || $[39] !== t8) {
|
|
487
|
+
t13 = /* @__PURE__ */ jsx(T1, {
|
|
488
|
+
open: t7,
|
|
489
|
+
onOpenChange: t8,
|
|
490
|
+
children: t12
|
|
491
|
+
});
|
|
492
|
+
$[36] = T1;
|
|
493
|
+
$[37] = t12;
|
|
494
|
+
$[38] = t7;
|
|
495
|
+
$[39] = t8;
|
|
496
|
+
$[40] = t13;
|
|
497
|
+
} else t13 = $[40];
|
|
498
|
+
return t13;
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* FormToolUI - Renders a dynamic form from JSON Schema
|
|
502
|
+
*
|
|
503
|
+
* HITL Pattern (AI SDK v6):
|
|
504
|
+
* - Model calls `form` tool with JSON Schema
|
|
505
|
+
* - This UI renders the form using @rjsf/shadcn
|
|
506
|
+
* - User fills out and submits form
|
|
507
|
+
* - addToolOutput() sends data to backend via WebSocket + updates local UI state
|
|
508
|
+
*
|
|
509
|
+
* Schema Handling:
|
|
510
|
+
* - Normalizes uppercase types (Gemini format) to lowercase (JSON Schema)
|
|
511
|
+
* - Validates schema with AJV and sends errors back to model if invalid
|
|
512
|
+
*/
|
|
513
|
+
function _temp(t0) {
|
|
514
|
+
const [key, value] = t0;
|
|
515
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
516
|
+
className: "flex gap-2 text-[11px]",
|
|
517
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
518
|
+
className: "font-medium text-muted-foreground",
|
|
519
|
+
children: [key, ":"]
|
|
520
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
521
|
+
className: "text-foreground/70",
|
|
522
|
+
children: formatValue(value)
|
|
523
|
+
})]
|
|
524
|
+
}, key);
|
|
525
|
+
}
|
|
526
|
+
const FormToolUI = makeAssistantToolUI({
|
|
527
|
+
toolName: "form",
|
|
528
|
+
render: ({ args, result, status, addResult, toolCallId }) => {
|
|
529
|
+
const toolExecution = useOptionalToolExecution();
|
|
530
|
+
const errorSentRef = useRef(false);
|
|
531
|
+
const [schemaError, setSchemaError] = useState(null);
|
|
532
|
+
const isWaiting = status.type === "requires-action";
|
|
533
|
+
const normalizedSchema = args.schema && typeof args.schema === "object" ? normalizeSchema(args.schema) : null;
|
|
534
|
+
useEffect(() => {
|
|
535
|
+
if (!normalizedSchema || !isWaiting || errorSentRef.current || result) return;
|
|
536
|
+
const validationError = validateSchema(normalizedSchema);
|
|
537
|
+
if (validationError) {
|
|
538
|
+
errorSentRef.current = true;
|
|
539
|
+
setSchemaError(validationError);
|
|
540
|
+
if (toolExecution) toolExecution.addToolOutput({
|
|
541
|
+
toolCallId,
|
|
542
|
+
output: `Error: ${validationError}`
|
|
543
|
+
});
|
|
544
|
+
else console.error("[FormToolUI] Cannot send schema error: ToolExecution context not available");
|
|
545
|
+
}
|
|
546
|
+
}, [
|
|
547
|
+
normalizedSchema,
|
|
548
|
+
isWaiting,
|
|
549
|
+
result,
|
|
550
|
+
toolExecution,
|
|
551
|
+
toolCallId
|
|
552
|
+
]);
|
|
553
|
+
if (schemaError) return /* @__PURE__ */ jsx(SchemaErrorDisplay, {
|
|
554
|
+
title: args.title ?? "Form",
|
|
555
|
+
error: schemaError
|
|
556
|
+
});
|
|
557
|
+
if (result) return /* @__PURE__ */ jsx(FormResultDisplay, {
|
|
558
|
+
title: args.title ?? "Form",
|
|
559
|
+
data: result
|
|
560
|
+
});
|
|
561
|
+
const handleSubmit = ({ formData }) => {
|
|
562
|
+
if (!formData) return;
|
|
563
|
+
if (!toolExecution) {
|
|
564
|
+
console.error("[FormToolUI] Cannot submit form: ToolExecution context not available", { toolCallId });
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
const outputValue = typeof formData === "object" ? JSON.stringify(formData) : String(formData);
|
|
568
|
+
toolExecution.addToolOutput({
|
|
569
|
+
toolCallId,
|
|
570
|
+
output: outputValue
|
|
571
|
+
});
|
|
572
|
+
};
|
|
573
|
+
if (!normalizedSchema) return /* @__PURE__ */ jsxs("div", {
|
|
574
|
+
className: "my-1 flex items-center gap-1.5 rounded-lg bg-muted/50 px-2 py-1.5 text-sm text-foreground/70",
|
|
575
|
+
children: [/* @__PURE__ */ jsx(FileText, { className: "h-3.5 w-3.5 animate-pulse text-muted-foreground" }), /* @__PURE__ */ jsx("span", {
|
|
576
|
+
className: "text-xs",
|
|
577
|
+
children: "Loading form..."
|
|
578
|
+
})]
|
|
579
|
+
});
|
|
580
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
581
|
+
className: "my-1 overflow-hidden rounded-lg bg-muted/50",
|
|
582
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
583
|
+
className: "flex items-center gap-1.5 px-2 py-1.5 border-b border-border",
|
|
584
|
+
children: [/* @__PURE__ */ jsx(FileText, { className: "h-3.5 w-3.5 text-foreground/70" }), /* @__PURE__ */ jsx("span", {
|
|
585
|
+
className: "text-xs font-medium text-foreground",
|
|
586
|
+
children: args.title ?? "Form"
|
|
587
|
+
})]
|
|
588
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
589
|
+
className: "px-2 py-2",
|
|
590
|
+
children: [args.description && /* @__PURE__ */ jsx("p", {
|
|
591
|
+
className: "text-xs text-muted-foreground mb-3",
|
|
592
|
+
children: args.description
|
|
593
|
+
}), /* @__PURE__ */ jsx(Form, {
|
|
594
|
+
schema: normalizedSchema,
|
|
595
|
+
validator,
|
|
596
|
+
onSubmit: handleSubmit,
|
|
597
|
+
disabled: !isWaiting,
|
|
598
|
+
className: "space-y-3",
|
|
599
|
+
uiSchema: { "ui:submitButtonOptions": { norender: true } },
|
|
600
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
601
|
+
className: "flex justify-end pt-1",
|
|
602
|
+
children: /* @__PURE__ */ jsxs(Button, {
|
|
603
|
+
type: "submit",
|
|
604
|
+
disabled: !isWaiting,
|
|
605
|
+
size: "sm",
|
|
606
|
+
className: "h-7 px-3 text-xs",
|
|
607
|
+
children: [/* @__PURE__ */ jsx(Check, { className: "h-3 w-3 mr-1" }), args.submitLabel || "Submit"]
|
|
608
|
+
})
|
|
609
|
+
})
|
|
610
|
+
})]
|
|
611
|
+
})]
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
var FormToolUI_default = FormToolUI;
|
|
616
|
+
|
|
617
|
+
//#endregion
|
|
618
|
+
export { Collapsible as a, Button as c, useOptionalToolExecution as i, cn as l, FormToolUI_default as n, CollapsibleContent as o, ToolExecutionProvider as r, CollapsibleTrigger as s, FormToolUI as t };
|
|
619
|
+
//# sourceMappingURL=FormToolUI-04m9zI5r.js.map
|