@copilotkit/vue 2.0.0-rc.2 → 2.0.0-rc.20

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 (241) hide show
  1. package/PARITY.md +3 -3
  2. package/dist/hooks/use-copilot-action.d.ts.map +1 -1
  3. package/dist/hooks/use-frontend-tool.d.ts +1 -1
  4. package/dist/hooks/use-frontend-tool.d.ts.map +1 -1
  5. package/dist/hooks/zod-parameters.d.ts +14 -0
  6. package/dist/hooks/zod-parameters.d.ts.map +1 -0
  7. package/dist/index.cjs +1 -73
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.mjs +353 -16908
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/use-render-activity-message-CsWYyd6r.cjs +91 -0
  12. package/dist/use-render-activity-message-CsWYyd6r.cjs.map +1 -0
  13. package/dist/use-render-activity-message-DntKKNdd.js +17418 -0
  14. package/dist/use-render-activity-message-DntKKNdd.js.map +1 -0
  15. package/dist/v2/components/InlineFeatureWarning.vue.d.ts.map +1 -1
  16. package/dist/v2/components/LicenseWarningBanner.vue.d.ts +2 -2
  17. package/dist/v2/components/LicenseWarningBanner.vue.d.ts.map +1 -1
  18. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts +13 -45
  19. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts.map +1 -1
  20. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts +1 -1
  21. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts.map +1 -1
  22. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts +13 -5
  23. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts.map +1 -1
  24. package/dist/v2/components/a2ui/catalog.d.ts.map +1 -1
  25. package/dist/v2/components/a2ui/utils.d.ts.map +1 -1
  26. package/dist/v2/components/a2ui.d.ts +3 -7
  27. package/dist/v2/components/a2ui.d.ts.map +1 -1
  28. package/dist/v2/components/chat/CopilotChat.vue.d.ts +2 -2
  29. package/dist/v2/components/chat/CopilotChat.vue.d.ts.map +1 -1
  30. package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts.map +1 -1
  31. package/dist/v2/components/chat/CopilotChatAttachmentQueue.vue.d.ts.map +1 -1
  32. package/dist/v2/components/chat/CopilotChatAttachmentRenderer.vue.d.ts.map +1 -1
  33. package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts +1 -1
  34. package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts.map +1 -1
  35. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts +6 -270
  36. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts.map +1 -1
  37. package/dist/v2/components/chat/CopilotChatInspectorButton.vue.d.ts.map +1 -1
  38. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts +1 -1
  39. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts.map +1 -1
  40. package/dist/v2/components/chat/CopilotChatReasoningMessage.vue.d.ts.map +1 -1
  41. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts +1 -1
  42. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts.map +1 -1
  43. package/dist/v2/components/chat/CopilotChatToolCallItem.vue.d.ts.map +1 -1
  44. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts +1 -1
  45. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts.map +1 -1
  46. package/dist/v2/components/chat/CopilotChatUserMessage.vue.d.ts.map +1 -1
  47. package/dist/v2/components/chat/CopilotChatView.vue.d.ts +2 -2
  48. package/dist/v2/components/chat/CopilotChatView.vue.d.ts.map +1 -1
  49. package/dist/v2/components/chat/CopilotChatWorkSummary.vue.d.ts.map +1 -1
  50. package/dist/v2/components/chat/CopilotModalHeader.vue.d.ts.map +1 -1
  51. package/dist/v2/components/chat/CopilotPopup.vue.d.ts +8 -3
  52. package/dist/v2/components/chat/CopilotPopup.vue.d.ts.map +1 -1
  53. package/dist/v2/components/chat/CopilotPopupView.vue.d.ts +5 -3
  54. package/dist/v2/components/chat/CopilotPopupView.vue.d.ts.map +1 -1
  55. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts +5 -3
  56. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts.map +1 -1
  57. package/dist/v2/components/chat/CopilotSidebar.vue.d.ts +8 -3
  58. package/dist/v2/components/chat/CopilotSidebar.vue.d.ts.map +1 -1
  59. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts +5 -3
  60. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts.map +1 -1
  61. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts +5 -3
  62. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts.map +1 -1
  63. package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts +0 -1
  64. package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts.map +1 -1
  65. package/dist/v2/components/chat/forwarded-slots.d.ts +12 -0
  66. package/dist/v2/components/chat/forwarded-slots.d.ts.map +1 -0
  67. package/dist/v2/components/chat/index.d.ts +28 -25
  68. package/dist/v2/components/chat/index.d.ts.map +1 -1
  69. package/dist/v2/components/chat/inspector-shortcuts.d.ts +2 -1
  70. package/dist/v2/components/chat/inspector-shortcuts.d.ts.map +1 -1
  71. package/dist/v2/components/chat/message-feedback.d.ts +18 -49
  72. package/dist/v2/components/chat/message-feedback.d.ts.map +1 -1
  73. package/dist/v2/components/chat/normalize-auto-scroll.d.ts +2 -2
  74. package/dist/v2/components/chat/normalize-auto-scroll.d.ts.map +1 -1
  75. package/dist/v2/components/chat/tool-call-display-context.d.ts +2 -19
  76. package/dist/v2/components/chat/tool-call-display-context.d.ts.map +1 -1
  77. package/dist/v2/components/chat/tool-call-group-parts.d.ts +7 -20
  78. package/dist/v2/components/chat/tool-call-group-parts.d.ts.map +1 -1
  79. package/dist/v2/components/chat/turn-work.d.ts +0 -2
  80. package/dist/v2/components/chat/turn-work.d.ts.map +1 -1
  81. package/dist/v2/components/chat/types.d.ts +8 -3
  82. package/dist/v2/components/chat/types.d.ts.map +1 -1
  83. package/dist/v2/components/chat/use-chat-labels.d.ts +8 -0
  84. package/dist/v2/components/chat/use-chat-labels.d.ts.map +1 -0
  85. package/dist/v2/components/chat/use-copy-feedback.d.ts +11 -0
  86. package/dist/v2/components/chat/use-copy-feedback.d.ts.map +1 -0
  87. package/dist/v2/components/icons/index.d.ts +968 -1
  88. package/dist/v2/components/icons/index.d.ts.map +1 -1
  89. package/dist/v2/hooks/use-attachments.d.ts.map +1 -1
  90. package/dist/v2/hooks/use-frontend-tool.d.ts +5 -0
  91. package/dist/v2/hooks/use-frontend-tool.d.ts.map +1 -1
  92. package/dist/v2/hooks/use-keyboard-height.d.ts +1 -1
  93. package/dist/v2/hooks/use-keyboard-height.d.ts.map +1 -1
  94. package/dist/v2/hooks/use-pin-to-send.d.ts +4 -12
  95. package/dist/v2/hooks/use-pin-to-send.d.ts.map +1 -1
  96. package/dist/v2/hooks/use-render-activity-message.d.ts +13 -9
  97. package/dist/v2/hooks/use-render-activity-message.d.ts.map +1 -1
  98. package/dist/v2/hooks/use-render-custom-messages.d.ts +5 -7
  99. package/dist/v2/hooks/use-render-custom-messages.d.ts.map +1 -1
  100. package/dist/v2/index.cjs +1 -1
  101. package/dist/v2/index.mjs +197 -200
  102. package/dist/v2/index.mjs.map +1 -1
  103. package/dist/v2/lib/is-mobile-viewport.d.ts +1 -14
  104. package/dist/v2/lib/is-mobile-viewport.d.ts.map +1 -1
  105. package/dist/v2/lib/processPartialHtml.d.ts +1 -2
  106. package/dist/v2/lib/processPartialHtml.d.ts.map +1 -1
  107. package/dist/v2/lib/shallow-stable.d.ts.map +1 -1
  108. package/dist/v2/lib/vue-core.d.ts +0 -1
  109. package/dist/v2/lib/vue-core.d.ts.map +1 -1
  110. package/dist/v2/providers/CopilotKitProvider.types.d.ts +0 -5
  111. package/dist/v2/providers/CopilotKitProvider.types.d.ts.map +1 -1
  112. package/dist/v2/providers/CopilotKitProvider.vue.d.ts +1 -1
  113. package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
  114. package/dist/v2/providers/markdown-renderer.d.ts +2 -2
  115. package/dist/v2/providers/markdown-renderer.d.ts.map +1 -1
  116. package/dist/v2/providers/types.d.ts +3 -46
  117. package/dist/v2/providers/types.d.ts.map +1 -1
  118. package/dist/v2/types/human-in-the-loop.d.ts +8 -29
  119. package/dist/v2/types/human-in-the-loop.d.ts.map +1 -1
  120. package/dist/v2/types/interrupt.d.ts +1 -22
  121. package/dist/v2/types/interrupt.d.ts.map +1 -1
  122. package/dist/v2/types/vue-activity-message-renderer.d.ts +16 -15
  123. package/dist/v2/types/vue-activity-message-renderer.d.ts.map +1 -1
  124. package/dist/v2/types/vue-custom-message-renderer.d.ts +7 -16
  125. package/dist/v2/types/vue-custom-message-renderer.d.ts.map +1 -1
  126. package/dist/v2/types/vue-tool-call-renderer.d.ts +16 -35
  127. package/dist/v2/types/vue-tool-call-renderer.d.ts.map +1 -1
  128. package/package.json +10 -11
  129. package/src/__tests__/build-entries.test.ts +27 -0
  130. package/src/hooks/__tests__/zod-parameters.test.ts +520 -0
  131. package/src/hooks/use-copilot-action.ts +2 -1
  132. package/src/hooks/use-frontend-tool.ts +3 -6
  133. package/src/hooks/zod-parameters.ts +162 -0
  134. package/src/v2/components/A2UIMessageRenderer.ts +3 -3
  135. package/src/v2/components/InlineFeatureWarning.vue +20 -21
  136. package/src/v2/components/LicenseWarningBanner.vue +27 -135
  137. package/src/v2/components/OpenGenerativeUIRenderer.ts +51 -373
  138. package/src/v2/components/__tests__/A2UICatalogContext.test.ts +1 -1
  139. package/src/v2/components/__tests__/LicenseWarningBanner.test.ts +60 -0
  140. package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.ts +55 -6
  141. package/src/v2/components/a2ui/A2UIBuiltInToolCallRenderer.ts +1 -1
  142. package/src/v2/components/a2ui/A2UICatalogContext.ts +10 -102
  143. package/src/v2/components/a2ui/A2UIRecoveryStates.ts +1 -1
  144. package/src/v2/components/a2ui/catalog.ts +1 -0
  145. package/src/v2/components/a2ui/utils.ts +2 -0
  146. package/src/v2/components/a2ui.ts +1 -1
  147. package/src/v2/components/chat/CopilotChat.vue +19 -40
  148. package/src/v2/components/chat/CopilotChatAssistantMessage.vue +19 -43
  149. package/src/v2/components/chat/CopilotChatAttachmentQueue.vue +14 -10
  150. package/src/v2/components/chat/CopilotChatAttachmentRenderer.vue +14 -6
  151. package/src/v2/components/chat/CopilotChatFeedbackCommentPopover.vue +2 -2
  152. package/src/v2/components/chat/CopilotChatInput.vue +40 -30
  153. package/src/v2/components/chat/CopilotChatInspectorButton.vue +45 -108
  154. package/src/v2/components/chat/CopilotChatMessageView.vue +72 -140
  155. package/src/v2/components/chat/CopilotChatReasoningMessage.vue +7 -15
  156. package/src/v2/components/chat/CopilotChatToolCallGroup.vue +60 -37
  157. package/src/v2/components/chat/CopilotChatToolCallItem.vue +3 -3
  158. package/src/v2/components/chat/CopilotChatToolCallsView.vue +15 -13
  159. package/src/v2/components/chat/CopilotChatUserMessage.vue +24 -112
  160. package/src/v2/components/chat/CopilotChatView.vue +5 -5
  161. package/src/v2/components/chat/CopilotChatWorkSummary.vue +26 -36
  162. package/src/v2/components/chat/CopilotModalHeader.vue +11 -23
  163. package/src/v2/components/chat/CopilotPopup.vue +23 -25
  164. package/src/v2/components/chat/CopilotPopupView.vue +10 -39
  165. package/src/v2/components/chat/CopilotPopupViewInternal.vue +14 -34
  166. package/src/v2/components/chat/CopilotSidebar.vue +23 -25
  167. package/src/v2/components/chat/CopilotSidebarView.vue +10 -39
  168. package/src/v2/components/chat/CopilotSidebarViewInternal.vue +14 -34
  169. package/src/v2/components/chat/StreamingMarkdownDefault.vue +4 -4
  170. package/src/v2/components/chat/__tests__/CopilotChat.labels.test.ts +19 -4
  171. package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.ts +26 -9
  172. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.learningFeedback.test.ts +5 -5
  173. package/src/v2/components/chat/__tests__/CopilotChatInput.test.ts +33 -1
  174. package/src/v2/components/chat/__tests__/CopilotChatMessageView.test.ts +247 -403
  175. package/src/v2/components/chat/__tests__/CopilotChatMessageView.toolCallDisplay.test.ts +1 -99
  176. package/src/v2/components/chat/__tests__/CopilotPopup.test.ts +90 -1
  177. package/src/v2/components/chat/__tests__/CopilotSidebar.test.ts +90 -1
  178. package/src/v2/components/chat/copilotChatToolCallItemRender.ts +3 -19
  179. package/src/v2/components/chat/forwarded-slots.ts +17 -0
  180. package/src/v2/components/chat/index.ts +0 -1
  181. package/src/v2/components/chat/inspector-shortcuts.ts +10 -16
  182. package/src/v2/components/chat/message-feedback.ts +62 -197
  183. package/src/v2/components/chat/normalize-auto-scroll.ts +3 -17
  184. package/src/v2/components/chat/tool-call-display-context.ts +2 -23
  185. package/src/v2/components/chat/tool-call-group-parts.ts +44 -85
  186. package/src/v2/components/chat/turn-work.ts +0 -9
  187. package/src/v2/components/chat/types.ts +12 -4
  188. package/src/v2/components/chat/use-chat-labels.ts +16 -0
  189. package/src/v2/components/chat/use-copy-feedback.ts +21 -0
  190. package/src/v2/components/icons/__tests__/icons.test.ts +72 -68
  191. package/src/v2/components/icons/index.ts +109 -27
  192. package/src/v2/hooks/__tests__/use-frontend-tool.e2e.test.ts +62 -1
  193. package/src/v2/hooks/__tests__/use-render-activity-message.test.ts +105 -0
  194. package/src/v2/hooks/__tests__/use-render-tool.test.ts +3 -6
  195. package/src/v2/hooks/__tests__/zod-regression.test.ts +5 -4
  196. package/src/v2/hooks/use-attachments.ts +6 -2
  197. package/src/v2/hooks/use-frontend-tool.ts +10 -10
  198. package/src/v2/hooks/use-keyboard-height.ts +17 -40
  199. package/src/v2/hooks/use-pin-to-send.ts +15 -99
  200. package/src/v2/hooks/use-render-activity-message.ts +27 -48
  201. package/src/v2/hooks/use-render-custom-messages.ts +14 -35
  202. package/src/v2/lib/__tests__/shallow-stable.test.ts +54 -0
  203. package/src/v2/lib/is-mobile-viewport.ts +5 -23
  204. package/src/v2/lib/processPartialHtml.ts +6 -21
  205. package/src/v2/lib/shallow-stable.ts +2 -16
  206. package/src/v2/lib/vue-core.ts +9 -13
  207. package/src/v2/providers/CopilotKitProvider.types.ts +0 -5
  208. package/src/v2/providers/CopilotKitProvider.vue +53 -112
  209. package/src/v2/providers/__tests__/CopilotKitProvider.a2ui.test.ts +1 -1
  210. package/src/v2/providers/__tests__/CopilotKitProvider.headersAtSendTime.test.ts +3 -3
  211. package/src/v2/providers/__tests__/CopilotKitProvider.learning.test.ts +3 -1
  212. package/src/v2/providers/__tests__/CopilotKitProvider.test.ts +17 -33
  213. package/src/v2/providers/markdown-renderer.ts +2 -2
  214. package/src/v2/providers/types.ts +3 -49
  215. package/src/v2/types/__tests__/defineToolCallRenderer.test.ts +28 -33
  216. package/src/v2/types/defineToolCallRenderer.ts +5 -4
  217. package/src/v2/types/human-in-the-loop.ts +8 -32
  218. package/src/v2/types/interrupt.ts +7 -31
  219. package/src/v2/types/vue-activity-message-renderer.ts +24 -15
  220. package/src/v2/types/vue-custom-message-renderer.ts +12 -16
  221. package/src/v2/types/vue-tool-call-renderer.ts +23 -38
  222. package/tsconfig.json +0 -1
  223. package/vite.config.ts +3 -4
  224. package/dist/v2/components/chat/BasicMarkdown.vue.d.ts +0 -9
  225. package/dist/v2/components/chat/BasicMarkdown.vue.d.ts.map +0 -1
  226. package/dist/v2/components/chat/tool-call-layout.d.ts +0 -115
  227. package/dist/v2/components/chat/tool-call-layout.d.ts.map +0 -1
  228. package/dist/v2/lib/message-feedback.d.ts +0 -33
  229. package/dist/v2/lib/message-feedback.d.ts.map +0 -1
  230. package/dist/v2/lib/transcription-client.d.ts +0 -19
  231. package/dist/v2/lib/transcription-client.d.ts.map +0 -1
  232. package/src/v2/components/chat/BasicMarkdown.vue +0 -160
  233. package/src/v2/components/chat/__tests__/BasicMarkdown.test.ts +0 -69
  234. package/src/v2/components/chat/__tests__/normalize-auto-scroll.test.ts +0 -39
  235. package/src/v2/components/chat/tool-call-layout.ts +0 -304
  236. package/src/v2/lib/__tests__/is-mobile-viewport.test.ts +0 -48
  237. package/src/v2/lib/__tests__/message-feedback.test.ts +0 -152
  238. package/src/v2/lib/__tests__/processPartialHtml.test.ts +0 -84
  239. package/src/v2/lib/__tests__/transcription-client.test.ts +0 -67
  240. package/src/v2/lib/message-feedback.ts +0 -120
  241. package/src/v2/lib/transcription-client.ts +0 -151
@@ -4,9 +4,14 @@ import CopilotChat from "./CopilotChat.vue";
4
4
  import CopilotPopupView from "./CopilotPopupView.vue";
5
5
  import CopilotPopupWelcomeScreen from "./CopilotPopupWelcomeScreen.vue";
6
6
  import InlineFeatureWarning from "../InlineFeatureWarning.vue";
7
+ import { forwardedSlotNames } from "./forwarded-slots";
7
8
  import { useLicenseContext } from "../../providers/useLicenseContext";
8
9
  import type {
10
+ CopilotChatFeatherSlotProps,
11
+ CopilotChatInterruptSlotProps,
9
12
  CopilotChatMessageViewSlotProps,
13
+ CopilotChatScrollToBottomButtonSlotProps,
14
+ CopilotChatScrollViewSlotProps,
10
15
  CopilotChatViewOverrideSlotProps,
11
16
  CopilotChatWelcomeScreenSlotProps,
12
17
  CopilotPopupProps,
@@ -53,14 +58,28 @@ defineSlots<{
53
58
  "toggle-button"?: (props: CopilotPopupViewToggleButtonSlotProps) => unknown;
54
59
  "chat-view"?: (props: CopilotChatViewOverrideSlotProps) => unknown;
55
60
  "message-view"?: (props: CopilotChatMessageViewSlotProps) => unknown;
61
+ "scroll-view"?: (props: CopilotChatScrollViewSlotProps) => unknown;
62
+ feather?: (props: CopilotChatFeatherSlotProps) => unknown;
63
+ "scroll-to-bottom-button"?: (
64
+ props: CopilotChatScrollToBottomButtonSlotProps,
65
+ ) => unknown;
66
+ interrupt?: (props: CopilotChatInterruptSlotProps) => unknown;
56
67
  input?: (props: CopilotSidebarWelcomeScreenInputSlotProps) => unknown;
57
68
  "suggestion-view"?: (
58
69
  props: CopilotSidebarWelcomeScreenSuggestionViewSlotProps,
59
70
  ) => unknown;
60
71
  "welcome-screen"?: (props: CopilotChatWelcomeScreenSlotProps) => unknown;
61
72
  "welcome-message"?: () => unknown;
73
+ // Any other slot goes to the chat view, as on CopilotChat.
74
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
75
+ [key: string]: ((props: any) => unknown) | undefined;
62
76
  }>();
63
77
 
78
+ // Slots this component renders itself and does not pass to the view. It passes
79
+ // every other slot to the view. It also renders `input` and `suggestion-view`
80
+ // in its welcome screen, so those two go to both places.
81
+ const OWN_SLOTS = ["chat-view", "welcome-screen", "welcome-message"] as const;
82
+
64
83
  defineEmits<{
65
84
  "submit-message": [value: string];
66
85
  stop: [];
@@ -125,15 +144,12 @@ watch(
125
144
  :on-finish-transcribe-with-audio="slotProps.onFinishTranscribeWithAudio"
126
145
  v-bind="popupViewEventBindings(slotProps)"
127
146
  >
128
- <template v-if="$slots.header" #header="headerProps">
129
- <slot name="header" v-bind="headerProps" />
130
- </template>
131
-
132
147
  <template
133
- v-if="$slots['toggle-button']"
134
- #toggle-button="toggleButtonProps"
148
+ v-for="slotName in forwardedSlotNames($slots, OWN_SLOTS)"
149
+ :key="slotName"
150
+ #[slotName]="forwardedProps"
135
151
  >
136
- <slot name="toggle-button" v-bind="toggleButtonProps" />
152
+ <slot :name="slotName" v-bind="forwardedProps" />
137
153
  </template>
138
154
 
139
155
  <template #welcome-screen="welcomeScreenProps">
@@ -159,24 +175,6 @@ watch(
159
175
  </template>
160
176
  </CopilotPopupWelcomeScreen>
161
177
  </template>
162
-
163
- <template
164
- v-if="$slots['message-view']"
165
- #message-view="messageViewProps"
166
- >
167
- <slot name="message-view" v-bind="messageViewProps" />
168
- </template>
169
-
170
- <template v-if="$slots.input" #input="inputProps">
171
- <slot name="input" v-bind="inputProps" />
172
- </template>
173
-
174
- <template
175
- v-if="$slots['suggestion-view']"
176
- #suggestion-view="suggestionViewProps"
177
- >
178
- <slot name="suggestion-view" v-bind="suggestionViewProps" />
179
- </template>
180
178
  </CopilotPopupView>
181
179
  </template>
182
180
  </CopilotChat>
@@ -1,9 +1,11 @@
1
1
  <script setup lang="ts">
2
2
  import { computed, useAttrs } from "vue";
3
3
  import CopilotChatConfigurationProvider from "../../providers/CopilotChatConfigurationProvider.vue";
4
+ import { forwardedSlotNames } from "./forwarded-slots";
4
5
  import CopilotPopupViewInternal from "./CopilotPopupViewInternal.vue";
5
6
  import type {
6
7
  CopilotChatFeatherSlotProps,
8
+ CopilotChatInterruptSlotProps,
7
9
  CopilotChatMessageViewSlotProps,
8
10
  CopilotChatScrollToBottomButtonSlotProps,
9
11
  CopilotChatScrollViewSlotProps,
@@ -44,12 +46,16 @@ defineSlots<{
44
46
  "scroll-to-bottom-button"?: (
45
47
  props: CopilotChatScrollToBottomButtonSlotProps,
46
48
  ) => unknown;
49
+ interrupt?: (props: CopilotChatInterruptSlotProps) => unknown;
47
50
  input?: (props: CopilotSidebarWelcomeScreenInputSlotProps) => unknown;
48
51
  "suggestion-view"?: (
49
52
  props: CopilotSidebarWelcomeScreenSuggestionViewSlotProps,
50
53
  ) => unknown;
51
54
  "welcome-screen"?: (props: CopilotChatWelcomeScreenSlotProps) => unknown;
52
55
  "welcome-message"?: () => unknown;
56
+ // Any other slot goes to the chat view, as on CopilotChat.
57
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
58
+ [key: string]: ((props: any) => unknown) | undefined;
53
59
  }>();
54
60
 
55
61
  const emit = defineEmits<{
@@ -112,47 +118,12 @@ const internalBindings = computed(() => ({
112
118
  <template>
113
119
  <CopilotChatConfigurationProvider :is-modal-default-open="defaultOpen">
114
120
  <CopilotPopupViewInternal v-bind="internalBindings">
115
- <template v-if="$slots.header" #header="slotProps">
116
- <slot name="header" v-bind="slotProps" />
117
- </template>
118
-
119
- <template v-if="$slots['toggle-button']" #toggle-button="slotProps">
120
- <slot name="toggle-button" v-bind="slotProps" />
121
- </template>
122
-
123
- <template v-if="$slots['message-view']" #message-view="slotProps">
124
- <slot name="message-view" v-bind="slotProps" />
125
- </template>
126
-
127
- <template v-if="$slots['scroll-view']" #scroll-view="slotProps">
128
- <slot name="scroll-view" v-bind="slotProps" />
129
- </template>
130
-
131
- <template v-if="$slots.feather" #feather="slotProps">
132
- <slot name="feather" v-bind="slotProps" />
133
- </template>
134
-
135
121
  <template
136
- v-if="$slots['scroll-to-bottom-button']"
137
- #scroll-to-bottom-button="slotProps"
122
+ v-for="slotName in forwardedSlotNames($slots)"
123
+ :key="slotName"
124
+ #[slotName]="slotProps"
138
125
  >
139
- <slot name="scroll-to-bottom-button" v-bind="slotProps" />
140
- </template>
141
-
142
- <template v-if="$slots.input" #input="slotProps">
143
- <slot name="input" v-bind="slotProps" />
144
- </template>
145
-
146
- <template v-if="$slots['suggestion-view']" #suggestion-view="slotProps">
147
- <slot name="suggestion-view" v-bind="slotProps" />
148
- </template>
149
-
150
- <template v-if="$slots['welcome-screen']" #welcome-screen="slotProps">
151
- <slot name="welcome-screen" v-bind="slotProps" />
152
- </template>
153
-
154
- <template v-if="$slots['welcome-message']" #welcome-message>
155
- <slot name="welcome-message" />
126
+ <slot :name="slotName" v-bind="slotProps" />
156
127
  </template>
157
128
  </CopilotPopupViewInternal>
158
129
  </CopilotChatConfigurationProvider>
@@ -13,8 +13,10 @@ import { useCopilotChatConfiguration } from "../../providers/useCopilotChatConfi
13
13
  import CopilotChatToggleButton from "./CopilotChatToggleButton.vue";
14
14
  import CopilotChatView from "./CopilotChatView.vue";
15
15
  import CopilotModalHeader from "./CopilotModalHeader.vue";
16
+ import { forwardedSlotNames } from "./forwarded-slots";
16
17
  import type {
17
18
  CopilotChatFeatherSlotProps,
19
+ CopilotChatInterruptSlotProps,
18
20
  CopilotChatMessageViewSlotProps,
19
21
  CopilotChatScrollToBottomButtonSlotProps,
20
22
  CopilotChatScrollViewSlotProps,
@@ -61,14 +63,22 @@ defineSlots<{
61
63
  "scroll-to-bottom-button"?: (
62
64
  props: CopilotChatScrollToBottomButtonSlotProps,
63
65
  ) => unknown;
66
+ interrupt?: (props: CopilotChatInterruptSlotProps) => unknown;
64
67
  input?: (props: CopilotSidebarWelcomeScreenInputSlotProps) => unknown;
65
68
  "suggestion-view"?: (
66
69
  props: CopilotSidebarWelcomeScreenSuggestionViewSlotProps,
67
70
  ) => unknown;
68
71
  "welcome-screen"?: (props: CopilotChatWelcomeScreenSlotProps) => unknown;
69
72
  "welcome-message"?: () => unknown;
73
+ // Any other slot goes to the chat view, as on CopilotChat.
74
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
75
+ [key: string]: ((props: any) => unknown) | undefined;
70
76
  }>();
71
77
 
78
+ // Slots this component renders itself. It passes every other slot to the
79
+ // chat view.
80
+ const OWN_SLOTS = ["header", "toggle-button"] as const;
81
+
72
82
  const emit = defineEmits<{
73
83
  "submit-message": [value: string];
74
84
  stop: [];
@@ -385,42 +395,12 @@ onBeforeUnmount(() => {
385
395
  :on-finish-transcribe-with-audio="onFinishTranscribeWithAudio"
386
396
  v-bind="chatViewBindings"
387
397
  >
388
- <template v-if="$slots['message-view']" #message-view="slotProps">
389
- <slot name="message-view" v-bind="slotProps" />
390
- </template>
391
-
392
- <template v-if="$slots['scroll-view']" #scroll-view="slotProps">
393
- <slot name="scroll-view" v-bind="slotProps" />
394
- </template>
395
-
396
- <template v-if="$slots.feather" #feather>
397
- <slot name="feather" />
398
- </template>
399
-
400
398
  <template
401
- v-if="$slots['scroll-to-bottom-button']"
402
- #scroll-to-bottom-button="slotProps"
399
+ v-for="slotName in forwardedSlotNames($slots, OWN_SLOTS)"
400
+ :key="slotName"
401
+ #[slotName]="slotProps"
403
402
  >
404
- <slot name="scroll-to-bottom-button" v-bind="slotProps" />
405
- </template>
406
-
407
- <template v-if="$slots.input" #input="slotProps">
408
- <slot name="input" v-bind="slotProps" />
409
- </template>
410
-
411
- <template
412
- v-if="$slots['suggestion-view']"
413
- #suggestion-view="slotProps"
414
- >
415
- <slot name="suggestion-view" v-bind="slotProps" />
416
- </template>
417
-
418
- <template v-if="$slots['welcome-screen']" #welcome-screen="slotProps">
419
- <slot name="welcome-screen" v-bind="slotProps" />
420
- </template>
421
-
422
- <template v-if="$slots['welcome-message']" #welcome-message>
423
- <slot name="welcome-message" />
403
+ <slot :name="slotName" v-bind="slotProps" />
424
404
  </template>
425
405
  </CopilotChatView>
426
406
  </div>
@@ -4,9 +4,14 @@ import CopilotChat from "./CopilotChat.vue";
4
4
  import CopilotSidebarView from "./CopilotSidebarView.vue";
5
5
  import CopilotSidebarWelcomeScreen from "./CopilotSidebarWelcomeScreen.vue";
6
6
  import InlineFeatureWarning from "../InlineFeatureWarning.vue";
7
+ import { forwardedSlotNames } from "./forwarded-slots";
7
8
  import { useLicenseContext } from "../../providers/useLicenseContext";
8
9
  import type {
10
+ CopilotChatFeatherSlotProps,
11
+ CopilotChatInterruptSlotProps,
9
12
  CopilotChatMessageViewSlotProps,
13
+ CopilotChatScrollToBottomButtonSlotProps,
14
+ CopilotChatScrollViewSlotProps,
10
15
  CopilotChatViewOverrideSlotProps,
11
16
  CopilotChatWelcomeScreenSlotProps,
12
17
  CopilotSidebarProps,
@@ -52,14 +57,28 @@ defineSlots<{
52
57
  "toggle-button"?: (props: CopilotSidebarViewToggleButtonSlotProps) => unknown;
53
58
  "chat-view"?: (props: CopilotChatViewOverrideSlotProps) => unknown;
54
59
  "message-view"?: (props: CopilotChatMessageViewSlotProps) => unknown;
60
+ "scroll-view"?: (props: CopilotChatScrollViewSlotProps) => unknown;
61
+ feather?: (props: CopilotChatFeatherSlotProps) => unknown;
62
+ "scroll-to-bottom-button"?: (
63
+ props: CopilotChatScrollToBottomButtonSlotProps,
64
+ ) => unknown;
65
+ interrupt?: (props: CopilotChatInterruptSlotProps) => unknown;
55
66
  input?: (props: CopilotSidebarWelcomeScreenInputSlotProps) => unknown;
56
67
  "suggestion-view"?: (
57
68
  props: CopilotSidebarWelcomeScreenSuggestionViewSlotProps,
58
69
  ) => unknown;
59
70
  "welcome-screen"?: (props: CopilotChatWelcomeScreenSlotProps) => unknown;
60
71
  "welcome-message"?: () => unknown;
72
+ // Any other slot goes to the chat view, as on CopilotChat.
73
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
74
+ [key: string]: ((props: any) => unknown) | undefined;
61
75
  }>();
62
76
 
77
+ // Slots this component renders itself and does not pass to the view. It passes
78
+ // every other slot to the view. It also renders `input` and `suggestion-view`
79
+ // in its welcome screen, so those two go to both places.
80
+ const OWN_SLOTS = ["chat-view", "welcome-screen", "welcome-message"] as const;
81
+
63
82
  defineEmits<{
64
83
  "submit-message": [value: string];
65
84
  stop: [];
@@ -123,15 +142,12 @@ watch(
123
142
  :on-finish-transcribe-with-audio="slotProps.onFinishTranscribeWithAudio"
124
143
  v-bind="sidebarViewEventBindings(slotProps)"
125
144
  >
126
- <template v-if="$slots.header" #header="headerProps">
127
- <slot name="header" v-bind="headerProps" />
128
- </template>
129
-
130
145
  <template
131
- v-if="$slots['toggle-button']"
132
- #toggle-button="toggleButtonProps"
146
+ v-for="slotName in forwardedSlotNames($slots, OWN_SLOTS)"
147
+ :key="slotName"
148
+ #[slotName]="forwardedProps"
133
149
  >
134
- <slot name="toggle-button" v-bind="toggleButtonProps" />
150
+ <slot :name="slotName" v-bind="forwardedProps" />
135
151
  </template>
136
152
 
137
153
  <template #welcome-screen="welcomeScreenProps">
@@ -157,24 +173,6 @@ watch(
157
173
  </template>
158
174
  </CopilotSidebarWelcomeScreen>
159
175
  </template>
160
-
161
- <template
162
- v-if="$slots['message-view']"
163
- #message-view="messageViewProps"
164
- >
165
- <slot name="message-view" v-bind="messageViewProps" />
166
- </template>
167
-
168
- <template v-if="$slots.input" #input="inputProps">
169
- <slot name="input" v-bind="inputProps" />
170
- </template>
171
-
172
- <template
173
- v-if="$slots['suggestion-view']"
174
- #suggestion-view="suggestionViewProps"
175
- >
176
- <slot name="suggestion-view" v-bind="suggestionViewProps" />
177
- </template>
178
176
  </CopilotSidebarView>
179
177
  </template>
180
178
  </CopilotChat>
@@ -1,9 +1,11 @@
1
1
  <script setup lang="ts">
2
2
  import { computed, useAttrs } from "vue";
3
3
  import CopilotChatConfigurationProvider from "../../providers/CopilotChatConfigurationProvider.vue";
4
+ import { forwardedSlotNames } from "./forwarded-slots";
4
5
  import CopilotSidebarViewInternal from "./CopilotSidebarViewInternal.vue";
5
6
  import type {
6
7
  CopilotChatFeatherSlotProps,
8
+ CopilotChatInterruptSlotProps,
7
9
  CopilotChatWelcomeScreenSlotProps,
8
10
  CopilotChatMessageViewSlotProps,
9
11
  CopilotChatScrollToBottomButtonSlotProps,
@@ -50,12 +52,16 @@ defineSlots<{
50
52
  "scroll-to-bottom-button"?: (
51
53
  props: CopilotChatScrollToBottomButtonSlotProps,
52
54
  ) => unknown;
55
+ interrupt?: (props: CopilotChatInterruptSlotProps) => unknown;
53
56
  input?: (props: CopilotSidebarWelcomeScreenInputSlotProps) => unknown;
54
57
  "suggestion-view"?: (
55
58
  props: CopilotSidebarWelcomeScreenSuggestionViewSlotProps,
56
59
  ) => unknown;
57
60
  "welcome-screen"?: (props: CopilotChatWelcomeScreenSlotProps) => unknown;
58
61
  "welcome-message"?: () => unknown;
62
+ // Any other slot goes to the chat view, as on CopilotChat.
63
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
64
+ [key: string]: ((props: any) => unknown) | undefined;
59
65
  }>();
60
66
 
61
67
  const emit = defineEmits<{
@@ -117,47 +123,12 @@ const forwardedEventListeners = computed(() => {
117
123
  <template>
118
124
  <CopilotChatConfigurationProvider :is-modal-default-open="defaultOpen">
119
125
  <CopilotSidebarViewInternal v-bind="internalBindings">
120
- <template v-if="$slots.header" #header="slotProps">
121
- <slot name="header" v-bind="slotProps" />
122
- </template>
123
-
124
- <template v-if="$slots['toggle-button']" #toggle-button="slotProps">
125
- <slot name="toggle-button" v-bind="slotProps" />
126
- </template>
127
-
128
- <template v-if="$slots['message-view']" #message-view="slotProps">
129
- <slot name="message-view" v-bind="slotProps" />
130
- </template>
131
-
132
- <template v-if="$slots['scroll-view']" #scroll-view="slotProps">
133
- <slot name="scroll-view" v-bind="slotProps" />
134
- </template>
135
-
136
- <template v-if="$slots.feather" #feather="slotProps">
137
- <slot name="feather" v-bind="slotProps" />
138
- </template>
139
-
140
126
  <template
141
- v-if="$slots['scroll-to-bottom-button']"
142
- #scroll-to-bottom-button="slotProps"
127
+ v-for="slotName in forwardedSlotNames($slots)"
128
+ :key="slotName"
129
+ #[slotName]="slotProps"
143
130
  >
144
- <slot name="scroll-to-bottom-button" v-bind="slotProps" />
145
- </template>
146
-
147
- <template v-if="$slots.input" #input="slotProps">
148
- <slot name="input" v-bind="slotProps" />
149
- </template>
150
-
151
- <template v-if="$slots['suggestion-view']" #suggestion-view="slotProps">
152
- <slot name="suggestion-view" v-bind="slotProps" />
153
- </template>
154
-
155
- <template v-if="$slots['welcome-screen']" #welcome-screen="slotProps">
156
- <slot name="welcome-screen" v-bind="slotProps" />
157
- </template>
158
-
159
- <template v-if="$slots['welcome-message']" #welcome-message>
160
- <slot name="welcome-message" />
131
+ <slot :name="slotName" v-bind="slotProps" />
161
132
  </template>
162
133
  </CopilotSidebarViewInternal>
163
134
  </CopilotChatConfigurationProvider>
@@ -13,8 +13,10 @@ import { useCopilotChatConfiguration } from "../../providers/useCopilotChatConfi
13
13
  import CopilotChatToggleButton from "./CopilotChatToggleButton.vue";
14
14
  import CopilotChatView from "./CopilotChatView.vue";
15
15
  import CopilotModalHeader from "./CopilotModalHeader.vue";
16
+ import { forwardedSlotNames } from "./forwarded-slots";
16
17
  import type {
17
18
  CopilotChatFeatherSlotProps,
19
+ CopilotChatInterruptSlotProps,
18
20
  CopilotChatMessageViewSlotProps,
19
21
  CopilotChatScrollToBottomButtonSlotProps,
20
22
  CopilotChatScrollViewSlotProps,
@@ -59,14 +61,22 @@ defineSlots<{
59
61
  "scroll-to-bottom-button"?: (
60
62
  props: CopilotChatScrollToBottomButtonSlotProps,
61
63
  ) => unknown;
64
+ interrupt?: (props: CopilotChatInterruptSlotProps) => unknown;
62
65
  input?: (props: CopilotSidebarWelcomeScreenInputSlotProps) => unknown;
63
66
  "suggestion-view"?: (
64
67
  props: CopilotSidebarWelcomeScreenSuggestionViewSlotProps,
65
68
  ) => unknown;
66
69
  "welcome-screen"?: (props: CopilotChatWelcomeScreenSlotProps) => unknown;
67
70
  "welcome-message"?: () => unknown;
71
+ // Any other slot goes to the chat view, as on CopilotChat.
72
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
73
+ [key: string]: ((props: any) => unknown) | undefined;
68
74
  }>();
69
75
 
76
+ // Slots this component renders itself. It passes every other slot to the
77
+ // chat view.
78
+ const OWN_SLOTS = ["header", "toggle-button"] as const;
79
+
70
80
  const emit = defineEmits<{
71
81
  "submit-message": [value: string];
72
82
  stop: [];
@@ -317,42 +327,12 @@ onBeforeUnmount(() => {
317
327
  :on-finish-transcribe-with-audio="onFinishTranscribeWithAudio"
318
328
  v-bind="chatViewEventProps"
319
329
  >
320
- <template v-if="$slots['message-view']" #message-view="slotProps">
321
- <slot name="message-view" v-bind="slotProps" />
322
- </template>
323
-
324
- <template v-if="$slots['scroll-view']" #scroll-view="slotProps">
325
- <slot name="scroll-view" v-bind="slotProps" />
326
- </template>
327
-
328
- <template v-if="$slots.feather" #feather>
329
- <slot name="feather" />
330
- </template>
331
-
332
330
  <template
333
- v-if="$slots['scroll-to-bottom-button']"
334
- #scroll-to-bottom-button="slotProps"
331
+ v-for="slotName in forwardedSlotNames($slots, OWN_SLOTS)"
332
+ :key="slotName"
333
+ #[slotName]="slotProps"
335
334
  >
336
- <slot name="scroll-to-bottom-button" v-bind="slotProps" />
337
- </template>
338
-
339
- <template v-if="$slots.input" #input="slotProps">
340
- <slot name="input" v-bind="slotProps" />
341
- </template>
342
-
343
- <template
344
- v-if="$slots['suggestion-view']"
345
- #suggestion-view="slotProps"
346
- >
347
- <slot name="suggestion-view" v-bind="slotProps" />
348
- </template>
349
-
350
- <template v-if="$slots['welcome-screen']" #welcome-screen="slotProps">
351
- <slot name="welcome-screen" v-bind="slotProps" />
352
- </template>
353
-
354
- <template v-if="$slots['welcome-message']" #welcome-message>
355
- <slot name="welcome-message" />
335
+ <slot :name="slotName" v-bind="slotProps" />
356
336
  </template>
357
337
  </CopilotChatView>
358
338
  </div>
@@ -1,9 +1,9 @@
1
1
  <script setup lang="ts">
2
2
  import { computed, h, watchEffect } from "vue";
3
- import { StreamingMarkdownRenderer } from "@copilotkit/markdown-renderer/vue";
4
- import type { VueStreamingMarkdownNodeRenderer } from "@copilotkit/markdown-renderer/vue";
5
- import { warnUnsupportedRichSyntaxOnce } from "@copilotkit/markdown-renderer";
6
- import type { StreamingMarkdownParserOptions } from "@copilotkit/markdown-renderer";
3
+ import { StreamingMarkdownRenderer } from "@copilotkit/markdown/vue";
4
+ import type { VueStreamingMarkdownNodeRenderer } from "@copilotkit/markdown/vue";
5
+ import { warnUnsupportedRichSyntaxOnce } from "@copilotkit/markdown";
6
+ import type { StreamingMarkdownParserOptions } from "@copilotkit/markdown";
7
7
  import type { DefaultMarkdownRendererProps } from "../../providers/markdown-renderer";
8
8
 
9
9
  const props = withDefaults(
@@ -1,7 +1,7 @@
1
1
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
2
  import { defineComponent, nextTick, onMounted } from "vue";
3
3
  import { fireEvent, render, screen } from "@testing-library/vue";
4
- import type { Message, ReasoningMessage } from "@ag-ui/core";
4
+ import type { ReasoningMessage } from "@ag-ui/core";
5
5
  import type { Attachment } from "@copilotkit/shared";
6
6
  import CopilotKitProvider from "../../../providers/CopilotKitProvider.vue";
7
7
  import CopilotChatConfigurationProvider from "../../../providers/CopilotChatConfigurationProvider.vue";
@@ -16,6 +16,8 @@ import { CopilotModalHeader, CopilotSidebarView } from "../index";
16
16
  // hard-coded English.
17
17
  const germanLabels: Partial<Record<keyof CopilotChatLabels, string>> = {
18
18
  reasoningMessageThinkingLabel: "Denkt nach…",
19
+ reasoningMessageThoughtForLabel: "Gedacht für {duration}",
20
+ reasoningMessageDurationFewSeconds: "ein paar Sekunden",
19
21
  chatInputSlashMenuLabel: "Befehle",
20
22
  chatInputSlashMenuEmptyText: "Keine Befehle gefunden",
21
23
  attachmentRemoveButtonLabel: "Anhang entfernen",
@@ -26,11 +28,11 @@ const germanLabels: Partial<Record<keyof CopilotChatLabels, string>> = {
26
28
  sidebarLabel: "Chat-Seitenleiste",
27
29
  };
28
30
 
29
- const reasoning = {
31
+ const reasoning: ReasoningMessage = {
30
32
  id: "reasoning-1",
31
33
  role: "reasoning",
32
34
  content: "",
33
- } as ReasoningMessage;
35
+ };
34
36
 
35
37
  const video: Attachment = {
36
38
  id: "clip",
@@ -66,7 +68,7 @@ function renderWithLabels(template: string) {
66
68
  return {
67
69
  labels: germanLabels,
68
70
  reasoning,
69
- reasoningMessages: [reasoning] as Message[],
71
+ reasoningMessages: [reasoning],
70
72
  attachments: [video],
71
73
  toolsMenu: [{ label: "Say hi", action: vi.fn() }],
72
74
  };
@@ -112,6 +114,19 @@ describe("chat strings from labels", () => {
112
114
  expect(screen.queryByText("Thinking…")).toBeNull();
113
115
  });
114
116
 
117
+ it("uses the configured duration labels once the model is done", () => {
118
+ renderWithLabels(`
119
+ <CopilotChatReasoningMessage
120
+ :message="reasoning"
121
+ :messages="reasoningMessages"
122
+ :is-running="false"
123
+ />
124
+ `);
125
+
126
+ expect(screen.getByText("Gedacht für ein paar Sekunden")).toBeDefined();
127
+ expect(screen.queryByText(/Thought for/)).toBeNull();
128
+ });
129
+
115
130
  it("passes the elapsed reasoning time to a custom header", async () => {
116
131
  vi.useFakeTimers();
117
132
  renderWithLabels(`
@@ -7,6 +7,7 @@ import {
7
7
  } from "@testing-library/vue";
8
8
  import { defineComponent, ref, toRaw } from "vue";
9
9
  import { afterEach, describe, expect, it, vi } from "vitest";
10
+ import type * as CoreModule from "@copilotkit/core";
10
11
  import type { AbstractAgent } from "@ag-ui/client";
11
12
  import { EventType } from "@ag-ui/client";
12
13
  import type { A2UITheme as Theme } from "../../../types";
@@ -160,11 +161,25 @@ vi.mock("phoenix", () => ({
160
161
  Socket: MockPhoenixSocket,
161
162
  }));
162
163
 
163
- vi.mock("@jetbrains/websandbox", () => ({
164
- default: {
165
- create: (...args: unknown[]) => mockWebsandboxCreate(...args),
166
- },
167
- }));
164
+ // Run the real core controller against a fake websandbox
165
+ vi.mock("@copilotkit/core", async (importOriginal) => {
166
+ const actual = await importOriginal<typeof CoreModule>();
167
+ class TestOpenGenerativeUIController
168
+ extends actual.ɵOpenGenerativeUIController
169
+ {
170
+ constructor() {
171
+ super({
172
+ loadWebsandbox: async () => ({
173
+ create: (...args) => mockWebsandboxCreate(...args),
174
+ }),
175
+ });
176
+ }
177
+ }
178
+ return {
179
+ ...actual,
180
+ ɵOpenGenerativeUIController: TestOpenGenerativeUIController,
181
+ };
182
+ });
168
183
 
169
184
  function jsonResponse(body: unknown, status = 200): Response {
170
185
  return {
@@ -667,13 +682,15 @@ describe("CopilotChat activity message rendering", () => {
667
682
 
668
683
  renderOpenGenerativeUIChat();
669
684
 
685
+ // The restored chat can remount the activity while it reconnects, so wait
686
+ // until exactly one sandbox, the restored one, is alive.
670
687
  await waitFor(() => {
671
- expect(mockWebsandboxCreate).toHaveBeenCalledTimes(2);
688
+ const created = mockWebsandboxCreate.mock.calls.length;
689
+ expect(created).toBeGreaterThanOrEqual(2);
690
+ expect(mockWebsandboxDestroy).toHaveBeenCalledTimes(created - 1);
672
691
  });
673
- expect(mockWebsandboxCreate.mock.calls[1]?.[1]).toMatchObject({
692
+ expect(mockWebsandboxCreate.mock.calls.at(-1)?.[1]).toMatchObject({
674
693
  frameContent: restoredHtml,
675
694
  });
676
-
677
- expect(mockWebsandboxDestroy).toHaveBeenCalledTimes(1);
678
695
  });
679
696
  });
@@ -10,12 +10,12 @@ import { useCopilotKit } from "../../../providers/useCopilotKit";
10
10
  import CopilotChatMessageView from "../CopilotChatMessageView.vue";
11
11
  import CopilotChatAssistantMessage from "../CopilotChatAssistantMessage.vue";
12
12
  import {
13
- MESSAGE_FEEDBACK_EVENT_NAME,
14
- getMessageFeedback,
15
- setMessageFeedback,
13
+ ɵFEEDBACK_COMMENT_CLOSE_DELAY_MS as FEEDBACK_COMMENT_CLOSE_DELAY_MS,
14
+ ɵMESSAGE_FEEDBACK_EVENT_NAME as MESSAGE_FEEDBACK_EVENT_NAME,
15
+ ɵgetMessageFeedback as getMessageFeedback,
16
+ ɵsetMessageFeedback as setMessageFeedback,
16
17
  ɵresetMessageFeedbackCache,
17
- } from "../../../lib/message-feedback";
18
- import { FEEDBACK_COMMENT_CLOSE_DELAY_MS } from "../message-feedback";
18
+ } from "@copilotkit/core";
19
19
 
20
20
  const THREAD_ID = "thread-1";
21
21
  const AGENT_ID = "agent-1";