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

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 (335) 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 +365 -16920
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/use-render-activity-message-BAhbpSDh.js +16200 -0
  12. package/dist/use-render-activity-message-BAhbpSDh.js.map +1 -0
  13. package/dist/use-render-activity-message-DJ6q1qHV.cjs +114 -0
  14. package/dist/use-render-activity-message-DJ6q1qHV.cjs.map +1 -0
  15. package/dist/v2/components/A2UIMessageRenderer.d.ts +14 -0
  16. package/dist/v2/components/A2UIMessageRenderer.d.ts.map +1 -1
  17. package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts +10 -3
  18. package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts.map +1 -1
  19. package/dist/v2/components/CopilotKitInspector.vue.d.ts +5 -1
  20. package/dist/v2/components/CopilotKitInspector.vue.d.ts.map +1 -1
  21. package/dist/v2/components/InlineFeatureWarning.vue.d.ts.map +1 -1
  22. package/dist/v2/components/LicenseWarningBanner.vue.d.ts +2 -2
  23. package/dist/v2/components/LicenseWarningBanner.vue.d.ts.map +1 -1
  24. package/dist/v2/components/MCPAppsActivityRenderer.d.ts.map +1 -1
  25. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts +13 -59
  26. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts.map +1 -1
  27. package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts +0 -5
  28. package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts.map +1 -1
  29. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts +10 -15
  30. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts.map +1 -1
  31. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts +14 -130
  32. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts.map +1 -1
  33. package/dist/v2/components/a2ui/catalog.d.ts.map +1 -1
  34. package/dist/v2/components/a2ui/utils.d.ts +3 -15
  35. package/dist/v2/components/a2ui/utils.d.ts.map +1 -1
  36. package/dist/v2/components/a2ui.d.ts +9 -8
  37. package/dist/v2/components/a2ui.d.ts.map +1 -1
  38. package/dist/v2/components/chat/CopilotChat.vue.d.ts +2 -2
  39. package/dist/v2/components/chat/CopilotChat.vue.d.ts.map +1 -1
  40. package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts.map +1 -1
  41. package/dist/v2/components/chat/CopilotChatAttachmentQueue.vue.d.ts.map +1 -1
  42. package/dist/v2/components/chat/CopilotChatAttachmentRenderer.vue.d.ts.map +1 -1
  43. package/dist/v2/components/chat/CopilotChatAudioRecorder.vue.d.ts +4 -8
  44. package/dist/v2/components/chat/CopilotChatAudioRecorder.vue.d.ts.map +1 -1
  45. package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts +1 -1
  46. package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts.map +1 -1
  47. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts +6 -270
  48. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts.map +1 -1
  49. package/dist/v2/components/chat/CopilotChatInspectorButton.vue.d.ts.map +1 -1
  50. package/dist/v2/components/chat/CopilotChatLightbox.vue.d.ts.map +1 -1
  51. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts +1 -1
  52. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts.map +1 -1
  53. package/dist/v2/components/chat/CopilotChatReasoningMessage.vue.d.ts.map +1 -1
  54. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts +1 -1
  55. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts.map +1 -1
  56. package/dist/v2/components/chat/CopilotChatToolCallItem.vue.d.ts.map +1 -1
  57. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts +1 -1
  58. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts.map +1 -1
  59. package/dist/v2/components/chat/CopilotChatUserMessage.vue.d.ts.map +1 -1
  60. package/dist/v2/components/chat/CopilotChatView.vue.d.ts +3 -3
  61. package/dist/v2/components/chat/CopilotChatView.vue.d.ts.map +1 -1
  62. package/dist/v2/components/chat/CopilotChatWorkSummary.vue.d.ts.map +1 -1
  63. package/dist/v2/components/chat/CopilotModalHeader.vue.d.ts.map +1 -1
  64. package/dist/v2/components/chat/CopilotPopup.vue.d.ts +8 -3
  65. package/dist/v2/components/chat/CopilotPopup.vue.d.ts.map +1 -1
  66. package/dist/v2/components/chat/CopilotPopupView.vue.d.ts +5 -3
  67. package/dist/v2/components/chat/CopilotPopupView.vue.d.ts.map +1 -1
  68. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts +5 -3
  69. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts.map +1 -1
  70. package/dist/v2/components/chat/CopilotSidebar.vue.d.ts +8 -3
  71. package/dist/v2/components/chat/CopilotSidebar.vue.d.ts.map +1 -1
  72. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts +6 -4
  73. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts.map +1 -1
  74. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts +6 -4
  75. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts.map +1 -1
  76. package/dist/v2/components/chat/CopilotThreadsDrawer.vue.d.ts.map +1 -1
  77. package/dist/v2/components/chat/StreamingMarkdownDefault.vue.d.ts +1 -0
  78. package/dist/v2/components/chat/StreamingMarkdownDefault.vue.d.ts.map +1 -1
  79. package/dist/v2/components/chat/audioRecorder.d.ts +3 -4
  80. package/dist/v2/components/chat/audioRecorder.d.ts.map +1 -1
  81. package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts +3 -3
  82. package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts.map +1 -1
  83. package/dist/v2/components/chat/forwarded-slots.d.ts +12 -0
  84. package/dist/v2/components/chat/forwarded-slots.d.ts.map +1 -0
  85. package/dist/v2/components/chat/index.d.ts +34 -31
  86. package/dist/v2/components/chat/index.d.ts.map +1 -1
  87. package/dist/v2/components/chat/inspector-shortcuts.d.ts +2 -1
  88. package/dist/v2/components/chat/inspector-shortcuts.d.ts.map +1 -1
  89. package/dist/v2/components/chat/message-feedback.d.ts +18 -49
  90. package/dist/v2/components/chat/message-feedback.d.ts.map +1 -1
  91. package/dist/v2/components/chat/tool-call-display-context.d.ts +4 -19
  92. package/dist/v2/components/chat/tool-call-display-context.d.ts.map +1 -1
  93. package/dist/v2/components/chat/tool-call-group-parts.d.ts +7 -20
  94. package/dist/v2/components/chat/tool-call-group-parts.d.ts.map +1 -1
  95. package/dist/v2/components/chat/turn-work.d.ts +0 -2
  96. package/dist/v2/components/chat/turn-work.d.ts.map +1 -1
  97. package/dist/v2/components/chat/types.d.ts +9 -4
  98. package/dist/v2/components/chat/types.d.ts.map +1 -1
  99. package/dist/v2/components/chat/use-chat-labels.d.ts +8 -0
  100. package/dist/v2/components/chat/use-chat-labels.d.ts.map +1 -0
  101. package/dist/v2/components/chat/use-copy-feedback.d.ts +11 -0
  102. package/dist/v2/components/chat/use-copy-feedback.d.ts.map +1 -0
  103. package/dist/v2/components/chat/use-lightbox.d.ts.map +1 -1
  104. package/dist/v2/components/icons/index.d.ts +968 -1
  105. package/dist/v2/components/icons/index.d.ts.map +1 -1
  106. package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts +1 -1
  107. package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts.map +1 -1
  108. package/dist/v2/hooks/use-agent-context.d.ts +2 -3
  109. package/dist/v2/hooks/use-agent-context.d.ts.map +1 -1
  110. package/dist/v2/hooks/use-agent.d.ts +4 -1
  111. package/dist/v2/hooks/use-agent.d.ts.map +1 -1
  112. package/dist/v2/hooks/use-attachments.d.ts +7 -0
  113. package/dist/v2/hooks/use-attachments.d.ts.map +1 -1
  114. package/dist/v2/hooks/use-capabilities.d.ts.map +1 -1
  115. package/dist/v2/hooks/use-component.d.ts +1 -0
  116. package/dist/v2/hooks/use-component.d.ts.map +1 -1
  117. package/dist/v2/hooks/use-configure-suggestions.d.ts +4 -9
  118. package/dist/v2/hooks/use-configure-suggestions.d.ts.map +1 -1
  119. package/dist/v2/hooks/use-default-render-tool.d.ts.map +1 -1
  120. package/dist/v2/hooks/use-frontend-tool.d.ts +5 -0
  121. package/dist/v2/hooks/use-frontend-tool.d.ts.map +1 -1
  122. package/dist/v2/hooks/use-human-in-the-loop.d.ts +2 -1
  123. package/dist/v2/hooks/use-human-in-the-loop.d.ts.map +1 -1
  124. package/dist/v2/hooks/use-interrupt.d.ts +0 -1
  125. package/dist/v2/hooks/use-interrupt.d.ts.map +1 -1
  126. package/dist/v2/hooks/use-keyboard-height.d.ts +1 -1
  127. package/dist/v2/hooks/use-keyboard-height.d.ts.map +1 -1
  128. package/dist/v2/hooks/use-pin-to-send.d.ts +4 -12
  129. package/dist/v2/hooks/use-pin-to-send.d.ts.map +1 -1
  130. package/dist/v2/hooks/use-render-activity-message.d.ts +13 -9
  131. package/dist/v2/hooks/use-render-activity-message.d.ts.map +1 -1
  132. package/dist/v2/hooks/use-render-custom-messages.d.ts +5 -7
  133. package/dist/v2/hooks/use-render-custom-messages.d.ts.map +1 -1
  134. package/dist/v2/hooks/use-suggestions.d.ts.map +1 -1
  135. package/dist/v2/hooks/use-threads.d.ts +0 -8
  136. package/dist/v2/hooks/use-threads.d.ts.map +1 -1
  137. package/dist/v2/index.cjs +1 -1
  138. package/dist/v2/index.mjs +197 -200
  139. package/dist/v2/index.mjs.map +1 -1
  140. package/dist/v2/lib/processPartialHtml.d.ts +1 -2
  141. package/dist/v2/lib/processPartialHtml.d.ts.map +1 -1
  142. package/dist/v2/lib/shallow-stable.d.ts.map +1 -1
  143. package/dist/v2/lib/vue-core.d.ts +12 -12
  144. package/dist/v2/lib/vue-core.d.ts.map +1 -1
  145. package/dist/v2/providers/CopilotChatConfigurationProvider.vue.d.ts.map +1 -1
  146. package/dist/v2/providers/CopilotKitProvider.types.d.ts +9 -129
  147. package/dist/v2/providers/CopilotKitProvider.types.d.ts.map +1 -1
  148. package/dist/v2/providers/CopilotKitProvider.vue.d.ts +9 -10
  149. package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
  150. package/dist/v2/providers/chat-configuration-store-key.d.ts +8 -0
  151. package/dist/v2/providers/chat-configuration-store-key.d.ts.map +1 -0
  152. package/dist/v2/providers/markdown-renderer.d.ts +4 -2
  153. package/dist/v2/providers/markdown-renderer.d.ts.map +1 -1
  154. package/dist/v2/providers/types.d.ts +3 -46
  155. package/dist/v2/providers/types.d.ts.map +1 -1
  156. package/dist/v2/providers/use-inspector-thread-override.d.ts +5 -0
  157. package/dist/v2/providers/use-inspector-thread-override.d.ts.map +1 -1
  158. package/dist/v2/types/human-in-the-loop.d.ts +8 -29
  159. package/dist/v2/types/human-in-the-loop.d.ts.map +1 -1
  160. package/dist/v2/types/interrupt.d.ts +1 -22
  161. package/dist/v2/types/interrupt.d.ts.map +1 -1
  162. package/dist/v2/types/vue-activity-message-renderer.d.ts +16 -15
  163. package/dist/v2/types/vue-activity-message-renderer.d.ts.map +1 -1
  164. package/dist/v2/types/vue-custom-message-renderer.d.ts +7 -16
  165. package/dist/v2/types/vue-custom-message-renderer.d.ts.map +1 -1
  166. package/dist/v2/types/vue-tool-call-renderer.d.ts +16 -35
  167. package/dist/v2/types/vue-tool-call-renderer.d.ts.map +1 -1
  168. package/package.json +10 -11
  169. package/src/__tests__/build-entries.test.ts +27 -0
  170. package/src/hooks/__tests__/zod-parameters.test.ts +520 -0
  171. package/src/hooks/use-copilot-action.ts +2 -1
  172. package/src/hooks/use-frontend-tool.ts +3 -6
  173. package/src/hooks/zod-parameters.ts +162 -0
  174. package/src/v2/__tests__/exports.test.ts +10 -0
  175. package/src/v2/__tests__/mocks/web-inspector.ts +6 -0
  176. package/src/v2/__tests__/utils/test-helpers.ts +34 -4
  177. package/src/v2/components/A2UIMessageRenderer.ts +98 -68
  178. package/src/v2/components/A2UISurfaceActivityRenderer.vue +68 -103
  179. package/src/v2/components/CopilotKitInspector.vue +104 -51
  180. package/src/v2/components/InlineFeatureWarning.vue +20 -21
  181. package/src/v2/components/LicenseWarningBanner.vue +27 -135
  182. package/src/v2/components/MCPAppsActivityRenderer.ts +75 -201
  183. package/src/v2/components/OpenGenerativeUIRenderer.ts +122 -446
  184. package/src/v2/components/__tests__/A2UIMessageRenderer.test.ts +171 -8
  185. package/src/v2/components/__tests__/CopilotKitInspector.test.ts +42 -0
  186. package/src/v2/components/__tests__/LicenseWarningBanner.test.ts +60 -0
  187. package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.ts +64 -8
  188. package/src/v2/components/__tests__/OpenGenerativeUIToolRenderer.test.ts +38 -0
  189. package/src/v2/components/a2ui/A2UIBuiltInToolCallRenderer.ts +2 -7
  190. package/src/v2/components/a2ui/A2UICatalogContext.ts +27 -185
  191. package/src/v2/components/a2ui/A2UIRecoveryStates.ts +127 -327
  192. package/src/v2/components/a2ui/catalog.ts +3 -3
  193. package/src/v2/components/a2ui/utils.ts +13 -65
  194. package/src/v2/components/a2ui.ts +15 -22
  195. package/src/v2/components/chat/CopilotChat.vue +147 -356
  196. package/src/v2/components/chat/CopilotChatAssistantMessage.vue +19 -43
  197. package/src/v2/components/chat/CopilotChatAttachmentQueue.vue +36 -55
  198. package/src/v2/components/chat/CopilotChatAttachmentRenderer.vue +14 -6
  199. package/src/v2/components/chat/CopilotChatAudioRecorder.vue +19 -246
  200. package/src/v2/components/chat/CopilotChatFeedbackCommentPopover.vue +2 -2
  201. package/src/v2/components/chat/CopilotChatInput.vue +108 -436
  202. package/src/v2/components/chat/CopilotChatInspectorButton.vue +45 -108
  203. package/src/v2/components/chat/CopilotChatLightbox.vue +10 -31
  204. package/src/v2/components/chat/CopilotChatMessageView.vue +82 -210
  205. package/src/v2/components/chat/CopilotChatReasoningMessage.vue +7 -15
  206. package/src/v2/components/chat/CopilotChatToolCallGroup.vue +63 -71
  207. package/src/v2/components/chat/CopilotChatToolCallItem.vue +8 -6
  208. package/src/v2/components/chat/CopilotChatToolCallsView.vue +31 -32
  209. package/src/v2/components/chat/CopilotChatUserMessage.vue +24 -112
  210. package/src/v2/components/chat/CopilotChatView.vue +33 -28
  211. package/src/v2/components/chat/CopilotChatWorkSummary.vue +26 -36
  212. package/src/v2/components/chat/CopilotModalHeader.vue +11 -23
  213. package/src/v2/components/chat/CopilotPopup.vue +23 -25
  214. package/src/v2/components/chat/CopilotPopupView.vue +10 -39
  215. package/src/v2/components/chat/CopilotPopupViewInternal.vue +35 -131
  216. package/src/v2/components/chat/CopilotSidebar.vue +23 -25
  217. package/src/v2/components/chat/CopilotSidebarView.vue +10 -39
  218. package/src/v2/components/chat/CopilotSidebarViewInternal.vue +38 -59
  219. package/src/v2/components/chat/CopilotThreadsDrawer.vue +37 -102
  220. package/src/v2/components/chat/StreamingMarkdownDefault.vue +15 -28
  221. package/src/v2/components/chat/__tests__/CopilotChat.labels.test.ts +19 -4
  222. package/src/v2/components/chat/__tests__/CopilotChat.test.ts +12 -10
  223. package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.ts +26 -9
  224. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.learningFeedback.test.ts +5 -5
  225. package/src/v2/components/chat/__tests__/CopilotChatAttachmentQueue.test.ts +28 -0
  226. package/src/v2/components/chat/__tests__/CopilotChatInput.test.ts +89 -1
  227. package/src/v2/components/chat/__tests__/CopilotChatMessageView.test.ts +247 -403
  228. package/src/v2/components/chat/__tests__/CopilotChatMessageView.toolCallDisplay.test.ts +1 -99
  229. package/src/v2/components/chat/__tests__/CopilotPopup.test.ts +90 -1
  230. package/src/v2/components/chat/__tests__/CopilotPopupView.test.ts +19 -0
  231. package/src/v2/components/chat/__tests__/CopilotSidebar.test.ts +90 -1
  232. package/src/v2/components/chat/__tests__/CopilotSidebarView.position.test.ts +32 -8
  233. package/src/v2/components/chat/__tests__/CopilotSidebarView.test.ts +2 -1
  234. package/src/v2/components/chat/__tests__/StreamingMarkdownDefault.test.ts +54 -0
  235. package/src/v2/components/chat/audioRecorder.ts +4 -7
  236. package/src/v2/components/chat/copilotChatToolCallItemRender.ts +24 -89
  237. package/src/v2/components/chat/forwarded-slots.ts +17 -0
  238. package/src/v2/components/chat/index.ts +0 -1
  239. package/src/v2/components/chat/inspector-shortcuts.ts +10 -16
  240. package/src/v2/components/chat/message-feedback.ts +62 -197
  241. package/src/v2/components/chat/tool-call-display-context.ts +6 -22
  242. package/src/v2/components/chat/tool-call-group-parts.ts +47 -108
  243. package/src/v2/components/chat/turn-work.ts +0 -9
  244. package/src/v2/components/chat/types.ts +12 -4
  245. package/src/v2/components/chat/use-chat-labels.ts +16 -0
  246. package/src/v2/components/chat/use-copy-feedback.ts +21 -0
  247. package/src/v2/components/chat/use-lightbox.ts +15 -33
  248. package/src/v2/components/icons/__tests__/icons.test.ts +72 -68
  249. package/src/v2/components/icons/index.ts +109 -27
  250. package/src/v2/hooks/__tests__/use-agent-error-state.test.ts +5 -3
  251. package/src/v2/hooks/__tests__/use-agent-stability.test.ts +25 -4
  252. package/src/v2/hooks/__tests__/use-agent-throttle.test.ts +5 -1
  253. package/src/v2/hooks/__tests__/use-agent.test.ts +6 -3
  254. package/src/v2/hooks/__tests__/use-component.test.ts +21 -0
  255. package/src/v2/hooks/__tests__/use-configure-suggestions.test.ts +30 -1
  256. package/src/v2/hooks/__tests__/use-default-render-tool.test.ts +10 -10
  257. package/src/v2/hooks/__tests__/use-frontend-tool.e2e.test.ts +66 -1
  258. package/src/v2/hooks/__tests__/use-human-in-the-loop.e2e.test.ts +6 -1
  259. package/src/v2/hooks/__tests__/use-human-in-the-loop.test.ts +187 -12
  260. package/src/v2/hooks/__tests__/use-interrupt.test.ts +97 -0
  261. package/src/v2/hooks/__tests__/use-render-activity-message.test.ts +106 -0
  262. package/src/v2/hooks/__tests__/use-render-tool.test.ts +3 -6
  263. package/src/v2/hooks/__tests__/use-threads.test.ts +48 -6
  264. package/src/v2/hooks/__tests__/zod-regression.test.ts +5 -4
  265. package/src/v2/hooks/use-agent-context.ts +4 -10
  266. package/src/v2/hooks/use-agent.ts +86 -290
  267. package/src/v2/hooks/use-attachments.ts +48 -168
  268. package/src/v2/hooks/use-capabilities.ts +2 -7
  269. package/src/v2/hooks/use-component.ts +7 -4
  270. package/src/v2/hooks/use-configure-suggestions.ts +28 -218
  271. package/src/v2/hooks/use-default-render-tool.ts +34 -94
  272. package/src/v2/hooks/use-frontend-tool.ts +10 -10
  273. package/src/v2/hooks/use-human-in-the-loop.ts +11 -80
  274. package/src/v2/hooks/use-interrupt.ts +29 -308
  275. package/src/v2/hooks/use-keyboard-height.ts +17 -40
  276. package/src/v2/hooks/use-pin-to-send.ts +15 -99
  277. package/src/v2/hooks/use-render-activity-message.ts +31 -55
  278. package/src/v2/hooks/use-render-custom-messages.ts +24 -88
  279. package/src/v2/hooks/use-suggestions.ts +9 -33
  280. package/src/v2/hooks/use-threads.ts +43 -273
  281. package/src/v2/lib/__tests__/shallow-stable.test.ts +54 -0
  282. package/src/v2/lib/__tests__/vue-core-renderers.test.ts +42 -0
  283. package/src/v2/lib/processPartialHtml.ts +6 -21
  284. package/src/v2/lib/shallow-stable.ts +2 -16
  285. package/src/v2/lib/vue-core.ts +69 -78
  286. package/src/v2/providers/CopilotChatConfigurationProvider.vue +48 -186
  287. package/src/v2/providers/CopilotKitProvider.types.ts +12 -132
  288. package/src/v2/providers/CopilotKitProvider.vue +237 -510
  289. package/src/v2/providers/__tests__/CopilotChatConfigurationProvider.test.ts +22 -2
  290. package/src/v2/providers/__tests__/CopilotKitProvider.a2ui.test.ts +20 -2
  291. package/src/v2/providers/__tests__/CopilotKitProvider.config.test.ts +124 -0
  292. package/src/v2/providers/__tests__/CopilotKitProvider.headersAtSendTime.test.ts +3 -3
  293. package/src/v2/providers/__tests__/CopilotKitProvider.learning.test.ts +3 -1
  294. package/src/v2/providers/__tests__/CopilotKitProvider.sandboxFunctions.test.ts +4 -1
  295. package/src/v2/providers/__tests__/CopilotKitProvider.test.ts +53 -26
  296. package/src/v2/providers/chat-configuration-store-key.ts +9 -0
  297. package/src/v2/providers/markdown-renderer.ts +8 -2
  298. package/src/v2/providers/types.ts +3 -49
  299. package/src/v2/providers/use-inspector-thread-override.ts +22 -80
  300. package/src/v2/types/__tests__/defineToolCallRenderer.test.ts +28 -33
  301. package/src/v2/types/defineToolCallRenderer.ts +5 -4
  302. package/src/v2/types/human-in-the-loop.ts +8 -32
  303. package/src/v2/types/interrupt.ts +7 -31
  304. package/src/v2/types/vue-activity-message-renderer.ts +24 -15
  305. package/src/v2/types/vue-custom-message-renderer.ts +12 -16
  306. package/src/v2/types/vue-tool-call-renderer.ts +23 -38
  307. package/tsconfig.json +0 -1
  308. package/vite.config.ts +8 -5
  309. package/vitest.config.ts +12 -7
  310. package/dist/v2/components/chat/BasicMarkdown.vue.d.ts +0 -9
  311. package/dist/v2/components/chat/BasicMarkdown.vue.d.ts.map +0 -1
  312. package/dist/v2/components/chat/normalize-auto-scroll.d.ts +0 -3
  313. package/dist/v2/components/chat/normalize-auto-scroll.d.ts.map +0 -1
  314. package/dist/v2/components/chat/tool-call-layout.d.ts +0 -115
  315. package/dist/v2/components/chat/tool-call-layout.d.ts.map +0 -1
  316. package/dist/v2/lib/is-mobile-viewport.d.ts +0 -15
  317. package/dist/v2/lib/is-mobile-viewport.d.ts.map +0 -1
  318. package/dist/v2/lib/message-feedback.d.ts +0 -33
  319. package/dist/v2/lib/message-feedback.d.ts.map +0 -1
  320. package/dist/v2/lib/transcription-client.d.ts +0 -19
  321. package/dist/v2/lib/transcription-client.d.ts.map +0 -1
  322. package/src/v2/components/__tests__/A2UICatalogContext.test.ts +0 -63
  323. package/src/v2/components/a2ui/__tests__/A2UIRecoveryStates.test.ts +0 -175
  324. package/src/v2/components/chat/BasicMarkdown.vue +0 -160
  325. package/src/v2/components/chat/__tests__/BasicMarkdown.test.ts +0 -69
  326. package/src/v2/components/chat/__tests__/normalize-auto-scroll.test.ts +0 -39
  327. package/src/v2/components/chat/normalize-auto-scroll.ts +0 -17
  328. package/src/v2/components/chat/tool-call-layout.ts +0 -304
  329. package/src/v2/lib/__tests__/is-mobile-viewport.test.ts +0 -48
  330. package/src/v2/lib/__tests__/message-feedback.test.ts +0 -152
  331. package/src/v2/lib/__tests__/processPartialHtml.test.ts +0 -84
  332. package/src/v2/lib/__tests__/transcription-client.test.ts +0 -67
  333. package/src/v2/lib/is-mobile-viewport.ts +0 -23
  334. package/src/v2/lib/message-feedback.ts +0 -120
  335. package/src/v2/lib/transcription-client.ts +0 -151
@@ -8,7 +8,6 @@ import { computed, onMounted, onScopeDispose, ref, watchEffect } from "vue";
8
8
  // below is kept at module scope.
9
9
  import type {
10
10
  CopilotKitThreadsDrawer as CopilotKitThreadsDrawerElement,
11
- DrawerThread,
12
11
  ThreadSelectedDetail,
13
12
  ArchiveDetail,
14
13
  UnarchiveDetail,
@@ -23,6 +22,12 @@ import type {
23
22
  // in this worktree predate it.
24
23
  type CollapseChangeDetail = { collapsed: boolean };
25
24
  import { DEFAULT_AGENT_ID } from "@copilotkit/shared";
25
+ import {
26
+ ɵcreateThreadsDrawerActions,
27
+ ɵgetThreadsDrawerElementProps,
28
+ ɵresolveThreadsLicense,
29
+ ɵtoDrawerThread,
30
+ } from "@copilotkit/core";
26
31
  import { useThreads } from "../../hooks/use-threads";
27
32
  import type { Thread } from "../../hooks/use-threads";
28
33
  import { useCopilotChatConfiguration } from "../../providers/useCopilotChatConfiguration";
@@ -71,15 +76,11 @@ const emit = defineEmits<{
71
76
  const config = useCopilotChatConfiguration();
72
77
  const license = useLicenseContext();
73
78
 
74
- const licensed = computed(() => {
75
- const status = license.value.status;
76
- // `unknown` is an unrecovered retryable entitlement lookup, not a settled
77
- // negative: fetch the list and let the threads endpoint decide.
78
- if (status === "unknown") return true;
79
- const present = status === "valid" || status === "expiring";
80
- return present && license.value.checkFeature("threads");
81
- });
82
- const licensePending = computed(() => license.value.status === null);
79
+ // `unknown` (an unrecovered entitlement lookup) counts as licensed so the
80
+ // threads endpoint decides; `null` (not reported yet) is pending.
81
+ const threadsLicense = computed(() => ɵresolveThreadsLicense(license.value));
82
+ const licensed = computed(() => threadsLicense.value.licensed);
83
+ const licensePending = computed(() => threadsLicense.value.licensePending);
83
84
 
84
85
  const resolvedAgentId = computed(
85
86
  () => props.agentId ?? config.value?.agentId ?? DEFAULT_AGENT_ID,
@@ -107,18 +108,8 @@ const threadsApi = useThreads({
107
108
  limit: () => props.limit,
108
109
  });
109
110
 
110
- function toDrawerThread(t: Thread): DrawerThread {
111
- return {
112
- id: t.id,
113
- name: t.name,
114
- archived: t.archived,
115
- createdAt: t.createdAt,
116
- updatedAt: t.updatedAt,
117
- ...(t.lastRunAt !== undefined ? { lastRunAt: t.lastRunAt } : {}),
118
- };
119
- }
120
111
  const drawerThreads = computed(() =>
121
- threadsApi.threads.value.map(toDrawerThread),
112
+ threadsApi.threads.value.map(ɵtoDrawerThread),
122
113
  );
123
114
 
124
115
  // Client-only element registration (SSR-safe). The element module is imported
@@ -144,10 +135,15 @@ watchEffect(
144
135
  const el = elRef.value;
145
136
  if (!el) return;
146
137
  el.threads = drawerThreads.value;
147
- el.loading = threadsApi.isLoading.value || licensePending.value;
138
+ const elementProps = ɵgetThreadsDrawerElementProps({
139
+ loading: threadsApi.isLoading.value,
140
+ licensed: licensed.value,
141
+ licensePending: licensePending.value,
142
+ });
143
+ el.loading = elementProps.loading;
148
144
  el.error = threadsApi.listError.value?.message ?? null;
149
145
  el.activeThreadId = activeThreadId.value;
150
- el.licensed = licensed.value || licensePending.value;
146
+ el.licensed = elementProps.licensed;
151
147
  el.hasMore = threadsApi.hasMoreThreads.value;
152
148
  el.fetchingMore = threadsApi.isFetchingMoreThreads.value;
153
149
  // Dedicated fetch-more error channel: drives the element's inline
@@ -177,101 +173,40 @@ const unregisterDrawer = config.value?.registerDrawer?.();
177
173
  if (unregisterDrawer) onScopeDispose(unregisterDrawer);
178
174
 
179
175
  // --- Outbound event handlers ------------------------------------------------
180
- /** The chat input textarea's documented `data-testid`. */
181
- const CHAT_INPUT_TESTID = "copilot-chat-input-textarea";
182
- /** The chat view container's documented `data-testid`. */
183
- const CHAT_CONTAINER_TESTID = "copilot-chat-view";
184
-
185
- /**
186
- * Returns the chat input element for focus-return after a thread is selected.
187
- *
188
- * Best-effort and SCOPED: walks up from the drawer's custom element looking
189
- * for an ancestor that contains a chat-view container
190
- * (`data-testid="copilot-chat-view"`), then returns the chat input within
191
- * that subtree. This avoids focusing the wrong composer on a page hosting
192
- * more than one chat (multi-chat dashboards), where a document-global lookup
193
- * would grab whichever input appears first in DOM order rather than the one
194
- * this drawer drives.
195
- *
196
- * Falls back to a document-global lookup when no scoping ancestor is found
197
- * (e.g. the drawer and chat share no common container, or headless usage).
198
- */
199
- function findChatInput(origin: Element | null): HTMLElement | null {
200
- if (typeof document === "undefined") return null;
201
- const container = origin?.closest?.(
202
- `[data-testid="${CHAT_CONTAINER_TESTID}"]`,
203
- );
204
- if (container) {
205
- const scoped = container.querySelector<HTMLElement>(
206
- `[data-testid="${CHAT_INPUT_TESTID}"]`,
207
- );
208
- if (scoped) return scoped;
209
- }
210
- return document.querySelector<HTMLElement>(
211
- `[data-testid="${CHAT_INPUT_TESTID}"]`,
212
- );
213
- }
214
-
215
- function focusChatInput() {
216
- findChatInput(elRef.value)?.focus();
217
- }
176
+ // Core owns the drawer actions; they read the latest values at call time.
177
+ const actions = ɵcreateThreadsDrawerActions({
178
+ getThreads: () => threadsApi,
179
+ getConfig: () => config.value,
180
+ getCallbacks: () => ({
181
+ onThreadSelect: props.onThreadSelect,
182
+ onNewThread: props.onNewThread,
183
+ }),
184
+ getElement: () => elRef.value,
185
+ });
218
186
 
219
187
  function onThreadSelected(event: Event) {
220
188
  const { threadId } = (event as CustomEvent<ThreadSelectedDetail>).detail;
221
- if (props.onThreadSelect) props.onThreadSelect(threadId);
222
- else config.value?.setActiveThreadId?.(threadId, { explicit: true });
223
- focusChatInput();
224
- }
225
- function handleNewThread() {
226
- threadsApi.startNewThread();
227
- if (props.onNewThread) props.onNewThread();
228
- else config.value?.startNewThread?.();
189
+ actions.selectThread(threadId);
229
190
  }
191
+ const handleNewThread = actions.newThread;
230
192
  function onArchive(event: Event) {
231
- const { threadId } = (event as CustomEvent<ArchiveDetail>).detail;
232
- void threadsApi
233
- .archiveThread(threadId)
234
- .catch((e) =>
235
- console.error("CopilotThreadsDrawer: archiveThread failed", e),
236
- );
193
+ actions.archive((event as CustomEvent<ArchiveDetail>).detail.threadId);
237
194
  }
238
195
  function onUnarchive(event: Event) {
239
- const { threadId } = (event as CustomEvent<UnarchiveDetail>).detail;
240
- void threadsApi
241
- .unarchiveThread(threadId)
242
- .catch((e) =>
243
- console.error("CopilotThreadsDrawer: unarchiveThread failed", e),
244
- );
196
+ actions.unarchive((event as CustomEvent<UnarchiveDetail>).detail.threadId);
245
197
  }
246
198
  function onDelete(event: Event) {
247
- const { threadId } = (event as CustomEvent<DeleteDetail>).detail;
248
- const wasActive = threadId === activeThreadId.value;
249
- void threadsApi
250
- .deleteThread(threadId)
251
- .then(() => {
252
- if (wasActive) {
253
- handleNewThread();
254
- }
255
- })
256
- .catch((e) =>
257
- console.error("CopilotThreadsDrawer: deleteThread failed", e),
258
- );
259
- }
260
- function onFilterChange() {
261
- threadsApi.refetchThreads();
199
+ actions.remove((event as CustomEvent<DeleteDetail>).detail.threadId);
262
200
  }
201
+ const onFilterChange = actions.refetch;
263
202
  function onCollapseChange(event: Event) {
264
203
  const { collapsed } = (event as CustomEvent<CollapseChangeDetail>).detail;
265
204
  emit("collapse-change", collapsed);
266
205
  }
267
206
  function onRetry(event: Event) {
268
- const { scope } = (event as CustomEvent<RetryDetail>).detail;
269
- if (scope === "fetch-more") threadsApi.fetchMoreThreads();
270
- else threadsApi.refetchThreads();
271
- }
272
- function onLoadMore() {
273
- threadsApi.fetchMoreThreads();
207
+ actions.retry((event as CustomEvent<RetryDetail>).detail.scope);
274
208
  }
209
+ const onLoadMore = actions.loadMore;
275
210
  function onOpenChange(event: Event) {
276
211
  const { open } = (event as CustomEvent<OpenChangeDetail>).detail;
277
212
  setDrawerOpen(open);
@@ -1,43 +1,26 @@
1
1
  <script setup lang="ts">
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";
2
+ import { computed, watchEffect } from "vue";
3
+ import { StreamingMarkdownRenderer } from "@copilotkit/markdown/vue";
4
+ import {
5
+ CHAT_MARKDOWN_NODE_CLASS_NAMES,
6
+ warnUnsupportedRichSyntaxOnce,
7
+ } from "@copilotkit/markdown";
8
+ import type { StreamingMarkdownParserOptions } from "@copilotkit/markdown";
7
9
  import type { DefaultMarkdownRendererProps } from "../../providers/markdown-renderer";
8
10
 
9
11
  const props = withDefaults(
10
12
  defineProps<
11
13
  { content: string; isStreaming?: boolean } & DefaultMarkdownRendererProps
12
14
  >(),
13
- { isStreaming: false },
15
+ { isStreaming: false, caret: undefined },
14
16
  );
15
17
 
18
+ // vue-tsc reads the renderer's `options` prop as the full options type; the
19
+ // renderer itself accepts a partial object.
16
20
  const resolvedOptions = computed(
17
21
  () => props.options as StreamingMarkdownParserOptions | undefined,
18
22
  );
19
23
 
20
- const defaultCodeBlockRenderer: VueStreamingMarkdownNodeRenderer = (
21
- node,
22
- defaultVNode,
23
- ) => {
24
- if (node.type !== "code-block") return defaultVNode;
25
- return h(
26
- "pre",
27
- {
28
- "data-streaming-markdown-node": "code-block",
29
- "data-node-open": String(!node.closed),
30
- class: "cpk-markdown-code-block",
31
- },
32
- [h("code", { "data-code-info": node.info ?? undefined }, node.text)],
33
- );
34
- };
35
-
36
- const mergedNodeRenderers = computed(() => ({
37
- codeBlock: defaultCodeBlockRenderer,
38
- ...props.nodeRenderers,
39
- }));
40
-
41
24
  // Dev-only: nudge upgraders from the bundled Streamdown default when their
42
25
  // content needs math/syntax highlighting the built-in renderer doesn't do.
43
26
  watchEffect(() => warnUnsupportedRichSyntaxOnce(props.content));
@@ -45,11 +28,15 @@ watchEffect(() => warnUnsupportedRichSyntaxOnce(props.content));
45
28
 
46
29
  <template>
47
30
  <StreamingMarkdownRenderer
31
+ v-if="props.content"
48
32
  :content="props.content"
49
33
  :is-complete="!props.isStreaming"
50
- :node-renderers="mergedNodeRenderers"
34
+ :node-renderers="props.nodeRenderers"
35
+ :node-class-names="CHAT_MARKDOWN_NODE_CLASS_NAMES"
51
36
  :caret="props.caret ?? props.isStreaming"
52
37
  :options="resolvedOptions"
53
38
  :class="props.class"
39
+ :on-link-click="props.onLinkClick"
40
+ :on-citation-click="props.onCitationClick"
54
41
  />
55
42
  </template>
@@ -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(`
@@ -60,6 +60,11 @@ describe("CopilotChat", () => {
60
60
  }) => void | Promise<void>,
61
61
  errorMessage: string,
62
62
  ) => Promise<void>;
63
+ emitError: (params: {
64
+ error: Error;
65
+ code: CopilotKitCoreErrorCode;
66
+ context?: Record<string, unknown>;
67
+ }) => Promise<void>;
63
68
  }
64
69
 
65
70
  beforeEach(() => {
@@ -405,16 +410,13 @@ describe("CopilotChat", () => {
405
410
  },
406
411
  });
407
412
 
408
- await (core as unknown as CopilotKitCoreTestAccess).notifySubscribers(
409
- (subscriber) =>
410
- subscriber.onError?.({
411
- copilotkit: core!,
412
- error: new Error("matching agent"),
413
- code: CopilotKitCoreErrorCode.AGENT_RUN_FAILED,
414
- context: { agentId: "default" },
415
- }),
416
- "test chat onError",
417
- );
413
+ // Through core's error path: the provider's onError is core's handler,
414
+ // the chat's is a subscriber.
415
+ await (core as unknown as CopilotKitCoreTestAccess).emitError({
416
+ error: new Error("matching agent"),
417
+ code: CopilotKitCoreErrorCode.AGENT_RUN_FAILED,
418
+ context: { agentId: "default" },
419
+ });
418
420
 
419
421
  await nextTick();
420
422
 
@@ -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";
@@ -186,6 +186,34 @@ describe("CopilotChatAttachmentQueue", () => {
186
186
  ).toContain("hello attachment preview");
187
187
  });
188
188
 
189
+ it("decodes a text document as UTF-8", async () => {
190
+ const { getByTestId } = render(CopilotChatAttachmentQueue, {
191
+ props: {
192
+ attachments: [
193
+ createAttachment({
194
+ id: "doc-utf8",
195
+ type: "document",
196
+ status: "ready",
197
+ // "héllo ✓" in UTF-8, base64-encoded.
198
+ source: {
199
+ type: "data",
200
+ value: "aMOpbGxvIOKckw==",
201
+ mimeType: "text/plain",
202
+ },
203
+ }),
204
+ ],
205
+ },
206
+ });
207
+
208
+ await fireEvent.click(
209
+ getByTestId("copilot-chat-attachment-document-button"),
210
+ );
211
+ expect(
212
+ screen.getByTestId("copilot-chat-attachment-lightbox-document-text")
213
+ .textContent,
214
+ ).toContain("héllo ✓");
215
+ });
216
+
189
217
  it("non-previewable document remains inert", async () => {
190
218
  const { getByTestId, queryByTestId } = render(CopilotChatAttachmentQueue, {
191
219
  props: {
@@ -128,9 +128,14 @@ beforeEach(() => {
128
128
  mockOnSubmitMessage.mockClear();
129
129
  vi.spyOn(HTMLCanvasElement.prototype, "getContext").mockImplementation(
130
130
  () =>
131
+ // A partial 2D context: the input measures text, and the recorder's
132
+ // waveform scales, clears, and fills.
131
133
  ({
132
134
  measureText: (text: string) => ({ width: text.length * 8 }),
133
135
  font: "",
136
+ scale: () => {},
137
+ clearRect: () => {},
138
+ fillRect: () => {},
134
139
  }) as unknown as CanvasRenderingContext2D,
135
140
  );
136
141
  });
@@ -397,6 +402,32 @@ describe("CopilotChatInput", () => {
397
402
  });
398
403
  });
399
404
 
405
+ it("does not empty the textarea to re-measure it on each keystroke on a phone", async () => {
406
+ vi.stubGlobal("matchMedia", (query: string) => ({
407
+ matches: query === "(max-width: 767px)",
408
+ }));
409
+ const valueSetter = vi.spyOn(HTMLTextAreaElement.prototype, "value", "set");
410
+ try {
411
+ renderWithProvider({
412
+ listeners: { onSubmitMessage: mockOnSubmitMessage },
413
+ });
414
+ const textarea = screen.getByRole("textbox");
415
+ await fireEvent.input(textarea, { target: { value: "ABCD" } });
416
+ const grid = textarea.closest("[data-layout]");
417
+ await waitFor(() => {
418
+ expect(grid?.getAttribute("data-layout")).toBe("expanded");
419
+ });
420
+
421
+ valueSetter.mockClear();
422
+ await fireEvent.input(textarea, { target: { value: "AEBCD" } });
423
+
424
+ expect(valueSetter).not.toHaveBeenCalledWith("");
425
+ } finally {
426
+ valueSetter.mockRestore();
427
+ vi.unstubAllGlobals();
428
+ }
429
+ });
430
+
400
431
  it("executes slash commands via keyboard selection", async () => {
401
432
  const handleFirst = vi.fn();
402
433
  const handleSecond = vi.fn();
@@ -477,6 +508,31 @@ describe("CopilotChatInput", () => {
477
508
  });
478
509
  });
479
510
 
511
+ it("opens the slash menu for typed text once commands arrive", async () => {
512
+ const toolsMenu = ref<{ label: string; action: () => void }[]>([]);
513
+ const Host = defineComponent({
514
+ setup: () => () =>
515
+ h(
516
+ CopilotChatConfigurationProvider,
517
+ { threadId: TEST_THREAD_ID },
518
+ {
519
+ default: () => h(CopilotChatInput, { toolsMenu: toolsMenu.value }),
520
+ },
521
+ ),
522
+ });
523
+ render(Host);
524
+
525
+ await fireEvent.input(screen.getByRole("textbox"), {
526
+ target: { value: "/sum" },
527
+ });
528
+ expect(screen.queryByTestId("copilot-slash-menu")).toBeNull();
529
+
530
+ toolsMenu.value = [{ label: "Summarize", action: vi.fn() }];
531
+
532
+ const menu = await screen.findByTestId("copilot-slash-menu");
533
+ expect(within(menu).getByRole("option").textContent).toContain("Summarize");
534
+ });
535
+
480
536
  it("limits slash menu height when commands exceed five items", async () => {
481
537
  const tools = Array.from({ length: 6 }, (_, index) => ({
482
538
  label: `Command ${index + 1}`,
@@ -559,6 +615,38 @@ describe("CopilotChatInput", () => {
559
615
  expect(screen.getByRole("button", { name: "Stop" })).toBe(getSendButton());
560
616
  });
561
617
 
618
+ describe("Enter while the agent runs", () => {
619
+ async function pressEnterWhileRunning(modelValue: string) {
620
+ const onStop = vi.fn();
621
+ renderWithProvider({
622
+ props: { modelValue, isRunning: true },
623
+ listeners: { onSubmitMessage: mockOnSubmitMessage, onStop },
624
+ });
625
+ await fireEvent.keyDown(
626
+ screen.getByPlaceholderText("Type a message..."),
627
+ {
628
+ key: "Enter",
629
+ shiftKey: false,
630
+ },
631
+ );
632
+ return onStop;
633
+ }
634
+
635
+ it("sends the typed text and does not stop the run", async () => {
636
+ const onStop = await pressEnterWhileRunning(" next question ");
637
+
638
+ expect(mockOnSubmitMessage).toHaveBeenCalledWith("next question");
639
+ expect(onStop).not.toHaveBeenCalled();
640
+ });
641
+
642
+ it("stops the run when the input is empty", async () => {
643
+ const onStop = await pressEnterWhileRunning("");
644
+
645
+ expect(onStop).toHaveBeenCalledOnce();
646
+ expect(mockOnSubmitMessage).not.toHaveBeenCalled();
647
+ });
648
+ });
649
+
562
650
  it("names the send button with the configured labels", () => {
563
651
  renderWithProvider({
564
652
  template: `
@@ -799,7 +887,7 @@ describe("CopilotChatInput", () => {
799
887
 
800
888
  await fireEvent.click(addButton);
801
889
  const menuItem = await screen.findByRole("menuitem", {
802
- name: "Add photos or files",
890
+ name: "Add attachments",
803
891
  });
804
892
  await fireEvent.click(menuItem);
805
893
  expect(handleAddFile).toHaveBeenCalledTimes(1);