@copilotkitnext/react 0.0.12 → 0.0.13-alpha.0

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