@yourgpt/copilot-sdk 2.1.5-alpha.1 → 2.1.5-alpha.3

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.
Files changed (76) hide show
  1. package/dist/{chunk-4QXY2PBG.js → chunk-3AONOZLY.js} +2 -2
  2. package/dist/{chunk-4QXY2PBG.js.map → chunk-3AONOZLY.js.map} +1 -1
  3. package/dist/{chunk-JKGFQUHJ.cjs → chunk-MDS23G2S.cjs} +5 -5
  4. package/dist/{chunk-JKGFQUHJ.cjs.map → chunk-MDS23G2S.cjs.map} +1 -1
  5. package/dist/{chunk-5Q72LZ5H.js → chunk-PT2TOHG5.js} +7 -3
  6. package/dist/chunk-PT2TOHG5.js.map +1 -0
  7. package/dist/{chunk-ENFWM3EY.js → chunk-RKGRQRZU.js} +3 -3
  8. package/dist/{chunk-ENFWM3EY.js.map → chunk-RKGRQRZU.js.map} +1 -1
  9. package/dist/{chunk-IXWNDR7H.cjs → chunk-TCPAT3WG.cjs} +35 -31
  10. package/dist/chunk-TCPAT3WG.cjs.map +1 -0
  11. package/dist/{chunk-246B6X5D.cjs → chunk-TPB7XED6.cjs} +2 -2
  12. package/dist/{chunk-246B6X5D.cjs.map → chunk-TPB7XED6.cjs.map} +1 -1
  13. package/dist/{chunk-I3SQUNTT.cjs → chunk-WIXFZUEZ.cjs} +23 -23
  14. package/dist/{chunk-I3SQUNTT.cjs.map → chunk-WIXFZUEZ.cjs.map} +1 -1
  15. package/dist/{chunk-UXJ6LIZB.js → chunk-WZ2TOZ7M.js} +4 -4
  16. package/dist/{chunk-UXJ6LIZB.js.map → chunk-WZ2TOZ7M.js.map} +1 -1
  17. package/dist/core/index.cjs +82 -82
  18. package/dist/core/index.d.cts +3 -3
  19. package/dist/core/index.d.ts +3 -3
  20. package/dist/core/index.js +3 -3
  21. package/dist/{index-CiExk87c.d.cts → index-CzJB8Ddo.d.cts} +1 -1
  22. package/dist/{index-Dwrcf-CP.d.ts → index-D7169xuR.d.ts} +1 -1
  23. package/dist/mcp/index.d.cts +3 -3
  24. package/dist/mcp/index.d.ts +3 -3
  25. package/dist/react/index.cjs +65 -65
  26. package/dist/react/index.d.cts +8 -4
  27. package/dist/react/index.d.ts +8 -4
  28. package/dist/react/index.js +4 -4
  29. package/dist/styles.css +43 -0
  30. package/dist/tools/anthropic/index.d.cts +1 -1
  31. package/dist/tools/anthropic/index.d.ts +1 -1
  32. package/dist/tools/brave/index.cjs +2 -2
  33. package/dist/tools/brave/index.d.cts +1 -1
  34. package/dist/tools/brave/index.d.ts +1 -1
  35. package/dist/tools/brave/index.js +1 -1
  36. package/dist/tools/exa/index.cjs +2 -2
  37. package/dist/tools/exa/index.d.cts +1 -1
  38. package/dist/tools/exa/index.d.ts +1 -1
  39. package/dist/tools/exa/index.js +1 -1
  40. package/dist/tools/google/index.cjs +2 -2
  41. package/dist/tools/google/index.d.cts +1 -1
  42. package/dist/tools/google/index.d.ts +1 -1
  43. package/dist/tools/google/index.js +1 -1
  44. package/dist/tools/openai/index.cjs +2 -2
  45. package/dist/tools/openai/index.d.cts +1 -1
  46. package/dist/tools/openai/index.d.ts +1 -1
  47. package/dist/tools/openai/index.js +1 -1
  48. package/dist/tools/searxng/index.cjs +2 -2
  49. package/dist/tools/searxng/index.d.cts +1 -1
  50. package/dist/tools/searxng/index.d.ts +1 -1
  51. package/dist/tools/searxng/index.js +1 -1
  52. package/dist/tools/serper/index.cjs +2 -2
  53. package/dist/tools/serper/index.d.cts +1 -1
  54. package/dist/tools/serper/index.d.ts +1 -1
  55. package/dist/tools/serper/index.js +1 -1
  56. package/dist/tools/tavily/index.cjs +2 -2
  57. package/dist/tools/tavily/index.d.cts +1 -1
  58. package/dist/tools/tavily/index.d.ts +1 -1
  59. package/dist/tools/tavily/index.js +1 -1
  60. package/dist/tools/web-search/index.cjs +3 -3
  61. package/dist/tools/web-search/index.d.cts +2 -2
  62. package/dist/tools/web-search/index.d.ts +2 -2
  63. package/dist/tools/web-search/index.js +2 -2
  64. package/dist/{tools-DHZhF5km.d.cts → tools-tmksfhUo.d.cts} +9 -0
  65. package/dist/{tools-DHZhF5km.d.ts → tools-tmksfhUo.d.ts} +9 -0
  66. package/dist/{types-BdX7uPj0.d.cts → types-BLw7mxtW.d.cts} +1 -1
  67. package/dist/{types-BTyJu0WD.d.ts → types-BqwW3Baj.d.ts} +1 -1
  68. package/dist/ui/index.cjs +798 -417
  69. package/dist/ui/index.cjs.map +1 -1
  70. package/dist/ui/index.d.cts +337 -108
  71. package/dist/ui/index.d.ts +337 -108
  72. package/dist/ui/index.js +745 -365
  73. package/dist/ui/index.js.map +1 -1
  74. package/package.json +1 -1
  75. package/dist/chunk-5Q72LZ5H.js.map +0 -1
  76. package/dist/chunk-IXWNDR7H.cjs.map +0 -1
package/dist/ui/index.js CHANGED
@@ -1,10 +1,10 @@
1
- import { useCopilot, useThreadManager } from '../chunk-5Q72LZ5H.js';
2
- import { createServerAdapter } from '../chunk-UXJ6LIZB.js';
1
+ import { useCopilot, useThreadManager } from '../chunk-PT2TOHG5.js';
2
+ import { createServerAdapter } from '../chunk-WZ2TOZ7M.js';
3
3
  import { DEFAULT_MCP_UI_SANDBOX, parseMCPUIMessage } from '../chunk-G4SF2PNQ.js';
4
4
  import '../chunk-EWVQWTNV.js';
5
5
  import '../chunk-VNLLW3ZI.js';
6
- import '../chunk-ENFWM3EY.js';
7
- import '../chunk-4QXY2PBG.js';
6
+ import '../chunk-RKGRQRZU.js';
7
+ import '../chunk-3AONOZLY.js';
8
8
  import '../chunk-LLM7AHMO.js';
9
9
  import '../chunk-RQ74USYU.js';
10
10
  import '../chunk-7W7QLZNC.js';
@@ -18,8 +18,8 @@ import '../chunk-DGUM43GV.js';
18
18
  import { clsx } from 'clsx';
19
19
  import { twMerge } from 'tailwind-merge';
20
20
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
21
- import * as React18 from 'react';
22
- import React18__default, { memo, createContext, useState, useRef, useId, useCallback, useLayoutEffect, useContext, useEffect } from 'react';
21
+ import * as React19 from 'react';
22
+ import React19__default, { memo, createContext, useState, useRef, useId, useCallback, useMemo, useLayoutEffect, useContext, useEffect } from 'react';
23
23
  import { Streamdown } from 'streamdown';
24
24
  import { code } from '@streamdown/code';
25
25
  import { Slot } from '@radix-ui/react-slot';
@@ -384,7 +384,7 @@ var buttonVariants = cva(
384
384
  }
385
385
  }
386
386
  );
387
- var Button = React18.forwardRef(
387
+ var Button = React19.forwardRef(
388
388
  ({ className, variant, size, asChild = false, ...props }, ref) => {
389
389
  const Comp = asChild ? Slot : "button";
390
390
  return /* @__PURE__ */ jsx(
@@ -625,7 +625,7 @@ function TooltipTrigger({
625
625
  disabled,
626
626
  ...props
627
627
  }) {
628
- if (asChild && React18__default.isValidElement(children)) {
628
+ if (asChild && React19__default.isValidElement(children)) {
629
629
  return /* @__PURE__ */ jsx(Tooltip$1.Trigger, { disabled, render: children, ...props });
630
630
  }
631
631
  return /* @__PURE__ */ jsx(Tooltip$1.Trigger, { disabled, ...props, children });
@@ -654,7 +654,7 @@ function TooltipContent({
654
654
  }
655
655
  ) }) });
656
656
  }
657
- var Avatar = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
657
+ var Avatar = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
658
658
  AvatarPrimitive.Root,
659
659
  {
660
660
  ref,
@@ -666,7 +666,7 @@ var Avatar = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ *
666
666
  }
667
667
  ));
668
668
  Avatar.displayName = AvatarPrimitive.Root.displayName;
669
- var AvatarImage = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
669
+ var AvatarImage = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
670
670
  AvatarPrimitive.Image,
671
671
  {
672
672
  ref,
@@ -675,7 +675,7 @@ var AvatarImage = React18.forwardRef(({ className, ...props }, ref) => /* @__PUR
675
675
  }
676
676
  ));
677
677
  AvatarImage.displayName = AvatarPrimitive.Image.displayName;
678
- var AvatarFallback = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
678
+ var AvatarFallback = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
679
679
  AvatarPrimitive.Fallback,
680
680
  {
681
681
  ref,
@@ -735,7 +735,34 @@ var MessageContent = ({
735
735
  );
736
736
  return markdown ? /* @__PURE__ */ jsx(Markdown, { className: classNames, ...props, children }) : /* @__PURE__ */ jsx("div", { className: classNames, ...props, children });
737
737
  };
738
- var Textarea = React18.forwardRef(({ className, ...props }, ref) => {
738
+ var MessageActions = ({
739
+ children,
740
+ className,
741
+ ...props
742
+ }) => /* @__PURE__ */ jsx(
743
+ "div",
744
+ {
745
+ className: cn(
746
+ "csdk-message-actions text-muted-foreground flex items-center gap-2",
747
+ className
748
+ ),
749
+ ...props,
750
+ children
751
+ }
752
+ );
753
+ var MessageAction = ({
754
+ tooltip,
755
+ children,
756
+ className,
757
+ side = "top",
758
+ ...props
759
+ }) => {
760
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { ...props, children: [
761
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children }),
762
+ /* @__PURE__ */ jsx(TooltipContent, { side, className, children: tooltip })
763
+ ] }) });
764
+ };
765
+ var Textarea = React19.forwardRef(({ className, ...props }, ref) => {
739
766
  return /* @__PURE__ */ jsx(
740
767
  "textarea",
741
768
  {
@@ -899,7 +926,7 @@ function PromptInputAction({
899
926
  }
900
927
  var HoverCard = HoverCardPrimitive.Root;
901
928
  var HoverCardTrigger = HoverCardPrimitive.Trigger;
902
- var HoverCardContent = React18.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
929
+ var HoverCardContent = React19.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
903
930
  HoverCardPrimitive.Content,
904
931
  {
905
932
  ref,
@@ -1442,7 +1469,7 @@ function SourcesCollapsible({
1442
1469
  defaultExpanded = false,
1443
1470
  className
1444
1471
  }) {
1445
- const [expanded, setExpanded] = React18.useState(defaultExpanded);
1472
+ const [expanded, setExpanded] = React19.useState(defaultExpanded);
1446
1473
  if (citations.length === 0) return null;
1447
1474
  return /* @__PURE__ */ jsxs("div", { className: cn("border rounded-lg", className), children: [
1448
1475
  /* @__PURE__ */ jsxs(
@@ -1508,7 +1535,7 @@ function SourcesList({
1508
1535
  if (compact) {
1509
1536
  return /* @__PURE__ */ jsxs("div", { className: cn("text-xs text-muted-foreground", className), children: [
1510
1537
  /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Sources: " }),
1511
- citations.map((c, i) => /* @__PURE__ */ jsxs(React18.Fragment, { children: [
1538
+ citations.map((c, i) => /* @__PURE__ */ jsxs(React19.Fragment, { children: [
1512
1539
  /* @__PURE__ */ jsxs(
1513
1540
  "a",
1514
1541
  {
@@ -1586,11 +1613,11 @@ function resultsToCitations(results) {
1586
1613
  domain: result.domain || getDomain3(result.url)
1587
1614
  }));
1588
1615
  }
1589
- var ReasoningContext = React18.createContext(
1616
+ var ReasoningContext = React19.createContext(
1590
1617
  null
1591
1618
  );
1592
1619
  function useReasoningContext() {
1593
- const context = React18.useContext(ReasoningContext);
1620
+ const context = React19.useContext(ReasoningContext);
1594
1621
  if (!context) {
1595
1622
  throw new Error(
1596
1623
  "Reasoning components must be used within a Reasoning provider"
@@ -1606,11 +1633,11 @@ function Reasoning({
1606
1633
  defaultOpen = false,
1607
1634
  className
1608
1635
  }) {
1609
- const [uncontrolledOpen, setUncontrolledOpen] = React18.useState(defaultOpen);
1610
- const prevStreamingRef = React18.useRef(isStreaming);
1636
+ const [uncontrolledOpen, setUncontrolledOpen] = React19.useState(defaultOpen);
1637
+ const prevStreamingRef = React19.useRef(isStreaming);
1611
1638
  const isControlled = controlledOpen !== void 0;
1612
1639
  const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
1613
- const setIsOpen = React18.useCallback(
1640
+ const setIsOpen = React19.useCallback(
1614
1641
  (open) => {
1615
1642
  if (onOpenChange) {
1616
1643
  onOpenChange(open);
@@ -1621,7 +1648,7 @@ function Reasoning({
1621
1648
  },
1622
1649
  [isControlled, onOpenChange]
1623
1650
  );
1624
- React18.useEffect(() => {
1651
+ React19.useEffect(() => {
1625
1652
  if (isStreaming && !prevStreamingRef.current) {
1626
1653
  setIsOpen(true);
1627
1654
  } else if (!isStreaming && prevStreamingRef.current) {
@@ -1677,9 +1704,9 @@ function ReasoningContent({
1677
1704
  className
1678
1705
  }) {
1679
1706
  const { isOpen } = useReasoningContext();
1680
- const contentRef = React18.useRef(null);
1681
- const [height, setHeight] = React18.useState(0);
1682
- React18.useEffect(() => {
1707
+ const contentRef = React19.useRef(null);
1708
+ const [height, setHeight] = React19.useState(0);
1709
+ React19.useEffect(() => {
1683
1710
  if (contentRef.current) {
1684
1711
  const resizeObserver = new ResizeObserver((entries) => {
1685
1712
  for (const entry of entries) {
@@ -1728,11 +1755,11 @@ function SimpleReasoning({
1728
1755
  /* @__PURE__ */ jsx(ReasoningContent, { markdown, children: content })
1729
1756
  ] });
1730
1757
  }
1731
- var CopilotUIContext = React18.createContext(
1758
+ var CopilotUIContext = React19.createContext(
1732
1759
  null
1733
1760
  );
1734
1761
  function useCopilotUI() {
1735
- const context = React18.useContext(CopilotUIContext);
1762
+ const context = React19.useContext(CopilotUIContext);
1736
1763
  if (!context) {
1737
1764
  return {
1738
1765
  debug: false,
@@ -1747,7 +1774,7 @@ function CopilotUIProvider({
1747
1774
  debug = false,
1748
1775
  defaultDebugExpanded = false
1749
1776
  }) {
1750
- const value = React18.useMemo(
1777
+ const value = React19.useMemo(
1751
1778
  () => ({
1752
1779
  debug,
1753
1780
  defaultDebugExpanded,
@@ -1890,7 +1917,7 @@ function ToolStep({
1890
1917
  }) {
1891
1918
  const { isDebug, defaultDebugExpanded } = useCopilotUI();
1892
1919
  const debug = debugProp ?? isDebug;
1893
- const [expanded, setExpanded] = React18.useState(
1920
+ const [expanded, setExpanded] = React19.useState(
1894
1921
  defaultExpanded ?? defaultDebugExpanded ?? false
1895
1922
  );
1896
1923
  const displayTitle = getDisplayTitle(step);
@@ -2371,9 +2398,9 @@ function ArrowUpRightIcon({ className }) {
2371
2398
  }
2372
2399
  );
2373
2400
  }
2374
- var ConfirmationContext = React18.createContext(null);
2401
+ var ConfirmationContext = React19.createContext(null);
2375
2402
  function useConfirmationContext() {
2376
- const context = React18.useContext(ConfirmationContext);
2403
+ const context = React19.useContext(ConfirmationContext);
2377
2404
  if (!context) {
2378
2405
  throw new Error(
2379
2406
  "Confirmation components must be used within a Confirmation provider"
@@ -2541,30 +2568,27 @@ function PermissionConfirmation({
2541
2568
  message,
2542
2569
  onApprove,
2543
2570
  onReject,
2544
- showPermissionOptions = true,
2545
- permissionOptions = DEFAULT_PERMISSION_OPTIONS,
2546
2571
  className
2547
2572
  }) {
2548
- const [selectedPermission, setSelectedPermission] = React18.useState("ask");
2549
- const [showOptions, setShowOptions] = React18.useState(false);
2550
2573
  const handleApprove = () => {
2551
- onApprove?.(selectedPermission);
2574
+ onApprove?.("ask");
2552
2575
  };
2553
2576
  const handleReject = () => {
2554
- onReject?.(
2555
- selectedPermission === "deny_always" ? "deny_always" : void 0
2556
- );
2577
+ onReject?.(void 0);
2557
2578
  };
2558
2579
  if (state === "approved") {
2559
2580
  return /* @__PURE__ */ jsxs(
2560
2581
  "div",
2561
2582
  {
2562
2583
  className: cn(
2563
- "flex items-center gap-2 px-4 py-2 text-sm text-green-600 dark:text-green-400 rounded-lg border bg-green-50 dark:bg-green-950/20",
2584
+ "csdk-confirm-result",
2585
+ "inline-flex items-center gap-2 px-3 py-1.5 text-sm",
2586
+ "rounded-2xl border border-green-200/70 dark:border-green-900/40",
2587
+ "bg-green-50 dark:bg-green-950/20 text-green-700 dark:text-green-400",
2564
2588
  className
2565
2589
  ),
2566
2590
  children: [
2567
- /* @__PURE__ */ jsx(CheckIcon, { className: "h-4 w-4" }),
2591
+ /* @__PURE__ */ jsx(CheckIcon, { className: "h-3.5 w-3.5 shrink-0" }),
2568
2592
  /* @__PURE__ */ jsx("span", { children: "Approved" })
2569
2593
  ]
2570
2594
  }
@@ -2575,11 +2599,14 @@ function PermissionConfirmation({
2575
2599
  "div",
2576
2600
  {
2577
2601
  className: cn(
2578
- "flex items-center gap-2 px-4 py-2 text-sm text-red-600 dark:text-red-400 rounded-lg border bg-red-50 dark:bg-red-950/20",
2602
+ "csdk-confirm-result",
2603
+ "inline-flex items-center gap-2 px-3 py-1.5 text-sm",
2604
+ "rounded-2xl border border-red-200/70 dark:border-red-900/40",
2605
+ "bg-red-50 dark:bg-red-950/20 text-red-700 dark:text-red-400",
2579
2606
  className
2580
2607
  ),
2581
2608
  children: [
2582
- /* @__PURE__ */ jsx(XIcon2, { className: "h-4 w-4" }),
2609
+ /* @__PURE__ */ jsx(XIcon2, { className: "h-3.5 w-3.5 shrink-0" }),
2583
2610
  /* @__PURE__ */ jsx("span", { children: "Rejected" })
2584
2611
  ]
2585
2612
  }
@@ -2589,81 +2616,47 @@ function PermissionConfirmation({
2589
2616
  "div",
2590
2617
  {
2591
2618
  className: cn(
2592
- "rounded-lg border bg-card text-card-foreground p-4",
2619
+ "csdk-confirm-card",
2620
+ "w-full rounded-2xl border border-border/60 bg-card text-card-foreground shadow-sm overflow-hidden",
2593
2621
  className
2594
2622
  ),
2595
2623
  children: [
2596
- /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 mb-3", children: [
2597
- /* @__PURE__ */ jsx(AlertTriangleIcon, { className: "mt-0.5 h-5 w-5 flex-shrink-0 text-amber-500" }),
2598
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
2599
- toolName && /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: toolName }),
2600
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: message || "This tool requires your approval to execute." })
2624
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 p-4", children: [
2625
+ /* @__PURE__ */ jsx("div", { className: "mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-xl bg-amber-100 dark:bg-amber-950/50", children: /* @__PURE__ */ jsx(AlertTriangleIcon, { className: "h-3.5 w-3.5 text-amber-600 dark:text-amber-400" }) }),
2626
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0 pt-0.5", children: [
2627
+ toolName && /* @__PURE__ */ jsx("p", { className: "text-[10px] font-semibold uppercase tracking-widest text-muted-foreground mb-1", children: toolName }),
2628
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-foreground leading-snug", children: message || "This tool requires your approval to execute." })
2601
2629
  ] })
2602
2630
  ] }),
2603
- showPermissionOptions && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
2604
- /* @__PURE__ */ jsxs(
2631
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2 px-4 pb-4", children: [
2632
+ /* @__PURE__ */ jsx(
2605
2633
  "button",
2606
2634
  {
2607
2635
  type: "button",
2608
- onClick: () => setShowOptions(!showOptions),
2609
- className: "flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors",
2610
- children: [
2611
- /* @__PURE__ */ jsx("span", { children: permissionOptions.find((o) => o.value === selectedPermission)?.label }),
2612
- /* @__PURE__ */ jsx(
2613
- "svg",
2614
- {
2615
- className: cn(
2616
- "h-4 w-4 transition-transform",
2617
- showOptions && "rotate-180"
2618
- ),
2619
- fill: "none",
2620
- viewBox: "0 0 24 24",
2621
- stroke: "currentColor",
2622
- strokeWidth: 2,
2623
- children: /* @__PURE__ */ jsx(
2624
- "path",
2625
- {
2626
- strokeLinecap: "round",
2627
- strokeLinejoin: "round",
2628
- d: "M19 9l-7 7-7-7"
2629
- }
2630
- )
2631
- }
2632
- )
2633
- ]
2636
+ onClick: handleReject,
2637
+ className: cn(
2638
+ "csdk-confirm-btn",
2639
+ "px-4 py-1.5 text-sm font-medium rounded-xl",
2640
+ "border border-border bg-transparent text-muted-foreground",
2641
+ "hover:bg-muted/60 hover:text-foreground"
2642
+ ),
2643
+ children: "Deny"
2634
2644
  }
2635
2645
  ),
2636
- showOptions && /* @__PURE__ */ jsx("div", { className: "mt-2 space-y-1 pl-1", children: permissionOptions.map((option) => /* @__PURE__ */ jsxs(
2637
- "label",
2646
+ /* @__PURE__ */ jsx(
2647
+ "button",
2638
2648
  {
2649
+ type: "button",
2650
+ onClick: handleApprove,
2639
2651
  className: cn(
2640
- "flex items-start gap-2 p-2 rounded-md cursor-pointer transition-colors",
2641
- selectedPermission === option.value ? "bg-primary/10" : "hover:bg-muted/50"
2652
+ "csdk-confirm-btn",
2653
+ "px-4 py-1.5 text-sm font-medium rounded-xl",
2654
+ "bg-primary text-primary-foreground",
2655
+ "hover:opacity-90"
2642
2656
  ),
2643
- children: [
2644
- /* @__PURE__ */ jsx(
2645
- "input",
2646
- {
2647
- type: "radio",
2648
- name: "permission",
2649
- value: option.value,
2650
- checked: selectedPermission === option.value,
2651
- onChange: () => setSelectedPermission(option.value),
2652
- className: "mt-0.5"
2653
- }
2654
- ),
2655
- /* @__PURE__ */ jsxs("div", { children: [
2656
- /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: option.label }),
2657
- option.description && /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: option.description })
2658
- ] })
2659
- ]
2660
- },
2661
- option.value
2662
- )) })
2663
- ] }),
2664
- /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
2665
- /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: handleReject, children: "Deny" }),
2666
- /* @__PURE__ */ jsx(Button, { variant: "default", size: "sm", onClick: handleApprove, children: "Allow" })
2657
+ children: "Allow"
2658
+ }
2659
+ )
2667
2660
  ] })
2668
2661
  ]
2669
2662
  }
@@ -2676,23 +2669,25 @@ function CompactPermissionConfirmation({
2676
2669
  onReject,
2677
2670
  className
2678
2671
  }) {
2679
- const [rememberChoice, setRememberChoice] = React18.useState(false);
2680
2672
  const handleApprove = () => {
2681
- onApprove?.(rememberChoice ? "allow_always" : "ask");
2673
+ onApprove?.("ask");
2682
2674
  };
2683
2675
  const handleReject = () => {
2684
- onReject?.(rememberChoice ? "deny_always" : void 0);
2676
+ onReject?.(void 0);
2685
2677
  };
2686
2678
  if (state === "approved") {
2687
2679
  return /* @__PURE__ */ jsxs(
2688
2680
  "div",
2689
2681
  {
2690
2682
  className: cn(
2691
- "flex items-center gap-2 px-4 py-2 text-sm text-green-600 dark:text-green-400",
2683
+ "csdk-confirm-result",
2684
+ "inline-flex items-center gap-2 px-3 py-1.5 text-sm",
2685
+ "rounded-2xl border border-green-200/70 dark:border-green-900/40",
2686
+ "bg-green-50 dark:bg-green-950/20 text-green-700 dark:text-green-400",
2692
2687
  className
2693
2688
  ),
2694
2689
  children: [
2695
- /* @__PURE__ */ jsx(CheckIcon, { className: "h-4 w-4" }),
2690
+ /* @__PURE__ */ jsx(CheckIcon, { className: "h-3.5 w-3.5 shrink-0" }),
2696
2691
  /* @__PURE__ */ jsx("span", { children: "Approved" })
2697
2692
  ]
2698
2693
  }
@@ -2703,11 +2698,14 @@ function CompactPermissionConfirmation({
2703
2698
  "div",
2704
2699
  {
2705
2700
  className: cn(
2706
- "flex items-center gap-2 px-4 py-2 text-sm text-red-600 dark:text-red-400",
2701
+ "csdk-confirm-result",
2702
+ "inline-flex items-center gap-2 px-3 py-1.5 text-sm",
2703
+ "rounded-2xl border border-red-200/70 dark:border-red-900/40",
2704
+ "bg-red-50 dark:bg-red-950/20 text-red-700 dark:text-red-400",
2707
2705
  className
2708
2706
  ),
2709
2707
  children: [
2710
- /* @__PURE__ */ jsx(XIcon2, { className: "h-4 w-4" }),
2708
+ /* @__PURE__ */ jsx(XIcon2, { className: "h-3.5 w-3.5 shrink-0" }),
2711
2709
  /* @__PURE__ */ jsx("span", { children: "Rejected" })
2712
2710
  ]
2713
2711
  }
@@ -2717,31 +2715,44 @@ function CompactPermissionConfirmation({
2717
2715
  "div",
2718
2716
  {
2719
2717
  className: cn(
2720
- "rounded-lg border bg-card text-card-foreground p-4",
2718
+ "csdk-confirm-card",
2719
+ "w-full rounded-2xl border border-border/60 bg-card text-card-foreground shadow-sm overflow-hidden",
2721
2720
  className
2722
2721
  ),
2723
2722
  children: [
2724
- /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 mb-3", children: [
2725
- /* @__PURE__ */ jsx(AlertTriangleIcon, { className: "mt-0.5 h-5 w-5 flex-shrink-0 text-amber-500" }),
2726
- /* @__PURE__ */ jsx("p", { className: "text-sm text-foreground", children: message || "This action requires your approval." })
2723
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 p-4", children: [
2724
+ /* @__PURE__ */ jsx("div", { className: "mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-xl bg-amber-100 dark:bg-amber-950/50", children: /* @__PURE__ */ jsx(AlertTriangleIcon, { className: "h-3.5 w-3.5 text-amber-600 dark:text-amber-400" }) }),
2725
+ /* @__PURE__ */ jsx("p", { className: "flex-1 min-w-0 pt-0.5 text-sm text-foreground leading-snug", children: message || "This action requires your approval." })
2727
2726
  ] }),
2728
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
2729
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm text-muted-foreground cursor-pointer", children: [
2730
- /* @__PURE__ */ jsx(
2731
- "input",
2732
- {
2733
- type: "checkbox",
2734
- checked: rememberChoice,
2735
- onChange: (e) => setRememberChoice(e.target.checked),
2736
- className: "rounded border-gray-300"
2737
- }
2738
- ),
2739
- "Don't ask again"
2740
- ] }),
2741
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
2742
- /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: handleReject, children: "Deny" }),
2743
- /* @__PURE__ */ jsx(Button, { variant: "default", size: "sm", onClick: handleApprove, children: "Allow" })
2744
- ] })
2727
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2 px-4 pb-4", children: [
2728
+ /* @__PURE__ */ jsx(
2729
+ "button",
2730
+ {
2731
+ type: "button",
2732
+ onClick: handleReject,
2733
+ className: cn(
2734
+ "csdk-confirm-btn",
2735
+ "px-4 py-1.5 text-sm font-medium rounded-xl",
2736
+ "border border-border bg-transparent text-muted-foreground",
2737
+ "hover:bg-muted/60 hover:text-foreground"
2738
+ ),
2739
+ children: "Deny"
2740
+ }
2741
+ ),
2742
+ /* @__PURE__ */ jsx(
2743
+ "button",
2744
+ {
2745
+ type: "button",
2746
+ onClick: handleApprove,
2747
+ className: cn(
2748
+ "csdk-confirm-btn",
2749
+ "px-4 py-1.5 text-sm font-medium rounded-xl",
2750
+ "bg-primary text-primary-foreground",
2751
+ "hover:opacity-90"
2752
+ ),
2753
+ children: "Allow"
2754
+ }
2755
+ )
2745
2756
  ] })
2746
2757
  ]
2747
2758
  }
@@ -3299,9 +3310,9 @@ function ModelSelector({
3299
3310
  showCapabilities = true,
3300
3311
  className
3301
3312
  }) {
3302
- const [isOpen, setIsOpen] = React18.useState(false);
3303
- const containerRef = React18.useRef(null);
3304
- React18.useEffect(() => {
3313
+ const [isOpen, setIsOpen] = React19.useState(false);
3314
+ const containerRef = React19.useRef(null);
3315
+ React19.useEffect(() => {
3305
3316
  function handleClickOutside(event) {
3306
3317
  if (containerRef.current && !containerRef.current.contains(event.target)) {
3307
3318
  setIsOpen(false);
@@ -3310,7 +3321,7 @@ function ModelSelector({
3310
3321
  document.addEventListener("mousedown", handleClickOutside);
3311
3322
  return () => document.removeEventListener("mousedown", handleClickOutside);
3312
3323
  }, []);
3313
- const selectedModel = React18.useMemo(() => {
3324
+ const selectedModel = React19.useMemo(() => {
3314
3325
  if (!value) return null;
3315
3326
  if (providers) {
3316
3327
  for (const provider of providers) {
@@ -3536,7 +3547,7 @@ function PopoverTrigger({
3536
3547
  className,
3537
3548
  ...props
3538
3549
  }) {
3539
- if (asChild && React18.isValidElement(children)) {
3550
+ if (asChild && React19.isValidElement(children)) {
3540
3551
  return /* @__PURE__ */ jsx(Popover$1.Trigger, { render: children, className, ...props });
3541
3552
  }
3542
3553
  return /* @__PURE__ */ jsx(Popover$1.Trigger, { className, ...props, children });
@@ -3671,8 +3682,8 @@ function ThreadPicker({
3671
3682
  itemClassName,
3672
3683
  newButtonClassName
3673
3684
  }) {
3674
- const [isOpen, setIsOpen] = React18.useState(false);
3675
- const selectedThread = React18.useMemo(() => {
3685
+ const [isOpen, setIsOpen] = React19.useState(false);
3686
+ const selectedThread = React19.useMemo(() => {
3676
3687
  if (!value) return null;
3677
3688
  return threads.find((t) => t.id === value) ?? null;
3678
3689
  }, [value, threads]);
@@ -3878,7 +3889,7 @@ function ThreadCard({
3878
3889
  showDelete = true,
3879
3890
  className
3880
3891
  }) {
3881
- const [isHovered, setIsHovered] = React18.useState(false);
3892
+ const [isHovered, setIsHovered] = React19.useState(false);
3882
3893
  const handleDelete = (e) => {
3883
3894
  e.stopPropagation();
3884
3895
  onDelete?.();
@@ -4119,10 +4130,10 @@ function MCPUIFrame({
4119
4130
  showLoading = true,
4120
4131
  testId
4121
4132
  }) {
4122
- const iframeRef = React18.useRef(null);
4123
- const [isLoading, setIsLoading] = React18.useState(true);
4124
- const [error, setError] = React18.useState(null);
4125
- React18.useEffect(() => {
4133
+ const iframeRef = React19.useRef(null);
4134
+ const [isLoading, setIsLoading] = React19.useState(true);
4135
+ const [error, setError] = React19.useState(null);
4136
+ React19.useEffect(() => {
4126
4137
  const handleMessage = (event) => {
4127
4138
  if (event.source !== iframeRef.current?.contentWindow) {
4128
4139
  return;
@@ -4135,17 +4146,17 @@ function MCPUIFrame({
4135
4146
  window.addEventListener("message", handleMessage);
4136
4147
  return () => window.removeEventListener("message", handleMessage);
4137
4148
  }, [onIntent]);
4138
- const handleLoad = React18.useCallback(() => {
4149
+ const handleLoad = React19.useCallback(() => {
4139
4150
  setIsLoading(false);
4140
4151
  onLoad?.();
4141
4152
  }, [onLoad]);
4142
- const handleError = React18.useCallback(() => {
4153
+ const handleError = React19.useCallback(() => {
4143
4154
  const err = new Error("Failed to load MCP UI content");
4144
4155
  setError(err);
4145
4156
  setIsLoading(false);
4146
4157
  onError?.(err);
4147
4158
  }, [onError]);
4148
- const { srcDoc, src } = React18.useMemo(() => {
4159
+ const { srcDoc, src } = React19.useMemo(() => {
4149
4160
  if (resource.mimeType === "text/html") {
4150
4161
  let content = resource.content || "";
4151
4162
  if (resource.blob && !resource.content) {
@@ -4295,6 +4306,284 @@ function MCPUIFrameList({
4295
4306
  `${resource.uri}-${index}`
4296
4307
  )) });
4297
4308
  }
4309
+ var MessageActionsContext = createContext(
4310
+ null
4311
+ );
4312
+ function MessageActionsProvider({
4313
+ children
4314
+ }) {
4315
+ const [registry, setRegistry] = useState(
4316
+ {}
4317
+ );
4318
+ const registerActions = useCallback(
4319
+ (role, actions) => {
4320
+ setRegistry((prev) => ({ ...prev, [role]: actions }));
4321
+ },
4322
+ []
4323
+ );
4324
+ const clearActions = useCallback((role) => {
4325
+ setRegistry((prev) => {
4326
+ const next = { ...prev };
4327
+ delete next[role];
4328
+ return next;
4329
+ });
4330
+ }, []);
4331
+ const getActions = useCallback(
4332
+ (role) => registry[role] ?? [],
4333
+ [registry]
4334
+ );
4335
+ return /* @__PURE__ */ jsx(
4336
+ MessageActionsContext.Provider,
4337
+ {
4338
+ value: { getActions, registerActions, clearActions },
4339
+ children
4340
+ }
4341
+ );
4342
+ }
4343
+ function useMessageActionsContext() {
4344
+ return useContext(MessageActionsContext);
4345
+ }
4346
+ createContext(null);
4347
+ function CopyIcon2() {
4348
+ return /* @__PURE__ */ jsxs(
4349
+ "svg",
4350
+ {
4351
+ width: "13",
4352
+ height: "13",
4353
+ viewBox: "0 0 24 24",
4354
+ fill: "none",
4355
+ stroke: "currentColor",
4356
+ strokeWidth: 2,
4357
+ strokeLinecap: "round",
4358
+ strokeLinejoin: "round",
4359
+ children: [
4360
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
4361
+ /* @__PURE__ */ jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
4362
+ ]
4363
+ }
4364
+ );
4365
+ }
4366
+ function CheckIcon3() {
4367
+ return /* @__PURE__ */ jsx(
4368
+ "svg",
4369
+ {
4370
+ width: "13",
4371
+ height: "13",
4372
+ viewBox: "0 0 24 24",
4373
+ fill: "none",
4374
+ stroke: "currentColor",
4375
+ strokeWidth: 2.5,
4376
+ strokeLinecap: "round",
4377
+ strokeLinejoin: "round",
4378
+ children: /* @__PURE__ */ jsx("path", { d: "M20 6L9 17l-5-5" })
4379
+ }
4380
+ );
4381
+ }
4382
+ function EditIcon() {
4383
+ return /* @__PURE__ */ jsxs(
4384
+ "svg",
4385
+ {
4386
+ width: "12",
4387
+ height: "12",
4388
+ viewBox: "0 0 24 24",
4389
+ fill: "none",
4390
+ stroke: "currentColor",
4391
+ strokeWidth: 2,
4392
+ strokeLinecap: "round",
4393
+ strokeLinejoin: "round",
4394
+ children: [
4395
+ /* @__PURE__ */ jsx("path", { d: "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" }),
4396
+ /* @__PURE__ */ jsx("path", { d: "M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" })
4397
+ ]
4398
+ }
4399
+ );
4400
+ }
4401
+ function ThumbsUpIcon3() {
4402
+ return /* @__PURE__ */ jsxs(
4403
+ "svg",
4404
+ {
4405
+ width: "13",
4406
+ height: "13",
4407
+ viewBox: "0 0 24 24",
4408
+ fill: "none",
4409
+ stroke: "currentColor",
4410
+ strokeWidth: 2,
4411
+ strokeLinecap: "round",
4412
+ strokeLinejoin: "round",
4413
+ children: [
4414
+ /* @__PURE__ */ jsx("path", { d: "M7 10v12" }),
4415
+ /* @__PURE__ */ jsx("path", { d: "M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z" })
4416
+ ]
4417
+ }
4418
+ );
4419
+ }
4420
+ function ThumbsDownIcon3() {
4421
+ return /* @__PURE__ */ jsxs(
4422
+ "svg",
4423
+ {
4424
+ width: "13",
4425
+ height: "13",
4426
+ viewBox: "0 0 24 24",
4427
+ fill: "none",
4428
+ stroke: "currentColor",
4429
+ strokeWidth: 2,
4430
+ strokeLinecap: "round",
4431
+ strokeLinejoin: "round",
4432
+ children: [
4433
+ /* @__PURE__ */ jsx("path", { d: "M17 14V2" }),
4434
+ /* @__PURE__ */ jsx("path", { d: "M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88Z" })
4435
+ ]
4436
+ }
4437
+ );
4438
+ }
4439
+ function CopyAction({ tooltip = "Copy", className }) {
4440
+ return null;
4441
+ }
4442
+ CopyAction.displayName = "CopyAction";
4443
+ function EditAction({ tooltip = "Edit", className }) {
4444
+ return null;
4445
+ }
4446
+ EditAction.displayName = "EditAction";
4447
+ function FeedbackAction({
4448
+ onFeedback,
4449
+ tooltip = "Feedback",
4450
+ className
4451
+ }) {
4452
+ return null;
4453
+ }
4454
+ FeedbackAction.displayName = "FeedbackAction";
4455
+ function Action({
4456
+ icon,
4457
+ tooltip,
4458
+ onClick,
4459
+ hidden,
4460
+ className
4461
+ }) {
4462
+ return null;
4463
+ }
4464
+ Action.displayName = "Action";
4465
+ function MessageActions2({ role, children }) {
4466
+ const ctx = useMessageActionsContext();
4467
+ const actions = useMemo(() => {
4468
+ const result = [];
4469
+ React19__default.Children.forEach(children, (child) => {
4470
+ if (!React19__default.isValidElement(child)) return;
4471
+ const props = child.props;
4472
+ const type = child.type;
4473
+ if (type === CopyAction || child.type?.displayName === "CopyAction") {
4474
+ result.push({
4475
+ id: "copy",
4476
+ icon: /* @__PURE__ */ jsx(CopyIcon2, {}),
4477
+ tooltip: props.tooltip ?? "Copy",
4478
+ onClick: ({ message }) => {
4479
+ navigator.clipboard.writeText(message.content ?? "");
4480
+ },
4481
+ className: props.className
4482
+ });
4483
+ } else if (type === EditAction || child.type?.displayName === "EditAction") {
4484
+ result.push({
4485
+ id: "edit",
4486
+ icon: /* @__PURE__ */ jsx(EditIcon, {}),
4487
+ tooltip: props.tooltip ?? "Edit",
4488
+ onClick: () => {
4489
+ },
4490
+ // handled internally by DefaultMessage via onEditMessage
4491
+ className: props.className
4492
+ });
4493
+ } else if (type === FeedbackAction || child.type?.displayName === "FeedbackAction") {
4494
+ const onFeedback = props.onFeedback;
4495
+ result.push(
4496
+ {
4497
+ id: "feedback-up",
4498
+ icon: /* @__PURE__ */ jsx(ThumbsUpIcon3, {}),
4499
+ tooltip: "Helpful",
4500
+ onClick: ({ message }) => onFeedback?.(message, "helpful"),
4501
+ className: props.className
4502
+ },
4503
+ {
4504
+ id: "feedback-down",
4505
+ icon: /* @__PURE__ */ jsx(ThumbsDownIcon3, {}),
4506
+ tooltip: "Not helpful",
4507
+ onClick: ({ message }) => onFeedback?.(message, "not-helpful"),
4508
+ className: props.className
4509
+ }
4510
+ );
4511
+ } else if (type === Action || child.type?.displayName === "Action") {
4512
+ result.push({
4513
+ id: props.id ?? props.tooltip,
4514
+ icon: props.icon,
4515
+ tooltip: props.tooltip,
4516
+ onClick: props.onClick,
4517
+ hidden: props.hidden,
4518
+ className: props.className
4519
+ });
4520
+ }
4521
+ });
4522
+ return result;
4523
+ }, [children]);
4524
+ useLayoutEffect(() => {
4525
+ if (!ctx) return;
4526
+ ctx.registerActions(role, actions);
4527
+ return () => ctx.clearActions(role);
4528
+ }, [ctx, role, actions]);
4529
+ return null;
4530
+ }
4531
+ function FloatingActions({
4532
+ message,
4533
+ role,
4534
+ align = "left",
4535
+ onEdit
4536
+ }) {
4537
+ const ctx = useMessageActionsContext();
4538
+ const [copiedId, setCopiedId] = React19.useState(null);
4539
+ if (!ctx) return null;
4540
+ const actions = ctx.getActions(role);
4541
+ if (actions.length === 0) return null;
4542
+ return /* @__PURE__ */ jsx(
4543
+ "div",
4544
+ {
4545
+ className: cn(
4546
+ "flex items-center gap-0.5 mt-1",
4547
+ "opacity-0 group-hover/message:opacity-100 transition-opacity duration-150",
4548
+ align === "right" ? "justify-end" : "justify-start"
4549
+ ),
4550
+ children: actions.map((action) => {
4551
+ const isHidden = typeof action.hidden === "function" ? action.hidden({ message }) : action.hidden;
4552
+ if (isHidden) return null;
4553
+ const isCopied = copiedId === action.id;
4554
+ return /* @__PURE__ */ jsx(
4555
+ "button",
4556
+ {
4557
+ type: "button",
4558
+ title: action.tooltip,
4559
+ "aria-label": action.tooltip,
4560
+ className: cn(
4561
+ "flex items-center justify-center size-6 rounded-md",
4562
+ "text-muted-foreground hover:text-foreground hover:bg-muted",
4563
+ "transition-colors",
4564
+ action.className
4565
+ ),
4566
+ onClick: () => {
4567
+ if (action.id === "edit" && onEdit) {
4568
+ onEdit();
4569
+ return;
4570
+ }
4571
+ if (action.id === "copy") {
4572
+ navigator.clipboard.writeText(message.content ?? "");
4573
+ setCopiedId("copy");
4574
+ setTimeout(() => setCopiedId(null), 1500);
4575
+ return;
4576
+ }
4577
+ action.onClick({ message });
4578
+ },
4579
+ children: action.id === "copy" && isCopied ? /* @__PURE__ */ jsx(CheckIcon3, {}) : action.icon
4580
+ },
4581
+ action.id
4582
+ );
4583
+ })
4584
+ }
4585
+ );
4586
+ }
4298
4587
  function DefaultMessage({
4299
4588
  message,
4300
4589
  userAvatar,
@@ -4325,24 +4614,24 @@ function DefaultMessage({
4325
4614
  const isUser = message.role === "user";
4326
4615
  const isCompactionMarker = message.role === "system" && message.metadata?.type === "compaction-marker";
4327
4616
  const isStreaming = isLastMessage && isLoading;
4328
- const [isEditing, setIsEditing] = React18.useState(false);
4329
- const [editValue, setEditValue] = React18.useState(message.content ?? "");
4330
- const editRef = React18.useRef(null);
4331
- const startEdit = React18.useCallback(() => {
4617
+ const [isEditing, setIsEditing] = React19.useState(false);
4618
+ const [editValue, setEditValue] = React19.useState(message.content ?? "");
4619
+ const editRef = React19.useRef(null);
4620
+ const startEdit = React19.useCallback(() => {
4332
4621
  setEditValue(message.content ?? "");
4333
4622
  setIsEditing(true);
4334
4623
  requestAnimationFrame(() => editRef.current?.focus());
4335
4624
  }, [message.content]);
4336
- const cancelEdit = React18.useCallback(() => {
4625
+ const cancelEdit = React19.useCallback(() => {
4337
4626
  setIsEditing(false);
4338
4627
  }, []);
4339
- const submitEdit = React18.useCallback(() => {
4628
+ const submitEdit = React19.useCallback(() => {
4340
4629
  const trimmed = editValue.trim();
4341
4630
  if (!trimmed || !onEditMessage) return;
4342
4631
  onEditMessage(message.id, trimmed);
4343
4632
  setIsEditing(false);
4344
4633
  }, [editValue, message.id, onEditMessage]);
4345
- const handleEditKeyDown = React18.useCallback(
4634
+ const handleEditKeyDown = React19.useCallback(
4346
4635
  (e) => {
4347
4636
  if (e.key === "Enter" && !e.shiftKey) {
4348
4637
  e.preventDefault();
@@ -4384,18 +4673,18 @@ function DefaultMessage({
4384
4673
  /* @__PURE__ */ jsx("div", { className: "flex-1 h-px bg-border" })
4385
4674
  ] });
4386
4675
  }
4387
- const { cleanContent: contentWithoutFollowUps, followUps } = React18.useMemo(() => {
4676
+ const { cleanContent: contentWithoutFollowUps, followUps } = React19.useMemo(() => {
4388
4677
  if (isUser || !message.content) {
4389
4678
  return { cleanContent: message.content, followUps: [] };
4390
4679
  }
4391
4680
  return parseFollowUps(message.content);
4392
4681
  }, [message.content, isUser]);
4393
- const cleanContent = React18.useMemo(() => {
4682
+ const cleanContent = React19.useMemo(() => {
4394
4683
  if (!contentWithoutFollowUps) return contentWithoutFollowUps;
4395
4684
  return contentWithoutFollowUps.replace(/\n*\*{0,2}Sources:?\*{0,2}\s*(\[.+?\]\(.+?\)[,\s]*)+$/gi, "").trim();
4396
4685
  }, [contentWithoutFollowUps]);
4397
4686
  const shouldShowFollowUps = showFollowUps && !isUser && isLastMessage && !isLoading && followUps.length > 0 && onFollowUpClick;
4398
- const sources = React18.useMemo(() => {
4687
+ const sources = React19.useMemo(() => {
4399
4688
  if (isUser || !citations.enabled) return [];
4400
4689
  const extractedSources = [];
4401
4690
  const addSource = (url, title, description) => {
@@ -4449,121 +4738,136 @@ function DefaultMessage({
4449
4738
  const shouldShowSources = citations.enabled && sources.length > 0;
4450
4739
  if (isUser) {
4451
4740
  const hasAttachments = message.attachments && message.attachments.length > 0;
4452
- return /* @__PURE__ */ jsxs(Message, { className: cn("flex gap-2 group/user-msg justify-end"), children: [
4453
- /* @__PURE__ */ jsx("div", { className: "flex flex-col items-end max-w-[80%] min-w-0", children: isEditing ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 w-full min-w-[200px]", children: [
4454
- /* @__PURE__ */ jsx(
4455
- "textarea",
4456
- {
4457
- ref: editRef,
4458
- value: editValue,
4459
- onChange: (e) => setEditValue(e.target.value),
4460
- onKeyDown: handleEditKeyDown,
4461
- rows: Math.max(2, (editValue.match(/\n/g) || []).length + 1),
4462
- className: cn(
4463
- "csdk-edit-textarea w-full rounded-lg px-3 py-2 text-sm resize-none",
4464
- "bg-primary text-primary-foreground placeholder:text-primary-foreground/50",
4465
- "focus:outline-none focus:ring-2 focus:ring-primary-foreground/30",
4466
- userMessageClassName
4467
- )
4468
- }
4469
- ),
4470
- /* @__PURE__ */ jsxs("div", { className: "flex gap-1.5 justify-end", children: [
4471
- /* @__PURE__ */ jsx(
4472
- "button",
4473
- {
4474
- type: "button",
4475
- onClick: cancelEdit,
4476
- className: "csdk-edit-cancel px-3 py-1 text-xs rounded-md bg-muted text-muted-foreground hover:bg-muted/80 transition-colors",
4477
- children: "Cancel"
4478
- }
4479
- ),
4480
- /* @__PURE__ */ jsx(
4481
- "button",
4482
- {
4483
- type: "button",
4484
- onClick: submitEdit,
4485
- disabled: !editValue.trim(),
4486
- className: "csdk-edit-submit px-3 py-1 text-xs rounded-md bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50 transition-colors",
4487
- children: "Send"
4488
- }
4489
- )
4490
- ] })
4491
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
4492
- message.content && /* @__PURE__ */ jsxs("div", { className: "relative", children: [
4493
- /* @__PURE__ */ jsx(
4494
- MessageContent,
4495
- {
4496
- className: cn(
4497
- "csdk-message-user rounded-lg px-4 py-2 bg-primary text-primary-foreground",
4498
- userMessageClassName
4741
+ return /* @__PURE__ */ jsxs(
4742
+ Message,
4743
+ {
4744
+ className: cn("flex gap-2 group/user-msg group/message justify-end"),
4745
+ children: [
4746
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col items-end max-w-[80%] min-w-0", children: isEditing ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 w-full min-w-[200px]", children: [
4747
+ /* @__PURE__ */ jsx(
4748
+ "textarea",
4749
+ {
4750
+ ref: editRef,
4751
+ value: editValue,
4752
+ onChange: (e) => setEditValue(e.target.value),
4753
+ onKeyDown: handleEditKeyDown,
4754
+ rows: Math.max(2, (editValue.match(/\n/g) || []).length + 1),
4755
+ className: cn(
4756
+ "csdk-edit-textarea w-full rounded-lg px-3 py-2 text-sm resize-none",
4757
+ "bg-primary text-primary-foreground placeholder:text-primary-foreground/50",
4758
+ "focus:outline-none focus:ring-2 focus:ring-primary-foreground/30",
4759
+ userMessageClassName
4760
+ )
4761
+ }
4762
+ ),
4763
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-1.5 justify-end", children: [
4764
+ /* @__PURE__ */ jsx(
4765
+ "button",
4766
+ {
4767
+ type: "button",
4768
+ onClick: cancelEdit,
4769
+ className: "csdk-edit-cancel px-3 py-1 text-xs rounded-md bg-muted text-muted-foreground hover:bg-muted/80 transition-colors",
4770
+ children: "Cancel"
4771
+ }
4499
4772
  ),
4500
- markdown: true,
4501
- size,
4502
- children: message.content
4503
- }
4504
- ),
4505
- showEditBtn && /* @__PURE__ */ jsx(
4506
- "button",
4507
- {
4508
- type: "button",
4509
- onClick: startEdit,
4510
- "aria-label": "Edit message",
4511
- className: cn(
4512
- "csdk-edit-btn absolute -left-7 top-1/2 -translate-y-1/2",
4513
- "size-6 flex items-center justify-center rounded-full",
4514
- "text-muted-foreground bg-background border border-border shadow-sm",
4515
- "opacity-0 group-hover/user-msg:opacity-100 transition-opacity",
4516
- "hover:text-foreground hover:bg-muted"
4773
+ /* @__PURE__ */ jsx(
4774
+ "button",
4775
+ {
4776
+ type: "button",
4777
+ onClick: submitEdit,
4778
+ disabled: !editValue.trim(),
4779
+ className: "csdk-edit-submit px-3 py-1 text-xs rounded-md bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50 transition-colors",
4780
+ children: "Send"
4781
+ }
4782
+ )
4783
+ ] })
4784
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
4785
+ message.content && /* @__PURE__ */ jsxs("div", { className: "relative", children: [
4786
+ /* @__PURE__ */ jsx(
4787
+ MessageContent,
4788
+ {
4789
+ className: cn(
4790
+ "csdk-message-user rounded-lg px-4 py-2 bg-primary text-primary-foreground",
4791
+ userMessageClassName
4792
+ ),
4793
+ markdown: true,
4794
+ size,
4795
+ children: message.content
4796
+ }
4517
4797
  ),
4518
- children: /* @__PURE__ */ jsxs(
4519
- "svg",
4798
+ showEditBtn && /* @__PURE__ */ jsx(
4799
+ "button",
4520
4800
  {
4521
- width: "12",
4522
- height: "12",
4523
- viewBox: "0 0 24 24",
4524
- fill: "none",
4525
- stroke: "currentColor",
4526
- strokeWidth: 2,
4527
- strokeLinecap: "round",
4528
- strokeLinejoin: "round",
4529
- children: [
4530
- /* @__PURE__ */ jsx("path", { d: "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" }),
4531
- /* @__PURE__ */ jsx("path", { d: "M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" })
4532
- ]
4801
+ type: "button",
4802
+ onClick: startEdit,
4803
+ "aria-label": "Edit message",
4804
+ className: cn(
4805
+ "csdk-edit-btn absolute -left-7 top-1/2 -translate-y-1/2",
4806
+ "size-6 flex items-center justify-center rounded-full",
4807
+ "text-muted-foreground bg-background border border-border shadow-sm",
4808
+ "opacity-0 group-hover/user-msg:opacity-100 transition-opacity",
4809
+ "hover:text-foreground hover:bg-muted"
4810
+ ),
4811
+ children: /* @__PURE__ */ jsxs(
4812
+ "svg",
4813
+ {
4814
+ width: "12",
4815
+ height: "12",
4816
+ viewBox: "0 0 24 24",
4817
+ fill: "none",
4818
+ stroke: "currentColor",
4819
+ strokeWidth: 2,
4820
+ strokeLinecap: "round",
4821
+ strokeLinejoin: "round",
4822
+ children: [
4823
+ /* @__PURE__ */ jsx("path", { d: "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" }),
4824
+ /* @__PURE__ */ jsx("path", { d: "M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" })
4825
+ ]
4826
+ }
4827
+ )
4533
4828
  }
4534
4829
  )
4830
+ ] }),
4831
+ hasAttachments && /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-2 justify-end", children: message.attachments.map((attachment, index) => /* @__PURE__ */ jsx(AttachmentPreview, { attachment }, index)) }),
4832
+ showBranchNav && /* @__PURE__ */ jsx(
4833
+ BranchNavigator,
4834
+ {
4835
+ siblingIndex: branchInfo.siblingIndex,
4836
+ totalSiblings: branchInfo.totalSiblings,
4837
+ hasPrevious: branchInfo.hasPrevious,
4838
+ hasNext: branchInfo.hasNext,
4839
+ onPrevious: () => onSwitchBranch(
4840
+ branchInfo.siblingIds[branchInfo.siblingIndex - 1]
4841
+ ),
4842
+ onNext: () => onSwitchBranch(
4843
+ branchInfo.siblingIds[branchInfo.siblingIndex + 1]
4844
+ ),
4845
+ className: "mt-1"
4846
+ }
4847
+ ),
4848
+ /* @__PURE__ */ jsx(
4849
+ FloatingActions,
4850
+ {
4851
+ message,
4852
+ role: "user",
4853
+ align: "right",
4854
+ onEdit: onEditMessage ? startEdit : void 0
4855
+ }
4856
+ )
4857
+ ] }) }),
4858
+ showUserAvatar && /* @__PURE__ */ jsx(
4859
+ MessageAvatar,
4860
+ {
4861
+ src: userAvatar.src,
4862
+ alt: "User",
4863
+ fallback: userAvatar.fallback,
4864
+ className: userAvatar.className,
4865
+ children: userAvatar.component
4535
4866
  }
4536
4867
  )
4537
- ] }),
4538
- hasAttachments && /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-2 justify-end", children: message.attachments.map((attachment, index) => /* @__PURE__ */ jsx(AttachmentPreview, { attachment }, index)) }),
4539
- showBranchNav && /* @__PURE__ */ jsx(
4540
- BranchNavigator,
4541
- {
4542
- siblingIndex: branchInfo.siblingIndex,
4543
- totalSiblings: branchInfo.totalSiblings,
4544
- hasPrevious: branchInfo.hasPrevious,
4545
- hasNext: branchInfo.hasNext,
4546
- onPrevious: () => onSwitchBranch(
4547
- branchInfo.siblingIds[branchInfo.siblingIndex - 1]
4548
- ),
4549
- onNext: () => onSwitchBranch(
4550
- branchInfo.siblingIds[branchInfo.siblingIndex + 1]
4551
- ),
4552
- className: "mt-1"
4553
- }
4554
- )
4555
- ] }) }),
4556
- showUserAvatar && /* @__PURE__ */ jsx(
4557
- MessageAvatar,
4558
- {
4559
- src: userAvatar.src,
4560
- alt: "User",
4561
- fallback: userAvatar.fallback,
4562
- className: userAvatar.className,
4563
- children: userAvatar.component
4564
- }
4565
- )
4566
- ] });
4868
+ ]
4869
+ }
4870
+ );
4567
4871
  }
4568
4872
  const isToolHidden = (exec) => {
4569
4873
  if (exec.hidden === true) return true;
@@ -4600,7 +4904,7 @@ function DefaultMessage({
4600
4904
  result: exec.result,
4601
4905
  error: exec.error
4602
4906
  }));
4603
- return /* @__PURE__ */ jsxs(Message, { className: "flex gap-2", children: [
4907
+ return /* @__PURE__ */ jsxs(Message, { className: "flex gap-2 group/message", children: [
4604
4908
  /* @__PURE__ */ jsx(
4605
4909
  MessageAvatar,
4606
4910
  {
@@ -4658,7 +4962,7 @@ function DefaultMessage({
4658
4962
  renderProps
4659
4963
  );
4660
4964
  if (output != null) {
4661
- return /* @__PURE__ */ jsx(React18.Fragment, { children: output }, exec.id);
4965
+ return /* @__PURE__ */ jsx(React19.Fragment, { children: output }, exec.id);
4662
4966
  }
4663
4967
  }
4664
4968
  if (mcpToolRenderer && (exec.source === "mcp" || toolDef?.source === "mcp")) {
@@ -4774,13 +5078,13 @@ function DefaultMessage({
4774
5078
  const output = toolDef.render(
4775
5079
  renderProps
4776
5080
  );
4777
- return /* @__PURE__ */ jsx(React18.Fragment, { children: output }, tool.id);
5081
+ return /* @__PURE__ */ jsx(React19.Fragment, { children: output }, tool.id);
4778
5082
  }
4779
5083
  return /* @__PURE__ */ jsx(
4780
5084
  PermissionConfirmation,
4781
5085
  {
4782
5086
  state: "pending",
4783
- toolName: tool.name,
5087
+ toolName: tool.approvalTitle ?? tool.name,
4784
5088
  message: tool.approvalMessage || `This tool wants to execute. Do you approve?`,
4785
5089
  onApprove: (permissionLevel) => onApproveToolExecution?.(
4786
5090
  tool.id,
@@ -4816,14 +5120,15 @@ function DefaultMessage({
4816
5120
  className: followUpClassName,
4817
5121
  buttonClassName: followUpButtonClassName
4818
5122
  }
4819
- )
5123
+ ),
5124
+ /* @__PURE__ */ jsx(FloatingActions, { message, role: "assistant", align: "left" })
4820
5125
  ] })
4821
5126
  )
4822
5127
  ] })
4823
5128
  ] });
4824
5129
  }
4825
5130
  function AttachmentPreview({ attachment }) {
4826
- const [expanded, setExpanded] = React18.useState(false);
5131
+ const [expanded, setExpanded] = React19.useState(false);
4827
5132
  if (attachment.type !== "image") {
4828
5133
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 rounded-lg border bg-muted/50 px-3 py-2 text-sm", children: [
4829
5134
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: attachment.type }),
@@ -5281,10 +5586,10 @@ function ChatView({ children, className }) {
5281
5586
  ChatView.displayName = "ChatView";
5282
5587
  function chatViewHasOnlyLayoutChildren(chatViewElement) {
5283
5588
  if (!chatViewElement?.props?.children) return false;
5284
- const childArray = React18__default.Children.toArray(chatViewElement.props.children);
5589
+ const childArray = React19__default.Children.toArray(chatViewElement.props.children);
5285
5590
  if (childArray.length === 0) return false;
5286
5591
  return childArray.every(
5287
- (child) => React18__default.isValidElement(child) && (child.type === Header || child.type === Footer)
5592
+ (child) => React19__default.isValidElement(child) && (child.type === Header || child.type === Footer)
5288
5593
  );
5289
5594
  }
5290
5595
  function Header({ children, className }) {
@@ -5422,18 +5727,18 @@ function ThreadPickerCompound(props) {
5422
5727
  );
5423
5728
  }
5424
5729
  function hasCompoundChild(children, ...components) {
5425
- return React18__default.Children.toArray(children).some(
5426
- (child) => React18__default.isValidElement(child) && components.includes(child.type)
5730
+ return React19__default.Children.toArray(children).some(
5731
+ (child) => React19__default.isValidElement(child) && components.includes(child.type)
5427
5732
  );
5428
5733
  }
5429
5734
  function findCompoundChild(children, component) {
5430
- return React18__default.Children.toArray(children).find(
5431
- (child) => React18__default.isValidElement(child) && child.type === component
5735
+ return React19__default.Children.toArray(children).find(
5736
+ (child) => React19__default.isValidElement(child) && child.type === component
5432
5737
  );
5433
5738
  }
5434
5739
  function filterCompoundChildren(children, ...components) {
5435
- return React18__default.Children.toArray(children).filter(
5436
- (child) => React18__default.isValidElement(child) && components.includes(child.type)
5740
+ return React19__default.Children.toArray(children).filter(
5741
+ (child) => React19__default.isValidElement(child) && components.includes(child.type)
5437
5742
  );
5438
5743
  }
5439
5744
  var DEFAULT_MAX_FILE_SIZE2 = 5 * 1024 * 1024;
@@ -5518,6 +5823,7 @@ function ChatComponent({
5518
5823
  // Citations/Sources
5519
5824
  citations,
5520
5825
  // Custom rendering
5826
+ messageView,
5521
5827
  renderMessage,
5522
5828
  renderInput,
5523
5829
  renderHeader,
@@ -5710,7 +6016,7 @@ function ChatComponent({
5710
6016
  },
5711
6017
  [onSendMessage]
5712
6018
  );
5713
- const contextValue = React18__default.useMemo(
6019
+ const contextValue = React19__default.useMemo(
5714
6020
  () => ({
5715
6021
  view,
5716
6022
  send,
@@ -5718,6 +6024,9 @@ function ChatComponent({
5718
6024
  onStop,
5719
6025
  attachmentsEnabled,
5720
6026
  placeholder,
6027
+ // Messages for Chat.MessageList primitive
6028
+ messages,
6029
+ registeredTools,
5721
6030
  // Thread management - passed from connected-chat
5722
6031
  onNewChat,
5723
6032
  threads,
@@ -5733,6 +6042,8 @@ function ChatComponent({
5733
6042
  onStop,
5734
6043
  attachmentsEnabled,
5735
6044
  placeholder,
6045
+ messages,
6046
+ registeredTools,
5736
6047
  onNewChat,
5737
6048
  threads,
5738
6049
  currentThreadId,
@@ -5741,7 +6052,7 @@ function ChatComponent({
5741
6052
  isThreadBusy
5742
6053
  ]
5743
6054
  );
5744
- return /* @__PURE__ */ jsx(CopilotChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
6055
+ return /* @__PURE__ */ jsx(MessageActionsProvider, { children: /* @__PURE__ */ jsx(CopilotChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
5745
6056
  "div",
5746
6057
  {
5747
6058
  className: cn(
@@ -5802,84 +6113,90 @@ function ChatComponent({
5802
6113
  className: cn("gap-4 p-4", classNames.messageList),
5803
6114
  children: [
5804
6115
  messages.length === 0 && /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-muted-foreground", children: welcomeMessage || "Send a message to start the conversation" }),
5805
- messages.map((message, index) => {
5806
- const isLastMessage = index === messages.length - 1;
5807
- const GROUP_THRESHOLD_MS = 5 * 60 * 1e3;
5808
- const shouldHideAvatar = (() => {
5809
- if (!groupConsecutiveMessages || index === 0)
5810
- return false;
5811
- let prevIdx = index - 1;
5812
- while (prevIdx >= 0) {
5813
- const prev = messages[prevIdx];
5814
- const isToolMsg = prev.role === "tool";
5815
- const isInvisibleSystem = prev.role === "system" && // eslint-disable-next-line @typescript-eslint/no-explicit-any
5816
- prev.metadata?.type !== "compaction-marker";
5817
- if (!isToolMsg && !isInvisibleSystem) break;
5818
- prevIdx--;
5819
- }
5820
- if (prevIdx < 0) return false;
5821
- const prevVisible = messages[prevIdx];
5822
- if (prevVisible.role !== message.role) return false;
5823
- const curTs = message.timestamp;
5824
- const prevTs = prevVisible.timestamp;
5825
- if (curTs && prevTs && curTs - prevTs > GROUP_THRESHOLD_MS)
5826
- return false;
5827
- return true;
5828
- })();
5829
- const isEmptyAssistant = message.role === "assistant" && !message.content?.trim();
5830
- const hasToolCalls = message.tool_calls && message.tool_calls.length > 0;
5831
- const hasToolExecutions = message.toolExecutions && message.toolExecutions.length > 0;
5832
- const hasPendingApprovals = message.toolExecutions?.some(
5833
- (exec) => exec.approvalStatus === "required"
5834
- );
5835
- if (isEmptyAssistant) {
5836
- const shouldShowMessage = hasToolCalls || hasToolExecutions || hasPendingApprovals || isLastMessage && (isLoading || isProcessing);
5837
- if (!shouldShowMessage) {
5838
- return null;
6116
+ (() => {
6117
+ const messageElements = messages.map((message, index) => {
6118
+ const isLastMessage = index === messages.length - 1;
6119
+ const GROUP_THRESHOLD_MS = 5 * 60 * 1e3;
6120
+ const shouldHideAvatar = (() => {
6121
+ if (!groupConsecutiveMessages || index === 0)
6122
+ return false;
6123
+ let prevIdx = index - 1;
6124
+ while (prevIdx >= 0) {
6125
+ const prev = messages[prevIdx];
6126
+ const isToolMsg = prev.role === "tool";
6127
+ const isInvisibleSystem = prev.role === "system" && // eslint-disable-next-line @typescript-eslint/no-explicit-any
6128
+ prev.metadata?.type !== "compaction-marker";
6129
+ if (!isToolMsg && !isInvisibleSystem) break;
6130
+ prevIdx--;
6131
+ }
6132
+ if (prevIdx < 0) return false;
6133
+ const prevVisible = messages[prevIdx];
6134
+ if (prevVisible.role !== message.role) return false;
6135
+ const curTs = message.timestamp;
6136
+ const prevTs = prevVisible.timestamp;
6137
+ if (curTs && prevTs && curTs - prevTs > GROUP_THRESHOLD_MS)
6138
+ return false;
6139
+ return true;
6140
+ })();
6141
+ const isEmptyAssistant = message.role === "assistant" && !message.content?.trim();
6142
+ const hasToolCalls = message.tool_calls && message.tool_calls.length > 0;
6143
+ const hasToolExecutions = message.toolExecutions && message.toolExecutions.length > 0;
6144
+ const hasPendingApprovals = message.toolExecutions?.some(
6145
+ (exec) => exec.approvalStatus === "required"
6146
+ );
6147
+ if (isEmptyAssistant) {
6148
+ const shouldShowMessage = hasToolCalls || hasToolExecutions || hasPendingApprovals || isLastMessage && (isLoading || isProcessing);
6149
+ if (!shouldShowMessage) {
6150
+ return null;
6151
+ }
5839
6152
  }
5840
- }
5841
- const savedExecutions = message.metadata?.toolExecutions;
5842
- const messageToolExecutions = message.toolExecutions || savedExecutions;
5843
- const messageWithExecutions = messageToolExecutions ? { ...message, toolExecutions: messageToolExecutions } : message;
5844
- const handleFollowUpClick = (question) => {
5845
- if (onSuggestionClick) {
5846
- onSuggestionClick(question);
5847
- } else {
5848
- onSendMessage?.(question);
5849
- }
5850
- };
5851
- return renderMessage ? /* @__PURE__ */ jsx(React18__default.Fragment, { children: renderMessage(messageWithExecutions, index) }, message.id) : /* @__PURE__ */ jsx(
5852
- DefaultMessage,
5853
- {
5854
- message: messageWithExecutions,
5855
- userAvatar: shouldHideAvatar && message.role === "user" ? { ...userAvatar, className: "invisible" } : userAvatar,
5856
- assistantAvatar: shouldHideAvatar && message.role === "assistant" ? { ...assistantAvatar, className: "invisible" } : assistantAvatar,
5857
- showUserAvatar,
5858
- userMessageClassName: classNames.userMessage,
5859
- assistantMessageClassName: classNames.assistantMessage,
5860
- size: fontSize,
5861
- isLastMessage,
5862
- isLoading,
5863
- isProcessing,
5864
- loaderVariant,
5865
- registeredTools,
5866
- toolRenderers,
5867
- mcpToolRenderer,
5868
- fallbackToolRenderer,
5869
- onApproveToolExecution,
5870
- onRejectToolExecution,
5871
- showFollowUps,
5872
- onFollowUpClick: handleFollowUpClick,
5873
- followUpClassName,
5874
- followUpButtonClassName,
5875
- citations: citations === false ? { enabled: false } : citations,
5876
- branchInfo: message.role === "user" ? getBranchInfo?.(message.id) ?? null : null,
5877
- onSwitchBranch,
5878
- onEditMessage
5879
- },
5880
- message.id
5881
- );
5882
- }),
6153
+ const savedExecutions = message.metadata?.toolExecutions;
6154
+ const messageToolExecutions = message.toolExecutions || savedExecutions;
6155
+ const messageWithExecutions = messageToolExecutions ? {
6156
+ ...message,
6157
+ toolExecutions: messageToolExecutions
6158
+ } : message;
6159
+ const handleFollowUpClick = (question) => {
6160
+ if (onSuggestionClick) {
6161
+ onSuggestionClick(question);
6162
+ } else {
6163
+ onSendMessage?.(question);
6164
+ }
6165
+ };
6166
+ return renderMessage ? /* @__PURE__ */ jsx(React19__default.Fragment, { children: renderMessage(messageWithExecutions, index) }, message.id) : /* @__PURE__ */ jsx(
6167
+ DefaultMessage,
6168
+ {
6169
+ message: messageWithExecutions,
6170
+ userAvatar: shouldHideAvatar && message.role === "user" ? { ...userAvatar, className: "invisible" } : userAvatar,
6171
+ assistantAvatar: shouldHideAvatar && message.role === "assistant" ? { ...assistantAvatar, className: "invisible" } : assistantAvatar,
6172
+ showUserAvatar,
6173
+ userMessageClassName: classNames.userMessage,
6174
+ assistantMessageClassName: classNames.assistantMessage,
6175
+ size: fontSize,
6176
+ isLastMessage,
6177
+ isLoading,
6178
+ isProcessing,
6179
+ loaderVariant,
6180
+ registeredTools,
6181
+ toolRenderers,
6182
+ mcpToolRenderer,
6183
+ fallbackToolRenderer,
6184
+ onApproveToolExecution,
6185
+ onRejectToolExecution,
6186
+ showFollowUps,
6187
+ onFollowUpClick: handleFollowUpClick,
6188
+ followUpClassName,
6189
+ followUpButtonClassName,
6190
+ citations: citations === false ? { enabled: false } : citations,
6191
+ branchInfo: message.role === "user" ? getBranchInfo?.(message.id) ?? null : null,
6192
+ onSwitchBranch,
6193
+ onEditMessage
6194
+ },
6195
+ message.id
6196
+ );
6197
+ });
6198
+ return messageView?.children ? messageView.children({ messages, messageElements }) : messageElements;
6199
+ })(),
5883
6200
  isLoading && !isProcessing && messages.length > 0 && messages[messages.length - 1]?.role === "user" && /* @__PURE__ */ jsx(
5884
6201
  DefaultMessage,
5885
6202
  {
@@ -6029,7 +6346,7 @@ function ChatComponent({
6029
6346
  rootFooter
6030
6347
  ]
6031
6348
  }
6032
- ) });
6349
+ ) }) });
6033
6350
  }
6034
6351
  var Chat = Object.assign(ChatComponent, {
6035
6352
  Root: ChatComponent,
@@ -6045,9 +6362,34 @@ var Chat = Object.assign(ChatComponent, {
6045
6362
  Suggestions: SuggestionsCompound,
6046
6363
  BackButton,
6047
6364
  // Navigation: start new chat
6048
- ThreadPicker: ThreadPickerCompound
6365
+ ThreadPicker: ThreadPickerCompound,
6049
6366
  // Thread switching
6367
+ // Message actions compound components
6368
+ MessageActions: MessageActions2,
6369
+ CopyAction,
6370
+ EditAction,
6371
+ FeedbackAction,
6372
+ Action
6050
6373
  });
6374
+ function MessageList({ children, className }) {
6375
+ const { messages, registeredTools } = useCopilotChatContext();
6376
+ return /* @__PURE__ */ jsx("div", { className, children: messages.map((message, index) => {
6377
+ if (children) {
6378
+ return /* @__PURE__ */ jsx(React19.Fragment, { children: children(message, index) }, message.id);
6379
+ }
6380
+ return /* @__PURE__ */ jsx(
6381
+ DefaultMessage,
6382
+ {
6383
+ message,
6384
+ userAvatar: { fallback: "U" },
6385
+ assistantAvatar: { fallback: "AI" },
6386
+ registeredTools,
6387
+ isLastMessage: index === messages.length - 1
6388
+ },
6389
+ message.id
6390
+ );
6391
+ }) });
6392
+ }
6051
6393
  function ToolExecutionMessage({
6052
6394
  executions,
6053
6395
  assistantAvatar = { fallback: "AI" },
@@ -6191,7 +6533,8 @@ function useInternalThreadManager(config = {}) {
6191
6533
  adapter,
6192
6534
  saveDebounce = 1e3,
6193
6535
  autoRestoreLastThread = true,
6194
- onThreadChange
6536
+ onThreadChange,
6537
+ enabled = true
6195
6538
  } = config;
6196
6539
  const threadManagerConfig = {
6197
6540
  adapter,
@@ -6280,6 +6623,7 @@ function useInternalThreadManager(config = {}) {
6280
6623
  });
6281
6624
  }, [clearCurrentThread, setMessages, onThreadChange]);
6282
6625
  useEffect(() => {
6626
+ if (!enabled) return;
6283
6627
  if (hasInitializedRef.current || !currentThread) {
6284
6628
  return;
6285
6629
  }
@@ -6311,8 +6655,9 @@ function useInternalThreadManager(config = {}) {
6311
6655
  requestAnimationFrame(() => {
6312
6656
  isLoadingMessagesRef.current = false;
6313
6657
  });
6314
- }, [adapter, currentThread, setMessages, getMessageSnapshot, onThreadChange]);
6658
+ }, [enabled, adapter, currentThread, setMessages, getMessageSnapshot, onThreadChange]);
6315
6659
  useEffect(() => {
6660
+ if (!enabled) return;
6316
6661
  if (isLoadingMessagesRef.current) {
6317
6662
  return;
6318
6663
  }
@@ -6345,6 +6690,7 @@ function useInternalThreadManager(config = {}) {
6345
6690
  updateCurrentThread({ messages: coreMessages });
6346
6691
  lastSavedSnapshotRef.current = currentSnapshot;
6347
6692
  }, [
6693
+ enabled,
6348
6694
  adapter,
6349
6695
  messages,
6350
6696
  currentThreadId,
@@ -6423,7 +6769,7 @@ function CopilotChatBase(props) {
6423
6769
  } = props;
6424
6770
  const persistenceConfig = parsePersistenceConfig(persistence, onThreadChange);
6425
6771
  const threadManagerResult = useInternalThreadManager(
6426
- persistenceConfig ?? { autoRestoreLastThread: false }
6772
+ persistenceConfig ?? { autoRestoreLastThread: false, enabled: false }
6427
6773
  );
6428
6774
  const isPersistenceEnabled = !!persistence;
6429
6775
  const {
@@ -6449,6 +6795,8 @@ function CopilotChatBase(props) {
6449
6795
  error: exec.error,
6450
6796
  timestamp: exec.startedAt ? exec.startedAt.getTime() : Date.now(),
6451
6797
  approvalStatus: exec.approvalStatus,
6798
+ approvalTitle: exec.approvalTitle,
6799
+ approvalMessage: exec.approvalMessage,
6452
6800
  hidden: exec.hidden
6453
6801
  })
6454
6802
  );
@@ -6590,7 +6938,7 @@ function CopilotChatBase(props) {
6590
6938
  footer: classNames.footer
6591
6939
  } : void 0;
6592
6940
  const { threadManager, handleSwitchThread, handleNewThread, isBusy } = threadManagerResult;
6593
- const handleDeleteThread = React18__default.useCallback(
6941
+ const handleDeleteThread = React19__default.useCallback(
6594
6942
  (threadId) => {
6595
6943
  const isCurrentThread = threadManager.currentThreadId === threadId;
6596
6944
  threadManager.deleteThread(threadId);
@@ -6718,6 +7066,38 @@ function PoweredBy({ className, showLogo = true }) {
6718
7066
  );
6719
7067
  }
6720
7068
 
6721
- export { AlertTriangleIcon, BotIcon, BranchNavigator, Button, CapabilityBadge, CapabilityList, Chat, ChatContainerContent, ChatContainerRoot, ChatContainerScrollAnchor, ChatWelcome, CheckIcon, ChevronDownIcon2 as ChevronDownIcon, ChevronLeftIcon, ChevronUpIcon, CitationBadge, CitationSuperscript, CloseIcon, CodeBlock, CompactPermissionConfirmation, Confirmation, ConfirmationActions, ConfirmationApproved, ConfirmationMessage, ConfirmationPending, ConfirmationRejected, ConnectedChat, CopilotChat, CopilotUIProvider, CopyIcon, DEFAULT_PERMISSION_OPTIONS, DevLogger, FeedbackBar, FollowUpQuestions, InlineToolSteps, Loader, MCPUIFrame, MCPUIFrameList, Markdown, MessageAvatar, MessageContent, Message as MessagePrimitive, MessageWithCitations, ModelSelector, PermissionConfirmation, PoweredBy, PromptInput, PromptInputAction, PromptInputActions, PromptInputTextarea, Reasoning, ReasoningContent, ReasoningTrigger, RefreshIcon, ScrollButton, SearchAnswer, SearchResults, SearchResultsWithAnswer, SendIcon, SimpleConfirmation, SimpleModelSelector, SimpleReasoning, SimpleSource, Source, SourceContent, SourceGroup, SourcePill, SourceTrigger, SourcesBar, SourcesCollapsible, SourcesList, StopIcon, ThreadCard, ThreadList, ThreadPicker, ThumbsDownIcon2 as ThumbsDownIcon, ThumbsUpIcon2 as ThumbsUpIcon, ToolExecutionMessage, ToolStep, ToolSteps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserIcon, XIcon2 as XIcon, annotationsToCitations, cn, parseFollowUps, resultsToCitations, useChatContainer, useCopilotChatContext, useCopilotUI };
7069
+ // src/ui/index.ts
7070
+ var ChatPrimitives = {
7071
+ // ── List ──────────────────────────────────────────────
7072
+ /** Renders the message list via render-prop. Falls back to DefaultMessage if no children. */
7073
+ MessageList,
7074
+ // ── Messages ──────────────────────────────────────────
7075
+ /** Full SDK message bubble (user + assistant + tools). Use as fallback inside MessageList. */
7076
+ DefaultMessage,
7077
+ /** Low-level message row wrapper (flex layout + avatar slot) */
7078
+ Message,
7079
+ /** Message avatar — image with fallback text/icon */
7080
+ MessageAvatar,
7081
+ /** Message content bubble — supports markdown */
7082
+ MessageContent,
7083
+ /** Action bar below a message (copy, feedback, etc.) */
7084
+ MessageActions,
7085
+ /** Single action button with tooltip inside MessageActions */
7086
+ MessageAction,
7087
+ // ── Layout ────────────────────────────────────────────
7088
+ /** Chat header bar with title and controls */
7089
+ Header: ChatHeader,
7090
+ /** Welcome screen shown when there are no messages */
7091
+ Welcome: ChatWelcome,
7092
+ /** Chat input / composer */
7093
+ Input: PromptInput,
7094
+ /** Scroll anchor — keeps the view pinned to the latest message */
7095
+ ScrollAnchor: ChatContainerScrollAnchor,
7096
+ // ── Indicators ────────────────────────────────────────
7097
+ /** Loading / streaming indicator (dots, wave, typing variants) */
7098
+ Loader
7099
+ };
7100
+
7101
+ export { AlertTriangleIcon, BotIcon, BranchNavigator, Button, CapabilityBadge, CapabilityList, Chat, ChatContainerContent, ChatContainerRoot, ChatContainerScrollAnchor, ChatPrimitives, ChatWelcome, CheckIcon, ChevronDownIcon2 as ChevronDownIcon, ChevronLeftIcon, ChevronUpIcon, CitationBadge, CitationSuperscript, CloseIcon, CodeBlock, CompactPermissionConfirmation, Confirmation, ConfirmationActions, ConfirmationApproved, ConfirmationMessage, ConfirmationPending, ConfirmationRejected, ConnectedChat, CopilotChat, CopilotUIProvider, CopyIcon, DEFAULT_PERMISSION_OPTIONS, DevLogger, FeedbackBar, FollowUpQuestions, InlineToolSteps, Loader, MCPUIFrame, MCPUIFrameList, Markdown, MessageAvatar, MessageContent, Message as MessagePrimitive, MessageWithCitations, ModelSelector, PermissionConfirmation, PoweredBy, PromptInput, PromptInputAction, PromptInputActions, PromptInputTextarea, Reasoning, ReasoningContent, ReasoningTrigger, RefreshIcon, ScrollButton, SearchAnswer, SearchResults, SearchResultsWithAnswer, SendIcon, SimpleConfirmation, SimpleModelSelector, SimpleReasoning, SimpleSource, Source, SourceContent, SourceGroup, SourcePill, SourceTrigger, SourcesBar, SourcesCollapsible, SourcesList, StopIcon, ThreadCard, ThreadList, ThreadPicker, ThumbsDownIcon2 as ThumbsDownIcon, ThumbsUpIcon2 as ThumbsUpIcon, ToolExecutionMessage, ToolStep, ToolSteps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserIcon, XIcon2 as XIcon, annotationsToCitations, cn, parseFollowUps, resultsToCitations, useChatContainer, useCopilotChatContext, useCopilotUI };
6722
7102
  //# sourceMappingURL=index.js.map
6723
7103
  //# sourceMappingURL=index.js.map