@copilotkitnext/react 0.0.12 → 0.0.13-alpha.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/index.mjs CHANGED
@@ -1,17 +1,13 @@
1
+ "use client";
2
+
1
3
  // src/components/chat/CopilotChatInput.tsx
2
- import {
3
- useState,
4
- useRef as useRef2,
5
- useEffect as useEffect2,
6
- forwardRef as forwardRef2,
7
- useImperativeHandle as useImperativeHandle2
8
- } from "react";
4
+ import { useState as useState2, useRef as useRef2, useEffect as useEffect2, forwardRef as forwardRef2, useImperativeHandle as useImperativeHandle2 } from "react";
9
5
  import { twMerge as twMerge3 } from "tailwind-merge";
10
6
  import { Plus, Settings2, Mic, ArrowUp, X, Check } from "lucide-react";
11
7
 
12
8
  // src/providers/CopilotChatConfigurationProvider.tsx
13
- import { createContext, useContext } from "react";
14
- import { DEFAULT_AGENT_ID } from "@copilotkitnext/shared";
9
+ import { createContext, useContext, useMemo, useState } from "react";
10
+ import { DEFAULT_AGENT_ID, randomUUID } from "@copilotkitnext/shared";
15
11
  import { jsx } from "react/jsx-runtime";
16
12
  var CopilotChatDefaultLabels = {
17
13
  chatInputPlaceholder: "Type a message...",
@@ -29,24 +25,56 @@ var CopilotChatDefaultLabels = {
29
25
  assistantMessageToolbarRegenerateLabel: "Regenerate",
30
26
  userMessageToolbarCopyMessageLabel: "Copy",
31
27
  userMessageToolbarEditMessageLabel: "Edit",
32
- chatDisclaimerText: "AI can make mistakes. Please verify important information."
28
+ chatDisclaimerText: "AI can make mistakes. Please verify important information.",
29
+ chatToggleOpenLabel: "Open chat",
30
+ chatToggleCloseLabel: "Close chat",
31
+ modalHeaderTitle: "CopilotKit Chat"
33
32
  };
34
33
  var CopilotChatConfiguration = createContext(null);
35
- var CopilotChatConfigurationProvider = ({
36
- children,
37
- labels = {},
38
- agentId,
39
- threadId
40
- }) => {
41
- const mergedLabels = {
42
- ...CopilotChatDefaultLabels,
43
- ...labels
44
- };
45
- const configurationValue = {
46
- labels: mergedLabels,
47
- agentId: agentId ?? DEFAULT_AGENT_ID,
48
- threadId
49
- };
34
+ var CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId, isModalDefaultOpen }) => {
35
+ const parentConfig = useContext(CopilotChatConfiguration);
36
+ const mergedLabels = useMemo(
37
+ () => ({
38
+ ...CopilotChatDefaultLabels,
39
+ ...parentConfig?.labels ?? {},
40
+ ...labels ?? {}
41
+ }),
42
+ [labels, parentConfig?.labels]
43
+ );
44
+ const resolvedAgentId = agentId ?? parentConfig?.agentId ?? DEFAULT_AGENT_ID;
45
+ const resolvedThreadId = useMemo(() => {
46
+ if (threadId) {
47
+ return threadId;
48
+ }
49
+ if (parentConfig?.threadId) {
50
+ return parentConfig.threadId;
51
+ }
52
+ return randomUUID();
53
+ }, [threadId, parentConfig?.threadId]);
54
+ const resolvedDefaultOpen = isModalDefaultOpen ?? parentConfig?.isModalDefaultOpen ?? true;
55
+ const [internalModalOpen, setInternalModalOpen] = useState(
56
+ parentConfig?.isModalOpen ?? resolvedDefaultOpen
57
+ );
58
+ const resolvedIsModalOpen = parentConfig?.isModalOpen ?? internalModalOpen;
59
+ const resolvedSetModalOpen = parentConfig?.setModalOpen ?? setInternalModalOpen;
60
+ const configurationValue = useMemo(
61
+ () => ({
62
+ labels: mergedLabels,
63
+ agentId: resolvedAgentId,
64
+ threadId: resolvedThreadId,
65
+ isModalOpen: resolvedIsModalOpen,
66
+ setModalOpen: resolvedSetModalOpen,
67
+ isModalDefaultOpen: resolvedDefaultOpen
68
+ }),
69
+ [
70
+ mergedLabels,
71
+ resolvedAgentId,
72
+ resolvedThreadId,
73
+ resolvedIsModalOpen,
74
+ resolvedSetModalOpen,
75
+ resolvedDefaultOpen
76
+ ]
77
+ );
50
78
  return /* @__PURE__ */ jsx(CopilotChatConfiguration.Provider, { value: configurationValue, children });
51
79
  };
52
80
  var useCopilotChatConfiguration = () => {
@@ -491,7 +519,7 @@ function CopilotChatInput({
491
519
  ...props
492
520
  }) {
493
521
  const isControlled = value !== void 0;
494
- const [internalValue, setInternalValue] = useState(() => value ?? "");
522
+ const [internalValue, setInternalValue] = useState2(() => value ?? "");
495
523
  useEffect2(() => {
496
524
  if (!isControlled && value !== void 0) {
497
525
  setInternalValue(value);
@@ -500,6 +528,18 @@ function CopilotChatInput({
500
528
  const resolvedValue = isControlled ? value ?? "" : internalValue;
501
529
  const inputRef = useRef2(null);
502
530
  const audioRecorderRef = useRef2(null);
531
+ const config = useCopilotChatConfiguration();
532
+ const previousModalStateRef = useRef2(void 0);
533
+ useEffect2(() => {
534
+ if (!autoFocus) {
535
+ previousModalStateRef.current = config?.isModalOpen;
536
+ return;
537
+ }
538
+ if (config?.isModalOpen && !previousModalStateRef.current) {
539
+ inputRef.current?.focus();
540
+ }
541
+ previousModalStateRef.current = config?.isModalOpen;
542
+ }, [config?.isModalOpen, autoFocus]);
503
543
  useEffect2(() => {
504
544
  const recorder = audioRecorderRef.current;
505
545
  if (!recorder) {
@@ -550,59 +590,32 @@ function CopilotChatInput({
550
590
  onKeyDown: handleKeyDown,
551
591
  autoFocus
552
592
  });
553
- const BoundAudioRecorder = renderSlot(
554
- audioRecorder,
555
- CopilotChatAudioRecorder,
556
- {
557
- ref: audioRecorderRef
558
- }
559
- );
593
+ const BoundAudioRecorder = renderSlot(audioRecorder, CopilotChatAudioRecorder, {
594
+ ref: audioRecorderRef
595
+ });
560
596
  const BoundSendButton = renderSlot(sendButton, CopilotChatInput.SendButton, {
561
597
  onClick: send,
562
598
  disabled: !resolvedValue.trim() || !onSubmitMessage
563
599
  });
564
- const BoundStartTranscribeButton = renderSlot(
565
- startTranscribeButton,
566
- CopilotChatInput.StartTranscribeButton,
567
- {
568
- onClick: onStartTranscribe
569
- }
570
- );
571
- const BoundCancelTranscribeButton = renderSlot(
572
- cancelTranscribeButton,
573
- CopilotChatInput.CancelTranscribeButton,
574
- {
575
- onClick: onCancelTranscribe
576
- }
577
- );
578
- const BoundFinishTranscribeButton = renderSlot(
579
- finishTranscribeButton,
580
- CopilotChatInput.FinishTranscribeButton,
581
- {
582
- onClick: onFinishTranscribe
583
- }
584
- );
585
- const BoundAddFileButton = renderSlot(
586
- addFileButton,
587
- CopilotChatInput.AddFileButton,
588
- {
589
- onClick: onAddFile,
590
- disabled: mode === "transcribe"
591
- }
592
- );
593
- const BoundToolsButton = renderSlot(
594
- toolsButton,
595
- CopilotChatInput.ToolsButton,
596
- {
597
- disabled: mode === "transcribe",
598
- toolsMenu
599
- }
600
- );
600
+ const BoundStartTranscribeButton = renderSlot(startTranscribeButton, CopilotChatInput.StartTranscribeButton, {
601
+ onClick: onStartTranscribe
602
+ });
603
+ const BoundCancelTranscribeButton = renderSlot(cancelTranscribeButton, CopilotChatInput.CancelTranscribeButton, {
604
+ onClick: onCancelTranscribe
605
+ });
606
+ const BoundFinishTranscribeButton = renderSlot(finishTranscribeButton, CopilotChatInput.FinishTranscribeButton, {
607
+ onClick: onFinishTranscribe
608
+ });
609
+ const BoundAddFileButton = renderSlot(addFileButton, CopilotChatInput.AddFileButton, {
610
+ onClick: onAddFile,
611
+ disabled: mode === "transcribe"
612
+ });
613
+ const BoundToolsButton = renderSlot(toolsButton, CopilotChatInput.ToolsButton, {
614
+ disabled: mode === "transcribe",
615
+ toolsMenu
616
+ });
601
617
  const BoundToolbar = renderSlot(
602
- typeof toolbar === "string" || toolbar === void 0 ? twMerge3(
603
- toolbar,
604
- "w-full h-[60px] bg-transparent flex items-center justify-between"
605
- ) : toolbar,
618
+ typeof toolbar === "string" || toolbar === void 0 ? twMerge3(toolbar, "w-full h-[60px] bg-transparent flex items-center justify-between") : toolbar,
606
619
  CopilotChatInput.Toolbar,
607
620
  {
608
621
  children: /* @__PURE__ */ jsxs3(Fragment, { children: [
@@ -643,6 +656,12 @@ function CopilotChatInput({
643
656
  additionalToolbarItems
644
657
  }) });
645
658
  }
659
+ const handleContainerClick = (e) => {
660
+ const target = e.target;
661
+ if (target.tagName !== "BUTTON" && !target.closest("button") && inputRef.current && mode === "input") {
662
+ inputRef.current.focus();
663
+ }
664
+ };
646
665
  return /* @__PURE__ */ jsxs3(
647
666
  "div",
648
667
  {
@@ -659,6 +678,7 @@ function CopilotChatInput({
659
678
  "shadow-[0_4px_4px_0_#0000000a,0_0_1px_0_#0000009e] rounded-[28px]",
660
679
  className
661
680
  ),
681
+ onClick: handleContainerClick,
662
682
  ...props,
663
683
  children: [
664
684
  mode === "transcribe" ? BoundAudioRecorder : BoundTextArea,
@@ -771,100 +791,83 @@ function CopilotChatInput({
771
791
  /* @__PURE__ */ jsx6(DropdownMenuContent, { side: "top", align: "end", children: renderMenuItems(toolsMenu) })
772
792
  ] });
773
793
  };
774
- CopilotChatInput2.Toolbar = ({
775
- className,
776
- ...props
777
- }) => /* @__PURE__ */ jsx6(
778
- "div",
779
- {
780
- className: twMerge3(
781
- "w-full h-[60px] bg-transparent flex items-center",
782
- className
783
- ),
784
- ...props
785
- }
786
- );
787
- CopilotChatInput2.TextArea = forwardRef2(
788
- function TextArea2({ maxRows = 5, style, className, ...props }, ref) {
789
- const internalTextareaRef = useRef2(null);
790
- const [maxHeight, setMaxHeight] = useState(0);
791
- const config = useCopilotChatConfiguration();
792
- const labels = config?.labels ?? CopilotChatDefaultLabels;
793
- useImperativeHandle2(
794
- ref,
795
- () => internalTextareaRef.current
796
- );
797
- const adjustHeight = () => {
794
+ CopilotChatInput2.Toolbar = ({ className, ...props }) => /* @__PURE__ */ jsx6("div", { className: twMerge3("w-full h-[60px] bg-transparent flex items-center", className), ...props });
795
+ CopilotChatInput2.TextArea = forwardRef2(function TextArea2({ maxRows = 5, style, className, ...props }, ref) {
796
+ const internalTextareaRef = useRef2(null);
797
+ const [maxHeight, setMaxHeight] = useState2(0);
798
+ const config = useCopilotChatConfiguration();
799
+ const labels = config?.labels ?? CopilotChatDefaultLabels;
800
+ useImperativeHandle2(ref, () => internalTextareaRef.current);
801
+ const adjustHeight = () => {
802
+ const textarea = internalTextareaRef.current;
803
+ if (textarea && maxHeight > 0) {
804
+ textarea.style.height = "auto";
805
+ textarea.style.height = `${Math.min(textarea.scrollHeight, maxHeight)}px`;
806
+ }
807
+ };
808
+ useEffect2(() => {
809
+ const calculateMaxHeight = () => {
798
810
  const textarea = internalTextareaRef.current;
799
- if (textarea && maxHeight > 0) {
811
+ if (textarea) {
812
+ const currentValue = textarea.value;
813
+ textarea.value = "";
800
814
  textarea.style.height = "auto";
801
- textarea.style.height = `${Math.min(textarea.scrollHeight, maxHeight)}px`;
802
- }
803
- };
804
- useEffect2(() => {
805
- const calculateMaxHeight = () => {
806
- const textarea = internalTextareaRef.current;
807
- if (textarea) {
808
- const currentValue = textarea.value;
809
- textarea.value = "";
815
+ const computedStyle = window.getComputedStyle(textarea);
816
+ const paddingTop = parseFloat(computedStyle.paddingTop);
817
+ const paddingBottom = parseFloat(computedStyle.paddingBottom);
818
+ const contentHeight = textarea.scrollHeight - paddingTop - paddingBottom;
819
+ setMaxHeight(contentHeight * maxRows + paddingTop + paddingBottom);
820
+ textarea.value = currentValue;
821
+ if (currentValue) {
810
822
  textarea.style.height = "auto";
811
- const computedStyle = window.getComputedStyle(textarea);
812
- const paddingTop = parseFloat(computedStyle.paddingTop);
813
- const paddingBottom = parseFloat(computedStyle.paddingBottom);
814
- const contentHeight = textarea.scrollHeight - paddingTop - paddingBottom;
815
- setMaxHeight(contentHeight * maxRows + paddingTop + paddingBottom);
816
- textarea.value = currentValue;
817
- if (currentValue) {
818
- textarea.style.height = "auto";
819
- textarea.style.height = `${Math.min(textarea.scrollHeight, contentHeight * maxRows + paddingTop + paddingBottom)}px`;
820
- }
821
- if (props.autoFocus) {
822
- textarea.focus();
823
- }
823
+ textarea.style.height = `${Math.min(textarea.scrollHeight, contentHeight * maxRows + paddingTop + paddingBottom)}px`;
824
+ }
825
+ if (props.autoFocus) {
826
+ textarea.focus();
824
827
  }
825
- };
826
- calculateMaxHeight();
827
- }, [maxRows, props.autoFocus]);
828
- useEffect2(() => {
829
- adjustHeight();
830
- }, [props.value, maxHeight]);
831
- const handleInput = (e) => {
832
- adjustHeight();
833
- if (props.onChange) {
834
- props.onChange(e);
835
828
  }
836
829
  };
837
- return /* @__PURE__ */ jsx6(
838
- "textarea",
839
- {
840
- ref: internalTextareaRef,
841
- ...props,
842
- onChange: handleInput,
843
- style: {
844
- overflow: "auto",
845
- resize: "none",
846
- maxHeight: `${maxHeight}px`,
847
- ...style
848
- },
849
- placeholder: labels.chatInputPlaceholder,
850
- className: twMerge3(
851
- // Layout and sizing
852
- "w-full p-5 pb-0",
853
- // Behavior
854
- "outline-none resize-none",
855
- // Background
856
- "bg-transparent",
857
- // Typography
858
- "antialiased font-regular leading-relaxed text-[16px]",
859
- // Placeholder styles
860
- "placeholder:text-[#00000077] dark:placeholder:text-[#fffc]",
861
- className
862
- ),
863
- rows: 1
864
- }
865
- );
866
- }
867
- );
830
+ calculateMaxHeight();
831
+ }, [maxRows, props.autoFocus]);
832
+ useEffect2(() => {
833
+ adjustHeight();
834
+ }, [props.value, maxHeight]);
835
+ const handleInput = (e) => {
836
+ adjustHeight();
837
+ if (props.onChange) {
838
+ props.onChange(e);
839
+ }
840
+ };
841
+ return /* @__PURE__ */ jsx6(
842
+ "textarea",
843
+ {
844
+ ref: internalTextareaRef,
845
+ ...props,
846
+ onChange: handleInput,
847
+ style: {
848
+ overflow: "auto",
849
+ resize: "none",
850
+ maxHeight: `${maxHeight}px`,
851
+ ...style
852
+ },
853
+ placeholder: labels.chatInputPlaceholder,
854
+ className: twMerge3(
855
+ // Layout and sizing
856
+ "w-full p-5 pb-0",
857
+ // Behavior
858
+ "outline-none resize-none",
859
+ // Background
860
+ "bg-transparent",
861
+ // Typography
862
+ "antialiased font-regular leading-relaxed text-[16px]",
863
+ // Placeholder styles
864
+ "placeholder:text-[#00000077] dark:placeholder:text-[#fffc]",
865
+ className
866
+ ),
867
+ rows: 1
868
+ }
869
+ );
870
+ });
868
871
  CopilotChatInput2.AudioRecorder = CopilotChatAudioRecorder;
869
872
  })(CopilotChatInput || (CopilotChatInput = {}));
870
873
  CopilotChatInput.TextArea.displayName = "CopilotChatInput.TextArea";
@@ -884,7 +887,7 @@ import remarkGfm from "remark-gfm";
884
887
  import remarkMath from "remark-math";
885
888
  import rehypePrettyCode from "rehype-pretty-code";
886
889
  import rehypeKatex from "rehype-katex";
887
- import { useState as useState5 } from "react";
890
+ import { useState as useState7 } from "react";
888
891
  import {
889
892
  Copy,
890
893
  Check as Check2,
@@ -898,11 +901,11 @@ import "katex/dist/katex.min.css";
898
901
  import { completePartialMarkdown } from "@copilotkitnext/core";
899
902
 
900
903
  // src/hooks/use-render-tool-call.tsx
901
- import { useCallback, useEffect as useEffect4, useState as useState3 } from "react";
904
+ import { useCallback, useEffect as useEffect4, useState as useState4 } from "react";
902
905
  import { ToolCallStatus } from "@copilotkitnext/core";
903
906
 
904
907
  // src/providers/CopilotKitProvider.tsx
905
- import { createContext as createContext2, useContext as useContext2, useMemo, useEffect as useEffect3, useState as useState2, useReducer, useRef as useRef3 } from "react";
908
+ import { createContext as createContext2, useContext as useContext2, useMemo as useMemo2, useEffect as useEffect3, useState as useState3, useReducer, useRef as useRef3 } from "react";
906
909
  import { z } from "zod";
907
910
  import { CopilotKitCore } from "@copilotkitnext/core";
908
911
  import { jsx as jsx7 } from "react/jsx-runtime";
@@ -914,7 +917,7 @@ var CopilotKitContext = createContext2({
914
917
  }
915
918
  });
916
919
  function useStableArrayProp(prop, warningMessage, isMeaningfulChange) {
917
- const empty = useMemo(() => [], []);
920
+ const empty = useMemo2(() => [], []);
918
921
  const value = prop ?? empty;
919
922
  const initial = useRef3(value);
920
923
  useEffect3(() => {
@@ -955,9 +958,9 @@ var CopilotKitProvider = ({
955
958
  humanInTheLoop,
956
959
  "humanInTheLoop must be a stable array. If you want to dynamically add or remove human-in-the-loop tools, use `useHumanInTheLoop` instead."
957
960
  );
958
- const initialRenderToolCalls = useMemo(() => renderToolCallsList, []);
959
- const [currentRenderToolCalls, setCurrentRenderToolCalls] = useState2([]);
960
- const processedHumanInTheLoopTools = useMemo(() => {
961
+ const initialRenderToolCalls = useMemo2(() => renderToolCallsList, []);
962
+ const [currentRenderToolCalls, setCurrentRenderToolCalls] = useState3([]);
963
+ const processedHumanInTheLoopTools = useMemo2(() => {
961
964
  const processedTools = [];
962
965
  const processedRenderToolCalls = [];
963
966
  humanInTheLoopList.forEach((tool) => {
@@ -986,13 +989,13 @@ var CopilotKitProvider = ({
986
989
  });
987
990
  return { tools: processedTools, renderToolCalls: processedRenderToolCalls };
988
991
  }, [humanInTheLoopList]);
989
- const allTools = useMemo(() => {
992
+ const allTools = useMemo2(() => {
990
993
  const tools = [];
991
994
  tools.push(...frontendToolsList);
992
995
  tools.push(...processedHumanInTheLoopTools.tools);
993
996
  return tools;
994
997
  }, [frontendToolsList, processedHumanInTheLoopTools]);
995
- const allRenderToolCalls = useMemo(() => {
998
+ const allRenderToolCalls = useMemo2(() => {
996
999
  const combined = [...renderToolCallsList];
997
1000
  frontendToolsList.forEach((tool) => {
998
1001
  if (tool.render) {
@@ -1009,10 +1012,9 @@ var CopilotKitProvider = ({
1009
1012
  combined.push(...processedHumanInTheLoopTools.renderToolCalls);
1010
1013
  return combined;
1011
1014
  }, [renderToolCallsList, frontendToolsList, processedHumanInTheLoopTools]);
1012
- const copilotkit = useMemo(() => {
1015
+ const copilotkit = useMemo2(() => {
1013
1016
  const config = {
1014
- // Don't set runtimeUrl during initialization to prevent server-side fetching
1015
- runtimeUrl: void 0,
1017
+ runtimeUrl,
1016
1018
  headers,
1017
1019
  properties,
1018
1020
  agents__unsafe_dev_only: agents,
@@ -1093,7 +1095,7 @@ function useRenderToolCall() {
1093
1095
  const { currentRenderToolCalls, copilotkit } = useCopilotKit();
1094
1096
  const config = useCopilotChatConfiguration();
1095
1097
  const agentId = config?.agentId ?? DEFAULT_AGENT_ID2;
1096
- const [executingToolCallIds, setExecutingToolCallIds] = useState3(() => /* @__PURE__ */ new Set());
1098
+ const [executingToolCallIds, setExecutingToolCallIds] = useState4(() => /* @__PURE__ */ new Set());
1097
1099
  useEffect4(() => {
1098
1100
  const unsubscribe = copilotkit.subscribe({
1099
1101
  onToolExecutionStart: ({ toolCallId }) => {
@@ -1206,10 +1208,10 @@ function useFrontendTool(tool) {
1206
1208
  }
1207
1209
 
1208
1210
  // src/hooks/use-human-in-the-loop.tsx
1209
- import { useState as useState4, useCallback as useCallback2, useRef as useRef4, useEffect as useEffect6 } from "react";
1211
+ import { useState as useState5, useCallback as useCallback2, useRef as useRef4, useEffect as useEffect6 } from "react";
1210
1212
  import React6 from "react";
1211
1213
  function useHumanInTheLoop(tool) {
1212
- const [status, setStatus] = useState4(
1214
+ const [status, setStatus] = useState5(
1213
1215
  "inProgress"
1214
1216
  );
1215
1217
  const statusRef = useRef4(status);
@@ -1280,7 +1282,7 @@ function useHumanInTheLoop(tool) {
1280
1282
  }
1281
1283
 
1282
1284
  // src/hooks/use-agent.tsx
1283
- import { useMemo as useMemo2, useEffect as useEffect7, useReducer as useReducer2 } from "react";
1285
+ import { useMemo as useMemo3, useEffect as useEffect7, useReducer as useReducer2 } from "react";
1284
1286
  import { DEFAULT_AGENT_ID as DEFAULT_AGENT_ID3 } from "@copilotkitnext/shared";
1285
1287
  var ALL_UPDATES = [
1286
1288
  "OnMessagesChanged" /* OnMessagesChanged */,
@@ -1291,11 +1293,11 @@ function useAgent({ agentId, updates } = {}) {
1291
1293
  agentId ??= DEFAULT_AGENT_ID3;
1292
1294
  const { copilotkit } = useCopilotKit();
1293
1295
  const [, forceUpdate] = useReducer2((x) => x + 1, 0);
1294
- const updateFlags = useMemo2(
1296
+ const updateFlags = useMemo3(
1295
1297
  () => updates ?? ALL_UPDATES,
1296
1298
  [JSON.stringify(updates)]
1297
1299
  );
1298
- const agent = useMemo2(() => {
1300
+ const agent = useMemo3(() => {
1299
1301
  return copilotkit.getAgent(agentId);
1300
1302
  }, [
1301
1303
  agentId,
@@ -1354,6 +1356,190 @@ function useAgentContext(context) {
1354
1356
  }, [description, value, copilotkit]);
1355
1357
  }
1356
1358
 
1359
+ // src/hooks/use-suggestions.tsx
1360
+ import { useCallback as useCallback3, useEffect as useEffect9, useMemo as useMemo4, useState as useState6 } from "react";
1361
+ import { DEFAULT_AGENT_ID as DEFAULT_AGENT_ID4 } from "@copilotkitnext/shared";
1362
+ function useSuggestions({ agentId } = {}) {
1363
+ const { copilotkit } = useCopilotKit();
1364
+ const config = useCopilotChatConfiguration();
1365
+ const resolvedAgentId = useMemo4(() => agentId ?? config?.agentId ?? DEFAULT_AGENT_ID4, [agentId, config?.agentId]);
1366
+ const [suggestions, setSuggestions] = useState6(() => {
1367
+ const result = copilotkit.getSuggestions(resolvedAgentId);
1368
+ return result.suggestions;
1369
+ });
1370
+ const [isLoading, setIsLoading] = useState6(() => {
1371
+ const result = copilotkit.getSuggestions(resolvedAgentId);
1372
+ return result.isLoading;
1373
+ });
1374
+ useEffect9(() => {
1375
+ const result = copilotkit.getSuggestions(resolvedAgentId);
1376
+ setSuggestions(result.suggestions);
1377
+ setIsLoading(result.isLoading);
1378
+ }, [copilotkit, resolvedAgentId]);
1379
+ useEffect9(() => {
1380
+ const unsubscribe = copilotkit.subscribe({
1381
+ onSuggestionsChanged: ({ agentId: changedAgentId, suggestions: suggestions2 }) => {
1382
+ if (changedAgentId !== resolvedAgentId) {
1383
+ return;
1384
+ }
1385
+ setSuggestions(suggestions2);
1386
+ },
1387
+ onSuggestionsStartedLoading: ({ agentId: changedAgentId }) => {
1388
+ if (changedAgentId !== resolvedAgentId) {
1389
+ return;
1390
+ }
1391
+ setIsLoading(true);
1392
+ },
1393
+ onSuggestionsFinishedLoading: ({ agentId: changedAgentId }) => {
1394
+ if (changedAgentId !== resolvedAgentId) {
1395
+ return;
1396
+ }
1397
+ setIsLoading(false);
1398
+ },
1399
+ onSuggestionsConfigChanged: () => {
1400
+ const result = copilotkit.getSuggestions(resolvedAgentId);
1401
+ setSuggestions(result.suggestions);
1402
+ setIsLoading(result.isLoading);
1403
+ }
1404
+ });
1405
+ return () => {
1406
+ unsubscribe();
1407
+ };
1408
+ }, [copilotkit, resolvedAgentId]);
1409
+ const reloadSuggestions = useCallback3(() => {
1410
+ copilotkit.reloadSuggestions(resolvedAgentId);
1411
+ }, [copilotkit, resolvedAgentId]);
1412
+ const clearSuggestions = useCallback3(() => {
1413
+ copilotkit.clearSuggestions(resolvedAgentId);
1414
+ }, [copilotkit, resolvedAgentId]);
1415
+ return {
1416
+ suggestions,
1417
+ reloadSuggestions,
1418
+ clearSuggestions,
1419
+ isLoading
1420
+ };
1421
+ }
1422
+
1423
+ // src/hooks/use-configure-suggestions.tsx
1424
+ import { useCallback as useCallback4, useEffect as useEffect10, useMemo as useMemo5, useRef as useRef5 } from "react";
1425
+ import { DEFAULT_AGENT_ID as DEFAULT_AGENT_ID5 } from "@copilotkitnext/shared";
1426
+ var EMPTY_DEPS = [];
1427
+ function useConfigureSuggestions(config, options) {
1428
+ const { copilotkit } = useCopilotKit();
1429
+ const chatConfig = useCopilotChatConfiguration();
1430
+ const extraDeps = options?.deps ?? EMPTY_DEPS;
1431
+ const resolvedConsumerAgentId = useMemo5(() => chatConfig?.agentId ?? DEFAULT_AGENT_ID5, [chatConfig?.agentId]);
1432
+ const rawConsumerAgentId = useMemo5(() => config ? config.consumerAgentId : void 0, [config]);
1433
+ const normalizationCacheRef = useRef5({
1434
+ serialized: null,
1435
+ config: null
1436
+ });
1437
+ const { normalizedConfig, serializedConfig } = useMemo5(() => {
1438
+ if (!config) {
1439
+ normalizationCacheRef.current = { serialized: null, config: null };
1440
+ return { normalizedConfig: null, serializedConfig: null };
1441
+ }
1442
+ if (config.available === "disabled") {
1443
+ normalizationCacheRef.current = { serialized: null, config: null };
1444
+ return { normalizedConfig: null, serializedConfig: null };
1445
+ }
1446
+ let built;
1447
+ if (isDynamicConfig(config)) {
1448
+ built = {
1449
+ ...config
1450
+ };
1451
+ } else {
1452
+ const normalizedSuggestions = normalizeStaticSuggestions(config.suggestions);
1453
+ const baseConfig = {
1454
+ ...config,
1455
+ suggestions: normalizedSuggestions
1456
+ };
1457
+ built = baseConfig;
1458
+ }
1459
+ const serialized = JSON.stringify(built);
1460
+ const cache = normalizationCacheRef.current;
1461
+ if (cache.serialized === serialized && cache.config) {
1462
+ return { normalizedConfig: cache.config, serializedConfig: serialized };
1463
+ }
1464
+ normalizationCacheRef.current = { serialized, config: built };
1465
+ return { normalizedConfig: built, serializedConfig: serialized };
1466
+ }, [config, resolvedConsumerAgentId, ...extraDeps]);
1467
+ const latestConfigRef = useRef5(null);
1468
+ latestConfigRef.current = normalizedConfig;
1469
+ const previousSerializedConfigRef = useRef5(null);
1470
+ const targetAgentId = useMemo5(() => {
1471
+ if (!normalizedConfig) {
1472
+ return resolvedConsumerAgentId;
1473
+ }
1474
+ const consumer = normalizedConfig.consumerAgentId;
1475
+ if (!consumer || consumer === "*") {
1476
+ return resolvedConsumerAgentId;
1477
+ }
1478
+ return consumer;
1479
+ }, [normalizedConfig, resolvedConsumerAgentId]);
1480
+ const isGlobalConfig = rawConsumerAgentId === void 0 || rawConsumerAgentId === "*";
1481
+ const requestReload = useCallback4(() => {
1482
+ if (!normalizedConfig) {
1483
+ return;
1484
+ }
1485
+ if (isGlobalConfig) {
1486
+ const agents = Object.values(copilotkit.agents ?? {});
1487
+ for (const entry of agents) {
1488
+ const agentId = entry.agentId;
1489
+ if (!agentId) {
1490
+ continue;
1491
+ }
1492
+ if (!entry.isRunning) {
1493
+ copilotkit.reloadSuggestions(agentId);
1494
+ }
1495
+ }
1496
+ return;
1497
+ }
1498
+ if (!targetAgentId) {
1499
+ return;
1500
+ }
1501
+ copilotkit.reloadSuggestions(targetAgentId);
1502
+ }, [copilotkit, isGlobalConfig, normalizedConfig, targetAgentId]);
1503
+ useEffect10(() => {
1504
+ if (!serializedConfig || !latestConfigRef.current) {
1505
+ return;
1506
+ }
1507
+ const id = copilotkit.addSuggestionsConfig(latestConfigRef.current);
1508
+ requestReload();
1509
+ return () => {
1510
+ copilotkit.removeSuggestionsConfig(id);
1511
+ };
1512
+ }, [copilotkit, serializedConfig, requestReload]);
1513
+ useEffect10(() => {
1514
+ if (!normalizedConfig) {
1515
+ previousSerializedConfigRef.current = null;
1516
+ return;
1517
+ }
1518
+ if (serializedConfig && previousSerializedConfigRef.current === serializedConfig) {
1519
+ return;
1520
+ }
1521
+ if (serializedConfig) {
1522
+ previousSerializedConfigRef.current = serializedConfig;
1523
+ }
1524
+ requestReload();
1525
+ }, [normalizedConfig, requestReload, serializedConfig]);
1526
+ useEffect10(() => {
1527
+ if (!normalizedConfig || extraDeps.length === 0) {
1528
+ return;
1529
+ }
1530
+ requestReload();
1531
+ }, [extraDeps.length, normalizedConfig, requestReload, ...extraDeps]);
1532
+ }
1533
+ function isDynamicConfig(config) {
1534
+ return "instructions" in config;
1535
+ }
1536
+ function normalizeStaticSuggestions(suggestions) {
1537
+ return suggestions.map((suggestion) => ({
1538
+ ...suggestion,
1539
+ isLoading: suggestion.isLoading ?? false
1540
+ }));
1541
+ }
1542
+
1357
1543
  // src/components/chat/CopilotChatToolCallsView.tsx
1358
1544
  import React7 from "react";
1359
1545
  import { Fragment as Fragment2, jsx as jsx9 } from "react/jsx-runtime";
@@ -1530,7 +1716,7 @@ function CopilotChatAssistantMessage({
1530
1716
  const CodeBlock = ({ children, className, onClick, ...props }) => {
1531
1717
  const config = useCopilotChatConfiguration();
1532
1718
  const labels = config?.labels ?? CopilotChatDefaultLabels;
1533
- const [copied, setCopied] = useState5(false);
1719
+ const [copied, setCopied] = useState7(false);
1534
1720
  const getCodeContent = (node) => {
1535
1721
  if (typeof node === "string") return node;
1536
1722
  if (Array.isArray(node)) return node.map(getCodeContent).join("");
@@ -1644,7 +1830,7 @@ function CopilotChatAssistantMessage({
1644
1830
  CopilotChatAssistantMessage2.CopyButton = ({ className, title, onClick, ...props }) => {
1645
1831
  const config = useCopilotChatConfiguration();
1646
1832
  const labels = config?.labels ?? CopilotChatDefaultLabels;
1647
- const [copied, setCopied] = useState5(false);
1833
+ const [copied, setCopied] = useState7(false);
1648
1834
  const handleClick = (event) => {
1649
1835
  setCopied(true);
1650
1836
  setTimeout(() => setCopied(false), 2e3);
@@ -1722,7 +1908,7 @@ CopilotChatAssistantMessage.RegenerateButton.displayName = "CopilotChatAssistant
1722
1908
  var CopilotChatAssistantMessage_default = CopilotChatAssistantMessage;
1723
1909
 
1724
1910
  // src/components/chat/CopilotChatUserMessage.tsx
1725
- import { useState as useState6 } from "react";
1911
+ import { useState as useState8 } from "react";
1726
1912
  import { Copy as Copy2, Check as Check3, Edit, ChevronLeft, ChevronRight } from "lucide-react";
1727
1913
  import { twMerge as twMerge5 } from "tailwind-merge";
1728
1914
  import { Fragment as Fragment4, jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
@@ -1867,7 +2053,7 @@ function CopilotChatUserMessage({
1867
2053
  CopilotChatUserMessage2.CopyButton = ({ className, title, onClick, ...props }) => {
1868
2054
  const config = useCopilotChatConfiguration();
1869
2055
  const labels = config?.labels ?? CopilotChatDefaultLabels;
1870
- const [copied, setCopied] = useState6(false);
2056
+ const [copied, setCopied] = useState8(false);
1871
2057
  const handleClick = (event) => {
1872
2058
  setCopied(true);
1873
2059
  setTimeout(() => setCopied(false), 2e3);
@@ -1960,9 +2146,118 @@ CopilotChatUserMessage.EditButton.displayName = "CopilotChatUserMessage.EditButt
1960
2146
  CopilotChatUserMessage.BranchNavigation.displayName = "CopilotChatUserMessage.BranchNavigation";
1961
2147
  var CopilotChatUserMessage_default = CopilotChatUserMessage;
1962
2148
 
2149
+ // src/components/chat/CopilotChatSuggestionPill.tsx
2150
+ import React8 from "react";
2151
+ import { Loader2 } from "lucide-react";
2152
+ import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
2153
+ var baseClasses = "group inline-flex h-8 items-center gap-1.5 rounded-full border border-border/60 bg-background px-3 text-xs leading-none text-foreground transition-colors cursor-pointer hover:bg-accent/60 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:text-muted-foreground disabled:hover:bg-background disabled:hover:text-muted-foreground pointer-events-auto";
2154
+ var labelClasses = "whitespace-nowrap font-medium leading-none";
2155
+ var CopilotChatSuggestionPill = React8.forwardRef(function CopilotChatSuggestionPill2({ className, children, icon, isLoading, type, ...props }, ref) {
2156
+ const showIcon = !isLoading && icon;
2157
+ return /* @__PURE__ */ jsxs6(
2158
+ "button",
2159
+ {
2160
+ ref,
2161
+ "data-slot": "suggestion-pill",
2162
+ className: cn(baseClasses, className),
2163
+ type: type ?? "button",
2164
+ "aria-busy": isLoading || void 0,
2165
+ disabled: isLoading || props.disabled,
2166
+ ...props,
2167
+ children: [
2168
+ isLoading ? /* @__PURE__ */ jsx12("span", { className: "flex h-4 w-4 items-center justify-center text-muted-foreground", children: /* @__PURE__ */ jsx12(Loader2, { className: "h-4 w-4 animate-spin", "aria-hidden": "true" }) }) : showIcon && /* @__PURE__ */ jsx12("span", { className: "flex h-4 w-4 items-center justify-center text-muted-foreground", children: icon }),
2169
+ /* @__PURE__ */ jsx12("span", { className: labelClasses, children })
2170
+ ]
2171
+ }
2172
+ );
2173
+ });
2174
+ CopilotChatSuggestionPill.displayName = "CopilotChatSuggestionPill";
2175
+ var CopilotChatSuggestionPill_default = CopilotChatSuggestionPill;
2176
+
2177
+ // src/components/chat/CopilotChatSuggestionView.tsx
2178
+ import React9 from "react";
2179
+ import { Fragment as Fragment5, jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
2180
+ var DefaultContainer = React9.forwardRef(function DefaultContainer2({ className, ...props }, ref) {
2181
+ return /* @__PURE__ */ jsx13(
2182
+ "div",
2183
+ {
2184
+ ref,
2185
+ className: cn(
2186
+ "flex flex-wrap items-center gap-2 px-4 sm:px-0 pointer-events-none",
2187
+ className
2188
+ ),
2189
+ ...props
2190
+ }
2191
+ );
2192
+ });
2193
+ var CopilotChatSuggestionView = React9.forwardRef(function CopilotChatSuggestionView2({
2194
+ suggestions,
2195
+ onSelectSuggestion,
2196
+ loadingIndexes,
2197
+ container,
2198
+ suggestion: suggestionSlot,
2199
+ className,
2200
+ children,
2201
+ ...restProps
2202
+ }, ref) {
2203
+ const loadingSet = React9.useMemo(() => {
2204
+ if (!loadingIndexes || loadingIndexes.length === 0) {
2205
+ return /* @__PURE__ */ new Set();
2206
+ }
2207
+ return new Set(loadingIndexes);
2208
+ }, [loadingIndexes]);
2209
+ const ContainerElement = renderSlot(container, DefaultContainer, {
2210
+ ref,
2211
+ className,
2212
+ ...restProps
2213
+ });
2214
+ const suggestionElements = suggestions.map((suggestion, index) => {
2215
+ const isLoading = loadingSet.has(index) || suggestion.isLoading === true;
2216
+ const pill = renderSlot(suggestionSlot, CopilotChatSuggestionPill_default, {
2217
+ children: suggestion.title,
2218
+ isLoading,
2219
+ type: "button",
2220
+ onClick: () => onSelectSuggestion?.(suggestion, index)
2221
+ });
2222
+ return React9.cloneElement(pill, {
2223
+ key: `${suggestion.title}-${index}`
2224
+ });
2225
+ });
2226
+ const boundContainer = React9.cloneElement(
2227
+ ContainerElement,
2228
+ void 0,
2229
+ suggestionElements
2230
+ );
2231
+ if (typeof children === "function") {
2232
+ const sampleSuggestion = renderSlot(suggestionSlot, CopilotChatSuggestionPill_default, {
2233
+ children: suggestions[0]?.title ?? "",
2234
+ isLoading: suggestions.length > 0 ? loadingSet.has(0) || suggestions[0]?.isLoading === true : false,
2235
+ type: "button"
2236
+ });
2237
+ return /* @__PURE__ */ jsx13(Fragment5, { children: children({
2238
+ container: boundContainer,
2239
+ suggestion: sampleSuggestion,
2240
+ suggestions,
2241
+ onSelectSuggestion,
2242
+ loadingIndexes,
2243
+ className,
2244
+ ...restProps
2245
+ }) });
2246
+ }
2247
+ if (children) {
2248
+ return /* @__PURE__ */ jsxs7(Fragment5, { children: [
2249
+ boundContainer,
2250
+ children
2251
+ ] });
2252
+ }
2253
+ return boundContainer;
2254
+ });
2255
+ CopilotChatSuggestionView.displayName = "CopilotChatSuggestionView";
2256
+ var CopilotChatSuggestionView_default = CopilotChatSuggestionView;
2257
+
1963
2258
  // src/components/chat/CopilotChatMessageView.tsx
1964
2259
  import { twMerge as twMerge6 } from "tailwind-merge";
1965
- import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
2260
+ import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
1966
2261
  function CopilotChatMessageView({
1967
2262
  messages = [],
1968
2263
  assistantMessage,
@@ -1992,7 +2287,7 @@ function CopilotChatMessageView({
1992
2287
  if (children) {
1993
2288
  return children({ messageElements, messages, isRunning });
1994
2289
  }
1995
- return /* @__PURE__ */ jsxs6("div", { className: twMerge6("flex flex-col", className), ...props, children: [
2290
+ return /* @__PURE__ */ jsxs8("div", { className: twMerge6("flex flex-col", className), ...props, children: [
1996
2291
  messageElements,
1997
2292
  isRunning && renderSlot(cursor, CopilotChatMessageView.Cursor, {})
1998
2293
  ] });
@@ -2001,7 +2296,7 @@ CopilotChatMessageView.Cursor = function Cursor({
2001
2296
  className,
2002
2297
  ...props
2003
2298
  }) {
2004
- return /* @__PURE__ */ jsx12(
2299
+ return /* @__PURE__ */ jsx14(
2005
2300
  "div",
2006
2301
  {
2007
2302
  className: twMerge6(
@@ -2015,11 +2310,11 @@ CopilotChatMessageView.Cursor = function Cursor({
2015
2310
  var CopilotChatMessageView_default = CopilotChatMessageView;
2016
2311
 
2017
2312
  // src/components/chat/CopilotChatView.tsx
2018
- import React8, { useRef as useRef5, useState as useState7, useEffect as useEffect9 } from "react";
2313
+ import React10, { useRef as useRef6, useState as useState9, useEffect as useEffect11 } from "react";
2019
2314
  import { twMerge as twMerge7 } from "tailwind-merge";
2020
2315
  import { StickToBottom, useStickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
2021
2316
  import { ChevronDown } from "lucide-react";
2022
- import { Fragment as Fragment5, jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
2317
+ import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
2023
2318
  function CopilotChatView({
2024
2319
  messageView,
2025
2320
  input,
@@ -2028,19 +2323,23 @@ function CopilotChatView({
2028
2323
  feather,
2029
2324
  inputContainer,
2030
2325
  disclaimer,
2326
+ suggestionView,
2031
2327
  messages = [],
2032
2328
  autoScroll = true,
2033
2329
  inputProps,
2034
2330
  isRunning = false,
2331
+ suggestions,
2332
+ suggestionLoadingIndexes,
2333
+ onSelectSuggestion,
2035
2334
  children,
2036
2335
  className,
2037
2336
  ...props
2038
2337
  }) {
2039
- const inputContainerRef = useRef5(null);
2040
- const [inputContainerHeight, setInputContainerHeight] = useState7(0);
2041
- const [isResizing, setIsResizing] = useState7(false);
2042
- const resizeTimeoutRef = useRef5(null);
2043
- useEffect9(() => {
2338
+ const inputContainerRef = useRef6(null);
2339
+ const [inputContainerHeight, setInputContainerHeight] = useState9(0);
2340
+ const [isResizing, setIsResizing] = useState9(false);
2341
+ const resizeTimeoutRef = useRef6(null);
2342
+ useEffect11(() => {
2044
2343
  const element = inputContainerRef.current;
2045
2344
  if (!element) return;
2046
2345
  const resizeObserver = new ResizeObserver((entries) => {
@@ -2074,40 +2373,38 @@ function CopilotChatView({
2074
2373
  messages,
2075
2374
  isRunning
2076
2375
  });
2077
- const BoundInput = renderSlot(
2078
- input,
2079
- CopilotChatInput_default,
2080
- inputProps ?? {}
2081
- );
2376
+ const BoundInput = renderSlot(input, CopilotChatInput_default, inputProps ?? {});
2377
+ const hasSuggestions = Array.isArray(suggestions) && suggestions.length > 0;
2378
+ const BoundSuggestionView = hasSuggestions ? renderSlot(
2379
+ suggestionView,
2380
+ CopilotChatSuggestionView_default,
2381
+ {
2382
+ suggestions,
2383
+ loadingIndexes: suggestionLoadingIndexes,
2384
+ onSelectSuggestion,
2385
+ className: "mb-3 lg:ml-4 lg:mr-4 ml-0 mr-0"
2386
+ }
2387
+ ) : null;
2082
2388
  const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
2083
2389
  const BoundScrollView = renderSlot(scrollView, CopilotChatView.ScrollView, {
2084
2390
  autoScroll,
2085
2391
  scrollToBottomButton,
2086
2392
  inputContainerHeight,
2087
2393
  isResizing,
2088
- children: /* @__PURE__ */ jsx13("div", { style: { paddingBottom: `${inputContainerHeight + 32}px` }, children: /* @__PURE__ */ jsx13("div", { className: "max-w-3xl mx-auto", children: BoundMessageView }) })
2394
+ children: /* @__PURE__ */ jsx15("div", { style: { paddingBottom: `${inputContainerHeight + (hasSuggestions ? 4 : 32)}px` }, children: /* @__PURE__ */ jsxs9("div", { className: "max-w-3xl mx-auto", children: [
2395
+ BoundMessageView,
2396
+ hasSuggestions ? /* @__PURE__ */ jsx15("div", { className: "px-4 sm:px-0 mt-4", children: BoundSuggestionView }) : null
2397
+ ] }) })
2398
+ });
2399
+ const BoundScrollToBottomButton = renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, {});
2400
+ const BoundDisclaimer = renderSlot(disclaimer, CopilotChatView.Disclaimer, {});
2401
+ const BoundInputContainer = renderSlot(inputContainer, CopilotChatView.InputContainer, {
2402
+ ref: inputContainerRef,
2403
+ children: /* @__PURE__ */ jsxs9(Fragment6, { children: [
2404
+ /* @__PURE__ */ jsx15("div", { className: "max-w-3xl mx-auto py-0 px-4 sm:px-0 [div[data-sidebar-chat]_&]:px-8 pointer-events-auto", children: BoundInput }),
2405
+ BoundDisclaimer
2406
+ ] })
2089
2407
  });
2090
- const BoundScrollToBottomButton = renderSlot(
2091
- scrollToBottomButton,
2092
- CopilotChatView.ScrollToBottomButton,
2093
- {}
2094
- );
2095
- const BoundDisclaimer = renderSlot(
2096
- disclaimer,
2097
- CopilotChatView.Disclaimer,
2098
- {}
2099
- );
2100
- const BoundInputContainer = renderSlot(
2101
- inputContainer,
2102
- CopilotChatView.InputContainer,
2103
- {
2104
- ref: inputContainerRef,
2105
- children: /* @__PURE__ */ jsxs7(Fragment5, { children: [
2106
- /* @__PURE__ */ jsx13("div", { className: "max-w-3xl mx-auto py-0 px-4 sm:px-0", children: BoundInput }),
2107
- BoundDisclaimer
2108
- ] })
2109
- }
2110
- );
2111
2408
  if (children) {
2112
2409
  return children({
2113
2410
  messageView: BoundMessageView,
@@ -2116,10 +2413,11 @@ function CopilotChatView({
2116
2413
  scrollToBottomButton: BoundScrollToBottomButton,
2117
2414
  feather: BoundFeather,
2118
2415
  inputContainer: BoundInputContainer,
2119
- disclaimer: BoundDisclaimer
2416
+ disclaimer: BoundDisclaimer,
2417
+ suggestionView: BoundSuggestionView ?? /* @__PURE__ */ jsx15(Fragment6, {})
2120
2418
  });
2121
2419
  }
2122
- return /* @__PURE__ */ jsxs7("div", { className: twMerge7("relative h-full", className), ...props, children: [
2420
+ return /* @__PURE__ */ jsxs9("div", { className: twMerge7("relative h-full", className), ...props, children: [
2123
2421
  BoundScrollView,
2124
2422
  BoundFeather,
2125
2423
  BoundInputContainer
@@ -2128,22 +2426,18 @@ function CopilotChatView({
2128
2426
  ((CopilotChatView2) => {
2129
2427
  const ScrollContent = ({ children, scrollToBottomButton, inputContainerHeight, isResizing }) => {
2130
2428
  const { isAtBottom, scrollToBottom } = useStickToBottomContext();
2131
- return /* @__PURE__ */ jsxs7(Fragment5, { children: [
2132
- /* @__PURE__ */ jsx13(StickToBottom.Content, { className: "overflow-y-scroll overflow-x-hidden", children: /* @__PURE__ */ jsx13("div", { className: "px-4 sm:px-0", children }) }),
2133
- !isAtBottom && !isResizing && /* @__PURE__ */ jsx13(
2429
+ return /* @__PURE__ */ jsxs9(Fragment6, { children: [
2430
+ /* @__PURE__ */ jsx15(StickToBottom.Content, { className: "overflow-y-scroll overflow-x-hidden", children: /* @__PURE__ */ jsx15("div", { className: "px-4 sm:px-0 [div[data-sidebar-chat]_&]:px-8", children }) }),
2431
+ !isAtBottom && !isResizing && /* @__PURE__ */ jsx15(
2134
2432
  "div",
2135
2433
  {
2136
- className: "absolute inset-x-0 flex justify-center z-10",
2434
+ className: "absolute inset-x-0 flex justify-center z-10 pointer-events-none",
2137
2435
  style: {
2138
2436
  bottom: `${inputContainerHeight + 16}px`
2139
2437
  },
2140
- children: renderSlot(
2141
- scrollToBottomButton,
2142
- CopilotChatView2.ScrollToBottomButton,
2143
- {
2144
- onClick: () => scrollToBottom()
2145
- }
2146
- )
2438
+ children: renderSlot(scrollToBottomButton, CopilotChatView2.ScrollToBottomButton, {
2439
+ onClick: () => scrollToBottom()
2440
+ })
2147
2441
  }
2148
2442
  )
2149
2443
  ] });
@@ -2157,13 +2451,13 @@ function CopilotChatView({
2157
2451
  className,
2158
2452
  ...props
2159
2453
  }) => {
2160
- const [hasMounted, setHasMounted] = useState7(false);
2454
+ const [hasMounted, setHasMounted] = useState9(false);
2161
2455
  const { scrollRef, contentRef, scrollToBottom } = useStickToBottom();
2162
- const [showScrollButton, setShowScrollButton] = useState7(false);
2163
- useEffect9(() => {
2456
+ const [showScrollButton, setShowScrollButton] = useState9(false);
2457
+ useEffect11(() => {
2164
2458
  setHasMounted(true);
2165
2459
  }, []);
2166
- useEffect9(() => {
2460
+ useEffect11(() => {
2167
2461
  if (autoScroll) return;
2168
2462
  const scrollElement = scrollRef.current;
2169
2463
  if (!scrollElement) return;
@@ -2181,45 +2475,44 @@ function CopilotChatView({
2181
2475
  };
2182
2476
  }, [scrollRef, autoScroll]);
2183
2477
  if (!hasMounted) {
2184
- return /* @__PURE__ */ jsx13("div", { className: "h-full max-h-full flex flex-col min-h-0 overflow-y-scroll overflow-x-hidden", children: /* @__PURE__ */ jsx13("div", { className: "px-4 sm:px-0", children }) });
2478
+ return /* @__PURE__ */ jsx15("div", { className: "h-full max-h-full flex flex-col min-h-0 overflow-y-scroll overflow-x-hidden", children: /* @__PURE__ */ jsx15("div", { className: "px-4 sm:px-0 [div[data-sidebar-chat]_&]:px-8", children }) });
2185
2479
  }
2186
2480
  if (!autoScroll) {
2187
- return /* @__PURE__ */ jsxs7(
2481
+ return /* @__PURE__ */ jsxs9(
2188
2482
  "div",
2189
2483
  {
2190
2484
  ref: scrollRef,
2191
- className: cn("h-full max-h-full flex flex-col min-h-0 overflow-y-scroll overflow-x-hidden relative", className),
2485
+ className: cn(
2486
+ "h-full max-h-full flex flex-col min-h-0 overflow-y-scroll overflow-x-hidden relative",
2487
+ className
2488
+ ),
2192
2489
  ...props,
2193
2490
  children: [
2194
- /* @__PURE__ */ jsx13("div", { ref: contentRef, className: "px-4 sm:px-0", children }),
2195
- showScrollButton && !isResizing && /* @__PURE__ */ jsx13(
2491
+ /* @__PURE__ */ jsx15("div", { ref: contentRef, className: "px-4 sm:px-0 [div[data-sidebar-chat]_&]:px-8", children }),
2492
+ showScrollButton && !isResizing && /* @__PURE__ */ jsx15(
2196
2493
  "div",
2197
2494
  {
2198
- className: "absolute inset-x-0 flex justify-center z-10",
2495
+ className: "absolute inset-x-0 flex justify-center z-10 pointer-events-none",
2199
2496
  style: {
2200
2497
  bottom: `${inputContainerHeight + 16}px`
2201
2498
  },
2202
- children: renderSlot(
2203
- scrollToBottomButton,
2204
- CopilotChatView2.ScrollToBottomButton,
2205
- {
2206
- onClick: () => scrollToBottom()
2207
- }
2208
- )
2499
+ children: renderSlot(scrollToBottomButton, CopilotChatView2.ScrollToBottomButton, {
2500
+ onClick: () => scrollToBottom()
2501
+ })
2209
2502
  }
2210
2503
  )
2211
2504
  ]
2212
2505
  }
2213
2506
  );
2214
2507
  }
2215
- return /* @__PURE__ */ jsx13(
2508
+ return /* @__PURE__ */ jsx15(
2216
2509
  StickToBottom,
2217
2510
  {
2218
2511
  className: cn("h-full max-h-full flex flex-col min-h-0 relative", className),
2219
2512
  resize: "smooth",
2220
2513
  initial: "smooth",
2221
2514
  ...props,
2222
- children: /* @__PURE__ */ jsx13(
2515
+ children: /* @__PURE__ */ jsx15(
2223
2516
  ScrollContent,
2224
2517
  {
2225
2518
  scrollToBottomButton,
@@ -2231,13 +2524,16 @@ function CopilotChatView({
2231
2524
  }
2232
2525
  );
2233
2526
  };
2234
- CopilotChatView2.ScrollToBottomButton = ({ className, ...props }) => /* @__PURE__ */ jsx13(
2527
+ CopilotChatView2.ScrollToBottomButton = ({
2528
+ className,
2529
+ ...props
2530
+ }) => /* @__PURE__ */ jsx15(
2235
2531
  Button,
2236
2532
  {
2237
2533
  variant: "outline",
2238
2534
  size: "sm",
2239
2535
  className: twMerge7(
2240
- "rounded-full w-10 h-10 p-0",
2536
+ "rounded-full w-10 h-10 p-0 pointer-events-auto",
2241
2537
  "bg-white dark:bg-gray-900",
2242
2538
  "shadow-lg border border-gray-200 dark:border-gray-700",
2243
2539
  "hover:bg-gray-50 dark:hover:bg-gray-800",
@@ -2245,14 +2541,10 @@ function CopilotChatView({
2245
2541
  className
2246
2542
  ),
2247
2543
  ...props,
2248
- children: /* @__PURE__ */ jsx13(ChevronDown, { className: "w-4 h-4 text-gray-600 dark:text-white" })
2544
+ children: /* @__PURE__ */ jsx15(ChevronDown, { className: "w-4 h-4 text-gray-600 dark:text-white" })
2249
2545
  }
2250
2546
  );
2251
- CopilotChatView2.Feather = ({
2252
- className,
2253
- style,
2254
- ...props
2255
- }) => /* @__PURE__ */ jsx13(
2547
+ CopilotChatView2.Feather = ({ className, style, ...props }) => /* @__PURE__ */ jsx15(
2256
2548
  "div",
2257
2549
  {
2258
2550
  className: cn(
@@ -2265,29 +2557,15 @@ function CopilotChatView({
2265
2557
  ...props
2266
2558
  }
2267
2559
  );
2268
- CopilotChatView2.InputContainer = React8.forwardRef(({ children, className, ...props }, ref) => /* @__PURE__ */ jsx13(
2269
- "div",
2270
- {
2271
- ref,
2272
- className: cn("absolute bottom-0 left-0 right-0 z-20", className),
2273
- ...props,
2274
- children
2275
- }
2276
- ));
2560
+ CopilotChatView2.InputContainer = React10.forwardRef(({ children, className, ...props }, ref) => /* @__PURE__ */ jsx15("div", { ref, className: cn("absolute bottom-0 left-0 right-0 z-20 pointer-events-none", className), ...props, children }));
2277
2561
  CopilotChatView2.InputContainer.displayName = "CopilotChatView.InputContainer";
2278
- CopilotChatView2.Disclaimer = ({
2279
- className,
2280
- ...props
2281
- }) => {
2562
+ CopilotChatView2.Disclaimer = ({ className, ...props }) => {
2282
2563
  const config = useCopilotChatConfiguration();
2283
2564
  const labels = config?.labels ?? CopilotChatDefaultLabels;
2284
- return /* @__PURE__ */ jsx13(
2565
+ return /* @__PURE__ */ jsx15(
2285
2566
  "div",
2286
2567
  {
2287
- className: cn(
2288
- "text-center text-xs text-muted-foreground py-3 px-4 max-w-3xl mx-auto",
2289
- className
2290
- ),
2568
+ className: cn("text-center text-xs text-muted-foreground py-3 px-4 max-w-3xl mx-auto", className),
2291
2569
  ...props,
2292
2570
  children: labels.chatDisclaimerText
2293
2571
  }
@@ -2297,32 +2575,31 @@ function CopilotChatView({
2297
2575
  var CopilotChatView_default = CopilotChatView;
2298
2576
 
2299
2577
  // src/components/chat/CopilotChat.tsx
2300
- import { DEFAULT_AGENT_ID as DEFAULT_AGENT_ID4, randomUUID } from "@copilotkitnext/shared";
2301
- import { useCallback as useCallback3, useEffect as useEffect10, useMemo as useMemo3 } from "react";
2578
+ import { DEFAULT_AGENT_ID as DEFAULT_AGENT_ID6, randomUUID as randomUUID2 } from "@copilotkitnext/shared";
2579
+ import { useCallback as useCallback5, useEffect as useEffect12, useMemo as useMemo6 } from "react";
2302
2580
  import { merge } from "ts-deepmerge";
2303
2581
  import { AGUIConnectNotImplementedError } from "@ag-ui/client";
2304
- import { jsx as jsx14 } from "react/jsx-runtime";
2305
- function CopilotChat({ agentId, threadId, labels, ...props }) {
2582
+ import { jsx as jsx16 } from "react/jsx-runtime";
2583
+ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen, ...props }) {
2306
2584
  const existingConfig = useCopilotChatConfiguration();
2307
- const resolvedAgentId = agentId ?? existingConfig?.agentId ?? DEFAULT_AGENT_ID4;
2308
- const resolvedThreadId = useMemo3(
2309
- () => threadId ?? existingConfig?.threadId ?? randomUUID(),
2585
+ const resolvedAgentId = agentId ?? existingConfig?.agentId ?? DEFAULT_AGENT_ID6;
2586
+ const resolvedThreadId = useMemo6(
2587
+ () => threadId ?? existingConfig?.threadId ?? randomUUID2(),
2310
2588
  [threadId, existingConfig?.threadId]
2311
2589
  );
2312
- const resolvedLabels = useMemo3(
2313
- () => ({
2314
- ...CopilotChatDefaultLabels,
2315
- ...existingConfig?.labels || {},
2316
- ...labels || {}
2317
- }),
2318
- [existingConfig?.labels, labels]
2319
- );
2320
2590
  const { agent } = useAgent({ agentId: resolvedAgentId });
2321
2591
  const { copilotkit } = useCopilotKit();
2322
- useEffect10(() => {
2592
+ const { suggestions: autoSuggestions } = useSuggestions({ agentId: resolvedAgentId });
2593
+ const {
2594
+ inputProps: providedInputProps,
2595
+ messageView: providedMessageView,
2596
+ suggestionView: providedSuggestionView,
2597
+ ...restProps
2598
+ } = props;
2599
+ useEffect12(() => {
2323
2600
  const connect = async (agent2) => {
2324
2601
  try {
2325
- await copilotkit.connectAgent({ agent: agent2, agentId: resolvedAgentId });
2602
+ await copilotkit.connectAgent({ agent: agent2 });
2326
2603
  } catch (error) {
2327
2604
  if (error instanceof AGUIConnectNotImplementedError) {
2328
2605
  } else {
@@ -2337,47 +2614,391 @@ function CopilotChat({ agentId, threadId, labels, ...props }) {
2337
2614
  return () => {
2338
2615
  };
2339
2616
  }, [resolvedThreadId, agent, copilotkit, resolvedAgentId]);
2340
- const onSubmitInput = useCallback3(
2617
+ const onSubmitInput = useCallback5(
2341
2618
  async (value) => {
2342
2619
  agent?.addMessage({
2343
- id: randomUUID(),
2620
+ id: randomUUID2(),
2344
2621
  role: "user",
2345
2622
  content: value
2346
2623
  });
2347
2624
  if (agent) {
2348
2625
  try {
2349
- await copilotkit.runAgent({ agent, agentId: resolvedAgentId });
2626
+ await copilotkit.runAgent({ agent });
2350
2627
  } catch (error) {
2351
2628
  console.error("CopilotChat: runAgent failed", error);
2352
2629
  }
2353
2630
  }
2354
2631
  },
2355
- [agent, copilotkit, resolvedAgentId]
2632
+ [agent, copilotkit]
2633
+ );
2634
+ const handleSelectSuggestion = useCallback5(
2635
+ async (suggestion) => {
2636
+ if (!agent) {
2637
+ return;
2638
+ }
2639
+ agent.addMessage({
2640
+ id: randomUUID2(),
2641
+ role: "user",
2642
+ content: suggestion.message
2643
+ });
2644
+ try {
2645
+ await copilotkit.runAgent({ agent });
2646
+ } catch (error) {
2647
+ console.error("CopilotChat: runAgent failed after selecting suggestion", error);
2648
+ }
2649
+ },
2650
+ [agent, copilotkit]
2356
2651
  );
2357
- const { inputProps: providedInputProps, messageView: providedMessageView, ...restProps } = props;
2358
2652
  const mergedProps = merge(
2359
2653
  {
2360
- isRunning: agent?.isRunning ?? false
2654
+ isRunning: agent?.isRunning ?? false,
2655
+ suggestions: autoSuggestions,
2656
+ onSelectSuggestion: handleSelectSuggestion,
2657
+ suggestionView: providedSuggestionView
2361
2658
  },
2362
2659
  {
2363
2660
  ...restProps,
2364
2661
  ...typeof providedMessageView === "string" ? { messageView: { className: providedMessageView } } : providedMessageView !== void 0 ? { messageView: providedMessageView } : {}
2365
2662
  }
2366
2663
  );
2367
- return /* @__PURE__ */ jsx14(CopilotChatConfigurationProvider, { agentId: resolvedAgentId, threadId: resolvedThreadId, labels: resolvedLabels, children: /* @__PURE__ */ jsx14(
2368
- CopilotChatView,
2664
+ const finalProps = merge(mergedProps, {
2665
+ messages: agent?.messages ?? [],
2666
+ inputProps: {
2667
+ onSubmitMessage: onSubmitInput,
2668
+ ...providedInputProps
2669
+ }
2670
+ });
2671
+ const RenderedChatView = renderSlot(chatView, CopilotChatView, finalProps);
2672
+ return /* @__PURE__ */ jsx16(
2673
+ CopilotChatConfigurationProvider,
2369
2674
  {
2370
- ...{
2371
- messages: agent?.messages ?? [],
2372
- inputProps: {
2373
- onSubmitMessage: onSubmitInput,
2374
- ...providedInputProps
2375
- },
2376
- ...mergedProps
2675
+ agentId: resolvedAgentId,
2676
+ threadId: resolvedThreadId,
2677
+ labels,
2678
+ isModalDefaultOpen,
2679
+ children: RenderedChatView
2680
+ }
2681
+ );
2682
+ }
2683
+ ((CopilotChat2) => {
2684
+ CopilotChat2.View = CopilotChatView;
2685
+ })(CopilotChat || (CopilotChat = {}));
2686
+
2687
+ // src/components/chat/CopilotChatToggleButton.tsx
2688
+ import React11, { useState as useState10 } from "react";
2689
+ import { MessageCircle, X as X2 } from "lucide-react";
2690
+ import { jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
2691
+ var DefaultOpenIcon = ({
2692
+ className,
2693
+ ...props
2694
+ }) => /* @__PURE__ */ jsx17(MessageCircle, { className: cn("h-6 w-6", className), strokeWidth: 1.75, fill: "currentColor", ...props });
2695
+ var DefaultCloseIcon = ({
2696
+ className,
2697
+ ...props
2698
+ }) => /* @__PURE__ */ jsx17(X2, { className: cn("h-6 w-6", className), strokeWidth: 1.75, ...props });
2699
+ DefaultOpenIcon.displayName = "CopilotChatToggleButton.OpenIcon";
2700
+ DefaultCloseIcon.displayName = "CopilotChatToggleButton.CloseIcon";
2701
+ var ICON_TRANSITION_STYLE = Object.freeze({
2702
+ transition: "opacity 120ms ease-out, transform 260ms cubic-bezier(0.22, 1, 0.36, 1)"
2703
+ });
2704
+ var ICON_WRAPPER_BASE = "pointer-events-none absolute inset-0 flex items-center justify-center will-change-transform";
2705
+ var BUTTON_BASE_CLASSES = cn(
2706
+ "fixed bottom-6 right-6 z-[1100] flex h-14 w-14 items-center justify-center",
2707
+ "rounded-full border border-primary bg-primary text-primary-foreground",
2708
+ "shadow-sm transition-all duration-200 ease-out",
2709
+ "hover:scale-[1.04] hover:shadow-md",
2710
+ "cursor-pointer",
2711
+ "active:scale-[0.96]",
2712
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
2713
+ "disabled:pointer-events-none disabled:opacity-60"
2714
+ );
2715
+ var CopilotChatToggleButton = React11.forwardRef(function CopilotChatToggleButton2({ openIcon, closeIcon, className, ...buttonProps }, ref) {
2716
+ const { onClick, type, disabled, ...restProps } = buttonProps;
2717
+ const configuration = useCopilotChatConfiguration();
2718
+ const labels = configuration?.labels ?? CopilotChatDefaultLabels;
2719
+ const [fallbackOpen, setFallbackOpen] = useState10(false);
2720
+ const isOpen = configuration?.isModalOpen ?? fallbackOpen;
2721
+ const setModalOpen = configuration?.setModalOpen ?? setFallbackOpen;
2722
+ const handleClick = (event) => {
2723
+ if (disabled) {
2724
+ return;
2725
+ }
2726
+ if (onClick) {
2727
+ onClick(event);
2728
+ }
2729
+ if (event.defaultPrevented) {
2730
+ return;
2731
+ }
2732
+ const nextOpen = !isOpen;
2733
+ setModalOpen(nextOpen);
2734
+ };
2735
+ const renderedOpenIcon = renderSlot(
2736
+ openIcon,
2737
+ DefaultOpenIcon,
2738
+ {
2739
+ className: "h-6 w-6",
2740
+ "aria-hidden": true,
2741
+ focusable: false
2742
+ }
2743
+ );
2744
+ const renderedCloseIcon = renderSlot(
2745
+ closeIcon,
2746
+ DefaultCloseIcon,
2747
+ {
2748
+ className: "h-6 w-6",
2749
+ "aria-hidden": true,
2750
+ focusable: false
2751
+ }
2752
+ );
2753
+ const openIconElement = /* @__PURE__ */ jsx17(
2754
+ "span",
2755
+ {
2756
+ "aria-hidden": "true",
2757
+ "data-slot": "chat-toggle-button-open-icon",
2758
+ className: ICON_WRAPPER_BASE,
2759
+ style: {
2760
+ ...ICON_TRANSITION_STYLE,
2761
+ opacity: isOpen ? 0 : 1,
2762
+ transform: `scale(${isOpen ? 0.75 : 1}) rotate(${isOpen ? 90 : 0}deg)`
2763
+ },
2764
+ children: renderedOpenIcon
2765
+ }
2766
+ );
2767
+ const closeIconElement = /* @__PURE__ */ jsx17(
2768
+ "span",
2769
+ {
2770
+ "aria-hidden": "true",
2771
+ "data-slot": "chat-toggle-button-close-icon",
2772
+ className: ICON_WRAPPER_BASE,
2773
+ style: {
2774
+ ...ICON_TRANSITION_STYLE,
2775
+ opacity: isOpen ? 1 : 0,
2776
+ transform: `scale(${isOpen ? 1 : 0.75}) rotate(${isOpen ? 0 : -90}deg)`
2777
+ },
2778
+ children: renderedCloseIcon
2779
+ }
2780
+ );
2781
+ return /* @__PURE__ */ jsxs10(
2782
+ "button",
2783
+ {
2784
+ ref,
2785
+ type: type ?? "button",
2786
+ "data-slot": "chat-toggle-button",
2787
+ "data-state": isOpen ? "open" : "closed",
2788
+ className: cn(BUTTON_BASE_CLASSES, className),
2789
+ "aria-label": isOpen ? labels.chatToggleCloseLabel : labels.chatToggleOpenLabel,
2790
+ "aria-pressed": isOpen,
2791
+ disabled,
2792
+ onClick: handleClick,
2793
+ ...restProps,
2794
+ children: [
2795
+ openIconElement,
2796
+ closeIconElement
2797
+ ]
2798
+ }
2799
+ );
2800
+ });
2801
+ CopilotChatToggleButton.displayName = "CopilotChatToggleButton";
2802
+ var CopilotChatToggleButton_default = CopilotChatToggleButton;
2803
+
2804
+ // src/components/chat/CopilotSidebarView.tsx
2805
+ import { useEffect as useEffect13, useRef as useRef7, useState as useState11 } from "react";
2806
+
2807
+ // src/components/chat/CopilotModalHeader.tsx
2808
+ import { useCallback as useCallback6 } from "react";
2809
+ import { X as X3 } from "lucide-react";
2810
+ import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
2811
+ function CopilotModalHeader({
2812
+ title,
2813
+ titleContent,
2814
+ closeButton,
2815
+ children,
2816
+ className,
2817
+ ...rest
2818
+ }) {
2819
+ const configuration = useCopilotChatConfiguration();
2820
+ const fallbackTitle = configuration?.labels.modalHeaderTitle ?? CopilotChatDefaultLabels.modalHeaderTitle;
2821
+ const resolvedTitle = title ?? fallbackTitle;
2822
+ const handleClose = useCallback6(() => {
2823
+ configuration?.setModalOpen(false);
2824
+ }, [configuration]);
2825
+ const BoundTitle = renderSlot(titleContent, CopilotModalHeader.Title, {
2826
+ children: resolvedTitle
2827
+ });
2828
+ const BoundCloseButton = renderSlot(closeButton, CopilotModalHeader.CloseButton, {
2829
+ onClick: handleClose
2830
+ });
2831
+ if (children) {
2832
+ return children({
2833
+ titleContent: BoundTitle,
2834
+ closeButton: BoundCloseButton,
2835
+ title: resolvedTitle,
2836
+ ...rest
2837
+ });
2838
+ }
2839
+ return /* @__PURE__ */ jsx18(
2840
+ "header",
2841
+ {
2842
+ "data-slot": "copilot-modal-header",
2843
+ className: cn(
2844
+ "flex items-center justify-between border-b border-border px-4 py-4",
2845
+ "bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80",
2846
+ className
2847
+ ),
2848
+ ...rest,
2849
+ children: /* @__PURE__ */ jsxs11("div", { className: "flex w-full items-center gap-2", children: [
2850
+ /* @__PURE__ */ jsx18("div", { className: "flex-1", "aria-hidden": "true" }),
2851
+ /* @__PURE__ */ jsx18("div", { className: "flex flex-1 justify-center text-center", children: BoundTitle }),
2852
+ /* @__PURE__ */ jsx18("div", { className: "flex flex-1 justify-end", children: BoundCloseButton })
2853
+ ] })
2854
+ }
2855
+ );
2856
+ }
2857
+ CopilotModalHeader.displayName = "CopilotModalHeader";
2858
+ ((CopilotModalHeader2) => {
2859
+ CopilotModalHeader2.Title = ({ children, className, ...props }) => /* @__PURE__ */ jsx18(
2860
+ "div",
2861
+ {
2862
+ className: cn(
2863
+ "w-full text-base font-medium leading-none tracking-tight text-foreground",
2864
+ className
2865
+ ),
2866
+ ...props,
2867
+ children
2868
+ }
2869
+ );
2870
+ CopilotModalHeader2.CloseButton = ({
2871
+ className,
2872
+ ...props
2873
+ }) => /* @__PURE__ */ jsx18(
2874
+ "button",
2875
+ {
2876
+ type: "button",
2877
+ className: cn(
2878
+ "inline-flex size-8 items-center justify-center rounded-full text-muted-foreground transition cursor-pointer",
2879
+ "hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
2880
+ className
2881
+ ),
2882
+ "aria-label": "Close",
2883
+ ...props,
2884
+ children: /* @__PURE__ */ jsx18(X3, { className: "h-4 w-4", "aria-hidden": "true" })
2885
+ }
2886
+ );
2887
+ })(CopilotModalHeader || (CopilotModalHeader = {}));
2888
+ CopilotModalHeader.Title.displayName = "CopilotModalHeader.Title";
2889
+ CopilotModalHeader.CloseButton.displayName = "CopilotModalHeader.CloseButton";
2890
+
2891
+ // src/components/chat/CopilotSidebarView.tsx
2892
+ import { Fragment as Fragment7, jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
2893
+ var DEFAULT_SIDEBAR_WIDTH = 480;
2894
+ var SIDEBAR_TRANSITION_MS = 260;
2895
+ function CopilotSidebarView({ header, width, ...props }) {
2896
+ const configuration = useCopilotChatConfiguration();
2897
+ const isSidebarOpen = configuration?.isModalOpen ?? false;
2898
+ const sidebarRef = useRef7(null);
2899
+ const [sidebarWidth, setSidebarWidth] = useState11(width ?? DEFAULT_SIDEBAR_WIDTH);
2900
+ const widthToCss = (w) => {
2901
+ return typeof w === "number" ? `${w}px` : w;
2902
+ };
2903
+ const widthToMargin = (w) => {
2904
+ if (typeof w === "number") {
2905
+ return `${w}px`;
2906
+ }
2907
+ return w;
2908
+ };
2909
+ useEffect13(() => {
2910
+ if (width !== void 0) {
2911
+ return;
2912
+ }
2913
+ if (typeof window === "undefined") {
2914
+ return;
2915
+ }
2916
+ const element = sidebarRef.current;
2917
+ if (!element) {
2918
+ return;
2919
+ }
2920
+ const updateWidth = () => {
2921
+ const rect = element.getBoundingClientRect();
2922
+ if (rect.width > 0) {
2923
+ setSidebarWidth(rect.width);
2924
+ }
2925
+ };
2926
+ updateWidth();
2927
+ if (typeof ResizeObserver !== "undefined") {
2928
+ const observer = new ResizeObserver(() => updateWidth());
2929
+ observer.observe(element);
2930
+ return () => observer.disconnect();
2931
+ }
2932
+ window.addEventListener("resize", updateWidth);
2933
+ return () => window.removeEventListener("resize", updateWidth);
2934
+ }, [width]);
2935
+ const headerElement = renderSlot(header, CopilotModalHeader, {});
2936
+ return /* @__PURE__ */ jsxs12(Fragment7, { children: [
2937
+ isSidebarOpen && /* @__PURE__ */ jsx19(
2938
+ "style",
2939
+ {
2940
+ dangerouslySetInnerHTML: {
2941
+ __html: `body {
2942
+ margin-inline-end: ${widthToMargin(sidebarWidth)};
2943
+ transition: margin-inline-end ${SIDEBAR_TRANSITION_MS}ms ease;
2944
+ }`
2945
+ }
2377
2946
  }
2947
+ ),
2948
+ /* @__PURE__ */ jsx19(CopilotChatToggleButton_default, {}),
2949
+ /* @__PURE__ */ jsx19(
2950
+ "aside",
2951
+ {
2952
+ ref: sidebarRef,
2953
+ "data-copilot-sidebar": true,
2954
+ className: cn(
2955
+ "fixed right-0 top-0 z-[1200] flex h-dvh max-h-screen",
2956
+ "border-l border-border bg-background text-foreground shadow-xl",
2957
+ "transition-transform duration-300 ease-out",
2958
+ isSidebarOpen ? "translate-x-0" : "translate-x-full pointer-events-none"
2959
+ ),
2960
+ style: { width: widthToCss(sidebarWidth) },
2961
+ "aria-hidden": !isSidebarOpen,
2962
+ "aria-label": "Copilot chat sidebar",
2963
+ role: "complementary",
2964
+ children: /* @__PURE__ */ jsxs12("div", { className: "flex h-full w-full flex-col overflow-hidden", children: [
2965
+ headerElement,
2966
+ /* @__PURE__ */ jsx19("div", { className: "flex-1 overflow-hidden", "data-sidebar-chat": true, children: /* @__PURE__ */ jsx19(CopilotChatView_default, { ...props }) })
2967
+ ] })
2968
+ }
2969
+ )
2970
+ ] });
2971
+ }
2972
+ CopilotSidebarView.displayName = "CopilotSidebarView";
2973
+
2974
+ // src/components/chat/CopilotSidebar.tsx
2975
+ import { useMemo as useMemo7 } from "react";
2976
+ import { jsx as jsx20 } from "react/jsx-runtime";
2977
+ function CopilotSidebar({ header, defaultOpen, width, ...chatProps }) {
2978
+ const SidebarViewOverride = useMemo7(() => {
2979
+ const Component = (viewProps) => {
2980
+ const { header: viewHeader, width: viewWidth, ...restProps } = viewProps;
2981
+ return /* @__PURE__ */ jsx20(
2982
+ CopilotSidebarView,
2983
+ {
2984
+ ...restProps,
2985
+ header: header ?? viewHeader,
2986
+ width: width ?? viewWidth
2987
+ }
2988
+ );
2989
+ };
2990
+ return Object.assign(Component, CopilotChatView_default);
2991
+ }, [header, width]);
2992
+ return /* @__PURE__ */ jsx20(
2993
+ CopilotChat,
2994
+ {
2995
+ ...chatProps,
2996
+ chatView: SidebarViewOverride,
2997
+ isModalDefaultOpen: defaultOpen
2378
2998
  }
2379
- ) });
2999
+ );
2380
3000
  }
3001
+ CopilotSidebar.displayName = "CopilotSidebar";
2381
3002
 
2382
3003
  // src/types/defineToolCallRender.ts
2383
3004
  import { z as z2 } from "zod";
@@ -2392,25 +3013,25 @@ function defineToolCallRender(def) {
2392
3013
  }
2393
3014
 
2394
3015
  // src/components/WildcardToolCallRender.tsx
2395
- import { useState as useState8 } from "react";
2396
- import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
3016
+ import { useState as useState12 } from "react";
3017
+ import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
2397
3018
  var WildcardToolCallRender = defineToolCallRender({
2398
3019
  name: "*",
2399
3020
  render: ({ args, result, name, status }) => {
2400
- const [isExpanded, setIsExpanded] = useState8(false);
3021
+ const [isExpanded, setIsExpanded] = useState12(false);
2401
3022
  const statusString = String(status);
2402
3023
  const isActive = statusString === "inProgress" || statusString === "executing";
2403
3024
  const isComplete = statusString === "complete";
2404
3025
  const statusStyles = isActive ? "bg-amber-100 text-amber-800 dark:bg-amber-500/15 dark:text-amber-400" : isComplete ? "bg-emerald-100 text-emerald-800 dark:bg-emerald-500/15 dark:text-emerald-400" : "bg-zinc-100 text-zinc-800 dark:bg-zinc-700/40 dark:text-zinc-300";
2405
- return /* @__PURE__ */ jsx15("div", { className: "mt-2 pb-2", children: /* @__PURE__ */ jsxs8("div", { className: "rounded-xl border border-zinc-200/60 dark:border-zinc-800/60 bg-white/70 dark:bg-zinc-900/50 shadow-sm backdrop-blur p-4", children: [
2406
- /* @__PURE__ */ jsxs8(
3026
+ return /* @__PURE__ */ jsx21("div", { className: "mt-2 pb-2", children: /* @__PURE__ */ jsxs13("div", { className: "rounded-xl border border-zinc-200/60 dark:border-zinc-800/60 bg-white/70 dark:bg-zinc-900/50 shadow-sm backdrop-blur p-4", children: [
3027
+ /* @__PURE__ */ jsxs13(
2407
3028
  "div",
2408
3029
  {
2409
3030
  className: "flex items-center justify-between gap-3 cursor-pointer",
2410
3031
  onClick: () => setIsExpanded(!isExpanded),
2411
3032
  children: [
2412
- /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2 min-w-0", children: [
2413
- /* @__PURE__ */ jsx15(
3033
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2 min-w-0", children: [
3034
+ /* @__PURE__ */ jsx21(
2414
3035
  "svg",
2415
3036
  {
2416
3037
  className: `h-4 w-4 text-zinc-500 dark:text-zinc-400 transition-transform ${isExpanded ? "rotate-90" : ""}`,
@@ -2418,7 +3039,7 @@ var WildcardToolCallRender = defineToolCallRender({
2418
3039
  viewBox: "0 0 24 24",
2419
3040
  strokeWidth: 2,
2420
3041
  stroke: "currentColor",
2421
- children: /* @__PURE__ */ jsx15(
3042
+ children: /* @__PURE__ */ jsx21(
2422
3043
  "path",
2423
3044
  {
2424
3045
  strokeLinecap: "round",
@@ -2428,10 +3049,10 @@ var WildcardToolCallRender = defineToolCallRender({
2428
3049
  )
2429
3050
  }
2430
3051
  ),
2431
- /* @__PURE__ */ jsx15("span", { className: "inline-block h-2 w-2 rounded-full bg-blue-500" }),
2432
- /* @__PURE__ */ jsx15("span", { className: "truncate text-sm font-medium text-zinc-900 dark:text-zinc-100", children: name })
3052
+ /* @__PURE__ */ jsx21("span", { className: "inline-block h-2 w-2 rounded-full bg-blue-500" }),
3053
+ /* @__PURE__ */ jsx21("span", { className: "truncate text-sm font-medium text-zinc-900 dark:text-zinc-100", children: name })
2433
3054
  ] }),
2434
- /* @__PURE__ */ jsx15(
3055
+ /* @__PURE__ */ jsx21(
2435
3056
  "span",
2436
3057
  {
2437
3058
  className: `inline-flex items-center rounded-full px-2 py-1 text-xs font-medium ${statusStyles}`,
@@ -2441,14 +3062,14 @@ var WildcardToolCallRender = defineToolCallRender({
2441
3062
  ]
2442
3063
  }
2443
3064
  ),
2444
- isExpanded && /* @__PURE__ */ jsxs8("div", { className: "mt-3 grid gap-4", children: [
2445
- /* @__PURE__ */ jsxs8("div", { children: [
2446
- /* @__PURE__ */ jsx15("div", { className: "text-xs uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "Arguments" }),
2447
- /* @__PURE__ */ jsx15("pre", { className: "mt-2 max-h-64 overflow-auto rounded-md bg-zinc-50 dark:bg-zinc-800/60 p-3 text-xs leading-relaxed text-zinc-800 dark:text-zinc-200 whitespace-pre-wrap break-words", children: JSON.stringify(args ?? {}, null, 2) })
3065
+ isExpanded && /* @__PURE__ */ jsxs13("div", { className: "mt-3 grid gap-4", children: [
3066
+ /* @__PURE__ */ jsxs13("div", { children: [
3067
+ /* @__PURE__ */ jsx21("div", { className: "text-xs uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "Arguments" }),
3068
+ /* @__PURE__ */ jsx21("pre", { className: "mt-2 max-h-64 overflow-auto rounded-md bg-zinc-50 dark:bg-zinc-800/60 p-3 text-xs leading-relaxed text-zinc-800 dark:text-zinc-200 whitespace-pre-wrap break-words", children: JSON.stringify(args ?? {}, null, 2) })
2448
3069
  ] }),
2449
- result !== void 0 && /* @__PURE__ */ jsxs8("div", { children: [
2450
- /* @__PURE__ */ jsx15("div", { className: "text-xs uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "Result" }),
2451
- /* @__PURE__ */ jsx15("pre", { className: "mt-2 max-h-64 overflow-auto rounded-md bg-zinc-50 dark:bg-zinc-800/60 p-3 text-xs leading-relaxed text-zinc-800 dark:text-zinc-200 whitespace-pre-wrap break-words", children: typeof result === "string" ? result : JSON.stringify(result, null, 2) })
3070
+ result !== void 0 && /* @__PURE__ */ jsxs13("div", { children: [
3071
+ /* @__PURE__ */ jsx21("div", { className: "text-xs uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "Result" }),
3072
+ /* @__PURE__ */ jsx21("pre", { className: "mt-2 max-h-64 overflow-auto rounded-md bg-zinc-50 dark:bg-zinc-800/60 p-3 text-xs leading-relaxed text-zinc-800 dark:text-zinc-200 whitespace-pre-wrap break-words", children: typeof result === "string" ? result : JSON.stringify(result, null, 2) })
2452
3073
  ] })
2453
3074
  ] })
2454
3075
  ] }) });
@@ -2462,18 +3083,28 @@ export {
2462
3083
  CopilotChatConfigurationProvider,
2463
3084
  CopilotChatInput_default as CopilotChatInput,
2464
3085
  CopilotChatMessageView_default as CopilotChatMessageView,
3086
+ CopilotChatSuggestionPill_default as CopilotChatSuggestionPill,
3087
+ CopilotChatSuggestionView_default as CopilotChatSuggestionView,
3088
+ CopilotChatToggleButton,
3089
+ DefaultCloseIcon as CopilotChatToggleButtonCloseIcon,
3090
+ DefaultOpenIcon as CopilotChatToggleButtonOpenIcon,
2465
3091
  CopilotChatToolCallsView_default as CopilotChatToolCallsView,
2466
3092
  CopilotChatUserMessage_default as CopilotChatUserMessage,
2467
3093
  CopilotChatView_default as CopilotChatView,
2468
3094
  CopilotKitProvider,
3095
+ CopilotModalHeader,
3096
+ CopilotSidebar,
3097
+ CopilotSidebarView,
2469
3098
  WildcardToolCallRender,
2470
3099
  defineToolCallRender,
2471
3100
  useAgent,
2472
3101
  useAgentContext,
3102
+ useConfigureSuggestions,
2473
3103
  useCopilotChatConfiguration,
2474
3104
  useCopilotKit,
2475
3105
  useFrontendTool,
2476
3106
  useHumanInTheLoop,
2477
- useRenderToolCall
3107
+ useRenderToolCall,
3108
+ useSuggestions
2478
3109
  };
2479
3110
  //# sourceMappingURL=index.mjs.map