@yourgpt/copilot-sdk 1.3.0 → 1.4.1

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/ui/index.js CHANGED
@@ -1,15 +1,15 @@
1
- import { useCopilot, useThreadManager } from '../chunk-N2SMQKRK.js';
2
- import { createServerAdapter } from '../chunk-CVD3X4MN.js';
1
+ import { useCopilot, useThreadManager } from '../chunk-7JQ5GJSK.js';
2
+ import { createServerAdapter } from '../chunk-T6W2Y3D6.js';
3
3
  import { clsx } from 'clsx';
4
4
  import { twMerge } from 'tailwind-merge';
5
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
- import * as React7 from 'react';
7
- import React7__default, { memo, createContext, useState, useRef, useLayoutEffect, useId, useCallback, useContext, useEffect } from 'react';
6
+ import * as React18 from 'react';
7
+ import React18__default, { memo, createContext, useState, useRef, useId, useCallback, useLayoutEffect, useContext, useEffect } from 'react';
8
8
  import { Streamdown } from 'streamdown';
9
9
  import { code } from '@streamdown/code';
10
10
  import { Slot } from '@radix-ui/react-slot';
11
11
  import { cva } from 'class-variance-authority';
12
- import { useStickToBottomContext, StickToBottom as StickToBottom$1 } from 'use-stick-to-bottom';
12
+ import { StickToBottom as StickToBottom$1, useStickToBottomContext } from 'use-stick-to-bottom';
13
13
  import { Tooltip as Tooltip$1 } from '@base-ui/react/tooltip';
14
14
  import * as AvatarPrimitive from '@radix-ui/react-avatar';
15
15
  import * as HoverCardPrimitive from '@radix-ui/react-hover-card';
@@ -486,7 +486,7 @@ var buttonVariants = cva(
486
486
  }
487
487
  }
488
488
  );
489
- var Button = React7.forwardRef(
489
+ var Button = React18.forwardRef(
490
490
  ({ className, variant, size, asChild = false, ...props }, ref) => {
491
491
  const Comp = asChild ? Slot : "button";
492
492
  return /* @__PURE__ */ jsx(
@@ -727,7 +727,7 @@ function TooltipTrigger({
727
727
  disabled,
728
728
  ...props
729
729
  }) {
730
- if (asChild && React7__default.isValidElement(children)) {
730
+ if (asChild && React18__default.isValidElement(children)) {
731
731
  return /* @__PURE__ */ jsx(Tooltip$1.Trigger, { disabled, render: children, ...props });
732
732
  }
733
733
  return /* @__PURE__ */ jsx(Tooltip$1.Trigger, { disabled, ...props, children });
@@ -756,7 +756,7 @@ function TooltipContent({
756
756
  }
757
757
  ) }) });
758
758
  }
759
- var Avatar = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
759
+ var Avatar = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
760
760
  AvatarPrimitive.Root,
761
761
  {
762
762
  ref,
@@ -768,7 +768,7 @@ var Avatar = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
768
768
  }
769
769
  ));
770
770
  Avatar.displayName = AvatarPrimitive.Root.displayName;
771
- var AvatarImage = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
771
+ var AvatarImage = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
772
772
  AvatarPrimitive.Image,
773
773
  {
774
774
  ref,
@@ -777,7 +777,7 @@ var AvatarImage = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE
777
777
  }
778
778
  ));
779
779
  AvatarImage.displayName = AvatarPrimitive.Image.displayName;
780
- var AvatarFallback = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
780
+ var AvatarFallback = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
781
781
  AvatarPrimitive.Fallback,
782
782
  {
783
783
  ref,
@@ -831,7 +831,7 @@ var MessageContent = ({
831
831
  );
832
832
  return markdown ? /* @__PURE__ */ jsx(Markdown, { className: classNames, ...props, children }) : /* @__PURE__ */ jsx("div", { className: classNames, ...props, children });
833
833
  };
834
- var Textarea = React7.forwardRef(({ className, ...props }, ref) => {
834
+ var Textarea = React18.forwardRef(({ className, ...props }, ref) => {
835
835
  return /* @__PURE__ */ jsx(
836
836
  "textarea",
837
837
  {
@@ -995,7 +995,7 @@ function PromptInputAction({
995
995
  }
996
996
  var HoverCard = HoverCardPrimitive.Root;
997
997
  var HoverCardTrigger = HoverCardPrimitive.Trigger;
998
- var HoverCardContent = React7.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
998
+ var HoverCardContent = React18.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
999
999
  HoverCardPrimitive.Content,
1000
1000
  {
1001
1001
  ref,
@@ -1095,11 +1095,11 @@ function SourceContent({
1095
1095
  }
1096
1096
  ) });
1097
1097
  }
1098
- var ReasoningContext = React7.createContext(
1098
+ var ReasoningContext = React18.createContext(
1099
1099
  null
1100
1100
  );
1101
1101
  function useReasoningContext() {
1102
- const context = React7.useContext(ReasoningContext);
1102
+ const context = React18.useContext(ReasoningContext);
1103
1103
  if (!context) {
1104
1104
  throw new Error(
1105
1105
  "Reasoning components must be used within a Reasoning provider"
@@ -1115,11 +1115,11 @@ function Reasoning({
1115
1115
  defaultOpen = false,
1116
1116
  className
1117
1117
  }) {
1118
- const [uncontrolledOpen, setUncontrolledOpen] = React7.useState(defaultOpen);
1119
- const prevStreamingRef = React7.useRef(isStreaming);
1118
+ const [uncontrolledOpen, setUncontrolledOpen] = React18.useState(defaultOpen);
1119
+ const prevStreamingRef = React18.useRef(isStreaming);
1120
1120
  const isControlled = controlledOpen !== void 0;
1121
1121
  const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
1122
- const setIsOpen = React7.useCallback(
1122
+ const setIsOpen = React18.useCallback(
1123
1123
  (open) => {
1124
1124
  if (onOpenChange) {
1125
1125
  onOpenChange(open);
@@ -1130,7 +1130,7 @@ function Reasoning({
1130
1130
  },
1131
1131
  [isControlled, onOpenChange]
1132
1132
  );
1133
- React7.useEffect(() => {
1133
+ React18.useEffect(() => {
1134
1134
  if (isStreaming && !prevStreamingRef.current) {
1135
1135
  setIsOpen(true);
1136
1136
  } else if (!isStreaming && prevStreamingRef.current) {
@@ -1186,9 +1186,9 @@ function ReasoningContent({
1186
1186
  className
1187
1187
  }) {
1188
1188
  const { isOpen } = useReasoningContext();
1189
- const contentRef = React7.useRef(null);
1190
- const [height, setHeight] = React7.useState(0);
1191
- React7.useEffect(() => {
1189
+ const contentRef = React18.useRef(null);
1190
+ const [height, setHeight] = React18.useState(0);
1191
+ React18.useEffect(() => {
1192
1192
  if (contentRef.current) {
1193
1193
  const resizeObserver = new ResizeObserver((entries) => {
1194
1194
  for (const entry of entries) {
@@ -1237,11 +1237,11 @@ function SimpleReasoning({
1237
1237
  /* @__PURE__ */ jsx(ReasoningContent, { markdown, children: content })
1238
1238
  ] });
1239
1239
  }
1240
- var CopilotUIContext = React7.createContext(
1240
+ var CopilotUIContext = React18.createContext(
1241
1241
  null
1242
1242
  );
1243
1243
  function useCopilotUI() {
1244
- const context = React7.useContext(CopilotUIContext);
1244
+ const context = React18.useContext(CopilotUIContext);
1245
1245
  if (!context) {
1246
1246
  return {
1247
1247
  debug: false,
@@ -1256,7 +1256,7 @@ function CopilotUIProvider({
1256
1256
  debug = false,
1257
1257
  defaultDebugExpanded = false
1258
1258
  }) {
1259
- const value = React7.useMemo(
1259
+ const value = React18.useMemo(
1260
1260
  () => ({
1261
1261
  debug,
1262
1262
  defaultDebugExpanded,
@@ -1398,7 +1398,7 @@ function ToolStep({
1398
1398
  }) {
1399
1399
  const { isDebug, defaultDebugExpanded } = useCopilotUI();
1400
1400
  const debug = debugProp ?? isDebug;
1401
- const [expanded, setExpanded] = React7.useState(
1401
+ const [expanded, setExpanded] = React18.useState(
1402
1402
  defaultExpanded ?? defaultDebugExpanded ?? false
1403
1403
  );
1404
1404
  const displayTitle = getDisplayTitle(step);
@@ -1621,6 +1621,22 @@ function ChevronUpIcon({ className }) {
1621
1621
  }
1622
1622
  );
1623
1623
  }
1624
+ function ChevronLeftIcon({ className }) {
1625
+ return /* @__PURE__ */ jsx(
1626
+ "svg",
1627
+ {
1628
+ xmlns: "http://www.w3.org/2000/svg",
1629
+ viewBox: "0 0 24 24",
1630
+ fill: "none",
1631
+ stroke: "currentColor",
1632
+ strokeWidth: "2",
1633
+ strokeLinecap: "round",
1634
+ strokeLinejoin: "round",
1635
+ className,
1636
+ children: /* @__PURE__ */ jsx("path", { d: "m15 18-6-6 6-6" })
1637
+ }
1638
+ );
1639
+ }
1624
1640
  function CopyIcon({ className }) {
1625
1641
  return /* @__PURE__ */ jsxs(
1626
1642
  "svg",
@@ -1863,9 +1879,9 @@ function ArrowUpRightIcon({ className }) {
1863
1879
  }
1864
1880
  );
1865
1881
  }
1866
- var ConfirmationContext = React7.createContext(null);
1882
+ var ConfirmationContext = React18.createContext(null);
1867
1883
  function useConfirmationContext() {
1868
- const context = React7.useContext(ConfirmationContext);
1884
+ const context = React18.useContext(ConfirmationContext);
1869
1885
  if (!context) {
1870
1886
  throw new Error(
1871
1887
  "Confirmation components must be used within a Confirmation provider"
@@ -2037,8 +2053,8 @@ function PermissionConfirmation({
2037
2053
  permissionOptions = DEFAULT_PERMISSION_OPTIONS,
2038
2054
  className
2039
2055
  }) {
2040
- const [selectedPermission, setSelectedPermission] = React7.useState("ask");
2041
- const [showOptions, setShowOptions] = React7.useState(false);
2056
+ const [selectedPermission, setSelectedPermission] = React18.useState("ask");
2057
+ const [showOptions, setShowOptions] = React18.useState(false);
2042
2058
  const handleApprove = () => {
2043
2059
  onApprove?.(selectedPermission);
2044
2060
  };
@@ -2168,7 +2184,7 @@ function CompactPermissionConfirmation({
2168
2184
  onReject,
2169
2185
  className
2170
2186
  }) {
2171
- const [rememberChoice, setRememberChoice] = React7.useState(false);
2187
+ const [rememberChoice, setRememberChoice] = React18.useState(false);
2172
2188
  const handleApprove = () => {
2173
2189
  onApprove?.(rememberChoice ? "allow_always" : "ask");
2174
2190
  };
@@ -2711,9 +2727,9 @@ function ModelSelector({
2711
2727
  showCapabilities = true,
2712
2728
  className
2713
2729
  }) {
2714
- const [isOpen, setIsOpen] = React7.useState(false);
2715
- const containerRef = React7.useRef(null);
2716
- React7.useEffect(() => {
2730
+ const [isOpen, setIsOpen] = React18.useState(false);
2731
+ const containerRef = React18.useRef(null);
2732
+ React18.useEffect(() => {
2717
2733
  function handleClickOutside(event) {
2718
2734
  if (containerRef.current && !containerRef.current.contains(event.target)) {
2719
2735
  setIsOpen(false);
@@ -2722,7 +2738,7 @@ function ModelSelector({
2722
2738
  document.addEventListener("mousedown", handleClickOutside);
2723
2739
  return () => document.removeEventListener("mousedown", handleClickOutside);
2724
2740
  }, []);
2725
- const selectedModel = React7.useMemo(() => {
2741
+ const selectedModel = React18.useMemo(() => {
2726
2742
  if (!value) return null;
2727
2743
  if (providers) {
2728
2744
  for (const provider of providers) {
@@ -2948,7 +2964,7 @@ function PopoverTrigger({
2948
2964
  className,
2949
2965
  ...props
2950
2966
  }) {
2951
- if (asChild && React7.isValidElement(children)) {
2967
+ if (asChild && React18.isValidElement(children)) {
2952
2968
  return /* @__PURE__ */ jsx(Popover$1.Trigger, { render: children, className, ...props });
2953
2969
  }
2954
2970
  return /* @__PURE__ */ jsx(Popover$1.Trigger, { className, ...props, children });
@@ -3083,8 +3099,8 @@ function ThreadPicker({
3083
3099
  itemClassName,
3084
3100
  newButtonClassName
3085
3101
  }) {
3086
- const [isOpen, setIsOpen] = React7.useState(false);
3087
- const selectedThread = React7.useMemo(() => {
3102
+ const [isOpen, setIsOpen] = React18.useState(false);
3103
+ const selectedThread = React18.useMemo(() => {
3088
3104
  if (!value) return null;
3089
3105
  return threads.find((t) => t.id === value) ?? null;
3090
3106
  }, [value, threads]);
@@ -3290,7 +3306,7 @@ function ThreadCard({
3290
3306
  showDelete = true,
3291
3307
  className
3292
3308
  }) {
3293
- const [isHovered, setIsHovered] = React7.useState(false);
3309
+ const [isHovered, setIsHovered] = React18.useState(false);
3294
3310
  const handleDelete = (e) => {
3295
3311
  e.stopPropagation();
3296
3312
  onDelete?.();
@@ -3541,7 +3557,7 @@ function DefaultMessage({
3541
3557
  }) {
3542
3558
  const isUser = message.role === "user";
3543
3559
  const isStreaming = isLastMessage && isLoading;
3544
- const { cleanContent, followUps } = React7.useMemo(() => {
3560
+ const { cleanContent, followUps } = React18.useMemo(() => {
3545
3561
  if (isUser || !message.content) {
3546
3562
  return { cleanContent: message.content, followUps: [] };
3547
3563
  }
@@ -3680,7 +3696,7 @@ function DefaultMessage({
3680
3696
  toolName: exec.name
3681
3697
  };
3682
3698
  const output = toolDef.render(renderProps);
3683
- return /* @__PURE__ */ jsx(React7.Fragment, { children: output }, exec.id);
3699
+ return /* @__PURE__ */ jsx(React18.Fragment, { children: output }, exec.id);
3684
3700
  }
3685
3701
  return null;
3686
3702
  }) }),
@@ -3716,7 +3732,7 @@ function DefaultMessage({
3716
3732
  approval: approvalCallbacks
3717
3733
  };
3718
3734
  const output = toolDef.render(renderProps);
3719
- return /* @__PURE__ */ jsx(React7.Fragment, { children: output }, tool.id);
3735
+ return /* @__PURE__ */ jsx(React18.Fragment, { children: output }, tool.id);
3720
3736
  }
3721
3737
  return /* @__PURE__ */ jsx(
3722
3738
  PermissionConfirmation,
@@ -3748,7 +3764,7 @@ function DefaultMessage({
3748
3764
  ] });
3749
3765
  }
3750
3766
  function AttachmentPreview({ attachment }) {
3751
- const [expanded, setExpanded] = React7.useState(false);
3767
+ const [expanded, setExpanded] = React18.useState(false);
3752
3768
  if (attachment.type !== "image") {
3753
3769
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 rounded-lg border bg-muted/50 px-3 py-2 text-sm", children: [
3754
3770
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: attachment.type }),
@@ -4168,6 +4184,199 @@ function ChatWelcome({
4168
4184
  }
4169
4185
  );
4170
4186
  }
4187
+ var CopilotChatContext = createContext(
4188
+ null
4189
+ );
4190
+ var useCopilotChatContext = () => {
4191
+ const ctx = useContext(CopilotChatContext);
4192
+ if (!ctx) {
4193
+ throw new Error(
4194
+ "useCopilotChatContext must be used within CopilotChat. Make sure you're using CopilotChat.Home, CopilotChat.Input, etc. inside <CopilotChat>"
4195
+ );
4196
+ }
4197
+ return ctx;
4198
+ };
4199
+ function HomeView({ children, className }) {
4200
+ const { view } = useCopilotChatContext();
4201
+ if (view !== "home") return null;
4202
+ return /* @__PURE__ */ jsx(
4203
+ "div",
4204
+ {
4205
+ className: cn(
4206
+ "csdk-chat-home-view flex flex-1 flex-col overflow-auto",
4207
+ className
4208
+ ),
4209
+ children: /* @__PURE__ */ jsx("div", { className: "flex flex-col items-center my-auto w-full", children })
4210
+ }
4211
+ );
4212
+ }
4213
+ var Home = HomeView;
4214
+ function ChatView({ children, className }) {
4215
+ const { view } = useCopilotChatContext();
4216
+ if (view !== "chat") return null;
4217
+ if (children) {
4218
+ return /* @__PURE__ */ jsx("div", { className: cn("csdk-chat-view flex flex-col", className), children });
4219
+ }
4220
+ return null;
4221
+ }
4222
+ ChatView.displayName = "ChatView";
4223
+ function chatViewHasOnlyLayoutChildren(chatViewElement) {
4224
+ if (!chatViewElement?.props?.children) return false;
4225
+ const childArray = React18__default.Children.toArray(chatViewElement.props.children);
4226
+ if (childArray.length === 0) return false;
4227
+ return childArray.every(
4228
+ (child) => React18__default.isValidElement(child) && (child.type === Header || child.type === Footer)
4229
+ );
4230
+ }
4231
+ function Header({ children, className }) {
4232
+ return /* @__PURE__ */ jsx("div", { className: cn("csdk-chat-header", className), children });
4233
+ }
4234
+ function Footer({ children, className }) {
4235
+ return /* @__PURE__ */ jsx("div", { className: cn("csdk-chat-footer", className), children });
4236
+ }
4237
+ function Input({ placeholder: placeholderProp, className }) {
4238
+ const {
4239
+ send,
4240
+ isLoading,
4241
+ onStop,
4242
+ placeholder: defaultPlaceholder
4243
+ } = useCopilotChatContext();
4244
+ const [value, setValue] = useState("");
4245
+ const handleSubmit = useCallback(() => {
4246
+ if (value.trim() && !isLoading) {
4247
+ send(value.trim());
4248
+ setValue("");
4249
+ }
4250
+ }, [value, isLoading, send]);
4251
+ return /* @__PURE__ */ jsxs(
4252
+ PromptInput,
4253
+ {
4254
+ value,
4255
+ onValueChange: setValue,
4256
+ isLoading,
4257
+ onSubmit: handleSubmit,
4258
+ className: cn("csdk-compound-input", className),
4259
+ children: [
4260
+ /* @__PURE__ */ jsx(
4261
+ PromptInputTextarea,
4262
+ {
4263
+ placeholder: placeholderProp ?? defaultPlaceholder
4264
+ }
4265
+ ),
4266
+ /* @__PURE__ */ jsx(PromptInputActions, { className: "justify-end", children: /* @__PURE__ */ jsx(PromptInputAction, { tooltip: isLoading ? "Stop" : "Send", children: isLoading ? /* @__PURE__ */ jsx(
4267
+ Button,
4268
+ {
4269
+ size: "sm",
4270
+ variant: "destructive",
4271
+ className: "csdk-button-stop rounded-full size-9",
4272
+ onClick: onStop,
4273
+ children: /* @__PURE__ */ jsx(StopIcon, { className: "h-4 w-4" })
4274
+ }
4275
+ ) : /* @__PURE__ */ jsx(
4276
+ Button,
4277
+ {
4278
+ size: "sm",
4279
+ className: "csdk-button-send rounded-full size-9",
4280
+ onClick: handleSubmit,
4281
+ disabled: !value.trim(),
4282
+ children: /* @__PURE__ */ jsx(ArrowUpIcon, { className: "h-4 w-4" })
4283
+ }
4284
+ ) }) })
4285
+ ]
4286
+ }
4287
+ );
4288
+ }
4289
+ function SuggestionsCompound({
4290
+ items,
4291
+ label,
4292
+ className,
4293
+ buttonClassName
4294
+ }) {
4295
+ const { send } = useCopilotChatContext();
4296
+ if (items.length === 0) return null;
4297
+ return /* @__PURE__ */ jsxs("div", { className: cn("csdk-compound-suggestions", className), children: [
4298
+ label && /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground mb-2 block", children: label }),
4299
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: items.map((item, i) => /* @__PURE__ */ jsx(
4300
+ "button",
4301
+ {
4302
+ onClick: () => send(item),
4303
+ className: cn(
4304
+ "csdk-followup-button px-3 py-1.5 text-sm rounded-full border",
4305
+ "bg-background hover:bg-accent transition-colors",
4306
+ buttonClassName
4307
+ ),
4308
+ children: item
4309
+ },
4310
+ i
4311
+ )) })
4312
+ ] });
4313
+ }
4314
+ function BackButton({
4315
+ className,
4316
+ children,
4317
+ disabled,
4318
+ "aria-label": ariaLabel = "Start new chat"
4319
+ }) {
4320
+ const { onNewChat, isThreadBusy } = useCopilotChatContext();
4321
+ if (!onNewChat) return null;
4322
+ return /* @__PURE__ */ jsx(
4323
+ "button",
4324
+ {
4325
+ type: "button",
4326
+ onClick: onNewChat,
4327
+ disabled: disabled || isThreadBusy,
4328
+ "aria-label": ariaLabel,
4329
+ className: cn(
4330
+ "csdk-back-button flex items-center gap-1 text-sm",
4331
+ "hover:bg-accent rounded px-2 py-1",
4332
+ "disabled:opacity-50 disabled:cursor-not-allowed",
4333
+ className
4334
+ ),
4335
+ children: children || /* @__PURE__ */ jsxs(Fragment, { children: [
4336
+ /* @__PURE__ */ jsx(ChevronLeftIcon, { className: "h-4 w-4" }),
4337
+ /* @__PURE__ */ jsx("span", { children: "New Chat" })
4338
+ ] })
4339
+ }
4340
+ );
4341
+ }
4342
+ function ThreadPickerCompound(props) {
4343
+ const {
4344
+ threads,
4345
+ currentThreadId,
4346
+ onSwitchThread,
4347
+ onNewChat,
4348
+ onDeleteThread,
4349
+ isThreadBusy
4350
+ } = useCopilotChatContext();
4351
+ if (!threads || !onSwitchThread) return null;
4352
+ return /* @__PURE__ */ jsx(
4353
+ ThreadPicker,
4354
+ {
4355
+ ...props,
4356
+ value: currentThreadId,
4357
+ threads,
4358
+ onSelect: onSwitchThread,
4359
+ onNewThread: onNewChat,
4360
+ onDeleteThread,
4361
+ disabled: isThreadBusy
4362
+ }
4363
+ );
4364
+ }
4365
+ function hasCompoundChild(children, ...components) {
4366
+ return React18__default.Children.toArray(children).some(
4367
+ (child) => React18__default.isValidElement(child) && components.includes(child.type)
4368
+ );
4369
+ }
4370
+ function findCompoundChild(children, component) {
4371
+ return React18__default.Children.toArray(children).find(
4372
+ (child) => React18__default.isValidElement(child) && child.type === component
4373
+ );
4374
+ }
4375
+ function filterCompoundChildren(children, ...components) {
4376
+ return React18__default.Children.toArray(children).filter(
4377
+ (child) => React18__default.isValidElement(child) && components.includes(child.type)
4378
+ );
4379
+ }
4171
4380
  var DEFAULT_MAX_FILE_SIZE2 = 5 * 1024 * 1024;
4172
4381
  var DEFAULT_ALLOWED_TYPES2 = ["image/*", "application/pdf"];
4173
4382
  function getAttachmentType2(mimeType) {
@@ -4193,12 +4402,14 @@ function fileToBase642(file) {
4193
4402
  function generateAttachmentId2() {
4194
4403
  return `att_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
4195
4404
  }
4196
- function Chat({
4405
+ function ChatComponent({
4197
4406
  // Core
4198
4407
  messages = [],
4199
4408
  onSendMessage,
4200
4409
  onStop,
4201
4410
  isLoading = false,
4411
+ // Compound children
4412
+ children,
4202
4413
  // Labels
4203
4414
  placeholder = "Type a message...",
4204
4415
  welcomeMessage,
@@ -4249,7 +4460,13 @@ function Chat({
4249
4460
  renderHeader,
4250
4461
  // Styling
4251
4462
  className,
4252
- classNames = {}
4463
+ classNames = {},
4464
+ // Thread management for compound components
4465
+ onNewChat,
4466
+ threads,
4467
+ currentThreadId,
4468
+ onSwitchThread,
4469
+ isThreadBusy
4253
4470
  }) {
4254
4471
  const [input, setInput] = useState("");
4255
4472
  const [pendingAttachments, setPendingAttachments] = useState([]);
@@ -4400,9 +4617,60 @@ function Chat({
4400
4617
  [onSuggestionClick, onSendMessage]
4401
4618
  );
4402
4619
  const acceptString = allowedFileTypes.join(",");
4403
- const showWelcome = messages.length === 0 && welcome !== false;
4620
+ const view = messages.length === 0 ? "home" : "chat";
4621
+ const hasCustomHome = hasCompoundChild(children, Home, HomeView);
4622
+ const hasCustomChatView = hasCompoundChild(children, ChatView);
4623
+ const hasCustomLayout = hasCustomHome || hasCustomChatView;
4624
+ const rootHeader = findCompoundChild(children, Header);
4625
+ const rootFooter = findCompoundChild(children, Footer);
4626
+ const viewChildren = filterCompoundChildren(
4627
+ children,
4628
+ HomeView,
4629
+ Home,
4630
+ ChatView
4631
+ );
4632
+ const chatViewElement = findCompoundChild(children, ChatView);
4633
+ const chatViewNeedsDefault = chatViewElement && (!chatViewElement.props.children || chatViewHasOnlyLayoutChildren(chatViewElement));
4634
+ const showDefaultWelcome = view === "home" && !hasCustomHome && welcome !== false;
4404
4635
  const welcomeConfig = typeof welcome === "object" ? welcome : void 0;
4405
- return /* @__PURE__ */ jsxs(
4636
+ const send = useCallback(
4637
+ (message, attachments) => {
4638
+ onSendMessage?.(message, attachments);
4639
+ },
4640
+ [onSendMessage]
4641
+ );
4642
+ const contextValue = React18__default.useMemo(
4643
+ () => ({
4644
+ view,
4645
+ send,
4646
+ isLoading,
4647
+ onStop,
4648
+ attachmentsEnabled,
4649
+ placeholder,
4650
+ // Thread management - passed from connected-chat
4651
+ onNewChat,
4652
+ threads,
4653
+ currentThreadId,
4654
+ onSwitchThread,
4655
+ onDeleteThread,
4656
+ isThreadBusy
4657
+ }),
4658
+ [
4659
+ view,
4660
+ send,
4661
+ isLoading,
4662
+ onStop,
4663
+ attachmentsEnabled,
4664
+ placeholder,
4665
+ onNewChat,
4666
+ threads,
4667
+ currentThreadId,
4668
+ onSwitchThread,
4669
+ onDeleteThread,
4670
+ isThreadBusy
4671
+ ]
4672
+ );
4673
+ return /* @__PURE__ */ jsx(CopilotChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
4406
4674
  "div",
4407
4675
  {
4408
4676
  className: cn(
@@ -4426,8 +4694,10 @@ function Chat({
4426
4694
  className: classNames.header
4427
4695
  }
4428
4696
  )),
4429
- showWelcome ? (
4430
- /* Welcome Screen (centered input) */
4697
+ rootHeader,
4698
+ hasCustomLayout && viewChildren,
4699
+ showDefaultWelcome ? (
4700
+ /* Default Welcome Screen (centered input) */
4431
4701
  /* @__PURE__ */ jsx(
4432
4702
  ChatWelcome,
4433
4703
  {
@@ -4448,249 +4718,265 @@ function Chat({
4448
4718
  processAttachment: processAttachmentProp
4449
4719
  }
4450
4720
  )
4451
- ) : (
4452
- /* Normal Chat UI (messages + input at bottom) */
4453
- /* @__PURE__ */ jsxs(Fragment, { children: [
4454
- /* @__PURE__ */ jsxs(
4455
- ChatContainerRoot,
4456
- {
4457
- className: cn("relative flex-1", classNames.container),
4458
- children: [
4459
- /* @__PURE__ */ jsxs(
4460
- ChatContainerContent,
4461
- {
4462
- className: cn("gap-4 p-4", classNames.messageList),
4463
- children: [
4464
- messages.length === 0 && /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-muted-foreground", children: welcomeMessage || "Send a message to start the conversation" }),
4465
- messages.map((message, index) => {
4466
- const isLastMessage = index === messages.length - 1;
4467
- const isEmptyAssistant = message.role === "assistant" && !message.content?.trim();
4468
- const hasToolCalls = message.tool_calls && message.tool_calls.length > 0;
4469
- const hasToolExecutions = message.toolExecutions && message.toolExecutions.length > 0;
4470
- const hasPendingApprovals = message.toolExecutions?.some(
4471
- (exec) => exec.approvalStatus === "required"
4472
- );
4473
- if (isEmptyAssistant) {
4474
- if (hasToolCalls || hasToolExecutions) ; else if (isLastMessage && hasPendingApprovals) ; else if (isLastMessage && isLoading && !isProcessing) {
4475
- return /* @__PURE__ */ jsxs(Message, { className: "flex gap-2", children: [
4476
- /* @__PURE__ */ jsx(
4477
- MessageAvatar,
4478
- {
4479
- src: assistantAvatar.src || "",
4480
- alt: "Assistant",
4481
- fallback: assistantAvatar.fallback,
4482
- fallbackIcon: !assistantAvatar.src ? /* @__PURE__ */ jsx(copilot_sdk_logo_default, { className: "size-5" }) : void 0,
4483
- className: "bg-background"
4484
- }
4485
- ),
4486
- /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-muted px-4 py-2", children: /* @__PURE__ */ jsx(Loader, { variant: loaderVariant, size: "sm" }) })
4487
- ] }, message.id);
4488
- } else {
4489
- return null;
4490
- }
4491
- }
4492
- const savedExecutions = message.metadata?.toolExecutions;
4493
- const messageToolExecutions = message.toolExecutions || savedExecutions;
4494
- const messageWithExecutions = messageToolExecutions ? { ...message, toolExecutions: messageToolExecutions } : message;
4495
- const handleFollowUpClick = (question) => {
4496
- if (onSuggestionClick) {
4497
- onSuggestionClick(question);
4498
- } else {
4499
- onSendMessage?.(question);
4500
- }
4501
- };
4502
- return renderMessage ? /* @__PURE__ */ jsx(React7__default.Fragment, { children: renderMessage(messageWithExecutions, index) }, message.id) : /* @__PURE__ */ jsx(
4503
- DefaultMessage,
4504
- {
4505
- message: messageWithExecutions,
4506
- userAvatar,
4507
- assistantAvatar,
4508
- showUserAvatar,
4509
- userMessageClassName: classNames.userMessage,
4510
- assistantMessageClassName: classNames.assistantMessage,
4511
- size: fontSize,
4512
- isLastMessage,
4513
- isLoading,
4514
- registeredTools,
4515
- toolRenderers,
4516
- onApproveToolExecution,
4517
- onRejectToolExecution,
4518
- showFollowUps,
4519
- onFollowUpClick: handleFollowUpClick,
4520
- followUpClassName,
4521
- followUpButtonClassName
4522
- },
4523
- message.id
4524
- );
4525
- }),
4526
- isProcessing && /* @__PURE__ */ jsxs(Message, { className: "flex gap-2", children: [
4527
- /* @__PURE__ */ jsx(
4528
- MessageAvatar,
4529
- {
4530
- src: assistantAvatar?.src || "",
4531
- alt: "Assistant",
4532
- fallback: assistantAvatar?.fallback || "AI",
4533
- fallbackIcon: !assistantAvatar?.src ? /* @__PURE__ */ jsx(copilot_sdk_logo_default, { className: "size-5" }) : void 0,
4534
- className: "bg-background"
4535
- }
4536
- ),
4537
- /* @__PURE__ */ jsxs("div", { className: "rounded-lg bg-muted px-4 py-2 flex items-center gap-2", children: [
4538
- /* @__PURE__ */ jsx(Loader, { variant: "dots", size: "sm" }),
4539
- /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Continuing..." })
4540
- ] })
4541
- ] }),
4542
- isLoading && !isProcessing && (() => {
4543
- const lastMessage = messages[messages.length - 1];
4544
- if (lastMessage?.role === "user") {
4721
+ ) : null,
4722
+ view === "chat" && (!hasCustomChatView || chatViewNeedsDefault) && /* @__PURE__ */ jsxs(Fragment, { children: [
4723
+ /* @__PURE__ */ jsxs(
4724
+ ChatContainerRoot,
4725
+ {
4726
+ className: cn("relative flex-1", classNames.container),
4727
+ children: [
4728
+ /* @__PURE__ */ jsxs(
4729
+ ChatContainerContent,
4730
+ {
4731
+ className: cn("gap-4 p-4", classNames.messageList),
4732
+ children: [
4733
+ messages.length === 0 && /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-muted-foreground", children: welcomeMessage || "Send a message to start the conversation" }),
4734
+ messages.map((message, index) => {
4735
+ const isLastMessage = index === messages.length - 1;
4736
+ const isEmptyAssistant = message.role === "assistant" && !message.content?.trim();
4737
+ const hasToolCalls = message.tool_calls && message.tool_calls.length > 0;
4738
+ const hasToolExecutions = message.toolExecutions && message.toolExecutions.length > 0;
4739
+ const hasPendingApprovals = message.toolExecutions?.some(
4740
+ (exec) => exec.approvalStatus === "required"
4741
+ );
4742
+ if (isEmptyAssistant) {
4743
+ if (hasToolCalls || hasToolExecutions) ; else if (isLastMessage && hasPendingApprovals) ; else if (isLastMessage && isLoading && !isProcessing) {
4545
4744
  return /* @__PURE__ */ jsxs(Message, { className: "flex gap-2", children: [
4546
4745
  /* @__PURE__ */ jsx(
4547
4746
  MessageAvatar,
4548
4747
  {
4549
- src: assistantAvatar?.src || "",
4748
+ src: assistantAvatar.src || "",
4550
4749
  alt: "Assistant",
4551
- fallback: assistantAvatar?.fallback || "AI",
4552
- fallbackIcon: !assistantAvatar?.src ? /* @__PURE__ */ jsx(copilot_sdk_logo_default, { className: "size-5" }) : void 0,
4750
+ fallback: assistantAvatar.fallback,
4751
+ fallbackIcon: !assistantAvatar.src ? /* @__PURE__ */ jsx(copilot_sdk_logo_default, { className: "size-5" }) : void 0,
4553
4752
  className: "bg-background"
4554
4753
  }
4555
4754
  ),
4556
4755
  /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-muted px-4 py-2", children: /* @__PURE__ */ jsx(Loader, { variant: loaderVariant, size: "sm" }) })
4557
- ] });
4756
+ ] }, message.id);
4757
+ } else {
4758
+ return null;
4558
4759
  }
4559
- return null;
4560
- })(),
4561
- /* @__PURE__ */ jsx(ChatContainerScrollAnchor, {})
4562
- ]
4563
- }
4564
- ),
4565
- /* @__PURE__ */ jsx("div", { className: "absolute right-4 bottom-4", children: /* @__PURE__ */ jsx(ScrollButton, { className: "shadow-sm" }) })
4566
- ]
4567
- }
4568
- ),
4569
- suggestions.length > 0 && !isLoading && /* @__PURE__ */ jsx(
4570
- Suggestions,
4571
- {
4572
- suggestions,
4573
- onSuggestionClick: handleSuggestionClick,
4574
- className: classNames.suggestions
4575
- }
4576
- ),
4577
- renderInput ? renderInput() : /* @__PURE__ */ jsxs("div", { className: cn("p-2 pt-0", classNames.input), children: [
4578
- pendingAttachments.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 p-2 mb-2 bg-muted/30 rounded-lg", children: pendingAttachments.map((att) => /* @__PURE__ */ jsxs("div", { className: "relative group", children: [
4579
- att.attachment.type === "image" ? /* @__PURE__ */ jsx(
4580
- "img",
4581
- {
4582
- src: att.previewUrl,
4583
- alt: att.file.name,
4584
- className: "w-16 h-16 object-cover rounded-lg border"
4585
- }
4586
- ) : /* @__PURE__ */ jsxs("div", { className: "w-16 h-16 bg-muted rounded-lg border flex flex-col items-center justify-center p-1", children: [
4587
- /* @__PURE__ */ jsx(
4588
- "svg",
4589
- {
4590
- className: "w-6 h-6 text-muted-foreground",
4591
- fill: "none",
4592
- viewBox: "0 0 24 24",
4593
- stroke: "currentColor",
4594
- children: /* @__PURE__ */ jsx(
4595
- "path",
4596
- {
4597
- strokeLinecap: "round",
4598
- strokeLinejoin: "round",
4599
- strokeWidth: 1.5,
4600
- d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
4601
4760
  }
4602
- )
4603
- }
4604
- ),
4605
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground truncate w-full text-center mt-1", children: att.file.name.length > 10 ? att.file.name.slice(0, 8) + "..." : att.file.name })
4606
- ] }),
4607
- att.status === "processing" && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-background/80 rounded-lg flex items-center justify-center", children: /* @__PURE__ */ jsx(Loader, { variant: "dots", size: "sm" }) }),
4608
- att.status === "error" && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-destructive/20 rounded-lg flex items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "text-destructive text-xs", children: "Error" }) }),
4761
+ const savedExecutions = message.metadata?.toolExecutions;
4762
+ const messageToolExecutions = message.toolExecutions || savedExecutions;
4763
+ const messageWithExecutions = messageToolExecutions ? { ...message, toolExecutions: messageToolExecutions } : message;
4764
+ const handleFollowUpClick = (question) => {
4765
+ if (onSuggestionClick) {
4766
+ onSuggestionClick(question);
4767
+ } else {
4768
+ onSendMessage?.(question);
4769
+ }
4770
+ };
4771
+ return renderMessage ? /* @__PURE__ */ jsx(React18__default.Fragment, { children: renderMessage(messageWithExecutions, index) }, message.id) : /* @__PURE__ */ jsx(
4772
+ DefaultMessage,
4773
+ {
4774
+ message: messageWithExecutions,
4775
+ userAvatar,
4776
+ assistantAvatar,
4777
+ showUserAvatar,
4778
+ userMessageClassName: classNames.userMessage,
4779
+ assistantMessageClassName: classNames.assistantMessage,
4780
+ size: fontSize,
4781
+ isLastMessage,
4782
+ isLoading,
4783
+ registeredTools,
4784
+ toolRenderers,
4785
+ onApproveToolExecution,
4786
+ onRejectToolExecution,
4787
+ showFollowUps,
4788
+ onFollowUpClick: handleFollowUpClick,
4789
+ followUpClassName,
4790
+ followUpButtonClassName
4791
+ },
4792
+ message.id
4793
+ );
4794
+ }),
4795
+ isProcessing && /* @__PURE__ */ jsxs(Message, { className: "flex gap-2", children: [
4796
+ /* @__PURE__ */ jsx(
4797
+ MessageAvatar,
4798
+ {
4799
+ src: assistantAvatar?.src || "",
4800
+ alt: "Assistant",
4801
+ fallback: assistantAvatar?.fallback || "AI",
4802
+ fallbackIcon: !assistantAvatar?.src ? /* @__PURE__ */ jsx(copilot_sdk_logo_default, { className: "size-5" }) : void 0,
4803
+ className: "bg-background"
4804
+ }
4805
+ ),
4806
+ /* @__PURE__ */ jsxs("div", { className: "rounded-lg bg-muted px-4 py-2 flex items-center gap-2", children: [
4807
+ /* @__PURE__ */ jsx(Loader, { variant: "dots", size: "sm" }),
4808
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Continuing..." })
4809
+ ] })
4810
+ ] }),
4811
+ isLoading && !isProcessing && (() => {
4812
+ const lastMessage = messages[messages.length - 1];
4813
+ if (lastMessage?.role === "user") {
4814
+ return /* @__PURE__ */ jsxs(Message, { className: "flex gap-2", children: [
4815
+ /* @__PURE__ */ jsx(
4816
+ MessageAvatar,
4817
+ {
4818
+ src: assistantAvatar?.src || "",
4819
+ alt: "Assistant",
4820
+ fallback: assistantAvatar?.fallback || "AI",
4821
+ fallbackIcon: !assistantAvatar?.src ? /* @__PURE__ */ jsx(copilot_sdk_logo_default, { className: "size-5" }) : void 0,
4822
+ className: "bg-background"
4823
+ }
4824
+ ),
4825
+ /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-muted px-4 py-2", children: /* @__PURE__ */ jsx(Loader, { variant: loaderVariant, size: "sm" }) })
4826
+ ] });
4827
+ }
4828
+ return null;
4829
+ })(),
4830
+ /* @__PURE__ */ jsx(ChatContainerScrollAnchor, {})
4831
+ ]
4832
+ }
4833
+ ),
4834
+ /* @__PURE__ */ jsx("div", { className: "absolute right-4 bottom-4", children: /* @__PURE__ */ jsx(ScrollButton, { className: "shadow-sm" }) })
4835
+ ]
4836
+ }
4837
+ ),
4838
+ suggestions.length > 0 && !isLoading && /* @__PURE__ */ jsx(
4839
+ Suggestions,
4840
+ {
4841
+ suggestions,
4842
+ onSuggestionClick: handleSuggestionClick,
4843
+ className: classNames.suggestions
4844
+ }
4845
+ ),
4846
+ renderInput ? renderInput() : /* @__PURE__ */ jsxs("div", { className: cn("p-2 pt-0", classNames.input), children: [
4847
+ pendingAttachments.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 p-2 mb-2 bg-muted/30 rounded-lg", children: pendingAttachments.map((att) => /* @__PURE__ */ jsxs("div", { className: "relative group", children: [
4848
+ att.attachment.type === "image" ? /* @__PURE__ */ jsx(
4849
+ "img",
4850
+ {
4851
+ src: att.previewUrl,
4852
+ alt: att.file.name,
4853
+ className: "w-16 h-16 object-cover rounded-lg border"
4854
+ }
4855
+ ) : /* @__PURE__ */ jsxs("div", { className: "w-16 h-16 bg-muted rounded-lg border flex flex-col items-center justify-center p-1", children: [
4609
4856
  /* @__PURE__ */ jsx(
4610
- "button",
4857
+ "svg",
4611
4858
  {
4612
- onClick: () => removePendingAttachment(att.id),
4613
- className: "absolute -top-1.5 -right-1.5 bg-destructive text-destructive-foreground rounded-full p-0.5 opacity-0 group-hover:opacity-100 transition-opacity",
4614
- type: "button",
4615
- children: /* @__PURE__ */ jsx(XIcon2, { className: "w-3 h-3" })
4859
+ className: "w-6 h-6 text-muted-foreground",
4860
+ fill: "none",
4861
+ viewBox: "0 0 24 24",
4862
+ stroke: "currentColor",
4863
+ children: /* @__PURE__ */ jsx(
4864
+ "path",
4865
+ {
4866
+ strokeLinecap: "round",
4867
+ strokeLinejoin: "round",
4868
+ strokeWidth: 1.5,
4869
+ d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
4870
+ }
4871
+ )
4616
4872
  }
4617
- )
4618
- ] }, att.id)) }),
4619
- /* @__PURE__ */ jsxs(
4620
- PromptInput,
4873
+ ),
4874
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground truncate w-full text-center mt-1", children: att.file.name.length > 10 ? att.file.name.slice(0, 8) + "..." : att.file.name })
4875
+ ] }),
4876
+ att.status === "processing" && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-background/80 rounded-lg flex items-center justify-center", children: /* @__PURE__ */ jsx(Loader, { variant: "dots", size: "sm" }) }),
4877
+ att.status === "error" && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-destructive/20 rounded-lg flex items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "text-destructive text-xs", children: "Error" }) }),
4878
+ /* @__PURE__ */ jsx(
4879
+ "button",
4621
4880
  {
4622
- value: input,
4623
- onValueChange: setInput,
4624
- isLoading,
4625
- onSubmit: handleSubmit,
4626
- className: "",
4627
- children: [
4628
- /* @__PURE__ */ jsx(PromptInputTextarea, { placeholder }),
4629
- /* @__PURE__ */ jsxs(PromptInputActions, { className: "flex justify-between", children: [
4630
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
4631
- PromptInputAction,
4632
- {
4633
- tooltip: attachmentsEnabled ? "Attach files" : attachmentsDisabledTooltip,
4634
- children: /* @__PURE__ */ jsxs(
4635
- "label",
4636
- {
4637
- htmlFor: fileInputId,
4638
- className: cn(
4639
- "csdk-button-attach flex h-8 w-8 items-center justify-center rounded-2xl",
4640
- attachmentsEnabled ? "hover:bg-secondary-foreground/10 cursor-pointer" : "opacity-50 cursor-not-allowed"
4641
- ),
4642
- children: [
4643
- /* @__PURE__ */ jsx(
4644
- "input",
4645
- {
4646
- ref: fileInputRef,
4647
- type: "file",
4648
- multiple: true,
4649
- accept: acceptString,
4650
- onChange: handleInputChange,
4651
- className: "hidden",
4652
- id: fileInputId,
4653
- disabled: !attachmentsEnabled
4654
- }
4655
- ),
4656
- /* @__PURE__ */ jsx(PlusIcon, { className: "text-primary size-5" })
4657
- ]
4658
- }
4659
- )
4660
- }
4661
- ) }),
4662
- /* @__PURE__ */ jsx(PromptInputAction, { tooltip: isLoading ? "Stop" : "Send", children: isLoading ? /* @__PURE__ */ jsx(
4663
- Button,
4664
- {
4665
- size: "sm",
4666
- variant: "destructive",
4667
- className: "csdk-button-stop rounded-full size-9",
4668
- onClick: onStop,
4669
- children: /* @__PURE__ */ jsx(StopIcon, { className: "h-4 w-4" })
4670
- }
4671
- ) : /* @__PURE__ */ jsx(
4672
- Button,
4673
- {
4674
- size: "sm",
4675
- className: "csdk-button-send rounded-full size-9",
4676
- onClick: handleSubmit,
4677
- disabled: !input.trim() && !pendingAttachments.some(
4678
- (att) => att.status === "ready"
4679
- ),
4680
- children: /* @__PURE__ */ jsx(ArrowUpIcon, { className: "h-4 w-4" })
4681
- }
4682
- ) })
4683
- ] })
4684
- ]
4881
+ onClick: () => removePendingAttachment(att.id),
4882
+ className: "absolute -top-1.5 -right-1.5 bg-destructive text-destructive-foreground rounded-full p-0.5 opacity-0 group-hover:opacity-100 transition-opacity",
4883
+ type: "button",
4884
+ children: /* @__PURE__ */ jsx(XIcon2, { className: "w-3 h-3" })
4685
4885
  }
4686
4886
  )
4687
- ] })
4887
+ ] }, att.id)) }),
4888
+ /* @__PURE__ */ jsxs(
4889
+ PromptInput,
4890
+ {
4891
+ value: input,
4892
+ onValueChange: setInput,
4893
+ isLoading,
4894
+ onSubmit: handleSubmit,
4895
+ className: "",
4896
+ children: [
4897
+ /* @__PURE__ */ jsx(PromptInputTextarea, { placeholder }),
4898
+ /* @__PURE__ */ jsxs(PromptInputActions, { className: "flex justify-between", children: [
4899
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
4900
+ PromptInputAction,
4901
+ {
4902
+ tooltip: attachmentsEnabled ? "Attach files" : attachmentsDisabledTooltip,
4903
+ children: /* @__PURE__ */ jsxs(
4904
+ "label",
4905
+ {
4906
+ htmlFor: fileInputId,
4907
+ className: cn(
4908
+ "csdk-button-attach flex h-8 w-8 items-center justify-center rounded-2xl",
4909
+ attachmentsEnabled ? "hover:bg-secondary-foreground/10 cursor-pointer" : "opacity-50 cursor-not-allowed"
4910
+ ),
4911
+ children: [
4912
+ /* @__PURE__ */ jsx(
4913
+ "input",
4914
+ {
4915
+ ref: fileInputRef,
4916
+ type: "file",
4917
+ multiple: true,
4918
+ accept: acceptString,
4919
+ onChange: handleInputChange,
4920
+ className: "hidden",
4921
+ id: fileInputId,
4922
+ disabled: !attachmentsEnabled
4923
+ }
4924
+ ),
4925
+ /* @__PURE__ */ jsx(PlusIcon, { className: "text-primary size-5" })
4926
+ ]
4927
+ }
4928
+ )
4929
+ }
4930
+ ) }),
4931
+ /* @__PURE__ */ jsx(PromptInputAction, { tooltip: isLoading ? "Stop" : "Send", children: isLoading ? /* @__PURE__ */ jsx(
4932
+ Button,
4933
+ {
4934
+ size: "sm",
4935
+ variant: "destructive",
4936
+ className: "csdk-button-stop rounded-full size-9",
4937
+ onClick: onStop,
4938
+ children: /* @__PURE__ */ jsx(StopIcon, { className: "h-4 w-4" })
4939
+ }
4940
+ ) : /* @__PURE__ */ jsx(
4941
+ Button,
4942
+ {
4943
+ size: "sm",
4944
+ className: "csdk-button-send rounded-full size-9",
4945
+ onClick: handleSubmit,
4946
+ disabled: !input.trim() && !pendingAttachments.some(
4947
+ (att) => att.status === "ready"
4948
+ ),
4949
+ children: /* @__PURE__ */ jsx(ArrowUpIcon, { className: "h-4 w-4" })
4950
+ }
4951
+ ) })
4952
+ ] })
4953
+ ]
4954
+ }
4955
+ )
4688
4956
  ] })
4689
- )
4957
+ ] }),
4958
+ rootFooter
4690
4959
  ]
4691
4960
  }
4692
- );
4961
+ ) });
4693
4962
  }
4963
+ var Chat = Object.assign(ChatComponent, {
4964
+ Root: ChatComponent,
4965
+ // Alias for layout composition pattern
4966
+ Home,
4967
+ // Backward compat alias
4968
+ HomeView,
4969
+ // New name
4970
+ ChatView,
4971
+ Header,
4972
+ Footer,
4973
+ Input,
4974
+ Suggestions: SuggestionsCompound,
4975
+ BackButton,
4976
+ // Navigation: start new chat
4977
+ ThreadPicker: ThreadPickerCompound
4978
+ // Thread switching
4979
+ });
4694
4980
  function ToolExecutionMessage({
4695
4981
  executions,
4696
4982
  assistantAvatar = { fallback: "AI" },
@@ -5021,13 +5307,14 @@ function parsePersistenceConfig(persistence, onThreadChange) {
5021
5307
  onThreadChange
5022
5308
  };
5023
5309
  }
5024
- function CopilotChat(props) {
5310
+ function CopilotChatBase(props) {
5025
5311
  const {
5026
5312
  persistence,
5027
5313
  showThreadPicker = false,
5028
5314
  onThreadChange,
5029
5315
  classNames,
5030
5316
  header,
5317
+ children,
5031
5318
  ...chatProps
5032
5319
  } = props;
5033
5320
  const persistenceConfig = parsePersistenceConfig(persistence, onThreadChange);
@@ -5167,7 +5454,7 @@ function CopilotChat(props) {
5167
5454
  footer: classNames.footer
5168
5455
  } : void 0;
5169
5456
  const { threadManager, handleSwitchThread, handleNewThread, isBusy } = threadManagerResult;
5170
- const handleDeleteThread = React7__default.useCallback(
5457
+ const handleDeleteThread = React18__default.useCallback(
5171
5458
  (threadId) => {
5172
5459
  const isCurrentThread = threadManager.currentThreadId === threadId;
5173
5460
  threadManager.deleteThread(threadId);
@@ -5218,10 +5505,33 @@ function CopilotChat(props) {
5218
5505
  renderHeader: useCustomHeader ? chatProps.renderHeader : void 0,
5219
5506
  recentThreads: isPersistenceEnabled ? threadManager.threads : void 0,
5220
5507
  onSelectThread: isPersistenceEnabled ? handleSwitchThread : void 0,
5221
- onDeleteThread: isPersistenceEnabled ? handleDeleteThread : void 0
5508
+ onDeleteThread: isPersistenceEnabled ? handleDeleteThread : void 0,
5509
+ onNewChat: handleNewThread,
5510
+ threads: isPersistenceEnabled ? threadManager.threads : void 0,
5511
+ currentThreadId: threadManager.currentThreadId,
5512
+ onSwitchThread: isPersistenceEnabled ? handleSwitchThread : void 0,
5513
+ isThreadBusy: isBusy,
5514
+ children
5222
5515
  }
5223
5516
  );
5224
5517
  }
5518
+ var CopilotChat = Object.assign(CopilotChatBase, {
5519
+ Root: CopilotChatBase,
5520
+ // Alias for layout composition pattern
5521
+ Home: Chat.Home,
5522
+ // Backward compat alias
5523
+ HomeView: Chat.HomeView,
5524
+ // New name
5525
+ ChatView: Chat.ChatView,
5526
+ Header: Chat.Header,
5527
+ Footer: Chat.Footer,
5528
+ Input: Chat.Input,
5529
+ Suggestions: Chat.Suggestions,
5530
+ BackButton: Chat.BackButton,
5531
+ // Navigation: start new chat
5532
+ ThreadPicker: Chat.ThreadPicker
5533
+ // Thread switching
5534
+ });
5225
5535
  var ConnectedChat = CopilotChat;
5226
5536
  function YourGPTLogo({ className }) {
5227
5537
  return /* @__PURE__ */ jsxs(
@@ -5269,6 +5579,6 @@ function PoweredBy({ className, showLogo = true }) {
5269
5579
  );
5270
5580
  }
5271
5581
 
5272
- export { AlertTriangleIcon, BotIcon, Button, CapabilityBadge, CapabilityList, Chat, ChatContainerContent, ChatContainerRoot, ChatContainerScrollAnchor, ChatWelcome, CheckIcon, ChevronDownIcon2 as ChevronDownIcon, ChevronUpIcon, CloseIcon, CodeBlock, CompactPermissionConfirmation, Confirmation, ConfirmationActions, ConfirmationApproved, ConfirmationMessage, ConfirmationPending, ConfirmationRejected, ConnectedChat, CopilotChat, CopilotUIProvider, CopyIcon, DEFAULT_PERMISSION_OPTIONS, DevLogger, FeedbackBar, FollowUpQuestions, InlineToolSteps, Loader, Markdown, MessageAvatar, MessageContent, Message as MessagePrimitive, ModelSelector, PermissionConfirmation, PoweredBy, PromptInput, PromptInputAction, PromptInputActions, PromptInputTextarea, Reasoning, ReasoningContent, ReasoningTrigger, RefreshIcon, ScrollButton, SendIcon, SimpleConfirmation, SimpleModelSelector, SimpleReasoning, Source, SourceContent, SourceTrigger, StopIcon, ThreadCard, ThreadList, ThreadPicker, ThumbsDownIcon2 as ThumbsDownIcon, ThumbsUpIcon2 as ThumbsUpIcon, ToolExecutionMessage, ToolStep, ToolSteps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserIcon, XIcon2 as XIcon, cn, parseFollowUps, useChatContainer, useCopilotUI };
5582
+ export { AlertTriangleIcon, BotIcon, Button, CapabilityBadge, CapabilityList, Chat, ChatContainerContent, ChatContainerRoot, ChatContainerScrollAnchor, ChatWelcome, CheckIcon, ChevronDownIcon2 as ChevronDownIcon, ChevronLeftIcon, ChevronUpIcon, CloseIcon, CodeBlock, CompactPermissionConfirmation, Confirmation, ConfirmationActions, ConfirmationApproved, ConfirmationMessage, ConfirmationPending, ConfirmationRejected, ConnectedChat, CopilotChat, CopilotUIProvider, CopyIcon, DEFAULT_PERMISSION_OPTIONS, DevLogger, FeedbackBar, FollowUpQuestions, InlineToolSteps, Loader, Markdown, MessageAvatar, MessageContent, Message as MessagePrimitive, ModelSelector, PermissionConfirmation, PoweredBy, PromptInput, PromptInputAction, PromptInputActions, PromptInputTextarea, Reasoning, ReasoningContent, ReasoningTrigger, RefreshIcon, ScrollButton, SendIcon, SimpleConfirmation, SimpleModelSelector, SimpleReasoning, Source, SourceContent, SourceTrigger, StopIcon, ThreadCard, ThreadList, ThreadPicker, ThumbsDownIcon2 as ThumbsDownIcon, ThumbsUpIcon2 as ThumbsUpIcon, ToolExecutionMessage, ToolStep, ToolSteps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserIcon, XIcon2 as XIcon, cn, parseFollowUps, useChatContainer, useCopilotChatContext, useCopilotUI };
5273
5583
  //# sourceMappingURL=index.js.map
5274
5584
  //# sourceMappingURL=index.js.map