@tinkrapp/widget 1.2.0 → 1.3.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/dist/react.cjs CHANGED
@@ -11,17 +11,18 @@ var react = require('motion/react');
11
11
  var lucideReact = require('lucide-react');
12
12
  var clsx = require('clsx');
13
13
  var tailwindMerge = require('tailwind-merge');
14
- var ReactMarkdown = require('react-markdown');
15
- var remarkGfm = require('remark-gfm');
14
+ var ReactMarkdown2 = require('react-markdown');
15
+ var remarkGfm3 = require('remark-gfm');
16
16
  var reactSlot = require('@radix-ui/react-slot');
17
17
  var TooltipPrimitive = require('@radix-ui/react-tooltip');
18
18
  var classVarianceAuthority = require('class-variance-authority');
19
+ var mermaid = require('mermaid');
19
20
  var shallow = require('zustand/shallow');
20
21
  var DialogPrimitive = require('@radix-ui/react-dialog');
21
22
  var AvatarPrimitive = require('@radix-ui/react-avatar');
23
+ var PopoverPrimitive = require('@radix-ui/react-popover');
22
24
  require('@assistant-ui/react-markdown/styles/dot.css');
23
25
  var reactMarkdown = require('@assistant-ui/react-markdown');
24
- var PopoverPrimitive = require('@radix-ui/react-popover');
25
26
 
26
27
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
27
28
 
@@ -45,9 +46,10 @@ function _interopNamespace(e) {
45
46
 
46
47
  var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
47
48
  var styled__default = /*#__PURE__*/_interopDefault(styled);
48
- var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
49
- var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
49
+ var ReactMarkdown2__default = /*#__PURE__*/_interopDefault(ReactMarkdown2);
50
+ var remarkGfm3__default = /*#__PURE__*/_interopDefault(remarkGfm3);
50
51
  var TooltipPrimitive__namespace = /*#__PURE__*/_interopNamespace(TooltipPrimitive);
52
+ var mermaid__default = /*#__PURE__*/_interopDefault(mermaid);
51
53
  var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
52
54
  var AvatarPrimitive__namespace = /*#__PURE__*/_interopNamespace(AvatarPrimitive);
53
55
  var PopoverPrimitive__namespace = /*#__PURE__*/_interopNamespace(PopoverPrimitive);
@@ -2267,6 +2269,383 @@ var ArtifactToolUIs = () => {
2267
2269
  /* @__PURE__ */ jsxRuntime.jsx(InfographicToolUI, {})
2268
2270
  ] });
2269
2271
  };
2272
+ var ToolCard = ({
2273
+ title,
2274
+ subtitle,
2275
+ isStreaming,
2276
+ isError = false,
2277
+ icon,
2278
+ persistentContent,
2279
+ children,
2280
+ footer
2281
+ }) => {
2282
+ const [manualExpanded, setManualExpanded] = React2.useState(null);
2283
+ const prevStreamingRef = React2.useRef(isStreaming);
2284
+ const contentRef = React2.useRef(null);
2285
+ const isExpanded = manualExpanded ?? isStreaming;
2286
+ React2.useEffect(() => {
2287
+ if (isStreaming && !prevStreamingRef.current) {
2288
+ setManualExpanded(null);
2289
+ }
2290
+ prevStreamingRef.current = isStreaming;
2291
+ }, [isStreaming]);
2292
+ React2.useEffect(() => {
2293
+ if (isStreaming && contentRef.current) {
2294
+ contentRef.current.scrollTop = contentRef.current.scrollHeight;
2295
+ }
2296
+ });
2297
+ const renderIcon = () => {
2298
+ if (icon) return icon;
2299
+ const iconClass = cn("h-4 w-4", isStreaming && "animate-spin");
2300
+ if (isStreaming) {
2301
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2Icon, { className: iconClass });
2302
+ }
2303
+ if (isError) {
2304
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircleIcon, { className: "h-4 w-4 text-red-400" });
2305
+ }
2306
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckIcon, { className: "h-4 w-4" });
2307
+ };
2308
+ const handleToggle = () => {
2309
+ if (!isStreaming) {
2310
+ setManualExpanded((prev2) => prev2 === null ? true : !prev2);
2311
+ }
2312
+ };
2313
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "my-2 overflow-hidden rounded-xl border border-border shadow-sm", children: [
2314
+ /* @__PURE__ */ jsxRuntime.jsxs(
2315
+ "div",
2316
+ {
2317
+ className: cn(
2318
+ "flex items-center gap-2 p-2 cursor-pointer transition-colors text-white bg-primary-foreground",
2319
+ !isStreaming && "hover:opacity-90"
2320
+ ),
2321
+ onClick: handleToggle,
2322
+ children: [
2323
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: renderIcon() }),
2324
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
2325
+ subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium opacity-80 leading-tight text-xs text-muted-foreground", children: subtitle }),
2326
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "truncate font-semibold leading-tight text-sm text-muted-foreground", children: title })
2327
+ ] }),
2328
+ /* @__PURE__ */ jsxRuntime.jsx(
2329
+ "button",
2330
+ {
2331
+ className: "p-1 rounded hover:bg-white/20 transition-colors",
2332
+ "aria-label": isExpanded ? "Collapse" : "Expand",
2333
+ onClick: (e) => {
2334
+ e.stopPropagation();
2335
+ handleToggle();
2336
+ },
2337
+ children: isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUpIcon, { className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: "h-4 w-4" })
2338
+ }
2339
+ )
2340
+ ]
2341
+ }
2342
+ ),
2343
+ persistentContent,
2344
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsx(
2345
+ "div",
2346
+ {
2347
+ ref: contentRef,
2348
+ className: "p-2 max-h-[400px] overflow-y-auto bg-secondary",
2349
+ children
2350
+ }
2351
+ ),
2352
+ isExpanded && footer && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end gap-2 border-t border-white/10 p-2 bg-primary-foreground/80", children: footer })
2353
+ ] });
2354
+ };
2355
+ var voiceLabels = {
2356
+ alloy: "Alloy",
2357
+ echo: "Echo",
2358
+ fable: "Fable",
2359
+ onyx: "Onyx",
2360
+ nova: "Nova",
2361
+ shimmer: "Shimmer"
2362
+ };
2363
+ var AudiobookToolUI = react$1.makeAssistantToolUI({
2364
+ toolName: "createAudiobook",
2365
+ render: function AudiobookUI({ args, result, status }) {
2366
+ const isStreaming = status.type === "running";
2367
+ const isError = status.type === "incomplete";
2368
+ const topic = result?.topic || args.topic || "Generating...";
2369
+ const voice = result?.voice || args.voice || "alloy";
2370
+ const message = result?.message || "Audiobook generation is coming soon! This feature will convert lessons into engaging audio format.";
2371
+ const resultStatus = result?.status || "pending";
2372
+ const persistentContent = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2 text-white/80 border-b border-white/10 bg-primary-foreground text-xs", children: [
2373
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Topic:" }),
2374
+ " ",
2375
+ topic,
2376
+ /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2377
+ " ",
2378
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground ml-2", children: "Voice:" }),
2379
+ " ",
2380
+ voiceLabels[voice] || voice
2381
+ ] })
2382
+ ] });
2383
+ return /* @__PURE__ */ jsxRuntime.jsx(
2384
+ ToolCard,
2385
+ {
2386
+ title: "Audiobook",
2387
+ subtitle: "Audio Learning",
2388
+ isStreaming,
2389
+ isError,
2390
+ icon: !isStreaming && !isError ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HeadphonesIcon, { className: "h-4 w-4" }) : void 0,
2391
+ persistentContent,
2392
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
2393
+ resultStatus === "pending" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 p-3 rounded-lg bg-amber-500/10 border border-amber-500/20", children: [
2394
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ClockIcon, { className: "h-5 w-5 text-amber-400 mt-0.5 shrink-0" }),
2395
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2396
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-amber-300", children: "Coming Soon" }),
2397
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-amber-200/70 mt-1", children: message })
2398
+ ] })
2399
+ ] }),
2400
+ resultStatus === "processing" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 text-sm text-white/70", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-pulse", children: "Processing audiobook..." }) }),
2401
+ resultStatus === "complete" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-green-400", children: "Audiobook generated successfully!" })
2402
+ ] })
2403
+ }
2404
+ );
2405
+ }
2406
+ });
2407
+ var OPTION_LETTERS = ["A", "B", "C", "D", "E", "F", "G", "H"];
2408
+ var QuestionItem = ({ question, questionNumber, value, onChange, disabled }) => {
2409
+ const options = Array.isArray(question.options) ? question.options : [];
2410
+ if (options.length === 0) {
2411
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
2412
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm font-medium text-foreground", children: [
2413
+ questionNumber,
2414
+ ". ",
2415
+ question.question
2416
+ ] }),
2417
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground italic", children: "No options available" })
2418
+ ] });
2419
+ }
2420
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
2421
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm font-medium text-foreground", children: [
2422
+ questionNumber,
2423
+ ". ",
2424
+ question.question
2425
+ ] }),
2426
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: options.map((option, index) => {
2427
+ const letter = OPTION_LETTERS[index] || String(index + 1);
2428
+ const isSelected = value === option;
2429
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2430
+ "button",
2431
+ {
2432
+ type: "button",
2433
+ onClick: () => !disabled && onChange(option),
2434
+ disabled,
2435
+ className: cn(
2436
+ "w-full flex items-center gap-2 px-3 py-2 rounded-lg text-left transition-colors",
2437
+ "text-sm",
2438
+ isSelected ? "bg-primary/20 text-foreground" : "bg-muted/50 text-muted-foreground hover:bg-muted",
2439
+ disabled && "opacity-50 cursor-not-allowed"
2440
+ ),
2441
+ children: [
2442
+ /* @__PURE__ */ jsxRuntime.jsx(
2443
+ "span",
2444
+ {
2445
+ className: cn(
2446
+ "flex items-center justify-center w-5 h-5 rounded text-xs font-medium",
2447
+ isSelected ? "bg-primary text-primary-foreground" : "bg-muted-foreground/20 text-muted-foreground"
2448
+ ),
2449
+ children: letter
2450
+ }
2451
+ ),
2452
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: option })
2453
+ ]
2454
+ },
2455
+ index
2456
+ );
2457
+ }) })
2458
+ ] });
2459
+ };
2460
+ var ClarifyingQuestionsInner = ({ args, result, status }) => {
2461
+ const [answers, setAnswers] = React2.useState({});
2462
+ const [additionalDetails, setAdditionalDetails] = React2.useState("");
2463
+ const [isSubmitting, setIsSubmitting] = React2.useState(false);
2464
+ const [isExpanded, setIsExpanded] = React2.useState(true);
2465
+ const [hasSubmitted, setHasSubmitted] = React2.useState(false);
2466
+ const composerRuntime = react$1.useComposerRuntime();
2467
+ const isStreaming = status.type === "running";
2468
+ const isError = status.type === "incomplete";
2469
+ const questions = result?.questions || args?.questions || [];
2470
+ const context = result?.context || args?.context || "";
2471
+ const totalQuestions = questions.length;
2472
+ const answeredCount = questions.filter(
2473
+ (q) => answers[q.id] && answers[q.id].trim() !== ""
2474
+ ).length;
2475
+ const allQuestionsAnswered = answeredCount === totalQuestions && totalQuestions > 0;
2476
+ const handleAnswerChange = (questionId, value) => {
2477
+ setAnswers((prev2) => ({
2478
+ ...prev2,
2479
+ [questionId]: value
2480
+ }));
2481
+ };
2482
+ const handleSubmit = React2.useCallback(
2483
+ async (skipped = false) => {
2484
+ setIsSubmitting(true);
2485
+ setHasSubmitted(true);
2486
+ try {
2487
+ let responseMessage = "";
2488
+ if (skipped) {
2489
+ responseMessage = "I'd like to skip these questions and proceed with the general answer.";
2490
+ } else {
2491
+ const answeredQuestions = questions.filter((q) => answers[q.id] && answers[q.id].trim() !== "").map((q) => `**${q.question}**: ${answers[q.id]}`).join("\n");
2492
+ responseMessage = `Here are my answers to your questions:
2493
+
2494
+ ${answeredQuestions}`;
2495
+ if (additionalDetails.trim()) {
2496
+ responseMessage += `
2497
+
2498
+ Additional details: ${additionalDetails}`;
2499
+ }
2500
+ }
2501
+ composerRuntime.setText(responseMessage);
2502
+ composerRuntime.send();
2503
+ } catch (error) {
2504
+ console.error("[ClarifyingQuestions] Submit error:", error);
2505
+ setIsSubmitting(false);
2506
+ setHasSubmitted(false);
2507
+ }
2508
+ },
2509
+ [questions, answers, additionalDetails, composerRuntime]
2510
+ );
2511
+ const handleSkip = () => {
2512
+ handleSubmit(true);
2513
+ };
2514
+ const handleContinue = () => {
2515
+ handleSubmit(false);
2516
+ };
2517
+ if (hasSubmitted) {
2518
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "my-2 overflow-hidden rounded-xl border border-border bg-card shadow-sm", children: [
2519
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 p-3 bg-muted/30", children: [
2520
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HelpCircleIcon, { className: "h-4 w-4 text-muted-foreground" }),
2521
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-foreground", children: "Questions Answered" })
2522
+ ] }),
2523
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3 space-y-2", children: questions.map((q, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm", children: [
2524
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-muted-foreground", children: [
2525
+ index + 1,
2526
+ ". ",
2527
+ q.question
2528
+ ] }),
2529
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-foreground font-medium mt-0.5", children: answers[q.id] || "Skipped" })
2530
+ ] }, q.id)) })
2531
+ ] });
2532
+ }
2533
+ if (isStreaming && questions.length === 0) {
2534
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "my-2 overflow-hidden rounded-xl border border-border bg-card shadow-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 p-3", children: [
2535
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2Icon, { className: "h-4 w-4 animate-spin text-muted-foreground" }),
2536
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Loading questions..." })
2537
+ ] }) });
2538
+ }
2539
+ if (isError) {
2540
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "my-2 overflow-hidden rounded-xl border border-destructive/50 bg-destructive/10 shadow-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 p-3", children: [
2541
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HelpCircleIcon, { className: "h-4 w-4 text-destructive" }),
2542
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-destructive", children: "Failed to load questions" })
2543
+ ] }) });
2544
+ }
2545
+ if (questions.length === 0) {
2546
+ return null;
2547
+ }
2548
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "my-2 overflow-hidden rounded-xl border border-border bg-card shadow-sm", children: [
2549
+ /* @__PURE__ */ jsxRuntime.jsxs(
2550
+ "button",
2551
+ {
2552
+ onClick: () => setIsExpanded(!isExpanded),
2553
+ className: "w-full flex items-center justify-between p-3 hover:bg-muted/30 transition-colors",
2554
+ children: [
2555
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2556
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HelpCircleIcon, { className: "h-4 w-4 text-muted-foreground" }),
2557
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-foreground", children: "Questions" })
2558
+ ] }),
2559
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2560
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
2561
+ answeredCount,
2562
+ " of ",
2563
+ totalQuestions
2564
+ ] }),
2565
+ isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUpIcon, { className: "h-4 w-4 text-muted-foreground" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: "h-4 w-4 text-muted-foreground" })
2566
+ ] })
2567
+ ]
2568
+ }
2569
+ ),
2570
+ isExpanded && context && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 pb-2 text-xs text-muted-foreground italic border-b border-border", children: context }),
2571
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2572
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-3 space-y-4", children: questions.map((question, index) => /* @__PURE__ */ jsxRuntime.jsx(
2573
+ QuestionItem,
2574
+ {
2575
+ question,
2576
+ questionNumber: index + 1,
2577
+ value: answers[question.id] || "",
2578
+ onChange: (value) => handleAnswerChange(question.id, value),
2579
+ disabled: isSubmitting
2580
+ },
2581
+ question.id
2582
+ )) }),
2583
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 pb-3", children: /* @__PURE__ */ jsxRuntime.jsx(
2584
+ "input",
2585
+ {
2586
+ type: "text",
2587
+ value: additionalDetails,
2588
+ onChange: (e) => setAdditionalDetails(e.target.value),
2589
+ disabled: isSubmitting,
2590
+ placeholder: "Add more optional details",
2591
+ className: cn(
2592
+ "w-full px-3 py-2 rounded-lg text-sm",
2593
+ "bg-muted/30 border border-border",
2594
+ "text-foreground placeholder:text-muted-foreground",
2595
+ "focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary",
2596
+ isSubmitting && "opacity-50 cursor-not-allowed"
2597
+ )
2598
+ }
2599
+ ) }),
2600
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-3 pb-3", children: [
2601
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: !allQuestionsAnswered && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: "Answer all questions to continue" }) }),
2602
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2603
+ /* @__PURE__ */ jsxRuntime.jsx(
2604
+ "button",
2605
+ {
2606
+ type: "button",
2607
+ onClick: handleSkip,
2608
+ disabled: isSubmitting,
2609
+ className: cn(
2610
+ "px-4 py-1.5 rounded-lg text-sm font-medium transition-colors",
2611
+ "text-muted-foreground hover:text-foreground hover:bg-muted",
2612
+ isSubmitting && "opacity-50 cursor-not-allowed"
2613
+ ),
2614
+ children: "Skip"
2615
+ }
2616
+ ),
2617
+ /* @__PURE__ */ jsxRuntime.jsx(
2618
+ "button",
2619
+ {
2620
+ type: "button",
2621
+ onClick: handleContinue,
2622
+ disabled: isSubmitting || !allQuestionsAnswered,
2623
+ className: cn(
2624
+ "flex items-center gap-1.5 px-4 py-1.5 rounded-lg text-sm font-medium transition-colors",
2625
+ "bg-primary text-primary-foreground",
2626
+ allQuestionsAnswered && !isSubmitting && "hover:bg-primary/90",
2627
+ (!allQuestionsAnswered || isSubmitting) && "opacity-50 cursor-not-allowed"
2628
+ ),
2629
+ children: isSubmitting ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2630
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2Icon, { className: "h-3.5 w-3.5 animate-spin" }),
2631
+ "Submitting..."
2632
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2633
+ "Continue",
2634
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "opacity-70", children: "\u21B5" })
2635
+ ] })
2636
+ }
2637
+ )
2638
+ ] })
2639
+ ] })
2640
+ ] })
2641
+ ] });
2642
+ };
2643
+ var ClarifyingQuestionsToolUI = react$1.makeAssistantToolUI({
2644
+ toolName: "askClarifyingQuestions",
2645
+ render: function ClarifyingQuestionsUI({ args, result, status }) {
2646
+ return /* @__PURE__ */ jsxRuntime.jsx(ClarifyingQuestionsInner, { args, result, status });
2647
+ }
2648
+ });
2270
2649
  function TooltipProvider({
2271
2650
  delayDuration = 0,
2272
2651
  ...props
@@ -2365,118 +2744,35 @@ var TooltipIconButton = React2.forwardRef(({ children, tooltip, side = "bottom",
2365
2744
  ] });
2366
2745
  });
2367
2746
  TooltipIconButton.displayName = "TooltipIconButton";
2368
- var ToolCard = ({
2369
- title,
2370
- subtitle,
2371
- isStreaming,
2372
- isError = false,
2373
- icon,
2374
- persistentContent,
2375
- children,
2376
- footer
2377
- }) => {
2378
- const [manualExpanded, setManualExpanded] = React2.useState(null);
2379
- const prevStreamingRef = React2.useRef(isStreaming);
2380
- const contentRef = React2.useRef(null);
2381
- const isExpanded = manualExpanded ?? isStreaming;
2382
- React2.useEffect(() => {
2383
- if (isStreaming && !prevStreamingRef.current) {
2384
- setManualExpanded(null);
2385
- }
2386
- prevStreamingRef.current = isStreaming;
2387
- }, [isStreaming]);
2388
- React2.useEffect(() => {
2389
- if (isStreaming && contentRef.current) {
2390
- contentRef.current.scrollTop = contentRef.current.scrollHeight;
2391
- }
2392
- });
2393
- const renderIcon = () => {
2394
- if (icon) return icon;
2395
- const iconClass = cn("h-4 w-4", isStreaming && "animate-spin");
2396
- if (isStreaming) {
2397
- return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2Icon, { className: iconClass });
2398
- }
2399
- if (isError) {
2400
- return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircleIcon, { className: "h-4 w-4 text-red-400" });
2401
- }
2402
- return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckIcon, { className: "h-4 w-4" });
2403
- };
2404
- const handleToggle = () => {
2405
- if (!isStreaming) {
2406
- setManualExpanded((prev2) => prev2 === null ? true : !prev2);
2407
- }
2747
+ var useCopyToClipboard = ({
2748
+ copiedDuration = 3e3
2749
+ } = {}) => {
2750
+ const [isCopied, setIsCopied] = React2.useState(false);
2751
+ const copyToClipboard = (value) => {
2752
+ if (!value) return;
2753
+ navigator.clipboard.writeText(value).then(() => {
2754
+ setIsCopied(true);
2755
+ setTimeout(() => setIsCopied(false), copiedDuration);
2756
+ });
2408
2757
  };
2409
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "my-2 overflow-hidden rounded-xl border border-border shadow-sm", children: [
2410
- /* @__PURE__ */ jsxRuntime.jsxs(
2411
- "div",
2412
- {
2413
- className: cn(
2414
- "flex items-center gap-2 p-2 cursor-pointer transition-colors text-white bg-primary-foreground",
2415
- !isStreaming && "hover:opacity-90"
2416
- ),
2417
- onClick: handleToggle,
2418
- children: [
2419
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center", children: renderIcon() }),
2420
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
2421
- subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium opacity-80 leading-tight text-xs text-muted-foreground", children: subtitle }),
2422
- /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "truncate font-semibold leading-tight text-sm text-muted-foreground", children: title })
2423
- ] }),
2424
- /* @__PURE__ */ jsxRuntime.jsx(
2425
- "button",
2426
- {
2427
- className: "p-1 rounded hover:bg-white/20 transition-colors",
2428
- "aria-label": isExpanded ? "Collapse" : "Expand",
2429
- onClick: (e) => {
2430
- e.stopPropagation();
2431
- handleToggle();
2432
- },
2433
- children: isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUpIcon, { className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: "h-4 w-4" })
2434
- }
2435
- )
2436
- ]
2437
- }
2438
- ),
2439
- persistentContent,
2440
- isExpanded && /* @__PURE__ */ jsxRuntime.jsx(
2441
- "div",
2442
- {
2443
- ref: contentRef,
2444
- className: "p-2 max-h-[400px] overflow-y-auto bg-secondary",
2445
- children
2446
- }
2447
- ),
2448
- isExpanded && footer && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end gap-2 border-t border-white/10 p-2 bg-primary-foreground/80", children: footer })
2449
- ] });
2450
- };
2451
- var useCopyToClipboard = ({
2452
- copiedDuration = 3e3
2453
- } = {}) => {
2454
- const [isCopied, setIsCopied] = React2.useState(false);
2455
- const copyToClipboard = (value) => {
2456
- if (!value) return;
2457
- navigator.clipboard.writeText(value).then(() => {
2458
- setIsCopied(true);
2459
- setTimeout(() => setIsCopied(false), copiedDuration);
2460
- });
2461
- };
2462
- return { isCopied, copyToClipboard };
2463
- };
2464
- var MarkdownContent = React2.memo(({ content }) => {
2465
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aui-md max-w-none text-white", children: /* @__PURE__ */ jsxRuntime.jsx(
2466
- ReactMarkdown__default.default,
2467
- {
2468
- remarkPlugins: [remarkGfm__default.default],
2469
- components: {
2470
- h1: ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
2471
- "h1",
2472
- {
2473
- className: cn(
2474
- "mb-2 font-extrabold tracking-tight last:mb-0 text-white",
2475
- className
2476
- ),
2477
- style: { fontSize: "12px" },
2478
- ...props
2479
- }
2758
+ return { isCopied, copyToClipboard };
2759
+ };
2760
+ var MarkdownContent = React2.memo(({ content }) => {
2761
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aui-md max-w-none text-white", children: /* @__PURE__ */ jsxRuntime.jsx(
2762
+ ReactMarkdown2__default.default,
2763
+ {
2764
+ remarkPlugins: [remarkGfm3__default.default],
2765
+ components: {
2766
+ h1: ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
2767
+ "h1",
2768
+ {
2769
+ className: cn(
2770
+ "mb-2 font-extrabold tracking-tight last:mb-0 text-white",
2771
+ className
2772
+ ),
2773
+ style: { fontSize: "12px" },
2774
+ ...props
2775
+ }
2480
2776
  ),
2481
2777
  h2: ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
2482
2778
  "h2",
@@ -2678,183 +2974,625 @@ var DetailedAnswerToolUI = react$1.makeAssistantToolUI({
2678
2974
  );
2679
2975
  }
2680
2976
  });
2681
- function Dialog({
2682
- ...props
2683
- }) {
2684
- return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Root, { "data-slot": "dialog", ...props });
2685
- }
2686
- function DialogTrigger({
2687
- ...props
2688
- }) {
2689
- return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Trigger, { "data-slot": "dialog-trigger", ...props });
2690
- }
2691
- function DialogPortal({
2692
- ...props
2693
- }) {
2694
- return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Portal, { "data-slot": "dialog-portal", ...props });
2695
- }
2696
- function DialogOverlay({
2697
- className,
2698
- ...props
2699
- }) {
2700
- return /* @__PURE__ */ jsxRuntime.jsx(
2701
- DialogPrimitive__namespace.Overlay,
2702
- {
2703
- "data-slot": "dialog-overlay",
2704
- className: cn(
2705
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
2706
- className
2707
- ),
2708
- ...props
2977
+ mermaid__default.default.initialize({
2978
+ startOnLoad: false,
2979
+ theme: "dark",
2980
+ securityLevel: "loose",
2981
+ fontFamily: "inherit"
2982
+ });
2983
+ var useCopyToClipboard2 = ({
2984
+ copiedDuration = 3e3
2985
+ } = {}) => {
2986
+ const [isCopied, setIsCopied] = React2.useState(false);
2987
+ const copyToClipboard = (value) => {
2988
+ if (!value) return;
2989
+ navigator.clipboard.writeText(value).then(() => {
2990
+ setIsCopied(true);
2991
+ setTimeout(() => setIsCopied(false), copiedDuration);
2992
+ });
2993
+ };
2994
+ return { isCopied, copyToClipboard };
2995
+ };
2996
+ var MermaidRenderer = React2.memo(
2997
+ ({ content, className }) => {
2998
+ const containerRef = React2.useRef(null);
2999
+ const uniqueId = React2.useId();
3000
+ const [svg, setSvg] = React2.useState("");
3001
+ const [error, setError] = React2.useState(null);
3002
+ React2.useEffect(() => {
3003
+ const renderDiagram = async () => {
3004
+ if (!content || !containerRef.current) return;
3005
+ try {
3006
+ setError(null);
3007
+ const id = `mermaid-${uniqueId.replace(/:/g, "-")}`;
3008
+ const { svg: renderedSvg } = await mermaid__default.default.render(id, content);
3009
+ setSvg(renderedSvg);
3010
+ } catch (err) {
3011
+ console.error("[Mermaid] Render error:", err);
3012
+ setError(
3013
+ err instanceof Error ? err.message : "Failed to render diagram"
3014
+ );
3015
+ }
3016
+ };
3017
+ renderDiagram();
3018
+ }, [content, uniqueId]);
3019
+ if (error) {
3020
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3 rounded-lg bg-red-500/10 border border-red-500/20 text-red-300 text-sm", children: [
3021
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium mb-1", children: "Failed to render diagram" }),
3022
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs opacity-80", children: error }),
3023
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "mt-2 p-2 bg-black/20 rounded text-xs overflow-x-auto", children: content })
3024
+ ] });
2709
3025
  }
2710
- );
2711
- }
2712
- function DialogContent({
2713
- className,
2714
- children,
2715
- showCloseButton = true,
2716
- ...props
2717
- }) {
2718
- return /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [
2719
- /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
2720
- /* @__PURE__ */ jsxRuntime.jsxs(
2721
- DialogPrimitive__namespace.Content,
3026
+ if (!svg) {
3027
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center p-4 text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-pulse", children: "Rendering diagram..." }) });
3028
+ }
3029
+ return /* @__PURE__ */ jsxRuntime.jsx(
3030
+ "div",
2722
3031
  {
2723
- "data-slot": "dialog-content",
3032
+ ref: containerRef,
2724
3033
  className: cn(
2725
- "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none sm:max-w-lg",
3034
+ "mermaid-diagram flex items-center justify-center overflow-x-auto",
2726
3035
  className
2727
3036
  ),
2728
- ...props,
2729
- children: [
2730
- children,
2731
- showCloseButton && /* @__PURE__ */ jsxRuntime.jsxs(
2732
- DialogPrimitive__namespace.Close,
2733
- {
2734
- "data-slot": "dialog-close",
2735
- className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
2736
- children: [
2737
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, {}),
2738
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
2739
- ]
2740
- }
2741
- )
2742
- ]
3037
+ dangerouslySetInnerHTML: { __html: svg }
2743
3038
  }
2744
- )
2745
- ] });
2746
- }
2747
- function DialogTitle({
2748
- className,
2749
- ...props
2750
- }) {
2751
- return /* @__PURE__ */ jsxRuntime.jsx(
2752
- DialogPrimitive__namespace.Title,
2753
- {
2754
- "data-slot": "dialog-title",
2755
- className: cn("text-lg leading-none font-semibold", className),
2756
- ...props
2757
- }
2758
- );
2759
- }
2760
- function Avatar2({
2761
- className,
2762
- ...props
2763
- }) {
2764
- return /* @__PURE__ */ jsxRuntime.jsx(
2765
- AvatarPrimitive__namespace.Root,
2766
- {
2767
- "data-slot": "avatar",
2768
- className: cn(
2769
- "relative flex size-8 shrink-0 overflow-hidden rounded-full",
2770
- className
2771
- ),
2772
- ...props
2773
- }
2774
- );
2775
- }
2776
- function AvatarImage({
2777
- className,
2778
- ...props
2779
- }) {
2780
- return /* @__PURE__ */ jsxRuntime.jsx(
2781
- AvatarPrimitive__namespace.Image,
2782
- {
2783
- "data-slot": "avatar-image",
2784
- className: cn("aspect-square size-full", className),
2785
- ...props
2786
- }
2787
- );
2788
- }
2789
- function AvatarFallback({
2790
- className,
2791
- ...props
2792
- }) {
2793
- return /* @__PURE__ */ jsxRuntime.jsx(
2794
- AvatarPrimitive__namespace.Fallback,
2795
- {
2796
- "data-slot": "avatar-fallback",
2797
- className: cn(
2798
- "bg-muted flex size-full items-center justify-center rounded-full",
2799
- className
2800
- ),
2801
- ...props
2802
- }
2803
- );
2804
- }
2805
- var useFileSrc = (file) => {
2806
- const [src, setSrc] = React2.useState(void 0);
2807
- React2.useEffect(() => {
2808
- if (!file) {
2809
- setSrc(void 0);
2810
- return;
2811
- }
2812
- const objectUrl = URL.createObjectURL(file);
2813
- setSrc(objectUrl);
2814
- return () => {
2815
- URL.revokeObjectURL(objectUrl);
2816
- };
2817
- }, [file]);
2818
- return src;
2819
- };
2820
- var useAttachmentSrc = () => {
2821
- const { file, src } = react$1.useAssistantState(
2822
- shallow.useShallow(({ attachment }) => {
2823
- if (attachment.type !== "image") return {};
2824
- if (attachment.file) return { file: attachment.file };
2825
- const src2 = attachment.content?.filter((c) => c.type === "image")[0]?.image;
2826
- if (!src2) return {};
2827
- return { src: src2 };
2828
- })
2829
- );
2830
- return useFileSrc(file) ?? src;
2831
- };
2832
- var AttachmentPreview = ({ src }) => {
2833
- return /* @__PURE__ */ jsxRuntime.jsx(
2834
- "img",
2835
- {
2836
- src,
2837
- alt: "Image Preview",
2838
- className: "aui-attachment-preview-image-loaded block h-auto max-h-[80vh] w-auto max-w-full object-contain"
2839
- }
2840
- );
3039
+ );
3040
+ }
3041
+ );
3042
+ MermaidRenderer.displayName = "MermaidRenderer";
3043
+ var diagramTypeLabels = {
3044
+ flowchart: "Flowchart",
3045
+ sequence: "Sequence Diagram",
3046
+ classDiagram: "Class Diagram",
3047
+ stateDiagram: "State Diagram",
3048
+ erDiagram: "ER Diagram",
3049
+ mindmap: "Mind Map"
2841
3050
  };
2842
- var AttachmentPreviewDialog = ({ children }) => {
2843
- const src = useAttachmentSrc();
2844
- if (!src) return children;
2845
- return /* @__PURE__ */ jsxRuntime.jsxs(Dialog, { children: [
2846
- /* @__PURE__ */ jsxRuntime.jsx(
2847
- DialogTrigger,
2848
- {
2849
- className: "aui-attachment-preview-trigger cursor-pointer transition-colors hover:bg-accent/50",
2850
- asChild: true,
2851
- children
3051
+ var MermaidToolUI = react$1.makeAssistantToolUI({
3052
+ toolName: "generateMermaidDiagram",
3053
+ render: function MermaidDiagramUI({ args, result, status }) {
3054
+ const { isCopied, copyToClipboard } = useCopyToClipboard2();
3055
+ const isStreaming = status.type === "running";
3056
+ const isError = status.type === "incomplete";
3057
+ const title = result?.title || args.title || "Generating diagram...";
3058
+ const content = result?.content || args.content || "";
3059
+ const explanation = result?.explanation || args.explanation || "";
3060
+ const diagramType = result?.diagramType || args.diagramType || "flowchart";
3061
+ const handleCopy = () => {
3062
+ if (content) {
3063
+ copyToClipboard(content);
2852
3064
  }
2853
- ),
2854
- /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "aui-attachment-preview-dialog-content p-2 sm:max-w-3xl [&>button]:rounded-full [&>button]:bg-foreground/60 [&>button]:p-1 [&>button]:opacity-100 [&>button]:ring-0! [&_svg]:text-background [&>button]:hover:[&_svg]:text-destructive", children: [
2855
- /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "aui-sr-only sr-only", children: "Image Attachment Preview" }),
2856
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aui-attachment-preview relative mx-auto flex max-h-[80dvh] w-full items-center justify-center overflow-hidden bg-background", children: /* @__PURE__ */ jsxRuntime.jsx(AttachmentPreview, { src }) })
2857
- ] })
3065
+ };
3066
+ const handleOpenFullScreen = () => {
3067
+ const newWindow = window.open("", "_blank");
3068
+ if (newWindow) {
3069
+ newWindow.document.write(`
3070
+ <!DOCTYPE html>
3071
+ <html>
3072
+ <head>
3073
+ <title>${title}</title>
3074
+ <meta charset="utf-8">
3075
+ <meta name="viewport" content="width=device-width, initial-scale=1">
3076
+ <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
3077
+ <style>
3078
+ body {
3079
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
3080
+ max-width: 1200px;
3081
+ margin: 0 auto;
3082
+ padding: 2rem;
3083
+ background: #1a1a1a;
3084
+ color: #fff;
3085
+ }
3086
+ h1 { border-bottom: 1px solid #333; padding-bottom: 0.5rem; }
3087
+ .mermaid { background: #2d2d2d; padding: 1rem; border-radius: 8px; }
3088
+ .explanation { margin-top: 1rem; color: #aaa; }
3089
+ </style>
3090
+ </head>
3091
+ <body>
3092
+ <h1>${title}</h1>
3093
+ <p class="explanation">${explanation}</p>
3094
+ <div class="mermaid">
3095
+ ${content}
3096
+ </div>
3097
+ <script>
3098
+ mermaid.initialize({ startOnLoad: true, theme: 'dark' });
3099
+ </script>
3100
+ </body>
3101
+ </html>
3102
+ `);
3103
+ newWindow.document.close();
3104
+ }
3105
+ };
3106
+ const persistentExplanation = explanation ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2 text-white/80 border-b border-white/10 bg-primary-foreground text-xs", children: [
3107
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
3108
+ diagramTypeLabels[diagramType] || diagramType,
3109
+ ":"
3110
+ ] }),
3111
+ " ",
3112
+ explanation
3113
+ ] }) : void 0;
3114
+ const footerActions = content ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3115
+ /* @__PURE__ */ jsxRuntime.jsx(
3116
+ TooltipIconButton,
3117
+ {
3118
+ tooltip: isCopied ? "Copied!" : "Copy mermaid code",
3119
+ onClick: handleCopy,
3120
+ className: "flex items-center justify-center rounded-md p-1.5 text-white/70 hover:bg-white/10 transition-colors",
3121
+ children: isCopied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckIcon, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CopyIcon, { className: "h-3.5 w-3.5" })
3122
+ }
3123
+ ),
3124
+ /* @__PURE__ */ jsxRuntime.jsx(
3125
+ TooltipIconButton,
3126
+ {
3127
+ tooltip: "Open in new window",
3128
+ onClick: handleOpenFullScreen,
3129
+ className: "flex items-center justify-center rounded-md p-1.5 text-white/70 hover:bg-white/10 transition-colors",
3130
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLinkIcon, { className: "h-3.5 w-3.5" })
3131
+ }
3132
+ )
3133
+ ] }) : void 0;
3134
+ return /* @__PURE__ */ jsxRuntime.jsx(
3135
+ ToolCard,
3136
+ {
3137
+ title,
3138
+ subtitle: diagramTypeLabels[diagramType] || "Diagram",
3139
+ isStreaming,
3140
+ isError,
3141
+ icon: !isStreaming && !isError ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.NetworkIcon, { className: "h-4 w-4" }) : void 0,
3142
+ persistentContent: persistentExplanation,
3143
+ footer: footerActions,
3144
+ children: content ? /* @__PURE__ */ jsxRuntime.jsx(MermaidRenderer, { content }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground italic", children: "Generating diagram..." })
3145
+ }
3146
+ );
3147
+ }
3148
+ });
3149
+ var difficultyConfig = {
3150
+ easy: {
3151
+ label: "Easy",
3152
+ className: "text-green-400 bg-green-500/10 border-green-500/20"
3153
+ },
3154
+ medium: {
3155
+ label: "Medium",
3156
+ className: "text-amber-400 bg-amber-500/10 border-amber-500/20"
3157
+ },
3158
+ hard: {
3159
+ label: "Hard",
3160
+ className: "text-red-400 bg-red-500/10 border-red-500/20"
3161
+ }
3162
+ };
3163
+ var QuizToolUI2 = react$1.makeAssistantToolUI({
3164
+ toolName: "createQuiz",
3165
+ render: function QuizUI({ args, result, status }) {
3166
+ const isStreaming = status.type === "running";
3167
+ const isError = status.type === "incomplete";
3168
+ const topic = result?.topic || args.topic || "Generating...";
3169
+ const questionCount = result?.questionCount || args.questionCount || 5;
3170
+ const difficulty = result?.difficulty || args.difficulty || "medium";
3171
+ const message = result?.message || "Quiz generation is coming soon! This feature will create interactive quizzes to test your knowledge.";
3172
+ const resultStatus = result?.status || "pending";
3173
+ const difficultyStyle = difficultyConfig[difficulty] || difficultyConfig.medium;
3174
+ const persistentContent = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2 text-white/80 border-b border-white/10 bg-primary-foreground text-xs flex items-center gap-3", children: [
3175
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
3176
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Topic:" }),
3177
+ " ",
3178
+ topic
3179
+ ] }),
3180
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
3181
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Questions:" }),
3182
+ " ",
3183
+ questionCount
3184
+ ] }),
3185
+ /* @__PURE__ */ jsxRuntime.jsx(
3186
+ "span",
3187
+ {
3188
+ className: `px-1.5 py-0.5 rounded text-xs font-medium border ${difficultyStyle.className}`,
3189
+ children: difficultyStyle.label
3190
+ }
3191
+ )
3192
+ ] });
3193
+ return /* @__PURE__ */ jsxRuntime.jsx(
3194
+ ToolCard,
3195
+ {
3196
+ title: "Quiz",
3197
+ subtitle: "Knowledge Test",
3198
+ isStreaming,
3199
+ isError,
3200
+ icon: !isStreaming && !isError ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HelpCircleIcon, { className: "h-4 w-4" }) : void 0,
3201
+ persistentContent,
3202
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
3203
+ resultStatus === "pending" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 p-3 rounded-lg bg-amber-500/10 border border-amber-500/20", children: [
3204
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ClockIcon, { className: "h-5 w-5 text-amber-400 mt-0.5 shrink-0" }),
3205
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3206
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-amber-300", children: "Coming Soon" }),
3207
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-amber-200/70 mt-1", children: message })
3208
+ ] })
3209
+ ] }),
3210
+ resultStatus === "processing" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 text-sm text-white/70", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-pulse", children: "Generating quiz questions..." }) }),
3211
+ resultStatus === "complete" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-green-400", children: "Quiz generated successfully! Ready to test your knowledge." })
3212
+ ] })
3213
+ }
3214
+ );
3215
+ }
3216
+ });
3217
+ var CATEGORY_LABELS = {
3218
+ attachment: "Attachments",
3219
+ description: "Description",
3220
+ caption: "Video",
3221
+ link: "Links",
3222
+ lesson: "Current Lesson"
3223
+ };
3224
+ function useContextMention(options = {}) {
3225
+ const { onInsertMention } = options;
3226
+ const widgetContext = React2.useContext(WidgetContext);
3227
+ if (!widgetContext) {
3228
+ throw new Error("useContextMention must be used within a WidgetProvider");
3229
+ }
3230
+ const { client } = widgetContext;
3231
+ const {
3232
+ selectedContext: selectedItems,
3233
+ addContextItem,
3234
+ removeContextItem,
3235
+ clearContext
3236
+ } = useMessageContext();
3237
+ const { lessonContext, hasLessonContext } = useLessonContext();
3238
+ React2.useEffect(() => {
3239
+ if (hasLessonContext && lessonContext) {
3240
+ const lessonItem = {
3241
+ id: lessonContext.lessonId,
3242
+ type: "lesson",
3243
+ title: lessonContext.lessonTitle,
3244
+ lessonTitle: lessonContext.lessonTitle,
3245
+ chapterTitle: lessonContext.chapterTitle
3246
+ };
3247
+ if (!selectedItems.some((item) => item.id === lessonItem.id)) {
3248
+ console.log(
3249
+ "[ContextMention] Auto-adding current lesson context:",
3250
+ lessonItem.title
3251
+ );
3252
+ addContextItem(lessonItem);
3253
+ }
3254
+ }
3255
+ }, [hasLessonContext]);
3256
+ const [isOpen, setIsOpen] = React2.useState(false);
3257
+ const [searchTerm, setSearchTerm] = React2.useState("");
3258
+ const [activeIndex, setActiveIndex] = React2.useState(0);
3259
+ const [isLoading, setIsLoading] = React2.useState(false);
3260
+ const [categories, setCategories] = React2.useState([]);
3261
+ const [hasMore, setHasMore] = React2.useState(false);
3262
+ const config = client.getConfig();
3263
+ const baseUrl = config.baseUrl || "http://localhost:3000";
3264
+ const assistantId = config.apiKey;
3265
+ const fetchContextItems = React2.useCallback(
3266
+ async (search = "", limit = 10) => {
3267
+ setIsLoading(true);
3268
+ try {
3269
+ const params = new URLSearchParams({
3270
+ limit: limit.toString()
3271
+ });
3272
+ if (search) {
3273
+ params.set("search", search);
3274
+ }
3275
+ const response = await fetch(
3276
+ `${baseUrl}/api/widget/context?${params.toString()}`,
3277
+ {
3278
+ headers: {
3279
+ "Content-Type": "application/json",
3280
+ "X-Assistant-Id": assistantId
3281
+ }
3282
+ }
3283
+ );
3284
+ if (!response.ok) {
3285
+ console.error(
3286
+ "[ContextMention] Failed to fetch context:",
3287
+ response.status
3288
+ );
3289
+ return;
3290
+ }
3291
+ const data = await response.json();
3292
+ setCategories(data.categories);
3293
+ setHasMore(data.hasMore);
3294
+ } catch (error) {
3295
+ console.error("[ContextMention] Error fetching context:", error);
3296
+ } finally {
3297
+ setIsLoading(false);
3298
+ }
3299
+ },
3300
+ [baseUrl, assistantId]
3301
+ );
3302
+ const openPopover = React2.useCallback(() => {
3303
+ setIsOpen(true);
3304
+ setSearchTerm("");
3305
+ setActiveIndex(0);
3306
+ fetchContextItems();
3307
+ }, [fetchContextItems]);
3308
+ const closePopover = React2.useCallback(() => {
3309
+ setIsOpen(false);
3310
+ setSearchTerm("");
3311
+ setActiveIndex(0);
3312
+ }, []);
3313
+ const updateSearch = React2.useCallback(
3314
+ (term) => {
3315
+ setSearchTerm(term);
3316
+ setActiveIndex(0);
3317
+ fetchContextItems(term);
3318
+ },
3319
+ [fetchContextItems]
3320
+ );
3321
+ const flattenedItems = React2.useMemo(() => {
3322
+ return categories.flatMap((category) => category.items);
3323
+ }, [categories]);
3324
+ const navigateDown = React2.useCallback(() => {
3325
+ setActiveIndex(
3326
+ (prev2) => prev2 < flattenedItems.length - 1 ? prev2 + 1 : prev2
3327
+ );
3328
+ }, [flattenedItems.length]);
3329
+ const navigateUp = React2.useCallback(() => {
3330
+ setActiveIndex((prev2) => prev2 > 0 ? prev2 - 1 : 0);
3331
+ }, []);
3332
+ const selectActiveItem = React2.useCallback(() => {
3333
+ const item = flattenedItems[activeIndex];
3334
+ if (item) {
3335
+ addContextItem(item);
3336
+ closePopover();
3337
+ onInsertMention?.(item);
3338
+ }
3339
+ }, [
3340
+ flattenedItems,
3341
+ activeIndex,
3342
+ addContextItem,
3343
+ closePopover,
3344
+ onInsertMention
3345
+ ]);
3346
+ const selectItem = React2.useCallback(
3347
+ (item) => {
3348
+ addContextItem(item);
3349
+ closePopover();
3350
+ onInsertMention?.(item);
3351
+ },
3352
+ [addContextItem, closePopover, onInsertMention]
3353
+ );
3354
+ const removeItem = React2.useCallback(
3355
+ (itemId) => {
3356
+ removeContextItem(itemId);
3357
+ },
3358
+ [removeContextItem]
3359
+ );
3360
+ const clearAll = React2.useCallback(() => {
3361
+ clearContext();
3362
+ }, [clearContext]);
3363
+ const handleKeyDown = React2.useCallback(
3364
+ (event) => {
3365
+ if (!isOpen) return;
3366
+ switch (event.key) {
3367
+ case "ArrowDown":
3368
+ event.preventDefault();
3369
+ navigateDown();
3370
+ break;
3371
+ case "ArrowUp":
3372
+ event.preventDefault();
3373
+ navigateUp();
3374
+ break;
3375
+ case "Enter":
3376
+ event.preventDefault();
3377
+ selectActiveItem();
3378
+ break;
3379
+ case "Escape":
3380
+ event.preventDefault();
3381
+ closePopover();
3382
+ break;
3383
+ }
3384
+ },
3385
+ [isOpen, navigateDown, navigateUp, selectActiveItem, closePopover]
3386
+ );
3387
+ const getCategoryLabel = React2.useCallback((type) => {
3388
+ return CATEGORY_LABELS[type] || type;
3389
+ }, []);
3390
+ return {
3391
+ // Selected items
3392
+ selectedItems,
3393
+ selectItem,
3394
+ removeItem,
3395
+ clearAll,
3396
+ // Popover state
3397
+ isOpen,
3398
+ openPopover,
3399
+ closePopover,
3400
+ // Search
3401
+ searchTerm,
3402
+ updateSearch,
3403
+ // Navigation
3404
+ activeIndex,
3405
+ setActiveIndex,
3406
+ navigateUp,
3407
+ navigateDown,
3408
+ selectActiveItem,
3409
+ handleKeyDown,
3410
+ // Data
3411
+ categories,
3412
+ flattenedItems,
3413
+ isLoading,
3414
+ hasMore,
3415
+ // Utilities
3416
+ getCategoryLabel
3417
+ };
3418
+ }
3419
+ function Dialog({
3420
+ ...props
3421
+ }) {
3422
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Root, { "data-slot": "dialog", ...props });
3423
+ }
3424
+ function DialogTrigger({
3425
+ ...props
3426
+ }) {
3427
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Trigger, { "data-slot": "dialog-trigger", ...props });
3428
+ }
3429
+ function DialogPortal({
3430
+ ...props
3431
+ }) {
3432
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Portal, { "data-slot": "dialog-portal", ...props });
3433
+ }
3434
+ function DialogOverlay({
3435
+ className,
3436
+ ...props
3437
+ }) {
3438
+ return /* @__PURE__ */ jsxRuntime.jsx(
3439
+ DialogPrimitive__namespace.Overlay,
3440
+ {
3441
+ "data-slot": "dialog-overlay",
3442
+ className: cn(
3443
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
3444
+ className
3445
+ ),
3446
+ ...props
3447
+ }
3448
+ );
3449
+ }
3450
+ function DialogContent({
3451
+ className,
3452
+ children,
3453
+ showCloseButton = true,
3454
+ ...props
3455
+ }) {
3456
+ return /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [
3457
+ /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
3458
+ /* @__PURE__ */ jsxRuntime.jsxs(
3459
+ DialogPrimitive__namespace.Content,
3460
+ {
3461
+ "data-slot": "dialog-content",
3462
+ className: cn(
3463
+ "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none sm:max-w-lg",
3464
+ className
3465
+ ),
3466
+ ...props,
3467
+ children: [
3468
+ children,
3469
+ showCloseButton && /* @__PURE__ */ jsxRuntime.jsxs(
3470
+ DialogPrimitive__namespace.Close,
3471
+ {
3472
+ "data-slot": "dialog-close",
3473
+ className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
3474
+ children: [
3475
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, {}),
3476
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
3477
+ ]
3478
+ }
3479
+ )
3480
+ ]
3481
+ }
3482
+ )
3483
+ ] });
3484
+ }
3485
+ function DialogTitle({
3486
+ className,
3487
+ ...props
3488
+ }) {
3489
+ return /* @__PURE__ */ jsxRuntime.jsx(
3490
+ DialogPrimitive__namespace.Title,
3491
+ {
3492
+ "data-slot": "dialog-title",
3493
+ className: cn("text-lg leading-none font-semibold", className),
3494
+ ...props
3495
+ }
3496
+ );
3497
+ }
3498
+ function Avatar2({
3499
+ className,
3500
+ ...props
3501
+ }) {
3502
+ return /* @__PURE__ */ jsxRuntime.jsx(
3503
+ AvatarPrimitive__namespace.Root,
3504
+ {
3505
+ "data-slot": "avatar",
3506
+ className: cn(
3507
+ "relative flex size-8 shrink-0 overflow-hidden rounded-full",
3508
+ className
3509
+ ),
3510
+ ...props
3511
+ }
3512
+ );
3513
+ }
3514
+ function AvatarImage({
3515
+ className,
3516
+ ...props
3517
+ }) {
3518
+ return /* @__PURE__ */ jsxRuntime.jsx(
3519
+ AvatarPrimitive__namespace.Image,
3520
+ {
3521
+ "data-slot": "avatar-image",
3522
+ className: cn("aspect-square size-full", className),
3523
+ ...props
3524
+ }
3525
+ );
3526
+ }
3527
+ function AvatarFallback({
3528
+ className,
3529
+ ...props
3530
+ }) {
3531
+ return /* @__PURE__ */ jsxRuntime.jsx(
3532
+ AvatarPrimitive__namespace.Fallback,
3533
+ {
3534
+ "data-slot": "avatar-fallback",
3535
+ className: cn(
3536
+ "bg-muted flex size-full items-center justify-center rounded-full",
3537
+ className
3538
+ ),
3539
+ ...props
3540
+ }
3541
+ );
3542
+ }
3543
+ var useFileSrc = (file) => {
3544
+ const [src, setSrc] = React2.useState(void 0);
3545
+ React2.useEffect(() => {
3546
+ if (!file) {
3547
+ setSrc(void 0);
3548
+ return;
3549
+ }
3550
+ const objectUrl = URL.createObjectURL(file);
3551
+ setSrc(objectUrl);
3552
+ return () => {
3553
+ URL.revokeObjectURL(objectUrl);
3554
+ };
3555
+ }, [file]);
3556
+ return src;
3557
+ };
3558
+ var useAttachmentSrc = () => {
3559
+ const { file, src } = react$1.useAssistantState(
3560
+ shallow.useShallow(({ attachment }) => {
3561
+ if (attachment.type !== "image") return {};
3562
+ if (attachment.file) return { file: attachment.file };
3563
+ const src2 = attachment.content?.filter((c) => c.type === "image")[0]?.image;
3564
+ if (!src2) return {};
3565
+ return { src: src2 };
3566
+ })
3567
+ );
3568
+ return useFileSrc(file) ?? src;
3569
+ };
3570
+ var AttachmentPreview = ({ src }) => {
3571
+ return /* @__PURE__ */ jsxRuntime.jsx(
3572
+ "img",
3573
+ {
3574
+ src,
3575
+ alt: "Image Preview",
3576
+ className: "aui-attachment-preview-image-loaded block h-auto max-h-[80vh] w-auto max-w-full object-contain"
3577
+ }
3578
+ );
3579
+ };
3580
+ var AttachmentPreviewDialog = ({ children }) => {
3581
+ const src = useAttachmentSrc();
3582
+ if (!src) return children;
3583
+ return /* @__PURE__ */ jsxRuntime.jsxs(Dialog, { children: [
3584
+ /* @__PURE__ */ jsxRuntime.jsx(
3585
+ DialogTrigger,
3586
+ {
3587
+ className: "aui-attachment-preview-trigger cursor-pointer transition-colors hover:bg-accent/50",
3588
+ asChild: true,
3589
+ children
3590
+ }
3591
+ ),
3592
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "aui-attachment-preview-dialog-content p-2 sm:max-w-3xl [&>button]:rounded-full [&>button]:bg-foreground/60 [&>button]:p-1 [&>button]:opacity-100 [&>button]:ring-0! [&_svg]:text-background [&>button]:hover:[&_svg]:text-destructive", children: [
3593
+ /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "aui-sr-only sr-only", children: "Image Attachment Preview" }),
3594
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aui-attachment-preview relative mx-auto flex max-h-[80dvh] w-full items-center justify-center overflow-hidden bg-background", children: /* @__PURE__ */ jsxRuntime.jsx(AttachmentPreview, { src }) })
3595
+ ] })
2858
3596
  ] });
2859
3597
  };
2860
3598
  var AttachmentThumb = () => {
@@ -2958,11 +3696,178 @@ var ComposerAddAttachment = () => {
2958
3696
  }
2959
3697
  ) });
2960
3698
  };
3699
+ function Popover({
3700
+ modal = false,
3701
+ ...props
3702
+ }) {
3703
+ return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Root, { modal, ...props });
3704
+ }
3705
+ function PopoverTrigger({
3706
+ ...props
3707
+ }) {
3708
+ return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Trigger, { ...props });
3709
+ }
3710
+ function PopoverContent({
3711
+ className,
3712
+ align = "start",
3713
+ sideOffset = 4,
3714
+ ...props
3715
+ }) {
3716
+ return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
3717
+ PopoverPrimitive__namespace.Content,
3718
+ {
3719
+ align,
3720
+ sideOffset,
3721
+ className: cn(
3722
+ "z-[10000] w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
3723
+ className
3724
+ ),
3725
+ style: {
3726
+ zIndex: 1e4,
3727
+ borderColor: theme.colors.border,
3728
+ ...props.style
3729
+ },
3730
+ ...props
3731
+ }
3732
+ ) });
3733
+ }
3734
+ var TYPE_ICONS = {
3735
+ attachment: lucideReact.FileIcon,
3736
+ description: lucideReact.FileTextIcon,
3737
+ caption: lucideReact.VideoIcon,
3738
+ link: lucideReact.LinkIcon
3739
+ };
3740
+ var ContextMentionPopover = ({
3741
+ isOpen,
3742
+ onOpenChange,
3743
+ categories,
3744
+ isLoading,
3745
+ activeIndex,
3746
+ flattenedItems,
3747
+ onSelectItem,
3748
+ onActiveIndexChange,
3749
+ getCategoryLabel,
3750
+ trigger,
3751
+ searchTerm
3752
+ }) => {
3753
+ const activeItemRef = React2.useRef(null);
3754
+ React2.useEffect(() => {
3755
+ if (isOpen && activeItemRef.current) {
3756
+ activeItemRef.current.scrollIntoView({
3757
+ block: "nearest",
3758
+ behavior: "smooth"
3759
+ });
3760
+ }
3761
+ }, [activeIndex, isOpen]);
3762
+ const getFlattenedIndex = (categoryIndex, itemIndex) => {
3763
+ let index = 0;
3764
+ for (let i = 0; i < categoryIndex; i++) {
3765
+ index += categories[i].items.length;
3766
+ }
3767
+ return index + itemIndex;
3768
+ };
3769
+ const hasNoResults = !isLoading && flattenedItems.length === 0;
3770
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: isOpen, onOpenChange, modal: false, children: [
3771
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: trigger }),
3772
+ /* @__PURE__ */ jsxRuntime.jsx(
3773
+ PopoverContent,
3774
+ {
3775
+ className: "w-72 max-h-80 overflow-y-auto p-0",
3776
+ align: "start",
3777
+ side: "top",
3778
+ sideOffset: 8,
3779
+ onOpenAutoFocus: (e) => e.preventDefault(),
3780
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
3781
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-10 border-b border-border bg-popover px-3 py-2", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium text-muted-foreground", children: searchTerm ? `Searching for "${searchTerm}"` : "Select context to focus on" }) }),
3782
+ isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LoaderIcon, { className: "size-5 animate-spin text-muted-foreground" }) }),
3783
+ hasNoResults && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-8 text-center text-sm text-muted-foreground", children: [
3784
+ "No context items found",
3785
+ searchTerm && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-xs mt-1", children: "Try a different search term" })
3786
+ ] }),
3787
+ !isLoading && categories.map((category, categoryIndex) => {
3788
+ if (category.items.length === 0) return null;
3789
+ const Icon = TYPE_ICONS[category.type] || lucideReact.FileIcon;
3790
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-1", children: [
3791
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-3 py-1.5", children: [
3792
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-3.5 text-muted-foreground" }),
3793
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-muted-foreground", children: getCategoryLabel(category.type) }),
3794
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground/60", children: [
3795
+ "(",
3796
+ category.items.length,
3797
+ ")"
3798
+ ] })
3799
+ ] }),
3800
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col", children: category.items.map((item, itemIndex) => {
3801
+ const flatIndex = getFlattenedIndex(
3802
+ categoryIndex,
3803
+ itemIndex
3804
+ );
3805
+ const isActive = flatIndex === activeIndex;
3806
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3807
+ "button",
3808
+ {
3809
+ ref: isActive ? activeItemRef : null,
3810
+ type: "button",
3811
+ className: cn(
3812
+ "flex flex-col items-start px-3 py-2 text-left text-sm transition-colors",
3813
+ "hover:bg-accent/10",
3814
+ isActive && "bg-accent/20"
3815
+ ),
3816
+ onClick: () => onSelectItem(item),
3817
+ onMouseEnter: () => onActiveIndexChange(flatIndex),
3818
+ children: [
3819
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate w-full font-medium text-foreground", children: item.title }),
3820
+ (item.lessonTitle || item.chapterTitle) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate w-full text-xs text-muted-foreground", children: item.chapterTitle && item.lessonTitle ? `${item.chapterTitle} > ${item.lessonTitle}` : item.lessonTitle || item.chapterTitle })
3821
+ ]
3822
+ },
3823
+ item.id
3824
+ );
3825
+ }) })
3826
+ ] }, category.type);
3827
+ })
3828
+ ] })
3829
+ }
3830
+ )
3831
+ ] });
3832
+ };
3833
+ var ContextPill = ({
3834
+ label,
3835
+ onRemove,
3836
+ readonly = false,
3837
+ className
3838
+ }) => {
3839
+ const showRemoveButton = !readonly && onRemove;
3840
+ return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
3841
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
3842
+ "div",
3843
+ {
3844
+ className: cn(
3845
+ "group flex items-center gap-1 rounded-md border border-muted-foreground py-1 px-1.5 text-xs",
3846
+ "max-w-[200px] cursor-default",
3847
+ className
3848
+ ),
3849
+ children: [
3850
+ showRemoveButton && /* @__PURE__ */ jsxRuntime.jsx(
3851
+ "button",
3852
+ {
3853
+ onClick: onRemove,
3854
+ "aria-label": `Remove ${label}`,
3855
+ className: "shrink-0 hover:text-destructive transition-colors",
3856
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { className: "size-3" })
3857
+ }
3858
+ ),
3859
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: label })
3860
+ ]
3861
+ }
3862
+ ) }),
3863
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", sideOffset: 4, children: label })
3864
+ ] });
3865
+ };
2961
3866
  var MarkdownTextImpl = () => {
2962
3867
  return /* @__PURE__ */ jsxRuntime.jsx(
2963
3868
  reactMarkdown.MarkdownTextPrimitive,
2964
3869
  {
2965
- remarkPlugins: [remarkGfm__default.default],
3870
+ remarkPlugins: [remarkGfm3__default.default],
2966
3871
  className: "aui-md",
2967
3872
  components: defaultComponents
2968
3873
  }
@@ -2970,7 +3875,7 @@ var MarkdownTextImpl = () => {
2970
3875
  };
2971
3876
  var MarkdownText = React2.memo(MarkdownTextImpl);
2972
3877
  var CodeHeader = ({ language, code }) => {
2973
- const { isCopied, copyToClipboard } = useCopyToClipboard2();
3878
+ const { isCopied, copyToClipboard } = useCopyToClipboard3();
2974
3879
  const onCopy = () => {
2975
3880
  if (!code || isCopied) return;
2976
3881
  copyToClipboard(code);
@@ -2983,7 +3888,7 @@ var CodeHeader = ({ language, code }) => {
2983
3888
  ] })
2984
3889
  ] });
2985
3890
  };
2986
- var useCopyToClipboard2 = ({
3891
+ var useCopyToClipboard3 = ({
2987
3892
  copiedDuration = 3e3
2988
3893
  } = {}) => {
2989
3894
  const [isCopied, setIsCopied] = React2.useState(false);
@@ -3122,256 +4027,55 @@ var defaultComponents = reactMarkdown.unstable_memoizeMarkdownComponents({
3122
4027
  td: ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
3123
4028
  "td",
3124
4029
  {
3125
- className: cn(
3126
- "aui-md-td border-b border-l px-4 py-2 text-left last:border-r [[align=center]]:text-center [[align=right]]:text-right",
3127
- className
3128
- ),
3129
- ...props
3130
- }
3131
- ),
3132
- tr: ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
3133
- "tr",
3134
- {
3135
- className: cn(
3136
- "aui-md-tr m-0 border-b p-0 first:border-t [&:last-child>td:first-child]:rounded-bl-lg [&:last-child>td:last-child]:rounded-br-lg",
3137
- className
3138
- ),
3139
- ...props
3140
- }
3141
- ),
3142
- sup: ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
3143
- "sup",
3144
- {
3145
- className: cn("aui-md-sup [&>a]:text-xs [&>a]:no-underline", className),
3146
- ...props
3147
- }
3148
- ),
3149
- pre: ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
3150
- "pre",
3151
- {
3152
- className: cn(
3153
- "aui-md-pre overflow-x-auto rounded-t-none! rounded-b-lg bg-black p-4 text-white",
3154
- className
3155
- ),
3156
- ...props
3157
- }
3158
- ),
3159
- code: function Code({ className, ...props }) {
3160
- const isCodeBlock = reactMarkdown.useIsMarkdownCodeBlock();
3161
- return /* @__PURE__ */ jsxRuntime.jsx(
3162
- "code",
3163
- {
3164
- className: cn(
3165
- !isCodeBlock && "aui-md-inline-code rounded border bg-muted font-semibold",
3166
- className
3167
- ),
3168
- ...props
3169
- }
3170
- );
3171
- },
3172
- CodeHeader
3173
- });
3174
- var ToolFallback = ({
3175
- toolName,
3176
- argsText,
3177
- result,
3178
- status
3179
- }) => {
3180
- const isStreaming = status?.type === "running";
3181
- const isError = status?.type === "incomplete";
3182
- const isCancelled = status?.type === "incomplete" && status.reason === "cancelled";
3183
- const cancelledReason = isCancelled && status.error ? typeof status.error === "string" ? status.error : JSON.stringify(status.error) : null;
3184
- const titlePrefix = isCancelled ? "Cancelled: " : isStreaming ? "Running: " : "";
3185
- return /* @__PURE__ */ jsxRuntime.jsx(
3186
- ToolCard,
3187
- {
3188
- title: `${titlePrefix}${toolName}`,
3189
- isStreaming,
3190
- isError,
3191
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 text-white", children: [
3192
- cancelledReason && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3193
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-white/70 mb-0.5", children: "Cancelled reason:" }),
3194
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-white/60", children: cancelledReason })
3195
- ] }),
3196
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(isCancelled && "opacity-60"), children: [
3197
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-white/70 mb-0.5", children: "Arguments:" }),
3198
- /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "whitespace-pre-wrap bg-black/20 p-1.5 rounded text-white/80", children: argsText })
3199
- ] }),
3200
- !isCancelled && result !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-white/10 pt-2", children: [
3201
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-white/70 mb-0.5", children: "Result:" }),
3202
- /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "whitespace-pre-wrap bg-black/20 p-1.5 rounded text-white/80", children: typeof result === "string" ? result : JSON.stringify(result, null, 2) })
3203
- ] })
3204
- ] })
4030
+ className: cn(
4031
+ "aui-md-td border-b border-l px-4 py-2 text-left last:border-r [[align=center]]:text-center [[align=right]]:text-right",
4032
+ className
4033
+ ),
4034
+ ...props
3205
4035
  }
3206
- );
3207
- };
3208
- var ContextPill = ({
3209
- label,
3210
- onRemove,
3211
- readonly = false,
3212
- className
3213
- }) => {
3214
- const showRemoveButton = !readonly && onRemove;
3215
- return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
3216
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
3217
- "div",
3218
- {
3219
- className: cn(
3220
- "group flex items-center gap-1 rounded-md border border-muted-foreground py-1 px-1.5 text-xs",
3221
- "max-w-[200px] cursor-default",
3222
- className
3223
- ),
3224
- children: [
3225
- showRemoveButton && /* @__PURE__ */ jsxRuntime.jsx(
3226
- "button",
3227
- {
3228
- onClick: onRemove,
3229
- "aria-label": `Remove ${label}`,
3230
- className: "shrink-0 hover:text-destructive transition-colors",
3231
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { className: "size-3" })
3232
- }
3233
- ),
3234
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: label })
3235
- ]
3236
- }
3237
- ) }),
3238
- /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", sideOffset: 4, children: label })
3239
- ] });
3240
- };
3241
- function Popover({
3242
- modal = false,
3243
- ...props
3244
- }) {
3245
- return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Root, { modal, ...props });
3246
- }
3247
- function PopoverTrigger({
3248
- ...props
3249
- }) {
3250
- return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Trigger, { ...props });
3251
- }
3252
- function PopoverContent({
3253
- className,
3254
- align = "start",
3255
- sideOffset = 4,
3256
- ...props
3257
- }) {
3258
- return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
3259
- PopoverPrimitive__namespace.Content,
4036
+ ),
4037
+ tr: ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
4038
+ "tr",
3260
4039
  {
3261
- align,
3262
- sideOffset,
3263
4040
  className: cn(
3264
- "z-[10000] w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
4041
+ "aui-md-tr m-0 border-b p-0 first:border-t [&:last-child>td:first-child]:rounded-bl-lg [&:last-child>td:last-child]:rounded-br-lg",
3265
4042
  className
3266
4043
  ),
3267
- style: {
3268
- zIndex: 1e4,
3269
- borderColor: theme.colors.border,
3270
- ...props.style
3271
- },
3272
4044
  ...props
3273
4045
  }
3274
- ) });
3275
- }
3276
- var TYPE_ICONS = {
3277
- attachment: lucideReact.FileIcon,
3278
- description: lucideReact.FileTextIcon,
3279
- caption: lucideReact.VideoIcon,
3280
- link: lucideReact.LinkIcon
3281
- };
3282
- var ContextMentionPopover = ({
3283
- isOpen,
3284
- onOpenChange,
3285
- categories,
3286
- isLoading,
3287
- activeIndex,
3288
- flattenedItems,
3289
- onSelectItem,
3290
- onActiveIndexChange,
3291
- getCategoryLabel,
3292
- trigger,
3293
- searchTerm
3294
- }) => {
3295
- const activeItemRef = React2.useRef(null);
3296
- React2.useEffect(() => {
3297
- if (isOpen && activeItemRef.current) {
3298
- activeItemRef.current.scrollIntoView({
3299
- block: "nearest",
3300
- behavior: "smooth"
3301
- });
4046
+ ),
4047
+ sup: ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
4048
+ "sup",
4049
+ {
4050
+ className: cn("aui-md-sup [&>a]:text-xs [&>a]:no-underline", className),
4051
+ ...props
3302
4052
  }
3303
- }, [activeIndex, isOpen]);
3304
- const getFlattenedIndex = (categoryIndex, itemIndex) => {
3305
- let index = 0;
3306
- for (let i = 0; i < categoryIndex; i++) {
3307
- index += categories[i].items.length;
4053
+ ),
4054
+ pre: ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
4055
+ "pre",
4056
+ {
4057
+ className: cn(
4058
+ "aui-md-pre overflow-x-auto rounded-t-none! rounded-b-lg bg-black p-4 text-white",
4059
+ className
4060
+ ),
4061
+ ...props
3308
4062
  }
3309
- return index + itemIndex;
3310
- };
3311
- const hasNoResults = !isLoading && flattenedItems.length === 0;
3312
- return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: isOpen, onOpenChange, modal: false, children: [
3313
- /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: trigger }),
3314
- /* @__PURE__ */ jsxRuntime.jsx(
3315
- PopoverContent,
4063
+ ),
4064
+ code: function Code({ className, ...props }) {
4065
+ const isCodeBlock = reactMarkdown.useIsMarkdownCodeBlock();
4066
+ return /* @__PURE__ */ jsxRuntime.jsx(
4067
+ "code",
3316
4068
  {
3317
- className: "w-72 max-h-80 overflow-y-auto p-0",
3318
- align: "start",
3319
- side: "top",
3320
- sideOffset: 8,
3321
- onOpenAutoFocus: (e) => e.preventDefault(),
3322
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
3323
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-10 border-b border-border bg-popover px-3 py-2", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium text-muted-foreground", children: searchTerm ? `Searching for "${searchTerm}"` : "Select context to focus on" }) }),
3324
- isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LoaderIcon, { className: "size-5 animate-spin text-muted-foreground" }) }),
3325
- hasNoResults && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-8 text-center text-sm text-muted-foreground", children: [
3326
- "No context items found",
3327
- searchTerm && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-xs mt-1", children: "Try a different search term" })
3328
- ] }),
3329
- !isLoading && categories.map((category, categoryIndex) => {
3330
- if (category.items.length === 0) return null;
3331
- const Icon = TYPE_ICONS[category.type] || lucideReact.FileIcon;
3332
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-1", children: [
3333
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-3 py-1.5", children: [
3334
- /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-3.5 text-muted-foreground" }),
3335
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-muted-foreground", children: getCategoryLabel(category.type) }),
3336
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground/60", children: [
3337
- "(",
3338
- category.items.length,
3339
- ")"
3340
- ] })
3341
- ] }),
3342
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col", children: category.items.map((item, itemIndex) => {
3343
- const flatIndex = getFlattenedIndex(
3344
- categoryIndex,
3345
- itemIndex
3346
- );
3347
- const isActive = flatIndex === activeIndex;
3348
- return /* @__PURE__ */ jsxRuntime.jsxs(
3349
- "button",
3350
- {
3351
- ref: isActive ? activeItemRef : null,
3352
- type: "button",
3353
- className: cn(
3354
- "flex flex-col items-start px-3 py-2 text-left text-sm transition-colors",
3355
- "hover:bg-accent/10",
3356
- isActive && "bg-accent/20"
3357
- ),
3358
- onClick: () => onSelectItem(item),
3359
- onMouseEnter: () => onActiveIndexChange(flatIndex),
3360
- children: [
3361
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate w-full font-medium text-foreground", children: item.title }),
3362
- (item.lessonTitle || item.chapterTitle) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate w-full text-xs text-muted-foreground", children: item.chapterTitle && item.lessonTitle ? `${item.chapterTitle} > ${item.lessonTitle}` : item.lessonTitle || item.chapterTitle })
3363
- ]
3364
- },
3365
- item.id
3366
- );
3367
- }) })
3368
- ] }, category.type);
3369
- })
3370
- ] })
4069
+ className: cn(
4070
+ !isCodeBlock && "aui-md-inline-code rounded border bg-muted font-semibold",
4071
+ className
4072
+ ),
4073
+ ...props
3371
4074
  }
3372
- )
3373
- ] });
3374
- };
4075
+ );
4076
+ },
4077
+ CodeHeader
4078
+ });
3375
4079
  var TYPE_ICON_SVGS = {
3376
4080
  attachment: '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/></svg>',
3377
4081
  description: '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M10 9H8"/><path d="M16 13H8"/><path d="M16 17H8"/></svg>',
@@ -3731,6 +4435,189 @@ var MentionComposerInput = React2.forwardRef(
3731
4435
  }
3732
4436
  );
3733
4437
  MentionComposerInput.displayName = "MentionComposerInput";
4438
+ var typeIcons = {
4439
+ markdown: lucideReact.FileTextIcon,
4440
+ mermaid: lucideReact.NetworkIcon
4441
+ };
4442
+ var typeColors = {
4443
+ markdown: "bg-emerald-500/10 text-emerald-500 border-emerald-500/20",
4444
+ mermaid: "bg-blue-500/10 text-blue-500 border-blue-500/20"
4445
+ };
4446
+ var typeLabels = {
4447
+ markdown: "Detailed Answer",
4448
+ mermaid: "Diagram"
4449
+ };
4450
+ var ArtifactCard2 = ({ artifact, onOpen }) => {
4451
+ const Icon = typeIcons[artifact.type] || lucideReact.FileTextIcon;
4452
+ const colorClass = typeColors[artifact.type] || typeColors.markdown;
4453
+ const label = typeLabels[artifact.type] || "Artifact";
4454
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4455
+ "button",
4456
+ {
4457
+ type: "button",
4458
+ onClick: () => onOpen(artifact),
4459
+ className: cn(
4460
+ "flex items-center gap-3 w-full rounded-lg border px-3 py-2.5 text-left transition-colors",
4461
+ "hover:bg-muted/50",
4462
+ colorClass
4463
+ ),
4464
+ children: [
4465
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-md bg-current/10", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-4 w-4" }) }),
4466
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
4467
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium opacity-70", children: label }),
4468
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium truncate text-foreground", children: artifact.title })
4469
+ ] }),
4470
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLinkIcon, { className: "h-4 w-4 shrink-0 opacity-50" })
4471
+ ]
4472
+ }
4473
+ );
4474
+ };
4475
+ var ArtifactDialog = ({ artifact, onClose }) => {
4476
+ if (!artifact) return null;
4477
+ const Icon = typeIcons[artifact.type] || lucideReact.FileTextIcon;
4478
+ const colorClass = typeColors[artifact.type] || typeColors.markdown;
4479
+ const label = typeLabels[artifact.type] || "Artifact";
4480
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
4481
+ /* @__PURE__ */ jsxRuntime.jsx(
4482
+ "div",
4483
+ {
4484
+ className: "absolute inset-0 bg-black/60 backdrop-blur-sm",
4485
+ onClick: onClose
4486
+ }
4487
+ ),
4488
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative z-10 w-full max-w-2xl max-h-[80vh] mx-4 overflow-hidden rounded-xl border border-border bg-background shadow-xl", children: [
4489
+ /* @__PURE__ */ jsxRuntime.jsxs(
4490
+ "div",
4491
+ {
4492
+ className: cn(
4493
+ "flex items-center justify-between gap-3 px-4 py-3 border-b border-border",
4494
+ colorClass
4495
+ ),
4496
+ children: [
4497
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
4498
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-md bg-current/10", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-4 w-4" }) }),
4499
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
4500
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium opacity-70", children: label }),
4501
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold truncate text-foreground", children: artifact.title })
4502
+ ] })
4503
+ ] }),
4504
+ /* @__PURE__ */ jsxRuntime.jsx(
4505
+ "button",
4506
+ {
4507
+ type: "button",
4508
+ onClick: onClose,
4509
+ className: "p-1.5 rounded-md hover:bg-muted/50 transition-colors text-foreground",
4510
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, { className: "h-5 w-5" })
4511
+ }
4512
+ )
4513
+ ]
4514
+ }
4515
+ ),
4516
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-y-auto max-h-[calc(80vh-60px)] p-4", children: artifact.type === "mermaid" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
4517
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 rounded-lg bg-muted/30 overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-sm text-muted-foreground whitespace-pre-wrap", children: artifact.content }) }),
4518
+ artifact.summary && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-foreground prose prose-sm dark:prose-invert max-w-none", children: /* @__PURE__ */ jsxRuntime.jsx(ReactMarkdown2__default.default, { remarkPlugins: [remarkGfm3__default.default], children: artifact.summary }) })
4519
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "prose prose-sm dark:prose-invert max-w-none", children: /* @__PURE__ */ jsxRuntime.jsx(ReactMarkdown2__default.default, { remarkPlugins: [remarkGfm3__default.default], children: artifact.content }) }) })
4520
+ ] })
4521
+ ] });
4522
+ };
4523
+ var MessageArtifacts = () => {
4524
+ const [artifacts, setArtifacts] = React2.useState([]);
4525
+ const [isLoading, setIsLoading] = React2.useState(false);
4526
+ const [selectedArtifact, setSelectedArtifact] = React2.useState(
4527
+ null
4528
+ );
4529
+ const widgetContext = React2.useContext(WidgetContext);
4530
+ const threadRuntime = react$1.useThreadRuntime();
4531
+ const messageId = react$1.useMessage((state) => {
4532
+ if (process.env.NODE_ENV === "development") {
4533
+ console.log("[MessageArtifacts] Message state:", state);
4534
+ }
4535
+ const id = state.id || state.message?.id;
4536
+ return id;
4537
+ });
4538
+ const threadId = threadRuntime?.getState()?.threadId;
4539
+ const fetchArtifacts = React2.useCallback(async () => {
4540
+ if (!threadId || !messageId || !widgetContext) return;
4541
+ const baseUrl = widgetContext.client.getConfig().baseUrl;
4542
+ setIsLoading(true);
4543
+ try {
4544
+ const response = await fetch(
4545
+ `${baseUrl}/api/widget/threads/${threadId}/artifacts?messageId=${messageId}`
4546
+ );
4547
+ if (response.ok) {
4548
+ const data = await response.json();
4549
+ setArtifacts(data.artifacts || []);
4550
+ }
4551
+ } catch (error) {
4552
+ console.error("[MessageArtifacts] Failed to fetch artifacts:", error);
4553
+ } finally {
4554
+ setIsLoading(false);
4555
+ }
4556
+ }, [threadId, messageId, widgetContext]);
4557
+ React2.useEffect(() => {
4558
+ fetchArtifacts();
4559
+ }, [fetchArtifacts]);
4560
+ if (isLoading) {
4561
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center gap-2 text-xs text-muted-foreground", children: [
4562
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2Icon, { className: "h-3 w-3 animate-spin" }),
4563
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Loading artifacts..." })
4564
+ ] });
4565
+ }
4566
+ if (artifacts.length === 0) {
4567
+ return null;
4568
+ }
4569
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4570
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 space-y-2", children: artifacts.map((artifact) => /* @__PURE__ */ jsxRuntime.jsx(
4571
+ ArtifactCard2,
4572
+ {
4573
+ artifact,
4574
+ onOpen: setSelectedArtifact
4575
+ },
4576
+ artifact.id
4577
+ )) }),
4578
+ selectedArtifact && /* @__PURE__ */ jsxRuntime.jsx(
4579
+ ArtifactDialog,
4580
+ {
4581
+ artifact: selectedArtifact,
4582
+ onClose: () => setSelectedArtifact(null)
4583
+ }
4584
+ )
4585
+ ] });
4586
+ };
4587
+ var ToolFallback = ({
4588
+ toolName,
4589
+ argsText,
4590
+ result,
4591
+ status
4592
+ }) => {
4593
+ const isStreaming = status?.type === "running";
4594
+ const isError = status?.type === "incomplete";
4595
+ const isCancelled = status?.type === "incomplete" && status.reason === "cancelled";
4596
+ const cancelledReason = isCancelled && status.error ? typeof status.error === "string" ? status.error : JSON.stringify(status.error) : null;
4597
+ const titlePrefix = isCancelled ? "Cancelled: " : isStreaming ? "Running: " : "";
4598
+ return /* @__PURE__ */ jsxRuntime.jsx(
4599
+ ToolCard,
4600
+ {
4601
+ title: `${titlePrefix}${toolName}`,
4602
+ isStreaming,
4603
+ isError,
4604
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 text-white", children: [
4605
+ cancelledReason && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
4606
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-white/70 mb-0.5", children: "Cancelled reason:" }),
4607
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-white/60", children: cancelledReason })
4608
+ ] }),
4609
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(isCancelled && "opacity-60"), children: [
4610
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-white/70 mb-0.5", children: "Arguments:" }),
4611
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "whitespace-pre-wrap bg-black/20 p-1.5 rounded text-white/80", children: argsText })
4612
+ ] }),
4613
+ !isCancelled && result !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-white/10 pt-2", children: [
4614
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-white/70 mb-0.5", children: "Result:" }),
4615
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "whitespace-pre-wrap bg-black/20 p-1.5 rounded text-white/80", children: typeof result === "string" ? result : JSON.stringify(result, null, 2) })
4616
+ ] })
4617
+ ] })
4618
+ }
4619
+ );
4620
+ };
3734
4621
  var TYPE_ICONS2 = {
3735
4622
  attachment: lucideReact.FileIcon,
3736
4623
  description: lucideReact.FileTextIcon,
@@ -3814,208 +4701,6 @@ var UserMessageContent = () => {
3814
4701
  }, [message.content]);
3815
4702
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: renderedContent });
3816
4703
  };
3817
- var CATEGORY_LABELS = {
3818
- attachment: "Attachments",
3819
- description: "Description",
3820
- caption: "Video",
3821
- link: "Links",
3822
- lesson: "Current Lesson"
3823
- };
3824
- function useContextMention(options = {}) {
3825
- const { onInsertMention } = options;
3826
- const widgetContext = React2.useContext(WidgetContext);
3827
- if (!widgetContext) {
3828
- throw new Error("useContextMention must be used within a WidgetProvider");
3829
- }
3830
- const { client } = widgetContext;
3831
- const {
3832
- selectedContext: selectedItems,
3833
- addContextItem,
3834
- removeContextItem,
3835
- clearContext
3836
- } = useMessageContext();
3837
- const { lessonContext, hasLessonContext } = useLessonContext();
3838
- React2.useEffect(() => {
3839
- if (hasLessonContext && lessonContext) {
3840
- const lessonItem = {
3841
- id: lessonContext.lessonId,
3842
- type: "lesson",
3843
- title: lessonContext.lessonTitle,
3844
- lessonTitle: lessonContext.lessonTitle,
3845
- chapterTitle: lessonContext.chapterTitle
3846
- };
3847
- if (!selectedItems.some((item) => item.id === lessonItem.id)) {
3848
- console.log(
3849
- "[ContextMention] Auto-adding current lesson context:",
3850
- lessonItem.title
3851
- );
3852
- addContextItem(lessonItem);
3853
- }
3854
- }
3855
- }, [hasLessonContext]);
3856
- const [isOpen, setIsOpen] = React2.useState(false);
3857
- const [searchTerm, setSearchTerm] = React2.useState("");
3858
- const [activeIndex, setActiveIndex] = React2.useState(0);
3859
- const [isLoading, setIsLoading] = React2.useState(false);
3860
- const [categories, setCategories] = React2.useState([]);
3861
- const [hasMore, setHasMore] = React2.useState(false);
3862
- const config = client.getConfig();
3863
- const baseUrl = config.baseUrl || "http://localhost:3000";
3864
- const assistantId = config.apiKey;
3865
- const fetchContextItems = React2.useCallback(
3866
- async (search = "", limit = 10) => {
3867
- setIsLoading(true);
3868
- try {
3869
- const params = new URLSearchParams({
3870
- limit: limit.toString()
3871
- });
3872
- if (search) {
3873
- params.set("search", search);
3874
- }
3875
- const response = await fetch(
3876
- `${baseUrl}/api/widget/context?${params.toString()}`,
3877
- {
3878
- headers: {
3879
- "Content-Type": "application/json",
3880
- "X-Assistant-Id": assistantId
3881
- }
3882
- }
3883
- );
3884
- if (!response.ok) {
3885
- console.error(
3886
- "[ContextMention] Failed to fetch context:",
3887
- response.status
3888
- );
3889
- return;
3890
- }
3891
- const data = await response.json();
3892
- setCategories(data.categories);
3893
- setHasMore(data.hasMore);
3894
- } catch (error) {
3895
- console.error("[ContextMention] Error fetching context:", error);
3896
- } finally {
3897
- setIsLoading(false);
3898
- }
3899
- },
3900
- [baseUrl, assistantId]
3901
- );
3902
- const openPopover = React2.useCallback(() => {
3903
- setIsOpen(true);
3904
- setSearchTerm("");
3905
- setActiveIndex(0);
3906
- fetchContextItems();
3907
- }, [fetchContextItems]);
3908
- const closePopover = React2.useCallback(() => {
3909
- setIsOpen(false);
3910
- setSearchTerm("");
3911
- setActiveIndex(0);
3912
- }, []);
3913
- const updateSearch = React2.useCallback(
3914
- (term) => {
3915
- setSearchTerm(term);
3916
- setActiveIndex(0);
3917
- fetchContextItems(term);
3918
- },
3919
- [fetchContextItems]
3920
- );
3921
- const flattenedItems = React2.useMemo(() => {
3922
- return categories.flatMap((category) => category.items);
3923
- }, [categories]);
3924
- const navigateDown = React2.useCallback(() => {
3925
- setActiveIndex(
3926
- (prev2) => prev2 < flattenedItems.length - 1 ? prev2 + 1 : prev2
3927
- );
3928
- }, [flattenedItems.length]);
3929
- const navigateUp = React2.useCallback(() => {
3930
- setActiveIndex((prev2) => prev2 > 0 ? prev2 - 1 : 0);
3931
- }, []);
3932
- const selectActiveItem = React2.useCallback(() => {
3933
- const item = flattenedItems[activeIndex];
3934
- if (item) {
3935
- addContextItem(item);
3936
- closePopover();
3937
- onInsertMention?.(item);
3938
- }
3939
- }, [
3940
- flattenedItems,
3941
- activeIndex,
3942
- addContextItem,
3943
- closePopover,
3944
- onInsertMention
3945
- ]);
3946
- const selectItem = React2.useCallback(
3947
- (item) => {
3948
- addContextItem(item);
3949
- closePopover();
3950
- onInsertMention?.(item);
3951
- },
3952
- [addContextItem, closePopover, onInsertMention]
3953
- );
3954
- const removeItem = React2.useCallback(
3955
- (itemId) => {
3956
- removeContextItem(itemId);
3957
- },
3958
- [removeContextItem]
3959
- );
3960
- const clearAll = React2.useCallback(() => {
3961
- clearContext();
3962
- }, [clearContext]);
3963
- const handleKeyDown = React2.useCallback(
3964
- (event) => {
3965
- if (!isOpen) return;
3966
- switch (event.key) {
3967
- case "ArrowDown":
3968
- event.preventDefault();
3969
- navigateDown();
3970
- break;
3971
- case "ArrowUp":
3972
- event.preventDefault();
3973
- navigateUp();
3974
- break;
3975
- case "Enter":
3976
- event.preventDefault();
3977
- selectActiveItem();
3978
- break;
3979
- case "Escape":
3980
- event.preventDefault();
3981
- closePopover();
3982
- break;
3983
- }
3984
- },
3985
- [isOpen, navigateDown, navigateUp, selectActiveItem, closePopover]
3986
- );
3987
- const getCategoryLabel = React2.useCallback((type) => {
3988
- return CATEGORY_LABELS[type] || type;
3989
- }, []);
3990
- return {
3991
- // Selected items
3992
- selectedItems,
3993
- selectItem,
3994
- removeItem,
3995
- clearAll,
3996
- // Popover state
3997
- isOpen,
3998
- openPopover,
3999
- closePopover,
4000
- // Search
4001
- searchTerm,
4002
- updateSearch,
4003
- // Navigation
4004
- activeIndex,
4005
- setActiveIndex,
4006
- navigateUp,
4007
- navigateDown,
4008
- selectActiveItem,
4009
- handleKeyDown,
4010
- // Data
4011
- categories,
4012
- flattenedItems,
4013
- isLoading,
4014
- hasMore,
4015
- // Utilities
4016
- getCategoryLabel
4017
- };
4018
- }
4019
4704
  var Thread = () => {
4020
4705
  return /* @__PURE__ */ jsxRuntime.jsx(
4021
4706
  react$1.ThreadPrimitive.Root,
@@ -4024,29 +4709,23 @@ var Thread = () => {
4024
4709
  style: {
4025
4710
  ["--thread-max-width"]: "44rem"
4026
4711
  },
4027
- children: /* @__PURE__ */ jsxRuntime.jsxs(
4028
- react$1.ThreadPrimitive.Viewport,
4029
- {
4030
- className: "aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll scroll-smooth px-4 pt-4",
4031
- children: [
4032
- /* @__PURE__ */ jsxRuntime.jsx(react$1.AssistantIf, { condition: ({ thread }) => thread.isEmpty, children: /* @__PURE__ */ jsxRuntime.jsx(ThreadWelcome, {}) }),
4033
- /* @__PURE__ */ jsxRuntime.jsx(
4034
- react$1.ThreadPrimitive.Messages,
4035
- {
4036
- components: {
4037
- UserMessage,
4038
- EditComposer,
4039
- AssistantMessage
4040
- }
4041
- }
4042
- ),
4043
- /* @__PURE__ */ jsxRuntime.jsxs(react$1.ThreadPrimitive.ViewportFooter, { className: "aui-thread-viewport-footer sticky bottom-0 mx-auto mt-auto flex w-full max-w-(--thread-max-width) flex-col gap-4 overflow-visible rounded-t-3xl bg-background pb-4", children: [
4044
- /* @__PURE__ */ jsxRuntime.jsx(ThreadScrollToBottom, {}),
4045
- /* @__PURE__ */ jsxRuntime.jsx(Composer, {})
4046
- ] })
4047
- ]
4048
- }
4049
- )
4712
+ children: /* @__PURE__ */ jsxRuntime.jsxs(react$1.ThreadPrimitive.Viewport, { className: "aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll scroll-smooth px-4 pt-4", children: [
4713
+ /* @__PURE__ */ jsxRuntime.jsx(react$1.AssistantIf, { condition: ({ thread }) => thread.isEmpty, children: /* @__PURE__ */ jsxRuntime.jsx(ThreadWelcome, {}) }),
4714
+ /* @__PURE__ */ jsxRuntime.jsx(
4715
+ react$1.ThreadPrimitive.Messages,
4716
+ {
4717
+ components: {
4718
+ UserMessage,
4719
+ EditComposer,
4720
+ AssistantMessage
4721
+ }
4722
+ }
4723
+ ),
4724
+ /* @__PURE__ */ jsxRuntime.jsxs(react$1.ThreadPrimitive.ViewportFooter, { className: "aui-thread-viewport-footer sticky bottom-0 mx-auto mt-auto flex w-full max-w-(--thread-max-width) flex-col overflow-visible rounded-t-3xl bg-background pb-4", children: [
4725
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsx(ThreadScrollToBottom, {}) }),
4726
+ /* @__PURE__ */ jsxRuntime.jsx(Composer, {})
4727
+ ] })
4728
+ ] })
4050
4729
  }
4051
4730
  );
4052
4731
  };
@@ -4056,8 +4735,8 @@ var ThreadScrollToBottom = () => {
4056
4735
  {
4057
4736
  tooltip: "Scroll to bottom",
4058
4737
  variant: "outline",
4059
- className: "aui-thread-scroll-to-bottom absolute -top-12 z-10 self-center rounded-full p-4 disabled:invisible dark:bg-background dark:hover:bg-accent",
4060
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownIcon, {})
4738
+ className: "aui-thread-scroll-to-bottom absolute -top-10 right-2 z-10 rounded-full p-2 disabled:invisible dark:bg-background dark:hover:bg-accent",
4739
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownIcon, { className: "h-4 w-4" })
4061
4740
  }
4062
4741
  ) });
4063
4742
  };
@@ -4354,7 +5033,8 @@ var AssistantMessage = () => {
4354
5033
  }
4355
5034
  }
4356
5035
  ),
4357
- /* @__PURE__ */ jsxRuntime.jsx(MessageError, {})
5036
+ /* @__PURE__ */ jsxRuntime.jsx(MessageError, {}),
5037
+ /* @__PURE__ */ jsxRuntime.jsx(MessageArtifacts, {})
4358
5038
  ] }),
4359
5039
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "aui-assistant-message-footer mt-1 ml-2 flex", children: [
4360
5040
  /* @__PURE__ */ jsxRuntime.jsx(BranchPicker, {}),
@@ -4601,6 +5281,10 @@ var ChatWidget = ({
4601
5281
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-1 h-full w-full overflow-hidden bg-background", children: [
4602
5282
  /* @__PURE__ */ jsxRuntime.jsx(ArtifactToolUIs, {}),
4603
5283
  /* @__PURE__ */ jsxRuntime.jsx(DetailedAnswerToolUI, {}),
5284
+ /* @__PURE__ */ jsxRuntime.jsx(MermaidToolUI, {}),
5285
+ /* @__PURE__ */ jsxRuntime.jsx(ClarifyingQuestionsToolUI, {}),
5286
+ /* @__PURE__ */ jsxRuntime.jsx(AudiobookToolUI, {}),
5287
+ /* @__PURE__ */ jsxRuntime.jsx(QuizToolUI2, {}),
4604
5288
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 flex-col min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden relative", children: /* @__PURE__ */ jsxRuntime.jsx(Thread, {}) }) }),
4605
5289
  /* @__PURE__ */ jsxRuntime.jsx(react.AnimatePresence, { children: sidebarOpen && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4606
5290
  /* @__PURE__ */ jsxRuntime.jsx(