@copilotkit/react-ui 1.10.6 → 1.50.0-beta.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.
Files changed (122) hide show
  1. package/dist/{chunk-H5Y4W7DM.mjs → chunk-3JYVJHL5.mjs} +6 -6
  2. package/dist/chunk-3YWFGNSM.mjs +32 -0
  3. package/dist/chunk-3YWFGNSM.mjs.map +1 -0
  4. package/dist/{chunk-BAD2NFZ7.mjs → chunk-CQ2WALZ7.mjs} +2 -2
  5. package/dist/{chunk-W7ONZTSW.mjs → chunk-E6WVAOQA.mjs} +11 -5
  6. package/dist/chunk-E6WVAOQA.mjs.map +1 -0
  7. package/dist/{chunk-ME2WM7IP.mjs → chunk-G35HUUDA.mjs} +36 -260
  8. package/dist/chunk-G35HUUDA.mjs.map +1 -0
  9. package/dist/{chunk-EZQA3UPQ.mjs → chunk-HBZW7E5Z.mjs} +16 -13
  10. package/dist/chunk-HBZW7E5Z.mjs.map +1 -0
  11. package/dist/{chunk-3QYTKBWC.mjs → chunk-IHFR6PYG.mjs} +8 -5
  12. package/dist/chunk-IHFR6PYG.mjs.map +1 -0
  13. package/dist/{chunk-5XLGXUQI.mjs → chunk-MPF6BJUF.mjs} +7 -3
  14. package/dist/chunk-MPF6BJUF.mjs.map +1 -0
  15. package/dist/{chunk-W26XFBEG.mjs → chunk-NGJ32FAP.mjs} +3 -3
  16. package/dist/chunk-NGJ32FAP.mjs.map +1 -0
  17. package/dist/{chunk-2LIO4Z3E.mjs → chunk-ODEHR7KI.mjs} +9 -2
  18. package/dist/chunk-ODEHR7KI.mjs.map +1 -0
  19. package/dist/chunk-OYRZ4VLU.mjs +12 -0
  20. package/dist/chunk-OYRZ4VLU.mjs.map +1 -0
  21. package/dist/chunk-QB3GUN2N.mjs +31 -0
  22. package/dist/chunk-QB3GUN2N.mjs.map +1 -0
  23. package/dist/{chunk-7RDGZ5JL.mjs → chunk-SOB5EIL7.mjs} +2 -2
  24. package/dist/components/chat/Chat.d.ts +3 -98
  25. package/dist/components/chat/Chat.js +100 -279
  26. package/dist/components/chat/Chat.js.map +1 -1
  27. package/dist/components/chat/Chat.mjs +12 -14
  28. package/dist/components/chat/Input.d.ts +1 -1
  29. package/dist/components/chat/Input.js +11 -8
  30. package/dist/components/chat/Input.js.map +1 -1
  31. package/dist/components/chat/Input.mjs +2 -2
  32. package/dist/components/chat/Messages.d.ts +4 -4
  33. package/dist/components/chat/Messages.js +44 -8
  34. package/dist/components/chat/Messages.js.map +1 -1
  35. package/dist/components/chat/Messages.mjs +5 -5
  36. package/dist/components/chat/Modal.d.ts +1 -6
  37. package/dist/components/chat/Modal.js +106 -283
  38. package/dist/components/chat/Modal.js.map +1 -1
  39. package/dist/components/chat/Modal.mjs +11 -11
  40. package/dist/components/chat/Popup.d.ts +1 -6
  41. package/dist/components/chat/Popup.js +106 -283
  42. package/dist/components/chat/Popup.js.map +1 -1
  43. package/dist/components/chat/Popup.mjs +12 -12
  44. package/dist/components/chat/Sidebar.d.ts +1 -6
  45. package/dist/components/chat/Sidebar.js +106 -283
  46. package/dist/components/chat/Sidebar.js.map +1 -1
  47. package/dist/components/chat/Sidebar.mjs +12 -12
  48. package/dist/components/chat/Suggestion.js.map +1 -1
  49. package/dist/components/chat/Suggestion.mjs +1 -1
  50. package/dist/components/chat/Suggestions.d.ts +1 -1
  51. package/dist/components/chat/Suggestions.js +19 -12
  52. package/dist/components/chat/Suggestions.js.map +1 -1
  53. package/dist/components/chat/Suggestions.mjs +2 -2
  54. package/dist/components/chat/index.d.ts +0 -5
  55. package/dist/components/chat/index.js +106 -283
  56. package/dist/components/chat/index.js.map +1 -1
  57. package/dist/components/chat/index.mjs +13 -13
  58. package/dist/components/chat/messages/AssistantMessage.js +7 -4
  59. package/dist/components/chat/messages/AssistantMessage.js.map +1 -1
  60. package/dist/components/chat/messages/AssistantMessage.mjs +1 -1
  61. package/dist/components/chat/messages/LegacyRenderMessage.js +37 -7
  62. package/dist/components/chat/messages/LegacyRenderMessage.js.map +1 -1
  63. package/dist/components/chat/messages/LegacyRenderMessage.mjs +4 -4
  64. package/dist/components/chat/messages/RenderMessage.js +30 -7
  65. package/dist/components/chat/messages/RenderMessage.js.map +1 -1
  66. package/dist/components/chat/messages/RenderMessage.mjs +3 -3
  67. package/dist/components/chat/messages/UserMessage.js +19 -3
  68. package/dist/components/chat/messages/UserMessage.js.map +1 -1
  69. package/dist/components/chat/messages/UserMessage.mjs +1 -1
  70. package/dist/components/chat/props.d.ts +16 -0
  71. package/dist/components/chat/props.js.map +1 -1
  72. package/dist/components/index.d.ts +0 -5
  73. package/dist/components/index.js +106 -283
  74. package/dist/components/index.js.map +1 -1
  75. package/dist/components/index.mjs +13 -13
  76. package/dist/hooks/index.d.ts +1 -0
  77. package/dist/hooks/index.js +2 -24
  78. package/dist/hooks/index.js.map +1 -1
  79. package/dist/hooks/index.mjs +1 -1
  80. package/dist/hooks/use-copilot-chat-suggestions.d.ts +4 -26
  81. package/dist/hooks/use-copilot-chat-suggestions.js +2 -24
  82. package/dist/hooks/use-copilot-chat-suggestions.js.map +1 -1
  83. package/dist/hooks/use-copilot-chat-suggestions.mjs +1 -1
  84. package/dist/index.css +8 -1
  85. package/dist/index.css.map +1 -1
  86. package/dist/index.d.ts +0 -5
  87. package/dist/index.js +109 -308
  88. package/dist/index.js.map +1 -1
  89. package/dist/index.mjs +14 -14
  90. package/dist/types/suggestions.d.ts +1 -0
  91. package/dist/types/suggestions.js.map +1 -1
  92. package/package.json +23 -22
  93. package/src/components/chat/Chat.tsx +40 -325
  94. package/src/components/chat/Input.tsx +13 -12
  95. package/src/components/chat/Messages.tsx +10 -4
  96. package/src/components/chat/Suggestion.tsx +2 -2
  97. package/src/components/chat/Suggestions.tsx +6 -2
  98. package/src/components/chat/messages/AssistantMessage.tsx +14 -4
  99. package/src/components/chat/messages/LegacyRenderMessage.tsx +7 -0
  100. package/src/components/chat/messages/RenderMessage.tsx +4 -0
  101. package/src/components/chat/messages/UserMessage.tsx +30 -6
  102. package/src/components/chat/props.ts +19 -0
  103. package/src/css/messages.css +10 -1
  104. package/src/hooks/use-copilot-chat-suggestions.tsx +6 -57
  105. package/src/types/suggestions.ts +1 -0
  106. package/tsup.config.ts +1 -1
  107. package/dist/chunk-226ZMOE3.mjs +0 -24
  108. package/dist/chunk-226ZMOE3.mjs.map +0 -1
  109. package/dist/chunk-2LIO4Z3E.mjs.map +0 -1
  110. package/dist/chunk-3QYTKBWC.mjs.map +0 -1
  111. package/dist/chunk-5XLGXUQI.mjs.map +0 -1
  112. package/dist/chunk-EYRKZDP5.mjs +0 -32
  113. package/dist/chunk-EYRKZDP5.mjs.map +0 -1
  114. package/dist/chunk-EZQA3UPQ.mjs.map +0 -1
  115. package/dist/chunk-ME2WM7IP.mjs.map +0 -1
  116. package/dist/chunk-VVL6JFCJ.mjs +0 -16
  117. package/dist/chunk-VVL6JFCJ.mjs.map +0 -1
  118. package/dist/chunk-W26XFBEG.mjs.map +0 -1
  119. package/dist/chunk-W7ONZTSW.mjs.map +0 -1
  120. /package/dist/{chunk-H5Y4W7DM.mjs.map → chunk-3JYVJHL5.mjs.map} +0 -0
  121. /package/dist/{chunk-BAD2NFZ7.mjs.map → chunk-CQ2WALZ7.mjs.map} +0 -0
  122. /package/dist/{chunk-7RDGZ5JL.mjs.map → chunk-SOB5EIL7.mjs.map} +0 -0
package/dist/index.mjs CHANGED
@@ -4,12 +4,12 @@ import "./chunk-MMVDU6DF.mjs";
4
4
  import "./chunk-SC6JRFAJ.mjs";
5
5
  import {
6
6
  CopilotSidebar
7
- } from "./chunk-7RDGZ5JL.mjs";
7
+ } from "./chunk-SOB5EIL7.mjs";
8
8
  import "./chunk-WB3YULQ4.mjs";
9
9
  import {
10
10
  CopilotPopup
11
- } from "./chunk-BAD2NFZ7.mjs";
12
- import "./chunk-H5Y4W7DM.mjs";
11
+ } from "./chunk-CQ2WALZ7.mjs";
12
+ import "./chunk-3JYVJHL5.mjs";
13
13
  import "./chunk-C3GSYRC3.mjs";
14
14
  import "./chunk-GDSZGYCE.mjs";
15
15
  import "./chunk-V7W6IM2V.mjs";
@@ -26,33 +26,32 @@ import "./chunk-BH6PCAAL.mjs";
26
26
  import "./chunk-UFN2VWSR.mjs";
27
27
  import {
28
28
  CopilotChat
29
- } from "./chunk-ME2WM7IP.mjs";
29
+ } from "./chunk-G35HUUDA.mjs";
30
30
  import {
31
31
  Suggestions
32
- } from "./chunk-226ZMOE3.mjs";
32
+ } from "./chunk-QB3GUN2N.mjs";
33
33
  import {
34
34
  Suggestion
35
- } from "./chunk-W26XFBEG.mjs";
35
+ } from "./chunk-NGJ32FAP.mjs";
36
36
  import "./chunk-PLHTVHUW.mjs";
37
- import "./chunk-EZQA3UPQ.mjs";
37
+ import "./chunk-HBZW7E5Z.mjs";
38
38
  import "./chunk-ELGRNEAO.mjs";
39
39
  import "./chunk-QIOJXTIQ.mjs";
40
- import "./chunk-W7ONZTSW.mjs";
41
- import "./chunk-2LIO4Z3E.mjs";
42
- import "./chunk-5XLGXUQI.mjs";
40
+ import "./chunk-E6WVAOQA.mjs";
41
+ import "./chunk-ODEHR7KI.mjs";
42
+ import "./chunk-MPF6BJUF.mjs";
43
43
  import {
44
44
  AssistantMessage
45
- } from "./chunk-3QYTKBWC.mjs";
45
+ } from "./chunk-IHFR6PYG.mjs";
46
46
  import {
47
47
  ImageRenderer
48
48
  } from "./chunk-DBKRAOH7.mjs";
49
49
  import {
50
50
  UserMessage
51
- } from "./chunk-VVL6JFCJ.mjs";
51
+ } from "./chunk-3YWFGNSM.mjs";
52
52
  import {
53
53
  Markdown
54
54
  } from "./chunk-JZ3RFQQ6.mjs";
55
- import "./chunk-O72ZB5V3.mjs";
56
55
  import {
57
56
  useChatContext
58
57
  } from "./chunk-IEMQ2SQW.mjs";
@@ -62,9 +61,10 @@ import "./chunk-IU3WTXLQ.mjs";
62
61
  import "./chunk-T26KLXLH.mjs";
63
62
  import {
64
63
  useCopilotChatSuggestions
65
- } from "./chunk-EYRKZDP5.mjs";
64
+ } from "./chunk-OYRZ4VLU.mjs";
66
65
  import "./chunk-54JAUBUJ.mjs";
67
66
  import "./chunk-JGMFJZMG.mjs";
67
+ import "./chunk-O72ZB5V3.mjs";
68
68
  import "./chunk-MRXNTQOX.mjs";
69
69
  export {
70
70
  AssistantMessage,
@@ -2,6 +2,7 @@ interface CopilotChatSuggestion {
2
2
  title: string;
3
3
  message: string;
4
4
  partial?: boolean;
5
+ isLoading?: boolean;
5
6
  className?: string;
6
7
  }
7
8
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/types/suggestions.ts"],"sourcesContent":["export interface CopilotChatSuggestion {\n title: string;\n message: string;\n partial?: boolean;\n className?: string;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../../src/types/suggestions.ts"],"sourcesContent":["export interface CopilotChatSuggestion {\n title: string;\n message: string;\n partial?: boolean;\n isLoading?: boolean;\n className?: string;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "publishConfig": {
10
10
  "access": "public"
11
11
  },
12
- "version": "1.10.6",
12
+ "version": "1.50.0-beta.0",
13
13
  "sideEffects": [
14
14
  "**/*.css"
15
15
  ],
@@ -25,35 +25,45 @@
25
25
  },
26
26
  "types": "./dist/index.d.ts",
27
27
  "license": "MIT",
28
+ "scripts": {
29
+ "build": "tsup --clean",
30
+ "dev": "tsup --watch --no-splitting",
31
+ "test": "jest",
32
+ "check-types": "tsc --noEmit",
33
+ "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist && rm -rf .next",
34
+ "link:global": "pnpm link --global",
35
+ "unlink:global": "pnpm unlink --global"
36
+ },
28
37
  "peerDependencies": {
38
+ "@copilotkitnext/core": "0.0.22",
29
39
  "react": "^18 || ^19 || ^19.0.0-rc"
30
40
  },
31
41
  "devDependencies": {
32
42
  "@types/jest": "^29.5.4",
33
- "@types/react": "^18.2.5",
43
+ "@types/react": "^19.1.0",
34
44
  "@types/react-syntax-highlighter": "^15.5.7",
35
45
  "eslint": "^8.56.0",
46
+ "eslint-config-custom": "workspace:*",
36
47
  "jest": "^29.6.4",
37
48
  "postcss": "^8.4.20",
38
49
  "react": "^18.2.0",
50
+ "tailwind-config": "workspace:*",
39
51
  "tailwindcss": "^3.3.0",
40
52
  "ts-jest": "^29.1.1",
53
+ "tsconfig": "workspace:*",
41
54
  "tsup": "^6.7.0",
42
- "typescript": "^5.2.3",
43
- "eslint-config-custom": "1.4.6",
44
- "tailwind-config": "1.4.6",
45
- "tsconfig": "1.4.6"
55
+ "typescript": "^5.2.3"
46
56
  },
47
57
  "dependencies": {
48
- "@headlessui/react": "^2.1.3",
58
+ "@copilotkit/react-core": "workspace:*",
59
+ "@copilotkit/runtime-client-gql": "workspace:*",
60
+ "@copilotkit/shared": "workspace:*",
61
+ "@headlessui/react": "^2.2.9",
49
62
  "react-markdown": "^10.1.0",
50
63
  "react-syntax-highlighter": "^15.6.1",
51
64
  "rehype-raw": "^7.0.0",
52
65
  "remark-gfm": "^4.0.1",
53
- "remark-math": "^6.0.0",
54
- "@copilotkit/react-core": "1.10.6",
55
- "@copilotkit/runtime-client-gql": "1.10.6",
56
- "@copilotkit/shared": "1.10.6"
66
+ "remark-math": "^6.0.0"
57
67
  },
58
68
  "keywords": [
59
69
  "copilotkit",
@@ -66,14 +76,5 @@
66
76
  "javascript",
67
77
  "automation",
68
78
  "textarea"
69
- ],
70
- "scripts": {
71
- "build": "tsup --clean",
72
- "dev": "tsup --watch --no-splitting",
73
- "test": "jest",
74
- "check-types": "tsc --noEmit",
75
- "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist && rm -rf .next",
76
- "link:global": "pnpm link --global",
77
- "unlink:global": "pnpm unlink --global"
78
- }
79
- }
79
+ ]
80
+ }
@@ -74,14 +74,14 @@ import { RenderMessage as DefaultRenderMessage } from "./messages/RenderMessage"
74
74
  import { AssistantMessage as DefaultAssistantMessage } from "./messages/AssistantMessage";
75
75
  import { UserMessage as DefaultUserMessage } from "./messages/UserMessage";
76
76
  import { ImageRenderer as DefaultImageRenderer } from "./messages/ImageRenderer";
77
- import React, { useEffect, useRef, useState, useCallback, useMemo } from "react";
77
+ import React, { useEffect, useRef, useState, useCallback } from "react";
78
78
  import {
79
79
  SystemMessageFunction,
80
- useCopilotChatInternal as useCopilotChat,
81
80
  useCopilotContext,
82
- useCopilotMessagesContext,
81
+ useCopilotChatInternal,
82
+ HintFunction,
83
+ type ChatSuggestions,
83
84
  } from "@copilotkit/react-core";
84
- import type { SuggestionItem } from "@copilotkit/react-core";
85
85
  import {
86
86
  CopilotKitError,
87
87
  CopilotKitErrorCode,
@@ -91,8 +91,8 @@ import {
91
91
  ErrorVisibility,
92
92
  styledConsole,
93
93
  CopilotErrorHandler,
94
+ randomUUID,
94
95
  } from "@copilotkit/shared";
95
- import { randomId } from "@copilotkit/shared";
96
96
  import {
97
97
  AssistantMessageProps,
98
98
  ChatError,
@@ -107,19 +107,9 @@ import {
107
107
  UserMessageProps,
108
108
  } from "./props";
109
109
 
110
- import { HintFunction, runAgent, stopAgent } from "@copilotkit/react-core";
111
110
  import { ImageUploadQueue } from "./ImageUploadQueue";
112
111
  import { Suggestions as DefaultRenderSuggestionsList } from "./Suggestions";
113
112
 
114
- /**
115
- * The type of suggestions to use in the chat.
116
- *
117
- * `auto` - Suggestions are generated automatically.
118
- * `manual` - Suggestions are controlled programmatically.
119
- * `SuggestionItem[]` - Static suggestions array.
120
- */
121
- export type ChatSuggestions = "auto" | "manual" | SuggestionItem[];
122
-
123
113
  /**
124
114
  * Props for CopilotChat component.
125
115
  */
@@ -448,6 +438,9 @@ export function CopilotChat({
448
438
  const { publicApiKey, chatApiEndpoint } = copilotApiConfig;
449
439
  const [selectedImages, setSelectedImages] = useState<Array<ImageUpload>>([]);
450
440
  const [chatError, setChatError] = useState<ChatError | null>(null);
441
+ const [messageFeedback, setMessageFeedback] = useState<Record<string, "thumbsUp" | "thumbsDown">>(
442
+ {},
443
+ );
451
444
  const fileInputRef = useRef<HTMLInputElement>(null);
452
445
 
453
446
  // Helper function to trigger event hooks only if publicApiKey is provided
@@ -622,15 +615,17 @@ export function CopilotChat({
622
615
  stopGeneration,
623
616
  reloadMessages,
624
617
  suggestions: currentSuggestions,
625
- } = useCopilotChatLogic(
618
+ isLoadingSuggestions,
619
+ agent,
620
+ } = useCopilotChatInternal({
626
621
  suggestions,
627
- makeSystemMessage,
628
- disableSystemMessage,
629
- onInProgress,
630
- onSubmitMessage,
631
- onStopGeneration,
632
- onReloadMessages,
633
- );
622
+ });
623
+ // makeSystemMessage,
624
+ // disableSystemMessage,
625
+ // onInProgress,
626
+ // onSubmitMessage,
627
+ // onStopGeneration,
628
+ // onReloadMessages,
634
629
 
635
630
  // Track loading state changes for chat start/stop events
636
631
  const prevIsLoading = useRef(isLoading);
@@ -656,7 +651,12 @@ export function CopilotChat({
656
651
  // Trigger message sent event
657
652
  triggerObservabilityHook("onMessageSent", text);
658
653
 
659
- return sendMessage(text, images);
654
+ // TODO: send images?
655
+ return sendMessage({
656
+ id: randomUUID(),
657
+ content: text,
658
+ role: "user",
659
+ });
660
660
  };
661
661
 
662
662
  const chatContext = React.useContext(ChatContext);
@@ -726,6 +726,12 @@ export function CopilotChat({
726
726
  onThumbsUp(message);
727
727
  }
728
728
 
729
+ // Update feedback state
730
+ setMessageFeedback((prev) => ({
731
+ ...prev,
732
+ [message.id]: "thumbsUp",
733
+ }));
734
+
729
735
  // Trigger feedback given event
730
736
  triggerObservabilityHook("onFeedbackGiven", message.id, "thumbsUp");
731
737
  };
@@ -735,6 +741,12 @@ export function CopilotChat({
735
741
  onThumbsDown(message);
736
742
  }
737
743
 
744
+ // Update feedback state
745
+ setMessageFeedback((prev) => ({
746
+ ...prev,
747
+ [message.id]: "thumbsDown",
748
+ }));
749
+
738
750
  // Trigger feedback given event
739
751
  triggerObservabilityHook("onFeedbackGiven", message.id, "thumbsDown");
740
752
  };
@@ -764,6 +776,7 @@ export function CopilotChat({
764
776
  onCopy={handleCopy}
765
777
  onThumbsUp={handleThumbsUp}
766
778
  onThumbsDown={handleThumbsDown}
779
+ messageFeedback={messageFeedback}
767
780
  markdownTagRenderers={markdownTagRenderers}
768
781
  ImageRenderer={ImageRenderer}
769
782
  ErrorMessage={ErrorMessage}
@@ -779,6 +792,7 @@ export function CopilotChat({
779
792
  <RenderSuggestionsList
780
793
  onSuggestionClick={handleSendMessage}
781
794
  suggestions={currentSuggestions}
795
+ isLoading={isLoadingSuggestions}
782
796
  />
783
797
  )}
784
798
  </Messages>
@@ -798,6 +812,8 @@ export function CopilotChat({
798
812
  )}
799
813
  <Input
800
814
  inProgress={isLoading}
815
+ chatReady={Boolean(agent)}
816
+ // @ts-ignore
801
817
  onSend={handleSendMessage}
802
818
  isVisible={isVisible}
803
819
  onStop={stopGeneration}
@@ -829,304 +845,3 @@ export function WrappedCopilotChat({
829
845
  }
830
846
  return <>{children}</>;
831
847
  }
832
-
833
- export const useCopilotChatLogic = (
834
- chatSuggestions: ChatSuggestions,
835
- makeSystemMessage?: SystemMessageFunction,
836
- disableSystemMessage?: boolean,
837
- onInProgress?: (isLoading: boolean) => void,
838
- onSubmitMessage?: (messageContent: string) => Promise<void> | void,
839
- onStopGeneration?: OnStopGeneration,
840
- onReloadMessages?: OnReloadMessages,
841
- ) => {
842
- const {
843
- messages,
844
- sendMessage,
845
- setMessages,
846
- reloadMessages: defaultReloadMessages,
847
- stopGeneration: defaultStopGeneration,
848
- runChatCompletion,
849
- isLoading,
850
- suggestions,
851
- setSuggestions,
852
- generateSuggestions,
853
- resetSuggestions: resetSuggestionsFromHook,
854
- isLoadingSuggestions,
855
- } = useCopilotChat({
856
- makeSystemMessage,
857
- disableSystemMessage,
858
- });
859
-
860
- const generalContext = useCopilotContext();
861
- const messagesContext = useCopilotMessagesContext();
862
-
863
- // Get actions from context for message conversion
864
- const { actions } = generalContext;
865
-
866
- // Suggestion state management
867
- const [suggestionsFailed, setSuggestionsFailed] = useState(false);
868
- const hasGeneratedInitialSuggestions = useRef<boolean>(false);
869
-
870
- // Handle static suggestions (when suggestions prop is an array)
871
- useEffect(() => {
872
- if (Array.isArray(chatSuggestions)) {
873
- setSuggestions(chatSuggestions);
874
- hasGeneratedInitialSuggestions.current = true;
875
- }
876
- }, [JSON.stringify(chatSuggestions), setSuggestions]);
877
-
878
- // Error handling wrapper
879
- const generateSuggestionsWithErrorHandling = useCallback(
880
- async (context: string) => {
881
- try {
882
- await generateSuggestions();
883
- } catch (error) {
884
- console.error("Failed to generate suggestions:", error);
885
- setSuggestionsFailed(true);
886
- }
887
- },
888
- [generateSuggestions],
889
- );
890
-
891
- // Automatic suggestion generation logic
892
- useEffect(() => {
893
- // Only proceed if in auto mode, not currently loading, and not failed
894
- if (chatSuggestions !== "auto" || isLoadingSuggestions || suggestionsFailed) {
895
- return;
896
- }
897
-
898
- // Don't run during chat loading (when the assistant is responding)
899
- if (isLoading) {
900
- return;
901
- }
902
-
903
- // Check if we have any configurations
904
- if (Object.keys(generalContext.chatSuggestionConfiguration).length === 0) {
905
- return;
906
- }
907
-
908
- // Generate initial suggestions when chat is empty
909
- if (messages.length === 0 && !hasGeneratedInitialSuggestions.current) {
910
- hasGeneratedInitialSuggestions.current = true;
911
- generateSuggestionsWithErrorHandling("initial");
912
- return;
913
- }
914
-
915
- // Generate post-message suggestions after assistant responds
916
- if (messages.length > 0 && suggestions.length === 0) {
917
- generateSuggestionsWithErrorHandling("post-message");
918
- return;
919
- }
920
- }, [
921
- chatSuggestions,
922
- isLoadingSuggestions,
923
- suggestionsFailed,
924
- messages.length,
925
- isLoading,
926
- suggestions.length,
927
- Object.keys(generalContext.chatSuggestionConfiguration).join(","), // Use stable string instead of object reference
928
- generateSuggestionsWithErrorHandling,
929
- ]);
930
-
931
- // Reset suggestion state when switching away from auto mode
932
- useEffect(() => {
933
- if (chatSuggestions !== "auto") {
934
- hasGeneratedInitialSuggestions.current = false;
935
- setSuggestionsFailed(false);
936
- }
937
- }, [chatSuggestions]);
938
-
939
- // Memoize context to prevent infinite re-renders
940
- const stableContext = useMemo(
941
- () => ({
942
- ...generalContext,
943
- ...messagesContext,
944
- }),
945
- [
946
- // Only include stable dependencies
947
- generalContext.actions,
948
- messagesContext.messages.length,
949
- generalContext.isLoading,
950
- ],
951
- );
952
-
953
- // Wrapper for resetSuggestions that also resets local state
954
- const resetSuggestions = useCallback(() => {
955
- resetSuggestionsFromHook();
956
- setSuggestionsFailed(false);
957
- hasGeneratedInitialSuggestions.current = false;
958
- }, [resetSuggestionsFromHook]);
959
-
960
- useEffect(() => {
961
- onInProgress?.(isLoading);
962
- }, [onInProgress, isLoading]);
963
-
964
- const safelySendMessage = async (
965
- messageContent: string,
966
- imagesToUse?: Array<{ contentType: string; bytes: string }>,
967
- ) => {
968
- const images = imagesToUse || [];
969
-
970
- // Clear existing suggestions when user sends a message
971
- // This prevents stale suggestions from remaining visible during new conversation flow
972
- if (chatSuggestions === "auto" || chatSuggestions === "manual") {
973
- setSuggestions([]);
974
- }
975
-
976
- let firstMessage: Message | null = null;
977
-
978
- // Send text message if content provided
979
- if (messageContent.trim().length > 0) {
980
- const textMessage: Message = {
981
- id: randomId(),
982
- role: "user",
983
- content: messageContent,
984
- };
985
-
986
- // Call user-provided submit handler if available
987
- if (onSubmitMessage) {
988
- try {
989
- await onSubmitMessage(messageContent);
990
- } catch (error) {
991
- console.error("Error in onSubmitMessage:", error);
992
- }
993
- }
994
-
995
- // Send the message and clear suggestions for auto/manual modes
996
- await sendMessage(textMessage, {
997
- followUp: images.length === 0,
998
- clearSuggestions: chatSuggestions === "auto" || chatSuggestions === "manual",
999
- });
1000
-
1001
- if (!firstMessage) {
1002
- firstMessage = textMessage;
1003
- }
1004
- }
1005
-
1006
- // Send image messages
1007
- if (images.length > 0) {
1008
- for (let i = 0; i < images.length; i++) {
1009
- const imageMessage = {
1010
- id: randomId(),
1011
- role: "user" as const,
1012
- image: {
1013
- format: images[i].contentType.replace("image/", ""),
1014
- bytes: images[i].bytes,
1015
- },
1016
- } as unknown as Message;
1017
- await sendMessage(imageMessage, { followUp: i === images.length - 1 });
1018
- if (!firstMessage) {
1019
- firstMessage = imageMessage;
1020
- }
1021
- }
1022
- }
1023
-
1024
- if (!firstMessage) {
1025
- // Should not happen if send button is properly disabled, but handle just in case
1026
- return { role: "user", content: "", id: randomId() } as Message; // Return a dummy message
1027
- }
1028
-
1029
- // The hook implicitly triggers API call on appendMessage.
1030
- // We return the first message sent (either text or first image)
1031
- return firstMessage;
1032
- };
1033
-
1034
- const currentAgentName = generalContext.agentSession?.agentName;
1035
- const restartCurrentAgent = async (hint?: HintFunction) => {
1036
- if (generalContext.agentSession) {
1037
- generalContext.setAgentSession({
1038
- ...generalContext.agentSession,
1039
- nodeName: undefined,
1040
- threadId: undefined,
1041
- });
1042
- generalContext.setCoagentStates((prevAgentStates) => {
1043
- return {
1044
- ...prevAgentStates,
1045
- [generalContext.agentSession!.agentName]: {
1046
- ...prevAgentStates[generalContext.agentSession!.agentName],
1047
- threadId: undefined,
1048
- nodeName: undefined,
1049
- runId: undefined,
1050
- },
1051
- };
1052
- });
1053
- }
1054
- };
1055
- const runCurrentAgent = async (hint?: HintFunction) => {
1056
- if (generalContext.agentSession) {
1057
- await runAgent(
1058
- generalContext.agentSession.agentName,
1059
- stableContext,
1060
- messagesContext.messages,
1061
- sendMessage,
1062
- runChatCompletion,
1063
- );
1064
- }
1065
- };
1066
- const stopCurrentAgent = () => {
1067
- if (generalContext.agentSession) {
1068
- stopAgent(generalContext.agentSession.agentName, stableContext);
1069
- }
1070
- };
1071
- const setCurrentAgentState = (state: any) => {
1072
- if (generalContext.agentSession) {
1073
- generalContext.setCoagentStates((prevAgentStates) => {
1074
- return {
1075
- ...prevAgentStates,
1076
- [generalContext.agentSession!.agentName]: {
1077
- state,
1078
- },
1079
- } as any;
1080
- });
1081
- }
1082
- };
1083
-
1084
- function stopGeneration() {
1085
- // Clear suggestions when stopping generation
1086
- setSuggestions([]);
1087
-
1088
- if (onStopGeneration) {
1089
- onStopGeneration({
1090
- messages: messages,
1091
- setMessages,
1092
- stopGeneration: defaultStopGeneration,
1093
- currentAgentName,
1094
- restartCurrentAgent,
1095
- stopCurrentAgent,
1096
- runCurrentAgent,
1097
- setCurrentAgentState,
1098
- });
1099
- } else {
1100
- defaultStopGeneration();
1101
- }
1102
- }
1103
- function reloadMessages(messageId: string) {
1104
- if (onReloadMessages) {
1105
- onReloadMessages({
1106
- messages: messages,
1107
- setMessages,
1108
- stopGeneration: defaultStopGeneration,
1109
- currentAgentName,
1110
- restartCurrentAgent,
1111
- stopCurrentAgent,
1112
- runCurrentAgent,
1113
- setCurrentAgentState,
1114
- messageId,
1115
- });
1116
- } else {
1117
- defaultReloadMessages(messageId);
1118
- }
1119
- }
1120
-
1121
- return {
1122
- messages,
1123
- isLoading,
1124
- suggestions,
1125
- sendMessage: safelySendMessage,
1126
- stopGeneration,
1127
- reloadMessages,
1128
- resetSuggestions,
1129
- context: stableContext,
1130
- actions,
1131
- };
1132
- };
@@ -3,7 +3,7 @@ import { InputProps } from "./props";
3
3
  import { useChatContext } from "./ChatContext";
4
4
  import AutoResizingTextarea from "./Textarea";
5
5
  import { usePushToTalk } from "../../hooks/use-push-to-talk";
6
- import { useCopilotContext } from "@copilotkit/react-core";
6
+ import { useCopilotContext, useCopilotChatInternal } from "@copilotkit/react-core";
7
7
  import { PoweredByTag } from "./PoweredByTag";
8
8
 
9
9
  const MAX_NEWLINES = 6;
@@ -11,7 +11,7 @@ const MAX_NEWLINES = 6;
11
11
  export const Input = ({
12
12
  inProgress,
13
13
  onSend,
14
- isVisible = false,
14
+ chatReady = true,
15
15
  onStop,
16
16
  onUpload,
17
17
  hideStopButton = false,
@@ -71,22 +71,22 @@ export const Input = ({
71
71
  });
72
72
 
73
73
  const isInProgress = inProgress || pushToTalkState === "transcribing";
74
- const buttonIcon =
75
- isInProgress && !hideStopButton ? context.icons.stopIcon : context.icons.sendIcon;
74
+ const { buttonIcon, buttonAlt } = useMemo(() => {
75
+ if (!chatReady) return { buttonIcon: context.icons.spinnerIcon, buttonAlt: "Loading" };
76
+ return isInProgress && !hideStopButton
77
+ ? { buttonIcon: context.icons.stopIcon, buttonAlt: "Stop" }
78
+ : { buttonIcon: context.icons.sendIcon, buttonAlt: "Send" };
79
+ }, [isInProgress, chatReady, hideStopButton, context.icons.stopIcon, context.icons.sendIcon]);
76
80
  const showPushToTalk =
77
81
  pushToTalkConfigured &&
78
82
  (pushToTalkState === "idle" || pushToTalkState === "recording") &&
79
83
  !inProgress;
80
84
 
81
- const canSend = useMemo(() => {
82
- const interruptEvent = copilotContext.langGraphInterruptAction?.event;
83
- const interruptInProgress =
84
- interruptEvent?.name === "LangGraphInterruptEvent" && !interruptEvent?.response;
85
+ const { interrupt } = useCopilotChatInternal();
85
86
 
86
- return (
87
- !isInProgress && text.trim().length > 0 && pushToTalkState === "idle" && !interruptInProgress
88
- );
89
- }, [copilotContext.langGraphInterruptAction?.event, isInProgress, text, pushToTalkState]);
87
+ const canSend = useMemo(() => {
88
+ return !isInProgress && text.trim().length > 0 && pushToTalkState === "idle" && !interrupt;
89
+ }, [interrupt, isInProgress, text, pushToTalkState]);
90
90
 
91
91
  const canStop = useMemo(() => {
92
92
  return isInProgress && !hideStopButton;
@@ -144,6 +144,7 @@ export const Input = ({
144
144
  data-copilotkit-in-progress={inProgress}
145
145
  data-test-id={inProgress ? "copilot-chat-request-in-progress" : "copilot-chat-ready"}
146
146
  className="copilotKitInputControlButton"
147
+ aria-label={buttonAlt}
147
148
  >
148
149
  {buttonIcon}
149
150
  </button>