@copilotkit/vue 1.57.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (437) hide show
  1. package/AGENTS.md +50 -0
  2. package/CHANGELOG.md +13 -0
  3. package/PARITY.md +434 -0
  4. package/README.md +396 -0
  5. package/dist/components/copilot-provider/CopilotKit.vue.d.ts +20 -0
  6. package/dist/components/copilot-provider/CopilotKit.vue.d.ts.map +1 -0
  7. package/dist/components/copilot-provider/index.d.ts +3 -0
  8. package/dist/components/copilot-provider/index.d.ts.map +1 -0
  9. package/dist/components/copilot-provider/types.d.ts +22 -0
  10. package/dist/components/copilot-provider/types.d.ts.map +1 -0
  11. package/dist/hooks/index.d.ts +7 -0
  12. package/dist/hooks/index.d.ts.map +1 -0
  13. package/dist/hooks/use-copilot-action.d.ts +27 -0
  14. package/dist/hooks/use-copilot-action.d.ts.map +1 -0
  15. package/dist/hooks/use-copilot-readable.d.ts +20 -0
  16. package/dist/hooks/use-copilot-readable.d.ts.map +1 -0
  17. package/dist/hooks/use-frontend-tool.d.ts +21 -0
  18. package/dist/hooks/use-frontend-tool.d.ts.map +1 -0
  19. package/dist/index.cjs +2 -0
  20. package/dist/index.cjs.map +1 -0
  21. package/dist/index.d.cts +10 -0
  22. package/dist/index.d.mts +10 -0
  23. package/dist/index.d.ts +10 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.mjs +252 -0
  26. package/dist/index.mjs.map +1 -0
  27. package/dist/styles.css +2 -0
  28. package/dist/use-render-activity-message-BRL1Rpl-.cjs +85 -0
  29. package/dist/use-render-activity-message-BRL1Rpl-.cjs.map +1 -0
  30. package/dist/use-render-activity-message-CqtxiFSs.js +8927 -0
  31. package/dist/use-render-activity-message-CqtxiFSs.js.map +1 -0
  32. package/dist/v2/components/A2UIMessageRenderer.d.ts +9 -0
  33. package/dist/v2/components/A2UIMessageRenderer.d.ts.map +1 -0
  34. package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts +16 -0
  35. package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts.map +1 -0
  36. package/dist/v2/components/CopilotKitInspector.vue.d.ts +7 -0
  37. package/dist/v2/components/CopilotKitInspector.vue.d.ts.map +1 -0
  38. package/dist/v2/components/InlineFeatureWarning.vue.d.ts +6 -0
  39. package/dist/v2/components/InlineFeatureWarning.vue.d.ts.map +1 -0
  40. package/dist/v2/components/LicenseWarningBanner.vue.d.ts +18 -0
  41. package/dist/v2/components/LicenseWarningBanner.vue.d.ts.map +1 -0
  42. package/dist/v2/components/MCPAppsActivityRenderer.d.ts +88 -0
  43. package/dist/v2/components/MCPAppsActivityRenderer.d.ts.map +1 -0
  44. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts +154 -0
  45. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts.map +1 -0
  46. package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts +19 -0
  47. package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts.map +1 -0
  48. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts +16 -0
  49. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts.map +1 -0
  50. package/dist/v2/components/a2ui/VueSurface.d.ts +62 -0
  51. package/dist/v2/components/a2ui/VueSurface.d.ts.map +1 -0
  52. package/dist/v2/components/a2ui/adapter.d.ts +38 -0
  53. package/dist/v2/components/a2ui/adapter.d.ts.map +1 -0
  54. package/dist/v2/components/a2ui/catalog.d.ts +29 -0
  55. package/dist/v2/components/a2ui/catalog.d.ts.map +1 -0
  56. package/dist/v2/components/a2ui/index.d.ts +5 -0
  57. package/dist/v2/components/a2ui/index.d.ts.map +1 -0
  58. package/dist/v2/components/a2ui/utils.d.ts +18 -0
  59. package/dist/v2/components/a2ui/utils.d.ts.map +1 -0
  60. package/dist/v2/components/a2ui.d.ts +12 -0
  61. package/dist/v2/components/a2ui.d.ts.map +1 -0
  62. package/dist/v2/components/chat/CopilotChat.vue.d.ts +50 -0
  63. package/dist/v2/components/chat/CopilotChat.vue.d.ts.map +1 -0
  64. package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts +164 -0
  65. package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts.map +1 -0
  66. package/dist/v2/components/chat/CopilotChatAttachmentQueue.vue.d.ts +12 -0
  67. package/dist/v2/components/chat/CopilotChatAttachmentQueue.vue.d.ts.map +1 -0
  68. package/dist/v2/components/chat/CopilotChatAttachmentRenderer.vue.d.ts +7 -0
  69. package/dist/v2/components/chat/CopilotChatAttachmentRenderer.vue.d.ts.map +1 -0
  70. package/dist/v2/components/chat/CopilotChatAudioRecorder.vue.d.ts +12 -0
  71. package/dist/v2/components/chat/CopilotChatAudioRecorder.vue.d.ts.map +1 -0
  72. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts +290 -0
  73. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts.map +1 -0
  74. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts +72 -0
  75. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts.map +1 -0
  76. package/dist/v2/components/chat/CopilotChatReasoningMessage.vue.d.ts +65 -0
  77. package/dist/v2/components/chat/CopilotChatReasoningMessage.vue.d.ts.map +1 -0
  78. package/dist/v2/components/chat/CopilotChatSuggestionPill.vue.d.ts +27 -0
  79. package/dist/v2/components/chat/CopilotChatSuggestionPill.vue.d.ts.map +1 -0
  80. package/dist/v2/components/chat/CopilotChatSuggestionView.vue.d.ts +26 -0
  81. package/dist/v2/components/chat/CopilotChatSuggestionView.vue.d.ts.map +1 -0
  82. package/dist/v2/components/chat/CopilotChatToggleButton.vue.d.ts +17 -0
  83. package/dist/v2/components/chat/CopilotChatToggleButton.vue.d.ts.map +1 -0
  84. package/dist/v2/components/chat/CopilotChatToggleButtonCloseIcon.d.ts +5 -0
  85. package/dist/v2/components/chat/CopilotChatToggleButtonCloseIcon.d.ts.map +1 -0
  86. package/dist/v2/components/chat/CopilotChatToggleButtonOpenIcon.d.ts +5 -0
  87. package/dist/v2/components/chat/CopilotChatToggleButtonOpenIcon.d.ts.map +1 -0
  88. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts +21 -0
  89. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts.map +1 -0
  90. package/dist/v2/components/chat/CopilotChatUserMessage.vue.d.ts +34 -0
  91. package/dist/v2/components/chat/CopilotChatUserMessage.vue.d.ts.map +1 -0
  92. package/dist/v2/components/chat/CopilotChatView.vue.d.ts +106 -0
  93. package/dist/v2/components/chat/CopilotChatView.vue.d.ts.map +1 -0
  94. package/dist/v2/components/chat/CopilotModalHeader.vue.d.ts +15 -0
  95. package/dist/v2/components/chat/CopilotModalHeader.vue.d.ts.map +1 -0
  96. package/dist/v2/components/chat/CopilotModalHeaderCloseButton.d.ts +5 -0
  97. package/dist/v2/components/chat/CopilotModalHeaderCloseButton.d.ts.map +1 -0
  98. package/dist/v2/components/chat/CopilotModalHeaderTitle.d.ts +5 -0
  99. package/dist/v2/components/chat/CopilotModalHeaderTitle.d.ts.map +1 -0
  100. package/dist/v2/components/chat/CopilotPopup.vue.d.ts +50 -0
  101. package/dist/v2/components/chat/CopilotPopup.vue.d.ts.map +1 -0
  102. package/dist/v2/components/chat/CopilotPopupView.vue.d.ts +55 -0
  103. package/dist/v2/components/chat/CopilotPopupView.vue.d.ts.map +1 -0
  104. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts +55 -0
  105. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts.map +1 -0
  106. package/dist/v2/components/chat/CopilotPopupWelcomeScreen.vue.d.ts +28 -0
  107. package/dist/v2/components/chat/CopilotPopupWelcomeScreen.vue.d.ts.map +1 -0
  108. package/dist/v2/components/chat/CopilotSidebar.vue.d.ts +48 -0
  109. package/dist/v2/components/chat/CopilotSidebar.vue.d.ts.map +1 -0
  110. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts +62 -0
  111. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts.map +1 -0
  112. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts +53 -0
  113. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts.map +1 -0
  114. package/dist/v2/components/chat/CopilotSidebarWelcomeScreen.vue.d.ts +28 -0
  115. package/dist/v2/components/chat/CopilotSidebarWelcomeScreen.vue.d.ts.map +1 -0
  116. package/dist/v2/components/chat/audioRecorder.d.ts +11 -0
  117. package/dist/v2/components/chat/audioRecorder.d.ts.map +1 -0
  118. package/dist/v2/components/chat/index.d.ts +682 -0
  119. package/dist/v2/components/chat/index.d.ts.map +1 -0
  120. package/dist/v2/components/chat/last-user-message-context.d.ts +29 -0
  121. package/dist/v2/components/chat/last-user-message-context.d.ts.map +1 -0
  122. package/dist/v2/components/chat/normalize-auto-scroll.d.ts +3 -0
  123. package/dist/v2/components/chat/normalize-auto-scroll.d.ts.map +1 -0
  124. package/dist/v2/components/chat/types.d.ts +380 -0
  125. package/dist/v2/components/chat/types.d.ts.map +1 -0
  126. package/dist/v2/components/icons/index.d.ts +2 -0
  127. package/dist/v2/components/icons/index.d.ts.map +1 -0
  128. package/dist/v2/components/index.d.ts +8 -0
  129. package/dist/v2/components/index.d.ts.map +1 -0
  130. package/dist/v2/hooks/index.d.ts +24 -0
  131. package/dist/v2/hooks/index.d.ts.map +1 -0
  132. package/dist/v2/hooks/use-agent-context.d.ts +24 -0
  133. package/dist/v2/hooks/use-agent-context.d.ts.map +1 -0
  134. package/dist/v2/hooks/use-agent.d.ts +53 -0
  135. package/dist/v2/hooks/use-agent.d.ts.map +1 -0
  136. package/dist/v2/hooks/use-attachments.d.ts +21 -0
  137. package/dist/v2/hooks/use-attachments.d.ts.map +1 -0
  138. package/dist/v2/hooks/use-capabilities.d.ts +16 -0
  139. package/dist/v2/hooks/use-capabilities.d.ts.map +1 -0
  140. package/dist/v2/hooks/use-component.d.ts +13 -0
  141. package/dist/v2/hooks/use-component.d.ts.map +1 -0
  142. package/dist/v2/hooks/use-configure-suggestions.d.ts +24 -0
  143. package/dist/v2/hooks/use-configure-suggestions.d.ts.map +1 -0
  144. package/dist/v2/hooks/use-default-render-tool.d.ts +14 -0
  145. package/dist/v2/hooks/use-default-render-tool.d.ts.map +1 -0
  146. package/dist/v2/hooks/use-frontend-tool.d.ts +19 -0
  147. package/dist/v2/hooks/use-frontend-tool.d.ts.map +1 -0
  148. package/dist/v2/hooks/use-human-in-the-loop.d.ts +19 -0
  149. package/dist/v2/hooks/use-human-in-the-loop.d.ts.map +1 -0
  150. package/dist/v2/hooks/use-interrupt.d.ts +36 -0
  151. package/dist/v2/hooks/use-interrupt.d.ts.map +1 -0
  152. package/dist/v2/hooks/use-katex-styles.d.ts +22 -0
  153. package/dist/v2/hooks/use-katex-styles.d.ts.map +1 -0
  154. package/dist/v2/hooks/use-keyboard-height.d.ts +33 -0
  155. package/dist/v2/hooks/use-keyboard-height.d.ts.map +1 -0
  156. package/dist/v2/hooks/use-pin-to-send.d.ts +28 -0
  157. package/dist/v2/hooks/use-pin-to-send.d.ts.map +1 -0
  158. package/dist/v2/hooks/use-render-activity-message.d.ts +21 -0
  159. package/dist/v2/hooks/use-render-activity-message.d.ts.map +1 -0
  160. package/dist/v2/hooks/use-render-custom-messages.d.ts +27 -0
  161. package/dist/v2/hooks/use-render-custom-messages.d.ts.map +1 -0
  162. package/dist/v2/hooks/use-render-tool.d.ts +36 -0
  163. package/dist/v2/hooks/use-render-tool.d.ts.map +1 -0
  164. package/dist/v2/hooks/use-suggestions.d.ts +26 -0
  165. package/dist/v2/hooks/use-suggestions.d.ts.map +1 -0
  166. package/dist/v2/hooks/use-threads.d.ts +42 -0
  167. package/dist/v2/hooks/use-threads.d.ts.map +1 -0
  168. package/dist/v2/index.cjs +2 -0
  169. package/dist/v2/index.cjs.map +1 -0
  170. package/dist/v2/index.d.cts +9 -0
  171. package/dist/v2/index.d.mts +9 -0
  172. package/dist/v2/index.d.ts +9 -0
  173. package/dist/v2/index.d.ts.map +1 -0
  174. package/dist/v2/index.mjs +75 -0
  175. package/dist/v2/index.mjs.map +1 -0
  176. package/dist/v2/lib/processPartialHtml.d.ts +3 -0
  177. package/dist/v2/lib/processPartialHtml.d.ts.map +1 -0
  178. package/dist/v2/lib/shallow-stable.d.ts +7 -0
  179. package/dist/v2/lib/shallow-stable.d.ts.map +1 -0
  180. package/dist/v2/lib/transcription-client.d.ts +19 -0
  181. package/dist/v2/lib/transcription-client.d.ts.map +1 -0
  182. package/dist/v2/lib/vue-core.d.ts +47 -0
  183. package/dist/v2/lib/vue-core.d.ts.map +1 -0
  184. package/dist/v2/providers/CopilotChatConfigurationProvider.types.d.ts +15 -0
  185. package/dist/v2/providers/CopilotChatConfigurationProvider.types.d.ts.map +1 -0
  186. package/dist/v2/providers/CopilotChatConfigurationProvider.vue.d.ts +17 -0
  187. package/dist/v2/providers/CopilotChatConfigurationProvider.vue.d.ts.map +1 -0
  188. package/dist/v2/providers/CopilotKitProvider.types.d.ts +61 -0
  189. package/dist/v2/providers/CopilotKitProvider.types.d.ts.map +1 -0
  190. package/dist/v2/providers/CopilotKitProvider.vue.d.ts +37 -0
  191. package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -0
  192. package/dist/v2/providers/SandboxFunctionsContext.d.ts +4 -0
  193. package/dist/v2/providers/SandboxFunctionsContext.d.ts.map +1 -0
  194. package/dist/v2/providers/index.d.ts +13 -0
  195. package/dist/v2/providers/index.d.ts.map +1 -0
  196. package/dist/v2/providers/keys.d.ts +17 -0
  197. package/dist/v2/providers/keys.d.ts.map +1 -0
  198. package/dist/v2/providers/license-context.d.ts +7 -0
  199. package/dist/v2/providers/license-context.d.ts.map +1 -0
  200. package/dist/v2/providers/types.d.ts +38 -0
  201. package/dist/v2/providers/types.d.ts.map +1 -0
  202. package/dist/v2/providers/useCopilotChatConfiguration.d.ts +4 -0
  203. package/dist/v2/providers/useCopilotChatConfiguration.d.ts.map +1 -0
  204. package/dist/v2/providers/useCopilotKit.d.ts +2 -0
  205. package/dist/v2/providers/useCopilotKit.d.ts.map +1 -0
  206. package/dist/v2/providers/useLicenseContext.d.ts +14 -0
  207. package/dist/v2/providers/useLicenseContext.d.ts.map +1 -0
  208. package/dist/v2/types/a2ui.d.ts +5 -0
  209. package/dist/v2/types/a2ui.d.ts.map +1 -0
  210. package/dist/v2/types/defineToolCallRenderer.d.ts +15 -0
  211. package/dist/v2/types/defineToolCallRenderer.d.ts.map +1 -0
  212. package/dist/v2/types/frontend-tool.d.ts +6 -0
  213. package/dist/v2/types/frontend-tool.d.ts.map +1 -0
  214. package/dist/v2/types/human-in-the-loop.d.ts +29 -0
  215. package/dist/v2/types/human-in-the-loop.d.ts.map +1 -0
  216. package/dist/v2/types/index.d.ts +10 -0
  217. package/dist/v2/types/index.d.ts.map +1 -0
  218. package/dist/v2/types/interrupt.d.ts +14 -0
  219. package/dist/v2/types/interrupt.d.ts.map +1 -0
  220. package/dist/v2/types/sandbox-function.d.ts +8 -0
  221. package/dist/v2/types/sandbox-function.d.ts.map +1 -0
  222. package/dist/v2/types/vue-activity-message-renderer.d.ts +18 -0
  223. package/dist/v2/types/vue-activity-message-renderer.d.ts.map +1 -0
  224. package/dist/v2/types/vue-custom-message-renderer.d.ts +19 -0
  225. package/dist/v2/types/vue-custom-message-renderer.d.ts.map +1 -0
  226. package/dist/v2/types/vue-tool-call-renderer.d.ts +37 -0
  227. package/dist/v2/types/vue-tool-call-renderer.d.ts.map +1 -0
  228. package/env.d.ts +7 -0
  229. package/eslint.config.mjs +42 -0
  230. package/package.json +130 -0
  231. package/scripts/scope-preflight.mjs +100 -0
  232. package/src/components/copilot-provider/CopilotKit.vue +18 -0
  233. package/src/components/copilot-provider/index.ts +2 -0
  234. package/src/components/copilot-provider/types.ts +24 -0
  235. package/src/hooks/index.ts +9 -0
  236. package/src/hooks/use-copilot-action.ts +168 -0
  237. package/src/hooks/use-copilot-readable.ts +75 -0
  238. package/src/hooks/use-frontend-tool.ts +76 -0
  239. package/src/index.ts +12 -0
  240. package/src/styles/globals.css +314 -0
  241. package/src/v2/__tests__/exports.test.ts +35 -0
  242. package/src/v2/__tests__/mocks/web-inspector.ts +5 -0
  243. package/src/v2/__tests__/setup.ts +141 -0
  244. package/src/v2/__tests__/utils/agents.ts +391 -0
  245. package/src/v2/__tests__/utils/mount.ts +83 -0
  246. package/src/v2/__tests__/utils/test-helpers.ts +712 -0
  247. package/src/v2/components/A2UIMessageRenderer.ts +125 -0
  248. package/src/v2/components/A2UISurfaceActivityRenderer.vue +186 -0
  249. package/src/v2/components/CopilotKitInspector.vue +42 -0
  250. package/src/v2/components/InlineFeatureWarning.vue +35 -0
  251. package/src/v2/components/LicenseWarningBanner.vue +196 -0
  252. package/src/v2/components/MCPAppsActivityRenderer.ts +778 -0
  253. package/src/v2/components/OpenGenerativeUIRenderer.ts +550 -0
  254. package/src/v2/components/__tests__/A2UIMessageRenderer.test.ts +271 -0
  255. package/src/v2/components/__tests__/CopilotKitInspector.test.ts +57 -0
  256. package/src/v2/components/__tests__/MCPAppsActivityRenderer.e2e.test.ts +851 -0
  257. package/src/v2/components/__tests__/MCPAppsActivityRenderer.test.ts +237 -0
  258. package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.ts +516 -0
  259. package/src/v2/components/a2ui/A2UIBuiltInToolCallRenderer.ts +295 -0
  260. package/src/v2/components/a2ui/A2UICatalogContext.ts +190 -0
  261. package/src/v2/components/a2ui/VueSurface.ts +144 -0
  262. package/src/v2/components/a2ui/adapter.ts +156 -0
  263. package/src/v2/components/a2ui/catalog.ts +858 -0
  264. package/src/v2/components/a2ui/index.ts +7 -0
  265. package/src/v2/components/a2ui/utils.ts +67 -0
  266. package/src/v2/components/a2ui.ts +30 -0
  267. package/src/v2/components/chat/CopilotChat.vue +777 -0
  268. package/src/v2/components/chat/CopilotChatAssistantMessage.vue +891 -0
  269. package/src/v2/components/chat/CopilotChatAttachmentQueue.vue +411 -0
  270. package/src/v2/components/chat/CopilotChatAttachmentRenderer.vue +87 -0
  271. package/src/v2/components/chat/CopilotChatAudioRecorder.vue +269 -0
  272. package/src/v2/components/chat/CopilotChatInput.vue +1271 -0
  273. package/src/v2/components/chat/CopilotChatMessageView.vue +476 -0
  274. package/src/v2/components/chat/CopilotChatReasoningMessage.vue +247 -0
  275. package/src/v2/components/chat/CopilotChatSuggestionPill.vue +56 -0
  276. package/src/v2/components/chat/CopilotChatSuggestionView.vue +93 -0
  277. package/src/v2/components/chat/CopilotChatToggleButton.vue +145 -0
  278. package/src/v2/components/chat/CopilotChatToggleButtonCloseIcon.ts +17 -0
  279. package/src/v2/components/chat/CopilotChatToggleButtonOpenIcon.ts +18 -0
  280. package/src/v2/components/chat/CopilotChatToolCallsView.vue +161 -0
  281. package/src/v2/components/chat/CopilotChatUserMessage.vue +322 -0
  282. package/src/v2/components/chat/CopilotChatView.vue +740 -0
  283. package/src/v2/components/chat/CopilotModalHeader.vue +73 -0
  284. package/src/v2/components/chat/CopilotModalHeaderCloseButton.ts +38 -0
  285. package/src/v2/components/chat/CopilotModalHeaderTitle.ts +22 -0
  286. package/src/v2/components/chat/CopilotPopup.vue +182 -0
  287. package/src/v2/components/chat/CopilotPopupView.vue +168 -0
  288. package/src/v2/components/chat/CopilotPopupViewInternal.vue +453 -0
  289. package/src/v2/components/chat/CopilotPopupWelcomeScreen.vue +140 -0
  290. package/src/v2/components/chat/CopilotSidebar.vue +178 -0
  291. package/src/v2/components/chat/CopilotSidebarView.vue +172 -0
  292. package/src/v2/components/chat/CopilotSidebarViewInternal.vue +366 -0
  293. package/src/v2/components/chat/CopilotSidebarWelcomeScreen.vue +142 -0
  294. package/src/v2/components/chat/__tests__/CopilotChat.attachments.test.ts +237 -0
  295. package/src/v2/components/chat/__tests__/CopilotChat.e2e.test.ts +1240 -0
  296. package/src/v2/components/chat/__tests__/CopilotChat.licenseWarning.test.ts +138 -0
  297. package/src/v2/components/chat/__tests__/CopilotChat.onError.test.ts +85 -0
  298. package/src/v2/components/chat/__tests__/CopilotChat.slots.e2e.test.ts +141 -0
  299. package/src/v2/components/chat/__tests__/CopilotChat.test.ts +652 -0
  300. package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.ts +683 -0
  301. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.slots.e2e.test.ts +768 -0
  302. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.test.ts +1108 -0
  303. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.thumbs.test.ts +87 -0
  304. package/src/v2/components/chat/__tests__/CopilotChatAttachmentQueue.test.ts +277 -0
  305. package/src/v2/components/chat/__tests__/CopilotChatAttachmentRenderer.test.ts +124 -0
  306. package/src/v2/components/chat/__tests__/CopilotChatCopyButton.clipboard.test.ts +230 -0
  307. package/src/v2/components/chat/__tests__/CopilotChatInput.bottomAnchored.test.ts +83 -0
  308. package/src/v2/components/chat/__tests__/CopilotChatInput.slots.e2e.test.ts +1139 -0
  309. package/src/v2/components/chat/__tests__/CopilotChatInput.test.ts +1051 -0
  310. package/src/v2/components/chat/__tests__/CopilotChatMessageView.slots.e2e.test.ts +141 -0
  311. package/src/v2/components/chat/__tests__/CopilotChatMessageView.test.ts +494 -0
  312. package/src/v2/components/chat/__tests__/CopilotChatPropsRerender.e2e.test.ts +181 -0
  313. package/src/v2/components/chat/__tests__/CopilotChatReasoningMessage.test.ts +73 -0
  314. package/src/v2/components/chat/__tests__/CopilotChatSuggestionPill.test.ts +73 -0
  315. package/src/v2/components/chat/__tests__/CopilotChatSuggestionView.slots.e2e.test.ts +674 -0
  316. package/src/v2/components/chat/__tests__/CopilotChatSuggestionView.test.ts +91 -0
  317. package/src/v2/components/chat/__tests__/CopilotChatToggleButton.test.ts +93 -0
  318. package/src/v2/components/chat/__tests__/CopilotChatToolCallsView.test.ts +382 -0
  319. package/src/v2/components/chat/__tests__/CopilotChatToolRendering.e2e.test.ts +1019 -0
  320. package/src/v2/components/chat/__tests__/CopilotChatToolRerenders.e2e.test.ts +516 -0
  321. package/src/v2/components/chat/__tests__/CopilotChatUserMessage.slots.e2e.test.ts +701 -0
  322. package/src/v2/components/chat/__tests__/CopilotChatUserMessage.test.ts +337 -0
  323. package/src/v2/components/chat/__tests__/CopilotChatView.connectingGate.test.ts +135 -0
  324. package/src/v2/components/chat/__tests__/CopilotChatView.inputOverlay.test.ts +278 -0
  325. package/src/v2/components/chat/__tests__/CopilotChatView.onClick.e2e.test.ts +1082 -0
  326. package/src/v2/components/chat/__tests__/CopilotChatView.pinToSend.test.ts +166 -0
  327. package/src/v2/components/chat/__tests__/CopilotChatView.slots.e2e.test.ts +1145 -0
  328. package/src/v2/components/chat/__tests__/CopilotChatView.test.ts +374 -0
  329. package/src/v2/components/chat/__tests__/CopilotModalHeader.slots.e2e.test.ts +636 -0
  330. package/src/v2/components/chat/__tests__/CopilotModalHeader.test.ts +112 -0
  331. package/src/v2/components/chat/__tests__/CopilotPopup.test.ts +58 -0
  332. package/src/v2/components/chat/__tests__/CopilotPopupView.slots.e2e.test.ts +725 -0
  333. package/src/v2/components/chat/__tests__/CopilotPopupView.test.ts +112 -0
  334. package/src/v2/components/chat/__tests__/CopilotSidebar.test.ts +58 -0
  335. package/src/v2/components/chat/__tests__/CopilotSidebarView.slots.e2e.test.ts +603 -0
  336. package/src/v2/components/chat/__tests__/CopilotSidebarView.test.ts +214 -0
  337. package/src/v2/components/chat/__tests__/MCPAppsUiMessage.e2e.test.ts +394 -0
  338. package/src/v2/components/chat/__tests__/copilot-chat-throttle.test.ts +82 -0
  339. package/src/v2/components/chat/__tests__/normalize-auto-scroll.test.ts +39 -0
  340. package/src/v2/components/chat/audioRecorder.ts +15 -0
  341. package/src/v2/components/chat/index.ts +52 -0
  342. package/src/v2/components/chat/last-user-message-context.ts +39 -0
  343. package/src/v2/components/chat/normalize-auto-scroll.ts +17 -0
  344. package/src/v2/components/chat/types.ts +481 -0
  345. package/src/v2/components/icons/__tests__/icons.test.ts +86 -0
  346. package/src/v2/components/icons/index.ts +22 -0
  347. package/src/v2/components/index.ts +7 -0
  348. package/src/v2/hooks/__tests__/standard-schema-types.test.ts +149 -0
  349. package/src/v2/hooks/__tests__/standard-schema.test.ts +315 -0
  350. package/src/v2/hooks/__tests__/use-agent-context-timing.e2e.test.ts +144 -0
  351. package/src/v2/hooks/__tests__/use-agent-context.test.ts +271 -0
  352. package/src/v2/hooks/__tests__/use-agent-error-state.test.ts +64 -0
  353. package/src/v2/hooks/__tests__/use-agent-stability.test.ts +268 -0
  354. package/src/v2/hooks/__tests__/use-agent-thread-isolation.test.ts +433 -0
  355. package/src/v2/hooks/__tests__/use-agent-throttle.test.ts +747 -0
  356. package/src/v2/hooks/__tests__/use-agent.e2e.test.ts +187 -0
  357. package/src/v2/hooks/__tests__/use-agent.test.ts +126 -0
  358. package/src/v2/hooks/__tests__/use-attachments.test.ts +181 -0
  359. package/src/v2/hooks/__tests__/use-component.test.ts +145 -0
  360. package/src/v2/hooks/__tests__/use-configure-suggestions.e2e.test.ts +527 -0
  361. package/src/v2/hooks/__tests__/use-configure-suggestions.test.ts +399 -0
  362. package/src/v2/hooks/__tests__/use-default-render-tool.test.ts +214 -0
  363. package/src/v2/hooks/__tests__/use-frontend-tool-available.test.ts +220 -0
  364. package/src/v2/hooks/__tests__/use-frontend-tool.e2e.test.ts +2320 -0
  365. package/src/v2/hooks/__tests__/use-frontend-tool.test.ts +648 -0
  366. package/src/v2/hooks/__tests__/use-human-in-the-loop.e2e.test.ts +1379 -0
  367. package/src/v2/hooks/__tests__/use-human-in-the-loop.test.ts +282 -0
  368. package/src/v2/hooks/__tests__/use-interrupt.test.ts +345 -0
  369. package/src/v2/hooks/__tests__/use-katex-styles.test.ts +69 -0
  370. package/src/v2/hooks/__tests__/use-keyboard-height.test.ts +199 -0
  371. package/src/v2/hooks/__tests__/use-pin-to-send.test.ts +363 -0
  372. package/src/v2/hooks/__tests__/use-render-tool.test.ts +329 -0
  373. package/src/v2/hooks/__tests__/use-suggestions.e2e.test.ts +397 -0
  374. package/src/v2/hooks/__tests__/use-suggestions.test.ts +198 -0
  375. package/src/v2/hooks/__tests__/use-threads.test.ts +1041 -0
  376. package/src/v2/hooks/__tests__/zod-regression.test.ts +339 -0
  377. package/src/v2/hooks/index.ts +29 -0
  378. package/src/v2/hooks/use-agent-context.ts +55 -0
  379. package/src/v2/hooks/use-agent.ts +345 -0
  380. package/src/v2/hooks/use-attachments.ts +261 -0
  381. package/src/v2/hooks/use-capabilities.ts +30 -0
  382. package/src/v2/hooks/use-component.ts +46 -0
  383. package/src/v2/hooks/use-configure-suggestions.ts +252 -0
  384. package/src/v2/hooks/use-default-render-tool.ts +130 -0
  385. package/src/v2/hooks/use-frontend-tool.ts +68 -0
  386. package/src/v2/hooks/use-human-in-the-loop.ts +90 -0
  387. package/src/v2/hooks/use-interrupt.ts +257 -0
  388. package/src/v2/hooks/use-katex-styles.ts +44 -0
  389. package/src/v2/hooks/use-keyboard-height.ts +87 -0
  390. package/src/v2/hooks/use-pin-to-send.ts +160 -0
  391. package/src/v2/hooks/use-render-activity-message.ts +92 -0
  392. package/src/v2/hooks/use-render-custom-messages.ts +129 -0
  393. package/src/v2/hooks/use-render-tool.ts +128 -0
  394. package/src/v2/hooks/use-suggestions.ts +98 -0
  395. package/src/v2/hooks/use-threads.ts +208 -0
  396. package/src/v2/index.ts +11 -0
  397. package/src/v2/lib/__tests__/processPartialHtml.test.ts +84 -0
  398. package/src/v2/lib/__tests__/transcription-client.test.ts +65 -0
  399. package/src/v2/lib/processPartialHtml.ts +21 -0
  400. package/src/v2/lib/shallow-stable.ts +54 -0
  401. package/src/v2/lib/transcription-client.ts +151 -0
  402. package/src/v2/lib/vue-core.ts +161 -0
  403. package/src/v2/providers/CopilotChatConfigurationProvider.types.ts +15 -0
  404. package/src/v2/providers/CopilotChatConfigurationProvider.vue +95 -0
  405. package/src/v2/providers/CopilotKitProvider.types.ts +66 -0
  406. package/src/v2/providers/CopilotKitProvider.vue +653 -0
  407. package/src/v2/providers/SandboxFunctionsContext.ts +11 -0
  408. package/src/v2/providers/__tests__/CopilotChatConfigurationProvider.test.ts +309 -0
  409. package/src/v2/providers/__tests__/CopilotKitProvider.debug.test.ts +295 -0
  410. package/src/v2/providers/__tests__/CopilotKitProvider.license.test.ts +110 -0
  411. package/src/v2/providers/__tests__/CopilotKitProvider.onError.test.ts +67 -0
  412. package/src/v2/providers/__tests__/CopilotKitProvider.renderCustomMessages.e2e.test.ts +901 -0
  413. package/src/v2/providers/__tests__/CopilotKitProvider.sandboxFunctions.test.ts +141 -0
  414. package/src/v2/providers/__tests__/CopilotKitProvider.stability.test.ts +871 -0
  415. package/src/v2/providers/__tests__/CopilotKitProvider.test.ts +603 -0
  416. package/src/v2/providers/__tests__/CopilotKitProvider.wildcard.test.ts +104 -0
  417. package/src/v2/providers/index.ts +21 -0
  418. package/src/v2/providers/keys.ts +25 -0
  419. package/src/v2/providers/license-context.ts +16 -0
  420. package/src/v2/providers/types.ts +40 -0
  421. package/src/v2/providers/useCopilotChatConfiguration.ts +11 -0
  422. package/src/v2/providers/useCopilotKit.ts +11 -0
  423. package/src/v2/providers/useLicenseContext.ts +21 -0
  424. package/src/v2/types/__tests__/defineToolCallRenderer.test.ts +157 -0
  425. package/src/v2/types/a2ui.ts +5 -0
  426. package/src/v2/types/defineToolCallRenderer.ts +32 -0
  427. package/src/v2/types/frontend-tool.ts +8 -0
  428. package/src/v2/types/human-in-the-loop.ts +38 -0
  429. package/src/v2/types/index.ts +9 -0
  430. package/src/v2/types/interrupt.ts +15 -0
  431. package/src/v2/types/sandbox-function.ts +8 -0
  432. package/src/v2/types/vue-activity-message-renderer.ts +22 -0
  433. package/src/v2/types/vue-custom-message-renderer.ts +24 -0
  434. package/src/v2/types/vue-tool-call-renderer.ts +44 -0
  435. package/tsconfig.json +27 -0
  436. package/vite.config.ts +49 -0
  437. package/vitest.config.ts +23 -0
@@ -0,0 +1,1108 @@
1
+ import { defineComponent } from "vue";
2
+ import { render, screen, fireEvent, waitFor } from "@testing-library/vue";
3
+ import { beforeEach, describe, expect, it, vi } from "vitest";
4
+ import type { AssistantMessage } from "@ag-ui/core";
5
+ import CopilotKitProvider from "../../../providers/CopilotKitProvider.vue";
6
+ import CopilotChatConfigurationProvider from "../../../providers/CopilotChatConfigurationProvider.vue";
7
+ import CopilotChatAssistantMessage from "../CopilotChatAssistantMessage.vue";
8
+
9
+ const TEST_THREAD_ID = "test-thread";
10
+
11
+ const mockWriteText = vi.fn();
12
+ Object.assign(navigator, {
13
+ clipboard: {
14
+ writeText: mockWriteText,
15
+ },
16
+ });
17
+
18
+ const mockOnThumbsUp = vi.fn();
19
+ const mockOnThumbsDown = vi.fn();
20
+ const mockOnReadAloud = vi.fn();
21
+ const mockOnRegenerate = vi.fn();
22
+
23
+ const basicMessage: AssistantMessage = {
24
+ role: "assistant",
25
+ content: "Hello, this is a test message from the assistant.",
26
+ id: "test-message-1",
27
+ };
28
+
29
+ function renderWithProvider(component: object) {
30
+ return render(component);
31
+ }
32
+
33
+ beforeEach(() => {
34
+ mockWriteText.mockReset();
35
+ mockOnThumbsUp.mockClear();
36
+ mockOnThumbsDown.mockClear();
37
+ mockOnReadAloud.mockClear();
38
+ mockOnRegenerate.mockClear();
39
+ });
40
+
41
+ describe("CopilotChatAssistantMessage", () => {
42
+ describe("Basic rendering", () => {
43
+ it("renders with default components and styling", () => {
44
+ const Host = defineComponent({
45
+ components: {
46
+ CopilotKitProvider,
47
+ CopilotChatConfigurationProvider,
48
+ CopilotChatAssistantMessage,
49
+ },
50
+ setup() {
51
+ return { basicMessage, TEST_THREAD_ID };
52
+ },
53
+ template: `
54
+ <CopilotKitProvider runtime-url="/api/copilotkit">
55
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
56
+ <CopilotChatAssistantMessage :message="basicMessage" />
57
+ </CopilotChatConfigurationProvider>
58
+ </CopilotKitProvider>
59
+ `,
60
+ });
61
+
62
+ renderWithProvider(Host);
63
+ expect(screen.getByRole("button", { name: /copy/i })).toBeDefined();
64
+ });
65
+
66
+ it("renders empty message gracefully", () => {
67
+ const emptyMessage: AssistantMessage = {
68
+ role: "assistant",
69
+ content: "",
70
+ id: "empty-message",
71
+ };
72
+
73
+ const Host = defineComponent({
74
+ components: {
75
+ CopilotKitProvider,
76
+ CopilotChatConfigurationProvider,
77
+ CopilotChatAssistantMessage,
78
+ },
79
+ setup() {
80
+ return { emptyMessage, TEST_THREAD_ID };
81
+ },
82
+ template: `
83
+ <CopilotKitProvider runtime-url="/api/copilotkit">
84
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
85
+ <CopilotChatAssistantMessage :message="emptyMessage" />
86
+ </CopilotChatConfigurationProvider>
87
+ </CopilotKitProvider>
88
+ `,
89
+ });
90
+
91
+ renderWithProvider(Host);
92
+
93
+ const container = document.querySelector(
94
+ '[data-message-id="empty-message"]',
95
+ );
96
+ expect(container).toBeDefined();
97
+ expect(screen.queryByRole("button", { name: /copy/i })).toBeNull();
98
+ });
99
+ });
100
+
101
+ describe("Callback functionality", () => {
102
+ it("renders only copy button when no callbacks provided", () => {
103
+ const Host = defineComponent({
104
+ components: {
105
+ CopilotKitProvider,
106
+ CopilotChatConfigurationProvider,
107
+ CopilotChatAssistantMessage,
108
+ },
109
+ setup() {
110
+ return { basicMessage, TEST_THREAD_ID };
111
+ },
112
+ template: `
113
+ <CopilotKitProvider runtime-url="/api/copilotkit">
114
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
115
+ <CopilotChatAssistantMessage :message="basicMessage" />
116
+ </CopilotChatConfigurationProvider>
117
+ </CopilotKitProvider>
118
+ `,
119
+ });
120
+
121
+ renderWithProvider(Host);
122
+
123
+ expect(screen.getByRole("button", { name: /copy/i })).toBeDefined();
124
+ expect(
125
+ screen.queryByRole("button", { name: /good response/i }),
126
+ ).toBeNull();
127
+ expect(
128
+ screen.queryByRole("button", { name: /bad response/i }),
129
+ ).toBeNull();
130
+ expect(screen.queryByRole("button", { name: /read aloud/i })).toBeNull();
131
+ expect(screen.queryByRole("button", { name: /regenerate/i })).toBeNull();
132
+ });
133
+
134
+ it("renders all buttons when all callbacks provided", () => {
135
+ const Host = defineComponent({
136
+ components: {
137
+ CopilotKitProvider,
138
+ CopilotChatConfigurationProvider,
139
+ CopilotChatAssistantMessage,
140
+ },
141
+ setup() {
142
+ return {
143
+ basicMessage,
144
+ TEST_THREAD_ID,
145
+ onThumbsUp: mockOnThumbsUp,
146
+ onThumbsDown: mockOnThumbsDown,
147
+ onReadAloud: mockOnReadAloud,
148
+ onRegenerate: mockOnRegenerate,
149
+ };
150
+ },
151
+ template: `
152
+ <CopilotKitProvider runtime-url="/api/copilotkit">
153
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
154
+ <CopilotChatAssistantMessage
155
+ :message="basicMessage"
156
+ @thumbs-up="onThumbsUp"
157
+ @thumbs-down="onThumbsDown"
158
+ @read-aloud="onReadAloud"
159
+ @regenerate="onRegenerate"
160
+ />
161
+ </CopilotChatConfigurationProvider>
162
+ </CopilotKitProvider>
163
+ `,
164
+ });
165
+
166
+ renderWithProvider(Host);
167
+
168
+ expect(screen.getByRole("button", { name: /copy/i })).toBeDefined();
169
+ expect(
170
+ screen.getByRole("button", { name: /good response/i }),
171
+ ).toBeDefined();
172
+ expect(
173
+ screen.getByRole("button", { name: /bad response/i }),
174
+ ).toBeDefined();
175
+ expect(screen.getByRole("button", { name: /read aloud/i })).toBeDefined();
176
+ expect(screen.getByRole("button", { name: /regenerate/i })).toBeDefined();
177
+ });
178
+
179
+ it("calls copy functionality when copy button clicked", async () => {
180
+ const Host = defineComponent({
181
+ components: {
182
+ CopilotKitProvider,
183
+ CopilotChatConfigurationProvider,
184
+ CopilotChatAssistantMessage,
185
+ },
186
+ setup() {
187
+ return { basicMessage, TEST_THREAD_ID };
188
+ },
189
+ template: `
190
+ <CopilotKitProvider runtime-url="/api/copilotkit">
191
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
192
+ <CopilotChatAssistantMessage :message="basicMessage" />
193
+ </CopilotChatConfigurationProvider>
194
+ </CopilotKitProvider>
195
+ `,
196
+ });
197
+
198
+ renderWithProvider(Host);
199
+
200
+ fireEvent.click(screen.getByRole("button", { name: /copy/i }));
201
+ await waitFor(() => {
202
+ expect(mockWriteText).toHaveBeenCalledWith(basicMessage.content);
203
+ });
204
+ });
205
+
206
+ it("calls thumbs up callback when thumbs up button clicked", () => {
207
+ const Host = defineComponent({
208
+ components: {
209
+ CopilotKitProvider,
210
+ CopilotChatConfigurationProvider,
211
+ CopilotChatAssistantMessage,
212
+ },
213
+ setup() {
214
+ return { basicMessage, TEST_THREAD_ID, onThumbsUp: mockOnThumbsUp };
215
+ },
216
+ template: `
217
+ <CopilotKitProvider runtime-url="/api/copilotkit">
218
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
219
+ <CopilotChatAssistantMessage :message="basicMessage" @thumbs-up="onThumbsUp" />
220
+ </CopilotChatConfigurationProvider>
221
+ </CopilotKitProvider>
222
+ `,
223
+ });
224
+
225
+ renderWithProvider(Host);
226
+ fireEvent.click(screen.getByRole("button", { name: /good response/i }));
227
+ expect(mockOnThumbsUp).toHaveBeenCalledTimes(1);
228
+ });
229
+
230
+ it("calls thumbs down callback when thumbs down button clicked", () => {
231
+ const Host = defineComponent({
232
+ components: {
233
+ CopilotKitProvider,
234
+ CopilotChatConfigurationProvider,
235
+ CopilotChatAssistantMessage,
236
+ },
237
+ setup() {
238
+ return {
239
+ basicMessage,
240
+ TEST_THREAD_ID,
241
+ onThumbsDown: mockOnThumbsDown,
242
+ };
243
+ },
244
+ template: `
245
+ <CopilotKitProvider runtime-url="/api/copilotkit">
246
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
247
+ <CopilotChatAssistantMessage :message="basicMessage" @thumbs-down="onThumbsDown" />
248
+ </CopilotChatConfigurationProvider>
249
+ </CopilotKitProvider>
250
+ `,
251
+ });
252
+
253
+ renderWithProvider(Host);
254
+ fireEvent.click(screen.getByRole("button", { name: /bad response/i }));
255
+ expect(mockOnThumbsDown).toHaveBeenCalledTimes(1);
256
+ });
257
+
258
+ it("calls read aloud callback when read aloud button clicked", () => {
259
+ const Host = defineComponent({
260
+ components: {
261
+ CopilotKitProvider,
262
+ CopilotChatConfigurationProvider,
263
+ CopilotChatAssistantMessage,
264
+ },
265
+ setup() {
266
+ return { basicMessage, TEST_THREAD_ID, onReadAloud: mockOnReadAloud };
267
+ },
268
+ template: `
269
+ <CopilotKitProvider runtime-url="/api/copilotkit">
270
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
271
+ <CopilotChatAssistantMessage :message="basicMessage" @read-aloud="onReadAloud" />
272
+ </CopilotChatConfigurationProvider>
273
+ </CopilotKitProvider>
274
+ `,
275
+ });
276
+
277
+ renderWithProvider(Host);
278
+ fireEvent.click(screen.getByRole("button", { name: /read aloud/i }));
279
+ expect(mockOnReadAloud).toHaveBeenCalledTimes(1);
280
+ });
281
+
282
+ it("calls regenerate callback when regenerate button clicked", () => {
283
+ const Host = defineComponent({
284
+ components: {
285
+ CopilotKitProvider,
286
+ CopilotChatConfigurationProvider,
287
+ CopilotChatAssistantMessage,
288
+ },
289
+ setup() {
290
+ return {
291
+ basicMessage,
292
+ TEST_THREAD_ID,
293
+ onRegenerate: mockOnRegenerate,
294
+ };
295
+ },
296
+ template: `
297
+ <CopilotKitProvider runtime-url="/api/copilotkit">
298
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
299
+ <CopilotChatAssistantMessage :message="basicMessage" @regenerate="onRegenerate" />
300
+ </CopilotChatConfigurationProvider>
301
+ </CopilotKitProvider>
302
+ `,
303
+ });
304
+
305
+ renderWithProvider(Host);
306
+ fireEvent.click(screen.getByRole("button", { name: /regenerate/i }));
307
+ expect(mockOnRegenerate).toHaveBeenCalledTimes(1);
308
+ });
309
+ });
310
+
311
+ describe("Additional toolbar items", () => {
312
+ it("renders additional toolbar items", () => {
313
+ const Host = defineComponent({
314
+ components: {
315
+ CopilotKitProvider,
316
+ CopilotChatConfigurationProvider,
317
+ CopilotChatAssistantMessage,
318
+ },
319
+ setup() {
320
+ return { basicMessage, TEST_THREAD_ID };
321
+ },
322
+ template: `
323
+ <CopilotKitProvider runtime-url="/api/copilotkit">
324
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
325
+ <CopilotChatAssistantMessage :message="basicMessage">
326
+ <template #toolbar-items>
327
+ <button data-testid="custom-toolbar-item">Custom Action</button>
328
+ </template>
329
+ </CopilotChatAssistantMessage>
330
+ </CopilotChatConfigurationProvider>
331
+ </CopilotKitProvider>
332
+ `,
333
+ });
334
+
335
+ renderWithProvider(Host);
336
+ expect(screen.getByTestId("custom-toolbar-item")).toBeDefined();
337
+ });
338
+ });
339
+
340
+ describe("Slot functionality - Custom Components", () => {
341
+ it("accepts custom MarkdownRenderer component", () => {
342
+ const Host = defineComponent({
343
+ components: {
344
+ CopilotKitProvider,
345
+ CopilotChatConfigurationProvider,
346
+ CopilotChatAssistantMessage,
347
+ },
348
+ setup() {
349
+ return { basicMessage, TEST_THREAD_ID };
350
+ },
351
+ template: `
352
+ <CopilotKitProvider runtime-url="/api/copilotkit">
353
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
354
+ <CopilotChatAssistantMessage :message="basicMessage">
355
+ <template #message-renderer="{ content }">
356
+ <div data-testid="custom-markdown">{{ content.toUpperCase() }}</div>
357
+ </template>
358
+ </CopilotChatAssistantMessage>
359
+ </CopilotChatConfigurationProvider>
360
+ </CopilotKitProvider>
361
+ `,
362
+ });
363
+
364
+ renderWithProvider(Host);
365
+ expect(screen.getByTestId("custom-markdown")).toBeDefined();
366
+ expect(
367
+ screen
368
+ .getByTestId("custom-markdown")
369
+ .textContent?.includes(basicMessage.content.toUpperCase()),
370
+ ).toBe(true);
371
+ });
372
+
373
+ it("accepts custom Toolbar component", () => {
374
+ const Host = defineComponent({
375
+ components: {
376
+ CopilotKitProvider,
377
+ CopilotChatConfigurationProvider,
378
+ CopilotChatAssistantMessage,
379
+ },
380
+ setup() {
381
+ return { basicMessage, TEST_THREAD_ID };
382
+ },
383
+ template: `
384
+ <CopilotKitProvider runtime-url="/api/copilotkit">
385
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
386
+ <CopilotChatAssistantMessage :message="basicMessage">
387
+ <template #toolbar>
388
+ <div data-testid="custom-toolbar">Custom Toolbar:</div>
389
+ </template>
390
+ </CopilotChatAssistantMessage>
391
+ </CopilotChatConfigurationProvider>
392
+ </CopilotKitProvider>
393
+ `,
394
+ });
395
+
396
+ renderWithProvider(Host);
397
+ expect(screen.getByTestId("custom-toolbar")).toBeDefined();
398
+ expect(
399
+ screen
400
+ .getByTestId("custom-toolbar")
401
+ .textContent?.includes("Custom Toolbar:"),
402
+ ).toBe(true);
403
+ });
404
+
405
+ it("accepts custom CopyButton component", () => {
406
+ const Host = defineComponent({
407
+ components: {
408
+ CopilotKitProvider,
409
+ CopilotChatConfigurationProvider,
410
+ CopilotChatAssistantMessage,
411
+ },
412
+ setup() {
413
+ return { basicMessage, TEST_THREAD_ID };
414
+ },
415
+ template: `
416
+ <CopilotKitProvider runtime-url="/api/copilotkit">
417
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
418
+ <CopilotChatAssistantMessage :message="basicMessage">
419
+ <template #copy-button="{ onCopy }">
420
+ <button data-testid="custom-copy-button" @click="onCopy">Custom Copy</button>
421
+ </template>
422
+ </CopilotChatAssistantMessage>
423
+ </CopilotChatConfigurationProvider>
424
+ </CopilotKitProvider>
425
+ `,
426
+ });
427
+
428
+ renderWithProvider(Host);
429
+ expect(screen.getByTestId("custom-copy-button")).toBeDefined();
430
+ expect(
431
+ screen
432
+ .getByTestId("custom-copy-button")
433
+ .textContent?.includes("Custom Copy"),
434
+ ).toBe(true);
435
+ });
436
+
437
+ it("accepts custom ThumbsUpButton component", () => {
438
+ const Host = defineComponent({
439
+ components: {
440
+ CopilotKitProvider,
441
+ CopilotChatConfigurationProvider,
442
+ CopilotChatAssistantMessage,
443
+ },
444
+ setup() {
445
+ return { basicMessage, TEST_THREAD_ID, onThumbsUp: mockOnThumbsUp };
446
+ },
447
+ template: `
448
+ <CopilotKitProvider runtime-url="/api/copilotkit">
449
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
450
+ <CopilotChatAssistantMessage :message="basicMessage" @thumbs-up="onThumbsUp">
451
+ <template #thumbs-up-button="{ onThumbsUp: onClick }">
452
+ <button data-testid="custom-thumbs-up" @click="onClick">Custom Like</button>
453
+ </template>
454
+ </CopilotChatAssistantMessage>
455
+ </CopilotChatConfigurationProvider>
456
+ </CopilotKitProvider>
457
+ `,
458
+ });
459
+
460
+ renderWithProvider(Host);
461
+ expect(screen.getByTestId("custom-thumbs-up")).toBeDefined();
462
+ expect(
463
+ screen
464
+ .getByTestId("custom-thumbs-up")
465
+ .textContent?.includes("Custom Like"),
466
+ ).toBe(true);
467
+ });
468
+
469
+ it("accepts custom ThumbsDownButton component", () => {
470
+ const Host = defineComponent({
471
+ components: {
472
+ CopilotKitProvider,
473
+ CopilotChatConfigurationProvider,
474
+ CopilotChatAssistantMessage,
475
+ },
476
+ setup() {
477
+ return {
478
+ basicMessage,
479
+ TEST_THREAD_ID,
480
+ onThumbsDown: mockOnThumbsDown,
481
+ };
482
+ },
483
+ template: `
484
+ <CopilotKitProvider runtime-url="/api/copilotkit">
485
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
486
+ <CopilotChatAssistantMessage :message="basicMessage" @thumbs-down="onThumbsDown">
487
+ <template #thumbs-down-button="{ onThumbsDown: onClick }">
488
+ <button data-testid="custom-thumbs-down" @click="onClick">Custom Dislike</button>
489
+ </template>
490
+ </CopilotChatAssistantMessage>
491
+ </CopilotChatConfigurationProvider>
492
+ </CopilotKitProvider>
493
+ `,
494
+ });
495
+
496
+ renderWithProvider(Host);
497
+ expect(screen.getByTestId("custom-thumbs-down")).toBeDefined();
498
+ expect(
499
+ screen
500
+ .getByTestId("custom-thumbs-down")
501
+ .textContent?.includes("Custom Dislike"),
502
+ ).toBe(true);
503
+ });
504
+
505
+ it("accepts custom ReadAloudButton component", () => {
506
+ const Host = defineComponent({
507
+ components: {
508
+ CopilotKitProvider,
509
+ CopilotChatConfigurationProvider,
510
+ CopilotChatAssistantMessage,
511
+ },
512
+ setup() {
513
+ return { basicMessage, TEST_THREAD_ID, onReadAloud: mockOnReadAloud };
514
+ },
515
+ template: `
516
+ <CopilotKitProvider runtime-url="/api/copilotkit">
517
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
518
+ <CopilotChatAssistantMessage :message="basicMessage" @read-aloud="onReadAloud">
519
+ <template #read-aloud-button="{ onReadAloud: onClick }">
520
+ <button data-testid="custom-read-aloud" @click="onClick">Custom Speak</button>
521
+ </template>
522
+ </CopilotChatAssistantMessage>
523
+ </CopilotChatConfigurationProvider>
524
+ </CopilotKitProvider>
525
+ `,
526
+ });
527
+
528
+ renderWithProvider(Host);
529
+ expect(screen.getByTestId("custom-read-aloud")).toBeDefined();
530
+ expect(
531
+ screen
532
+ .getByTestId("custom-read-aloud")
533
+ .textContent?.includes("Custom Speak"),
534
+ ).toBe(true);
535
+ });
536
+
537
+ it("accepts custom RegenerateButton component", () => {
538
+ const Host = defineComponent({
539
+ components: {
540
+ CopilotKitProvider,
541
+ CopilotChatConfigurationProvider,
542
+ CopilotChatAssistantMessage,
543
+ },
544
+ setup() {
545
+ return {
546
+ basicMessage,
547
+ TEST_THREAD_ID,
548
+ onRegenerate: mockOnRegenerate,
549
+ };
550
+ },
551
+ template: `
552
+ <CopilotKitProvider runtime-url="/api/copilotkit">
553
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
554
+ <CopilotChatAssistantMessage :message="basicMessage" @regenerate="onRegenerate">
555
+ <template #regenerate-button="{ onRegenerate: onClick }">
556
+ <button data-testid="custom-regenerate" @click="onClick">Custom Retry</button>
557
+ </template>
558
+ </CopilotChatAssistantMessage>
559
+ </CopilotChatConfigurationProvider>
560
+ </CopilotKitProvider>
561
+ `,
562
+ });
563
+
564
+ renderWithProvider(Host);
565
+ expect(screen.getByTestId("custom-regenerate")).toBeDefined();
566
+ expect(
567
+ screen
568
+ .getByTestId("custom-regenerate")
569
+ .textContent?.includes("Custom Retry"),
570
+ ).toBe(true);
571
+ });
572
+ });
573
+
574
+ describe("Slot functionality - Custom Classes", () => {
575
+ it("applies custom className to component", () => {
576
+ const Host = defineComponent({
577
+ components: {
578
+ CopilotKitProvider,
579
+ CopilotChatConfigurationProvider,
580
+ CopilotChatAssistantMessage,
581
+ },
582
+ setup() {
583
+ return { basicMessage, TEST_THREAD_ID };
584
+ },
585
+ template: `
586
+ <CopilotKitProvider runtime-url="/api/copilotkit">
587
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
588
+ <CopilotChatAssistantMessage :message="basicMessage" class="custom-container-class" />
589
+ </CopilotChatConfigurationProvider>
590
+ </CopilotKitProvider>
591
+ `,
592
+ });
593
+
594
+ const { container } = renderWithProvider(Host);
595
+ expect(container.querySelector(".custom-container-class")).toBeDefined();
596
+ });
597
+
598
+ it("applies custom className to MarkdownRenderer slot", () => {
599
+ const Host = defineComponent({
600
+ components: {
601
+ CopilotKitProvider,
602
+ CopilotChatConfigurationProvider,
603
+ CopilotChatAssistantMessage,
604
+ },
605
+ setup() {
606
+ return { basicMessage, TEST_THREAD_ID };
607
+ },
608
+ template: `
609
+ <CopilotKitProvider runtime-url="/api/copilotkit">
610
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
611
+ <CopilotChatAssistantMessage :message="basicMessage">
612
+ <template #message-renderer="{ content }">
613
+ <div class="custom-markdown-class">{{ content }}</div>
614
+ </template>
615
+ </CopilotChatAssistantMessage>
616
+ </CopilotChatConfigurationProvider>
617
+ </CopilotKitProvider>
618
+ `,
619
+ });
620
+
621
+ const { container } = renderWithProvider(Host);
622
+ expect(container.querySelector(".custom-markdown-class")).toBeDefined();
623
+ });
624
+
625
+ it("applies custom className to Toolbar slot", () => {
626
+ const Host = defineComponent({
627
+ components: {
628
+ CopilotKitProvider,
629
+ CopilotChatConfigurationProvider,
630
+ CopilotChatAssistantMessage,
631
+ },
632
+ setup() {
633
+ return { basicMessage, TEST_THREAD_ID };
634
+ },
635
+ template: `
636
+ <CopilotKitProvider runtime-url="/api/copilotkit">
637
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
638
+ <CopilotChatAssistantMessage :message="basicMessage">
639
+ <template #toolbar>
640
+ <div class="custom-toolbar-class">Toolbar</div>
641
+ </template>
642
+ </CopilotChatAssistantMessage>
643
+ </CopilotChatConfigurationProvider>
644
+ </CopilotKitProvider>
645
+ `,
646
+ });
647
+
648
+ const { container } = renderWithProvider(Host);
649
+ expect(container.querySelector(".custom-toolbar-class")).toBeDefined();
650
+ });
651
+
652
+ it("applies custom className to CopyButton slot", () => {
653
+ const Host = defineComponent({
654
+ components: {
655
+ CopilotKitProvider,
656
+ CopilotChatConfigurationProvider,
657
+ CopilotChatAssistantMessage,
658
+ },
659
+ setup() {
660
+ return { basicMessage, TEST_THREAD_ID };
661
+ },
662
+ template: `
663
+ <CopilotKitProvider runtime-url="/api/copilotkit">
664
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
665
+ <CopilotChatAssistantMessage :message="basicMessage">
666
+ <template #copy-button="{ onCopy }">
667
+ <button class="custom-copy-button-class" @click="onCopy">Copy</button>
668
+ </template>
669
+ </CopilotChatAssistantMessage>
670
+ </CopilotChatConfigurationProvider>
671
+ </CopilotKitProvider>
672
+ `,
673
+ });
674
+
675
+ const { container } = renderWithProvider(Host);
676
+ expect(
677
+ container.querySelector(".custom-copy-button-class"),
678
+ ).toBeDefined();
679
+ });
680
+ });
681
+
682
+ describe("Children render prop functionality", () => {
683
+ it("supports custom layout via children render prop", () => {
684
+ const Host = defineComponent({
685
+ components: {
686
+ CopilotKitProvider,
687
+ CopilotChatConfigurationProvider,
688
+ CopilotChatAssistantMessage,
689
+ },
690
+ setup() {
691
+ return { basicMessage, TEST_THREAD_ID };
692
+ },
693
+ template: `
694
+ <CopilotKitProvider runtime-url="/api/copilotkit">
695
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
696
+ <CopilotChatAssistantMessage :message="basicMessage">
697
+ <template #layout="{ message, content }">
698
+ <div data-testid="custom-layout">
699
+ <h2>Custom Layout for: {{ message.id }}</h2>
700
+ <div>{{ content }}</div>
701
+ <div data-testid="custom-toolbar-wrapper">toolbar-wrapper</div>
702
+ </div>
703
+ </template>
704
+ </CopilotChatAssistantMessage>
705
+ </CopilotChatConfigurationProvider>
706
+ </CopilotKitProvider>
707
+ `,
708
+ });
709
+
710
+ renderWithProvider(Host);
711
+
712
+ expect(screen.getByTestId("custom-layout")).toBeDefined();
713
+ expect(
714
+ screen.getByText(`Custom Layout for: ${basicMessage.id}`),
715
+ ).toBeDefined();
716
+ expect(screen.getByTestId("custom-toolbar-wrapper")).toBeDefined();
717
+ });
718
+
719
+ it("provides all slot components to children render prop", () => {
720
+ const Host = defineComponent({
721
+ components: {
722
+ CopilotKitProvider,
723
+ CopilotChatConfigurationProvider,
724
+ CopilotChatAssistantMessage,
725
+ },
726
+ setup() {
727
+ return {
728
+ basicMessage,
729
+ TEST_THREAD_ID,
730
+ onThumbsUp: mockOnThumbsUp,
731
+ onThumbsDown: mockOnThumbsDown,
732
+ onReadAloud: mockOnReadAloud,
733
+ onRegenerate: mockOnRegenerate,
734
+ };
735
+ },
736
+ template: `
737
+ <CopilotKitProvider runtime-url="/api/copilotkit">
738
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
739
+ <CopilotChatAssistantMessage
740
+ :message="basicMessage"
741
+ @thumbs-up="onThumbsUp"
742
+ @thumbs-down="onThumbsDown"
743
+ @read-aloud="onReadAloud"
744
+ @regenerate="onRegenerate"
745
+ >
746
+ <template #layout="{ messageRenderer, toolbar, copyButton, thumbsUpButton, thumbsDownButton, readAloudButton, regenerateButton }">
747
+ <div data-testid="all-slots-layout">
748
+ <div data-testid="markdown-present">{{ !!messageRenderer }}</div>
749
+ <div data-testid="toolbar-present">{{ !!toolbar }}</div>
750
+ <div data-testid="individual-buttons">
751
+ <button v-if="copyButton">copy</button>
752
+ <button v-if="thumbsUpButton">up</button>
753
+ <button v-if="thumbsDownButton">down</button>
754
+ <button v-if="readAloudButton">read</button>
755
+ <button v-if="regenerateButton">regen</button>
756
+ </div>
757
+ </div>
758
+ </template>
759
+ </CopilotChatAssistantMessage>
760
+ </CopilotChatConfigurationProvider>
761
+ </CopilotKitProvider>
762
+ `,
763
+ });
764
+
765
+ renderWithProvider(Host);
766
+ expect(screen.getByTestId("all-slots-layout")).toBeDefined();
767
+ expect(screen.getByTestId("individual-buttons")).toBeDefined();
768
+ expect(screen.getAllByRole("button").length).toBeGreaterThanOrEqual(5);
769
+ });
770
+
771
+ it("provides callback props to children render prop", () => {
772
+ const Host = defineComponent({
773
+ components: {
774
+ CopilotKitProvider,
775
+ CopilotChatConfigurationProvider,
776
+ CopilotChatAssistantMessage,
777
+ },
778
+ setup() {
779
+ return {
780
+ basicMessage,
781
+ TEST_THREAD_ID,
782
+ onThumbsUp: mockOnThumbsUp,
783
+ onThumbsDown: mockOnThumbsDown,
784
+ onReadAloud: mockOnReadAloud,
785
+ onRegenerate: mockOnRegenerate,
786
+ };
787
+ },
788
+ template: `
789
+ <CopilotKitProvider runtime-url="/api/copilotkit">
790
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
791
+ <CopilotChatAssistantMessage
792
+ :message="basicMessage"
793
+ @thumbs-up="onThumbsUp"
794
+ @thumbs-down="onThumbsDown"
795
+ @read-aloud="onReadAloud"
796
+ @regenerate="onRegenerate"
797
+ >
798
+ <template #layout="{ onThumbsUp, onThumbsDown, onReadAloud, onRegenerate }">
799
+ <div data-testid="callback-test">
800
+ <button @click="onThumbsUp" data-testid="custom-thumbs-up">Custom Thumbs Up</button>
801
+ <button @click="onThumbsDown" data-testid="custom-thumbs-down">Custom Thumbs Down</button>
802
+ <button @click="onReadAloud" data-testid="custom-read-aloud">Custom Read Aloud</button>
803
+ <button @click="onRegenerate" data-testid="custom-regenerate">Custom Regenerate</button>
804
+ </div>
805
+ </template>
806
+ </CopilotChatAssistantMessage>
807
+ </CopilotChatConfigurationProvider>
808
+ </CopilotKitProvider>
809
+ `,
810
+ });
811
+
812
+ renderWithProvider(Host);
813
+
814
+ fireEvent.click(screen.getByTestId("custom-thumbs-up"));
815
+ fireEvent.click(screen.getByTestId("custom-thumbs-down"));
816
+ fireEvent.click(screen.getByTestId("custom-read-aloud"));
817
+ fireEvent.click(screen.getByTestId("custom-regenerate"));
818
+
819
+ expect(mockOnThumbsUp).toHaveBeenCalledTimes(1);
820
+ expect(mockOnThumbsDown).toHaveBeenCalledTimes(1);
821
+ expect(mockOnReadAloud).toHaveBeenCalledTimes(1);
822
+ expect(mockOnRegenerate).toHaveBeenCalledTimes(1);
823
+ });
824
+ });
825
+
826
+ describe("Toolbar visibility functionality", () => {
827
+ it("shows toolbar by default (toolbarVisible = true by default)", () => {
828
+ const Host = defineComponent({
829
+ components: {
830
+ CopilotKitProvider,
831
+ CopilotChatConfigurationProvider,
832
+ CopilotChatAssistantMessage,
833
+ },
834
+ setup() {
835
+ return { basicMessage, TEST_THREAD_ID };
836
+ },
837
+ template: `
838
+ <CopilotKitProvider runtime-url="/api/copilotkit">
839
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
840
+ <CopilotChatAssistantMessage :message="basicMessage" />
841
+ </CopilotChatConfigurationProvider>
842
+ </CopilotKitProvider>
843
+ `,
844
+ });
845
+ renderWithProvider(Host);
846
+ expect(screen.getByRole("button", { name: /copy/i })).toBeDefined();
847
+ });
848
+
849
+ it("shows toolbar when toolbarVisible is explicitly true", () => {
850
+ const Host = defineComponent({
851
+ components: {
852
+ CopilotKitProvider,
853
+ CopilotChatConfigurationProvider,
854
+ CopilotChatAssistantMessage,
855
+ },
856
+ setup() {
857
+ return { basicMessage, TEST_THREAD_ID };
858
+ },
859
+ template: `
860
+ <CopilotKitProvider runtime-url="/api/copilotkit">
861
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
862
+ <CopilotChatAssistantMessage :message="basicMessage" :toolbar-visible="true" />
863
+ </CopilotChatConfigurationProvider>
864
+ </CopilotKitProvider>
865
+ `,
866
+ });
867
+ renderWithProvider(Host);
868
+ expect(screen.getByRole("button", { name: /copy/i })).toBeDefined();
869
+ });
870
+
871
+ it("hides toolbar when toolbarVisible is false", () => {
872
+ const Host = defineComponent({
873
+ components: {
874
+ CopilotKitProvider,
875
+ CopilotChatConfigurationProvider,
876
+ CopilotChatAssistantMessage,
877
+ },
878
+ setup() {
879
+ return { basicMessage, TEST_THREAD_ID };
880
+ },
881
+ template: `
882
+ <CopilotKitProvider runtime-url="/api/copilotkit">
883
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
884
+ <CopilotChatAssistantMessage :message="basicMessage" :toolbar-visible="false" />
885
+ </CopilotChatConfigurationProvider>
886
+ </CopilotKitProvider>
887
+ `,
888
+ });
889
+
890
+ renderWithProvider(Host);
891
+ expect(screen.queryByRole("button", { name: /copy/i })).toBeNull();
892
+ });
893
+
894
+ it("always passes toolbar and toolbarVisible to children render prop", () => {
895
+ const childrenSpy = vi.fn(() => "");
896
+ const Host = defineComponent({
897
+ components: {
898
+ CopilotKitProvider,
899
+ CopilotChatConfigurationProvider,
900
+ CopilotChatAssistantMessage,
901
+ },
902
+ setup() {
903
+ return { basicMessage, TEST_THREAD_ID, childrenSpy };
904
+ },
905
+ template: `
906
+ <CopilotKitProvider runtime-url="/api/copilotkit">
907
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
908
+ <CopilotChatAssistantMessage :message="basicMessage" :toolbar-visible="false">
909
+ <template #layout="{ toolbar, toolbarVisible, message }">
910
+ <span class="cpk:hidden">{{ childrenSpy(toolbar, toolbarVisible, message) }}</span>
911
+ <div data-testid="children-render" />
912
+ </template>
913
+ </CopilotChatAssistantMessage>
914
+ </CopilotChatConfigurationProvider>
915
+ </CopilotKitProvider>
916
+ `,
917
+ });
918
+
919
+ renderWithProvider(Host);
920
+ expect(childrenSpy).toHaveBeenCalled();
921
+ const firstCall = childrenSpy.mock.calls[0];
922
+ expect(firstCall[0]).toBeDefined();
923
+ expect(firstCall[1]).toBe(false);
924
+ expect(firstCall[2]).toEqual(basicMessage);
925
+ expect(screen.getByTestId("children-render")).toBeDefined();
926
+ });
927
+
928
+ it("passes toolbarVisible true to children render prop by default", () => {
929
+ const childrenSpy = vi.fn(() => "");
930
+ const Host = defineComponent({
931
+ components: {
932
+ CopilotKitProvider,
933
+ CopilotChatConfigurationProvider,
934
+ CopilotChatAssistantMessage,
935
+ },
936
+ setup() {
937
+ return { basicMessage, TEST_THREAD_ID, childrenSpy };
938
+ },
939
+ template: `
940
+ <CopilotKitProvider runtime-url="/api/copilotkit">
941
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
942
+ <CopilotChatAssistantMessage :message="basicMessage">
943
+ <template #layout="{ toolbar, toolbarVisible, message }">
944
+ <span class="cpk:hidden">{{ childrenSpy(toolbar, toolbarVisible, message) }}</span>
945
+ <div />
946
+ </template>
947
+ </CopilotChatAssistantMessage>
948
+ </CopilotChatConfigurationProvider>
949
+ </CopilotKitProvider>
950
+ `,
951
+ });
952
+
953
+ renderWithProvider(Host);
954
+ expect(childrenSpy).toHaveBeenCalled();
955
+ const firstCall = childrenSpy.mock.calls[0];
956
+ expect(firstCall[0]).toBeDefined();
957
+ expect(firstCall[1]).toBe(true);
958
+ expect(firstCall[2]).toEqual(basicMessage);
959
+ });
960
+
961
+ it("children can use toolbarVisible to conditionally render toolbar", () => {
962
+ const Host = defineComponent({
963
+ components: {
964
+ CopilotKitProvider,
965
+ CopilotChatConfigurationProvider,
966
+ CopilotChatAssistantMessage,
967
+ },
968
+ setup() {
969
+ return { basicMessage, TEST_THREAD_ID };
970
+ },
971
+ template: `
972
+ <CopilotKitProvider runtime-url="/api/copilotkit">
973
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
974
+ <CopilotChatAssistantMessage :message="basicMessage" :toolbar-visible="false">
975
+ <template #layout="{ toolbarVisible }">
976
+ <div data-testid="custom-layout">
977
+ <div data-testid="content">Custom content</div>
978
+ <div v-if="toolbarVisible" data-testid="conditional-toolbar">Toolbar</div>
979
+ <div v-else data-testid="no-toolbar">No toolbar</div>
980
+ </div>
981
+ </template>
982
+ </CopilotChatAssistantMessage>
983
+ </CopilotChatConfigurationProvider>
984
+ </CopilotKitProvider>
985
+ `,
986
+ });
987
+
988
+ renderWithProvider(Host);
989
+ expect(screen.getByTestId("custom-layout")).toBeDefined();
990
+ expect(screen.getByTestId("content")).toBeDefined();
991
+ expect(screen.queryByTestId("conditional-toolbar")).toBeNull();
992
+ expect(screen.getByTestId("no-toolbar")).toBeDefined();
993
+ });
994
+ });
995
+
996
+ describe("Error handling", () => {
997
+ it("handles copy errors gracefully", async () => {
998
+ mockWriteText.mockRejectedValueOnce(new Error("Clipboard error"));
999
+ const consoleSpy = vi
1000
+ .spyOn(console, "error")
1001
+ .mockImplementation(() => {});
1002
+
1003
+ const Host = defineComponent({
1004
+ components: {
1005
+ CopilotKitProvider,
1006
+ CopilotChatConfigurationProvider,
1007
+ CopilotChatAssistantMessage,
1008
+ },
1009
+ setup() {
1010
+ return { basicMessage, TEST_THREAD_ID };
1011
+ },
1012
+ template: `
1013
+ <CopilotKitProvider runtime-url="/api/copilotkit">
1014
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
1015
+ <CopilotChatAssistantMessage :message="basicMessage" />
1016
+ </CopilotChatConfigurationProvider>
1017
+ </CopilotKitProvider>
1018
+ `,
1019
+ });
1020
+
1021
+ renderWithProvider(Host);
1022
+ fireEvent.click(screen.getByRole("button", { name: /copy/i }));
1023
+
1024
+ await waitFor(() => {
1025
+ expect(consoleSpy).toHaveBeenCalledWith(
1026
+ "Failed to copy to clipboard:",
1027
+ expect.any(Error),
1028
+ );
1029
+ });
1030
+
1031
+ consoleSpy.mockRestore();
1032
+ });
1033
+
1034
+ it("handles null message content gracefully", () => {
1035
+ const nullContentMessage: AssistantMessage = {
1036
+ role: "assistant",
1037
+ content: null as never,
1038
+ id: "null-content",
1039
+ };
1040
+
1041
+ const Host = defineComponent({
1042
+ components: {
1043
+ CopilotKitProvider,
1044
+ CopilotChatConfigurationProvider,
1045
+ CopilotChatAssistantMessage,
1046
+ },
1047
+ setup() {
1048
+ return { nullContentMessage, TEST_THREAD_ID };
1049
+ },
1050
+ template: `
1051
+ <CopilotKitProvider runtime-url="/api/copilotkit">
1052
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
1053
+ <CopilotChatAssistantMessage :message="nullContentMessage" />
1054
+ </CopilotChatConfigurationProvider>
1055
+ </CopilotKitProvider>
1056
+ `,
1057
+ });
1058
+
1059
+ renderWithProvider(Host);
1060
+ const container = document.querySelector(
1061
+ '[data-message-id="null-content"]',
1062
+ );
1063
+ expect(container).toBeDefined();
1064
+ expect(screen.queryByRole("button", { name: /copy/i })).toBeNull();
1065
+ });
1066
+ });
1067
+
1068
+ describe("Vue-specific semantics", () => {
1069
+ it("renders markdown image and table actions", () => {
1070
+ const message: AssistantMessage = {
1071
+ id: "assistant-vue-extra",
1072
+ role: "assistant",
1073
+ content: `![Alt text](https://example.com/image.png)\n\n| Feature | Supported |\n| --- | --- |\n| Tables | yes |`,
1074
+ timestamp: new Date(),
1075
+ };
1076
+
1077
+ const Host = defineComponent({
1078
+ components: {
1079
+ CopilotKitProvider,
1080
+ CopilotChatConfigurationProvider,
1081
+ CopilotChatAssistantMessage,
1082
+ },
1083
+ setup() {
1084
+ return { message, TEST_THREAD_ID };
1085
+ },
1086
+ template: `
1087
+ <CopilotKitProvider runtime-url="/api/copilotkit">
1088
+ <CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
1089
+ <CopilotChatAssistantMessage :message="message" />
1090
+ </CopilotChatConfigurationProvider>
1091
+ </CopilotKitProvider>
1092
+ `,
1093
+ });
1094
+
1095
+ renderWithProvider(Host);
1096
+ expect(
1097
+ document.querySelector('button[title="Download image"]'),
1098
+ ).toBeDefined();
1099
+ expect(document.querySelector("table")).toBeDefined();
1100
+ expect(
1101
+ document.querySelector('button[title="Copy table"]'),
1102
+ ).toBeDefined();
1103
+ expect(
1104
+ document.querySelector('button[title="Download table"]'),
1105
+ ).toBeDefined();
1106
+ });
1107
+ });
1108
+ });