@copilotkit/vue 2.0.0-rc.3 → 2.0.0-rc.31

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 (343) hide show
  1. package/CONTRIBUTOR_GUIDE.md +1 -1
  2. package/PARITY.md +3 -3
  3. package/dist/hooks/use-copilot-action.d.ts.map +1 -1
  4. package/dist/hooks/use-frontend-tool.d.ts +1 -1
  5. package/dist/hooks/use-frontend-tool.d.ts.map +1 -1
  6. package/dist/hooks/zod-parameters.d.ts +14 -0
  7. package/dist/hooks/zod-parameters.d.ts.map +1 -0
  8. package/dist/index.cjs +1 -73
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.mjs +365 -16920
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/use-render-activity-message-BMTHA_P2.js +15901 -0
  13. package/dist/use-render-activity-message-BMTHA_P2.js.map +1 -0
  14. package/dist/use-render-activity-message-CH3beu7z.cjs +113 -0
  15. package/dist/use-render-activity-message-CH3beu7z.cjs.map +1 -0
  16. package/dist/v2/components/A2UIMessageRenderer.d.ts +14 -0
  17. package/dist/v2/components/A2UIMessageRenderer.d.ts.map +1 -1
  18. package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts +10 -3
  19. package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts.map +1 -1
  20. package/dist/v2/components/CopilotKitInspector.vue.d.ts +5 -1
  21. package/dist/v2/components/CopilotKitInspector.vue.d.ts.map +1 -1
  22. package/dist/v2/components/InlineFeatureWarning.vue.d.ts.map +1 -1
  23. package/dist/v2/components/LicenseWarningBanner.vue.d.ts +2 -2
  24. package/dist/v2/components/LicenseWarningBanner.vue.d.ts.map +1 -1
  25. package/dist/v2/components/MCPAppsActivityRenderer.d.ts.map +1 -1
  26. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts +13 -59
  27. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts.map +1 -1
  28. package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts +3 -11
  29. package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts.map +1 -1
  30. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts +10 -15
  31. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts.map +1 -1
  32. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts +14 -130
  33. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts.map +1 -1
  34. package/dist/v2/components/a2ui/catalog.d.ts.map +1 -1
  35. package/dist/v2/components/a2ui/utils.d.ts +3 -15
  36. package/dist/v2/components/a2ui/utils.d.ts.map +1 -1
  37. package/dist/v2/components/a2ui.d.ts +9 -8
  38. package/dist/v2/components/a2ui.d.ts.map +1 -1
  39. package/dist/v2/components/chat/CopilotChat.vue.d.ts +2 -2
  40. package/dist/v2/components/chat/CopilotChat.vue.d.ts.map +1 -1
  41. package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts.map +1 -1
  42. package/dist/v2/components/chat/CopilotChatAttachmentQueue.vue.d.ts.map +1 -1
  43. package/dist/v2/components/chat/CopilotChatAttachmentRenderer.vue.d.ts.map +1 -1
  44. package/dist/v2/components/chat/CopilotChatAudioRecorder.vue.d.ts +4 -8
  45. package/dist/v2/components/chat/CopilotChatAudioRecorder.vue.d.ts.map +1 -1
  46. package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts +1 -1
  47. package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts.map +1 -1
  48. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts +7 -286
  49. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts.map +1 -1
  50. package/dist/v2/components/chat/CopilotChatInspectorButton.vue.d.ts.map +1 -1
  51. package/dist/v2/components/chat/CopilotChatLightbox.vue.d.ts.map +1 -1
  52. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts +1 -1
  53. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts.map +1 -1
  54. package/dist/v2/components/chat/CopilotChatReasoningMessage.vue.d.ts.map +1 -1
  55. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts +1 -1
  56. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts.map +1 -1
  57. package/dist/v2/components/chat/CopilotChatToolCallItem.vue.d.ts.map +1 -1
  58. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts +1 -1
  59. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts.map +1 -1
  60. package/dist/v2/components/chat/CopilotChatUserMessage.vue.d.ts.map +1 -1
  61. package/dist/v2/components/chat/CopilotChatView.vue.d.ts +3 -3
  62. package/dist/v2/components/chat/CopilotChatView.vue.d.ts.map +1 -1
  63. package/dist/v2/components/chat/CopilotChatWorkSummary.vue.d.ts.map +1 -1
  64. package/dist/v2/components/chat/CopilotModalHeader.vue.d.ts.map +1 -1
  65. package/dist/v2/components/chat/CopilotPopup.vue.d.ts +8 -3
  66. package/dist/v2/components/chat/CopilotPopup.vue.d.ts.map +1 -1
  67. package/dist/v2/components/chat/CopilotPopupView.vue.d.ts +5 -3
  68. package/dist/v2/components/chat/CopilotPopupView.vue.d.ts.map +1 -1
  69. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts +5 -3
  70. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts.map +1 -1
  71. package/dist/v2/components/chat/CopilotSidebar.vue.d.ts +8 -3
  72. package/dist/v2/components/chat/CopilotSidebar.vue.d.ts.map +1 -1
  73. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts +6 -4
  74. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts.map +1 -1
  75. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts +6 -4
  76. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts.map +1 -1
  77. package/dist/v2/components/chat/CopilotThreadsDrawer.vue.d.ts.map +1 -1
  78. package/dist/v2/components/chat/StreamingMarkdownDefault.vue.d.ts +1 -0
  79. package/dist/v2/components/chat/StreamingMarkdownDefault.vue.d.ts.map +1 -1
  80. package/dist/v2/components/chat/audioRecorder.d.ts +3 -4
  81. package/dist/v2/components/chat/audioRecorder.d.ts.map +1 -1
  82. package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts +4 -4
  83. package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts.map +1 -1
  84. package/dist/v2/components/chat/forwarded-slots.d.ts +12 -0
  85. package/dist/v2/components/chat/forwarded-slots.d.ts.map +1 -0
  86. package/dist/v2/components/chat/index.d.ts +34 -31
  87. package/dist/v2/components/chat/index.d.ts.map +1 -1
  88. package/dist/v2/components/chat/inspector-shortcuts.d.ts +2 -1
  89. package/dist/v2/components/chat/inspector-shortcuts.d.ts.map +1 -1
  90. package/dist/v2/components/chat/message-feedback.d.ts +38 -49
  91. package/dist/v2/components/chat/message-feedback.d.ts.map +1 -1
  92. package/dist/v2/components/chat/tool-call-display-context.d.ts +4 -19
  93. package/dist/v2/components/chat/tool-call-display-context.d.ts.map +1 -1
  94. package/dist/v2/components/chat/tool-call-group-parts.d.ts +7 -20
  95. package/dist/v2/components/chat/tool-call-group-parts.d.ts.map +1 -1
  96. package/dist/v2/components/chat/turn-work.d.ts +0 -2
  97. package/dist/v2/components/chat/turn-work.d.ts.map +1 -1
  98. package/dist/v2/components/chat/types.d.ts +9 -4
  99. package/dist/v2/components/chat/types.d.ts.map +1 -1
  100. package/dist/v2/components/chat/use-chat-labels.d.ts +8 -0
  101. package/dist/v2/components/chat/use-chat-labels.d.ts.map +1 -0
  102. package/dist/v2/components/chat/use-copy-feedback.d.ts +11 -0
  103. package/dist/v2/components/chat/use-copy-feedback.d.ts.map +1 -0
  104. package/dist/v2/components/chat/use-lightbox.d.ts.map +1 -1
  105. package/dist/v2/components/icons/index.d.ts +968 -1
  106. package/dist/v2/components/icons/index.d.ts.map +1 -1
  107. package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts +1 -1
  108. package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts.map +1 -1
  109. package/dist/v2/hooks/use-agent-context.d.ts +2 -3
  110. package/dist/v2/hooks/use-agent-context.d.ts.map +1 -1
  111. package/dist/v2/hooks/use-agent.d.ts +4 -1
  112. package/dist/v2/hooks/use-agent.d.ts.map +1 -1
  113. package/dist/v2/hooks/use-attachments.d.ts +7 -0
  114. package/dist/v2/hooks/use-attachments.d.ts.map +1 -1
  115. package/dist/v2/hooks/use-capabilities.d.ts.map +1 -1
  116. package/dist/v2/hooks/use-component.d.ts +1 -0
  117. package/dist/v2/hooks/use-component.d.ts.map +1 -1
  118. package/dist/v2/hooks/use-configure-suggestions.d.ts +4 -9
  119. package/dist/v2/hooks/use-configure-suggestions.d.ts.map +1 -1
  120. package/dist/v2/hooks/use-default-render-tool.d.ts +2 -7
  121. package/dist/v2/hooks/use-default-render-tool.d.ts.map +1 -1
  122. package/dist/v2/hooks/use-frontend-tool.d.ts +5 -0
  123. package/dist/v2/hooks/use-frontend-tool.d.ts.map +1 -1
  124. package/dist/v2/hooks/use-human-in-the-loop.d.ts +2 -1
  125. package/dist/v2/hooks/use-human-in-the-loop.d.ts.map +1 -1
  126. package/dist/v2/hooks/use-interrupt.d.ts +0 -1
  127. package/dist/v2/hooks/use-interrupt.d.ts.map +1 -1
  128. package/dist/v2/hooks/use-keyboard-height.d.ts +1 -1
  129. package/dist/v2/hooks/use-keyboard-height.d.ts.map +1 -1
  130. package/dist/v2/hooks/use-pin-to-send.d.ts +4 -12
  131. package/dist/v2/hooks/use-pin-to-send.d.ts.map +1 -1
  132. package/dist/v2/hooks/use-render-activity-message.d.ts +13 -9
  133. package/dist/v2/hooks/use-render-activity-message.d.ts.map +1 -1
  134. package/dist/v2/hooks/use-render-custom-messages.d.ts +5 -7
  135. package/dist/v2/hooks/use-render-custom-messages.d.ts.map +1 -1
  136. package/dist/v2/hooks/use-render-tool.d.ts +1 -1
  137. package/dist/v2/hooks/use-render-tool.d.ts.map +1 -1
  138. package/dist/v2/hooks/use-suggestions.d.ts.map +1 -1
  139. package/dist/v2/hooks/use-threads.d.ts +6 -23
  140. package/dist/v2/hooks/use-threads.d.ts.map +1 -1
  141. package/dist/v2/index.cjs +1 -1
  142. package/dist/v2/index.mjs +197 -200
  143. package/dist/v2/index.mjs.map +1 -1
  144. package/dist/v2/lib/processPartialHtml.d.ts +1 -2
  145. package/dist/v2/lib/processPartialHtml.d.ts.map +1 -1
  146. package/dist/v2/lib/shallow-stable.d.ts.map +1 -1
  147. package/dist/v2/lib/vue-core.d.ts +33 -19
  148. package/dist/v2/lib/vue-core.d.ts.map +1 -1
  149. package/dist/v2/providers/CopilotChatConfigurationProvider.vue.d.ts.map +1 -1
  150. package/dist/v2/providers/CopilotKitProvider.types.d.ts +9 -129
  151. package/dist/v2/providers/CopilotKitProvider.types.d.ts.map +1 -1
  152. package/dist/v2/providers/CopilotKitProvider.vue.d.ts +9 -10
  153. package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
  154. package/dist/v2/providers/chat-configuration-store-key.d.ts +8 -0
  155. package/dist/v2/providers/chat-configuration-store-key.d.ts.map +1 -0
  156. package/dist/v2/providers/markdown-renderer.d.ts +4 -2
  157. package/dist/v2/providers/markdown-renderer.d.ts.map +1 -1
  158. package/dist/v2/providers/types.d.ts +3 -46
  159. package/dist/v2/providers/types.d.ts.map +1 -1
  160. package/dist/v2/providers/use-inspector-thread-override.d.ts +5 -0
  161. package/dist/v2/providers/use-inspector-thread-override.d.ts.map +1 -1
  162. package/dist/v2/types/defineToolCallRenderer.d.ts +1 -1
  163. package/dist/v2/types/defineToolCallRenderer.d.ts.map +1 -1
  164. package/dist/v2/types/human-in-the-loop.d.ts +8 -29
  165. package/dist/v2/types/human-in-the-loop.d.ts.map +1 -1
  166. package/dist/v2/types/interrupt.d.ts +1 -22
  167. package/dist/v2/types/interrupt.d.ts.map +1 -1
  168. package/dist/v2/types/vue-activity-message-renderer.d.ts +16 -15
  169. package/dist/v2/types/vue-activity-message-renderer.d.ts.map +1 -1
  170. package/dist/v2/types/vue-custom-message-renderer.d.ts +7 -16
  171. package/dist/v2/types/vue-custom-message-renderer.d.ts.map +1 -1
  172. package/dist/v2/types/vue-tool-call-renderer.d.ts +16 -35
  173. package/dist/v2/types/vue-tool-call-renderer.d.ts.map +1 -1
  174. package/package.json +12 -13
  175. package/src/__tests__/build-entries.test.ts +29 -0
  176. package/src/hooks/__tests__/zod-parameters.test.ts +520 -0
  177. package/src/hooks/use-copilot-action.ts +2 -1
  178. package/src/hooks/use-frontend-tool.ts +3 -6
  179. package/src/hooks/zod-parameters.ts +162 -0
  180. package/src/v2/__tests__/exports.test.ts +10 -0
  181. package/src/v2/__tests__/mocks/web-inspector.ts +6 -0
  182. package/src/v2/__tests__/utils/test-helpers.ts +34 -4
  183. package/src/v2/components/A2UIMessageRenderer.ts +98 -68
  184. package/src/v2/components/A2UISurfaceActivityRenderer.vue +68 -103
  185. package/src/v2/components/CopilotKitInspector.vue +104 -51
  186. package/src/v2/components/InlineFeatureWarning.vue +20 -21
  187. package/src/v2/components/LicenseWarningBanner.vue +27 -135
  188. package/src/v2/components/MCPAppsActivityRenderer.ts +75 -201
  189. package/src/v2/components/OpenGenerativeUIRenderer.ts +122 -446
  190. package/src/v2/components/__tests__/A2UIMessageRenderer.test.ts +171 -8
  191. package/src/v2/components/__tests__/CopilotKitInspector.test.ts +42 -0
  192. package/src/v2/components/__tests__/LicenseWarningBanner.test.ts +60 -0
  193. package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.ts +64 -8
  194. package/src/v2/components/__tests__/OpenGenerativeUIToolRenderer.test.ts +38 -0
  195. package/src/v2/components/a2ui/A2UIBuiltInToolCallRenderer.ts +6 -26
  196. package/src/v2/components/a2ui/A2UICatalogContext.ts +27 -185
  197. package/src/v2/components/a2ui/A2UIRecoveryStates.ts +127 -327
  198. package/src/v2/components/a2ui/catalog.ts +3 -3
  199. package/src/v2/components/a2ui/utils.ts +13 -65
  200. package/src/v2/components/a2ui.ts +15 -22
  201. package/src/v2/components/chat/CopilotChat.vue +121 -498
  202. package/src/v2/components/chat/CopilotChatAssistantMessage.vue +47 -184
  203. package/src/v2/components/chat/CopilotChatAttachmentQueue.vue +36 -55
  204. package/src/v2/components/chat/CopilotChatAttachmentRenderer.vue +14 -6
  205. package/src/v2/components/chat/CopilotChatAudioRecorder.vue +19 -246
  206. package/src/v2/components/chat/CopilotChatFeedbackCommentPopover.vue +12 -77
  207. package/src/v2/components/chat/CopilotChatInput.vue +139 -654
  208. package/src/v2/components/chat/CopilotChatInspectorButton.vue +45 -108
  209. package/src/v2/components/chat/CopilotChatLightbox.vue +10 -31
  210. package/src/v2/components/chat/CopilotChatMessageView.vue +96 -274
  211. package/src/v2/components/chat/CopilotChatReasoningMessage.vue +27 -62
  212. package/src/v2/components/chat/CopilotChatToolCallGroup.vue +63 -71
  213. package/src/v2/components/chat/CopilotChatToolCallItem.vue +8 -6
  214. package/src/v2/components/chat/CopilotChatToolCallsView.vue +31 -32
  215. package/src/v2/components/chat/CopilotChatUserMessage.vue +24 -112
  216. package/src/v2/components/chat/CopilotChatView.vue +123 -161
  217. package/src/v2/components/chat/CopilotChatWorkSummary.vue +26 -36
  218. package/src/v2/components/chat/CopilotModalHeader.vue +11 -23
  219. package/src/v2/components/chat/CopilotPopup.vue +23 -25
  220. package/src/v2/components/chat/CopilotPopupView.vue +10 -39
  221. package/src/v2/components/chat/CopilotPopupViewInternal.vue +49 -185
  222. package/src/v2/components/chat/CopilotSidebar.vue +23 -25
  223. package/src/v2/components/chat/CopilotSidebarView.vue +10 -39
  224. package/src/v2/components/chat/CopilotSidebarViewInternal.vue +56 -100
  225. package/src/v2/components/chat/CopilotThreadsDrawer.vue +43 -105
  226. package/src/v2/components/chat/StreamingMarkdownDefault.vue +15 -28
  227. package/src/v2/components/chat/__tests__/CopilotChat.labels.test.ts +19 -4
  228. package/src/v2/components/chat/__tests__/CopilotChat.test.ts +12 -10
  229. package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.ts +26 -9
  230. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.learningFeedback.test.ts +5 -5
  231. package/src/v2/components/chat/__tests__/CopilotChatAttachmentQueue.test.ts +28 -0
  232. package/src/v2/components/chat/__tests__/CopilotChatInput.test.ts +132 -1
  233. package/src/v2/components/chat/__tests__/CopilotChatMessageView.test.ts +247 -403
  234. package/src/v2/components/chat/__tests__/CopilotChatMessageView.toolCallDisplay.test.ts +1 -99
  235. package/src/v2/components/chat/__tests__/CopilotChatView.pinToSend.test.ts +43 -1
  236. package/src/v2/components/chat/__tests__/CopilotPopup.test.ts +90 -1
  237. package/src/v2/components/chat/__tests__/CopilotPopupView.test.ts +19 -0
  238. package/src/v2/components/chat/__tests__/CopilotSidebar.test.ts +90 -1
  239. package/src/v2/components/chat/__tests__/CopilotSidebarView.position.test.ts +32 -8
  240. package/src/v2/components/chat/__tests__/CopilotSidebarView.test.ts +2 -1
  241. package/src/v2/components/chat/__tests__/StreamingMarkdownDefault.test.ts +54 -0
  242. package/src/v2/components/chat/audioRecorder.ts +4 -7
  243. package/src/v2/components/chat/copilotChatToolCallItemRender.ts +25 -90
  244. package/src/v2/components/chat/forwarded-slots.ts +17 -0
  245. package/src/v2/components/chat/index.ts +0 -1
  246. package/src/v2/components/chat/inspector-shortcuts.ts +10 -16
  247. package/src/v2/components/chat/message-feedback.ts +92 -195
  248. package/src/v2/components/chat/tool-call-display-context.ts +6 -22
  249. package/src/v2/components/chat/tool-call-group-parts.ts +47 -108
  250. package/src/v2/components/chat/turn-work.ts +0 -9
  251. package/src/v2/components/chat/types.ts +12 -4
  252. package/src/v2/components/chat/use-chat-labels.ts +16 -0
  253. package/src/v2/components/chat/use-copy-feedback.ts +21 -0
  254. package/src/v2/components/chat/use-lightbox.ts +15 -33
  255. package/src/v2/components/icons/__tests__/icons.test.ts +72 -68
  256. package/src/v2/components/icons/index.ts +109 -27
  257. package/src/v2/hooks/__tests__/use-agent-error-state.test.ts +5 -3
  258. package/src/v2/hooks/__tests__/use-agent-stability.test.ts +25 -4
  259. package/src/v2/hooks/__tests__/use-agent-throttle.test.ts +5 -1
  260. package/src/v2/hooks/__tests__/use-agent.test.ts +6 -3
  261. package/src/v2/hooks/__tests__/use-component.test.ts +21 -0
  262. package/src/v2/hooks/__tests__/use-configure-suggestions.test.ts +30 -1
  263. package/src/v2/hooks/__tests__/use-default-render-tool.test.ts +10 -10
  264. package/src/v2/hooks/__tests__/use-frontend-tool.e2e.test.ts +66 -1
  265. package/src/v2/hooks/__tests__/use-human-in-the-loop.e2e.test.ts +6 -1
  266. package/src/v2/hooks/__tests__/use-human-in-the-loop.test.ts +187 -12
  267. package/src/v2/hooks/__tests__/use-interrupt.test.ts +97 -0
  268. package/src/v2/hooks/__tests__/use-render-activity-message.test.ts +106 -0
  269. package/src/v2/hooks/__tests__/use-render-tool.test.ts +3 -6
  270. package/src/v2/hooks/__tests__/use-threads.test.ts +48 -6
  271. package/src/v2/hooks/__tests__/zod-regression.test.ts +5 -4
  272. package/src/v2/hooks/use-agent-context.ts +4 -10
  273. package/src/v2/hooks/use-agent.ts +86 -290
  274. package/src/v2/hooks/use-attachments.ts +48 -168
  275. package/src/v2/hooks/use-capabilities.ts +2 -7
  276. package/src/v2/hooks/use-component.ts +7 -4
  277. package/src/v2/hooks/use-configure-suggestions.ts +29 -220
  278. package/src/v2/hooks/use-default-render-tool.ts +31 -152
  279. package/src/v2/hooks/use-frontend-tool.ts +15 -25
  280. package/src/v2/hooks/use-human-in-the-loop.ts +11 -80
  281. package/src/v2/hooks/use-interrupt.ts +29 -308
  282. package/src/v2/hooks/use-keyboard-height.ts +17 -40
  283. package/src/v2/hooks/use-pin-to-send.ts +15 -99
  284. package/src/v2/hooks/use-render-activity-message.ts +35 -57
  285. package/src/v2/hooks/use-render-custom-messages.ts +24 -88
  286. package/src/v2/hooks/use-render-tool.ts +2 -4
  287. package/src/v2/hooks/use-suggestions.ts +17 -36
  288. package/src/v2/hooks/use-threads.ts +49 -288
  289. package/src/v2/lib/__tests__/shallow-stable.test.ts +54 -0
  290. package/src/v2/lib/__tests__/vue-core-renderers.test.ts +42 -0
  291. package/src/v2/lib/processPartialHtml.ts +6 -21
  292. package/src/v2/lib/shallow-stable.ts +2 -16
  293. package/src/v2/lib/vue-core.ts +90 -85
  294. package/src/v2/providers/CopilotChatConfigurationProvider.vue +48 -186
  295. package/src/v2/providers/CopilotKitProvider.types.ts +12 -132
  296. package/src/v2/providers/CopilotKitProvider.vue +291 -641
  297. package/src/v2/providers/__tests__/CopilotChatConfigurationProvider.test.ts +22 -2
  298. package/src/v2/providers/__tests__/CopilotKitProvider.a2ui.test.ts +38 -2
  299. package/src/v2/providers/__tests__/CopilotKitProvider.config.test.ts +124 -0
  300. package/src/v2/providers/__tests__/CopilotKitProvider.headersAtSendTime.test.ts +3 -3
  301. package/src/v2/providers/__tests__/CopilotKitProvider.learning.test.ts +3 -1
  302. package/src/v2/providers/__tests__/CopilotKitProvider.sandboxFunctions.test.ts +4 -1
  303. package/src/v2/providers/__tests__/CopilotKitProvider.test.ts +88 -28
  304. package/src/v2/providers/chat-configuration-store-key.ts +9 -0
  305. package/src/v2/providers/markdown-renderer.ts +8 -2
  306. package/src/v2/providers/types.ts +3 -49
  307. package/src/v2/providers/use-inspector-thread-override.ts +22 -80
  308. package/src/v2/types/__tests__/defineToolCallRenderer.test.ts +28 -33
  309. package/src/v2/types/defineToolCallRenderer.ts +7 -6
  310. package/src/v2/types/human-in-the-loop.ts +8 -32
  311. package/src/v2/types/interrupt.ts +7 -31
  312. package/src/v2/types/vue-activity-message-renderer.ts +24 -15
  313. package/src/v2/types/vue-custom-message-renderer.ts +12 -16
  314. package/src/v2/types/vue-tool-call-renderer.ts +23 -38
  315. package/tsconfig.json +0 -1
  316. package/vite.config.ts +8 -5
  317. package/vitest.config.ts +12 -7
  318. package/dist/v2/components/chat/BasicMarkdown.vue.d.ts +0 -9
  319. package/dist/v2/components/chat/BasicMarkdown.vue.d.ts.map +0 -1
  320. package/dist/v2/components/chat/normalize-auto-scroll.d.ts +0 -3
  321. package/dist/v2/components/chat/normalize-auto-scroll.d.ts.map +0 -1
  322. package/dist/v2/components/chat/tool-call-layout.d.ts +0 -115
  323. package/dist/v2/components/chat/tool-call-layout.d.ts.map +0 -1
  324. package/dist/v2/lib/is-mobile-viewport.d.ts +0 -15
  325. package/dist/v2/lib/is-mobile-viewport.d.ts.map +0 -1
  326. package/dist/v2/lib/message-feedback.d.ts +0 -33
  327. package/dist/v2/lib/message-feedback.d.ts.map +0 -1
  328. package/dist/v2/lib/transcription-client.d.ts +0 -19
  329. package/dist/v2/lib/transcription-client.d.ts.map +0 -1
  330. package/src/v2/components/__tests__/A2UICatalogContext.test.ts +0 -63
  331. package/src/v2/components/a2ui/__tests__/A2UIRecoveryStates.test.ts +0 -175
  332. package/src/v2/components/chat/BasicMarkdown.vue +0 -160
  333. package/src/v2/components/chat/__tests__/BasicMarkdown.test.ts +0 -69
  334. package/src/v2/components/chat/__tests__/normalize-auto-scroll.test.ts +0 -39
  335. package/src/v2/components/chat/normalize-auto-scroll.ts +0 -17
  336. package/src/v2/components/chat/tool-call-layout.ts +0 -304
  337. package/src/v2/lib/__tests__/is-mobile-viewport.test.ts +0 -48
  338. package/src/v2/lib/__tests__/message-feedback.test.ts +0 -152
  339. package/src/v2/lib/__tests__/processPartialHtml.test.ts +0 -84
  340. package/src/v2/lib/__tests__/transcription-client.test.ts +0 -67
  341. package/src/v2/lib/is-mobile-viewport.ts +0 -23
  342. package/src/v2/lib/message-feedback.ts +0 -120
  343. package/src/v2/lib/transcription-client.ts +0 -151
@@ -1,20 +1,29 @@
1
1
  <script setup lang="ts">
2
2
  import {
3
3
  computed,
4
- nextTick,
5
4
  onBeforeUnmount,
6
5
  onMounted,
7
6
  ref,
8
7
  useAttrs,
9
8
  watch,
10
9
  } from "vue";
10
+ import {
11
+ ɵSIDEBAR_DEFAULT_WIDTH,
12
+ ɵSIDEBAR_TRANSITION_MS,
13
+ ɵcreateDockedSidebar,
14
+ ɵdimensionToCss,
15
+ ɵwatchElementWidth,
16
+ } from "@copilotkit/core";
17
+ import type { ɵDockedSidebar } from "@copilotkit/core";
11
18
  import { CopilotChatDefaultLabels } from "../../providers/types";
12
19
  import { useCopilotChatConfiguration } from "../../providers/useCopilotChatConfiguration";
13
20
  import CopilotChatToggleButton from "./CopilotChatToggleButton.vue";
14
21
  import CopilotChatView from "./CopilotChatView.vue";
15
22
  import CopilotModalHeader from "./CopilotModalHeader.vue";
23
+ import { forwardedSlotNames } from "./forwarded-slots";
16
24
  import type {
17
25
  CopilotChatFeatherSlotProps,
26
+ CopilotChatInterruptSlotProps,
18
27
  CopilotChatMessageViewSlotProps,
19
28
  CopilotChatScrollToBottomButtonSlotProps,
20
29
  CopilotChatScrollViewSlotProps,
@@ -28,9 +37,6 @@ import type {
28
37
 
29
38
  defineOptions({ inheritAttrs: false });
30
39
 
31
- const DEFAULT_SIDEBAR_WIDTH = 480;
32
- const SIDEBAR_TRANSITION_MS = 260;
33
-
34
40
  const props = withDefaults(
35
41
  defineProps<Omit<CopilotSidebarViewProps, "defaultOpen">>(),
36
42
  {
@@ -59,14 +65,22 @@ defineSlots<{
59
65
  "scroll-to-bottom-button"?: (
60
66
  props: CopilotChatScrollToBottomButtonSlotProps,
61
67
  ) => unknown;
68
+ interrupt?: (props: CopilotChatInterruptSlotProps) => unknown;
62
69
  input?: (props: CopilotSidebarWelcomeScreenInputSlotProps) => unknown;
63
70
  "suggestion-view"?: (
64
71
  props: CopilotSidebarWelcomeScreenSuggestionViewSlotProps,
65
72
  ) => unknown;
66
73
  "welcome-screen"?: (props: CopilotChatWelcomeScreenSlotProps) => unknown;
67
74
  "welcome-message"?: () => unknown;
75
+ // Any other slot goes to the chat view, as on CopilotChat.
76
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
77
+ [key: string]: ((props: any) => unknown) | undefined;
68
78
  }>();
69
79
 
80
+ // Slots this component renders itself. It passes every other slot to the
81
+ // chat view.
82
+ const OWN_SLOTS = ["header", "toggle-button"] as const;
83
+
70
84
  const emit = defineEmits<{
71
85
  "submit-message": [value: string];
72
86
  stop: [];
@@ -86,9 +100,8 @@ const config = useCopilotChatConfiguration();
86
100
 
87
101
  const sidebarRef = ref<HTMLElement | null>(null);
88
102
  const measuredSidebarWidth = ref<number | string>(
89
- props.width ?? DEFAULT_SIDEBAR_WIDTH,
103
+ props.width ?? ɵSIDEBAR_DEFAULT_WIDTH,
90
104
  );
91
- let resizeObserver: ResizeObserver | null = null;
92
105
 
93
106
  const isSidebarOpen = computed(() => config.value?.isModalOpen ?? false);
94
107
  const resolvedSidebarWidth = computed(
@@ -112,43 +125,23 @@ const asideAttrs = computed(() => {
112
125
  const asideStyle = computed(
113
126
  () =>
114
127
  ({
115
- "--sidebar-width": widthToCss(resolvedSidebarWidth.value),
128
+ "--sidebar-width": widthCss.value,
116
129
  paddingTop: "env(safe-area-inset-top)",
117
130
  paddingBottom: "env(safe-area-inset-bottom)",
118
131
  }) as Record<string, string>,
119
132
  );
120
- // The page makes room on the docked edge (desktop only).
121
- const bodyMarginStyle = computed(() => {
122
- const margin =
123
- props.position === "left" ? "margin-inline-start" : "margin-inline-end";
124
- return `
125
- @media (min-width: 768px) {
126
- body {
127
- ${margin}: ${widthToMargin(resolvedSidebarWidth.value)};
128
- transition: ${margin} ${SIDEBAR_TRANSITION_MS}ms ease;
129
- }
130
- }
131
- `;
132
- });
133
-
134
- function widthToCss(width: number | string): string {
135
- return typeof width === "number" ? `${width}px` : width;
136
- }
137
-
138
- function widthToMargin(width: number | string): string {
139
- return typeof width === "number" ? `${width}px` : width;
140
- }
141
-
142
- function updateMeasuredWidth() {
143
- if (props.width !== undefined || !sidebarRef.value) {
144
- return;
145
- }
133
+ const widthCss = computed(() =>
134
+ ɵdimensionToCss(resolvedSidebarWidth.value, ɵSIDEBAR_DEFAULT_WIDTH),
135
+ );
146
136
 
147
- const nextWidth = sidebarRef.value.getBoundingClientRect().width;
148
- if (nextWidth > 0) {
149
- measuredSidebarWidth.value = nextWidth;
150
- }
151
- }
137
+ // The page makes room on the docked edge (desktop only).
138
+ let dock: ɵDockedSidebar | undefined;
139
+ watch(
140
+ [isSidebarOpen, () => props.position, widthCss],
141
+ ([open, position, width]) => {
142
+ dock?.set({ open, position, width });
143
+ },
144
+ );
152
145
 
153
146
  function closeSidebar() {
154
147
  config.value?.setModalOpen?.(false);
@@ -223,46 +216,39 @@ const chatViewEventProps = computed(() => {
223
216
  return listeners;
224
217
  });
225
218
 
219
+ // Without a `width` prop, the page margin follows the width the CSS gives
220
+ // the sidebar.
226
221
  watch(
227
- () => props.width,
228
- (nextWidth) => {
229
- if (nextWidth !== undefined) {
230
- measuredSidebarWidth.value = nextWidth;
231
- return;
232
- }
233
- updateMeasuredWidth();
222
+ [sidebarRef, () => props.width],
223
+ ([element, width], _old, onCleanup) => {
224
+ if (width !== undefined || !element) return;
225
+ onCleanup(
226
+ ɵwatchElementWidth(element, (next) => {
227
+ measuredSidebarWidth.value = next;
228
+ }),
229
+ );
234
230
  },
231
+ { flush: "post" },
235
232
  );
236
233
 
237
- onMounted(async () => {
238
- await nextTick();
239
- updateMeasuredWidth();
240
-
241
- if (
242
- props.width !== undefined ||
243
- !sidebarRef.value ||
244
- typeof ResizeObserver === "undefined"
245
- ) {
246
- return;
247
- }
248
-
249
- resizeObserver = new ResizeObserver(() => {
250
- updateMeasuredWidth();
234
+ onMounted(() => {
235
+ dock = ɵcreateDockedSidebar(document, {
236
+ transitionMs: ɵSIDEBAR_TRANSITION_MS,
237
+ });
238
+ dock.set({
239
+ open: isSidebarOpen.value,
240
+ position: props.position,
241
+ width: widthCss.value,
251
242
  });
252
- resizeObserver.observe(sidebarRef.value);
253
243
  });
254
244
 
255
245
  onBeforeUnmount(() => {
256
- resizeObserver?.disconnect();
257
- resizeObserver = null;
246
+ dock?.dispose();
247
+ dock = undefined;
258
248
  });
259
249
  </script>
260
250
 
261
251
  <template>
262
- <component :is="'style'" v-if="isSidebarOpen">
263
- {{ bodyMarginStyle }}
264
- </component>
265
-
266
252
  <slot
267
253
  name="toggle-button"
268
254
  :is-open="isSidebarOpen"
@@ -317,42 +303,12 @@ onBeforeUnmount(() => {
317
303
  :on-finish-transcribe-with-audio="onFinishTranscribeWithAudio"
318
304
  v-bind="chatViewEventProps"
319
305
  >
320
- <template v-if="$slots['message-view']" #message-view="slotProps">
321
- <slot name="message-view" v-bind="slotProps" />
322
- </template>
323
-
324
- <template v-if="$slots['scroll-view']" #scroll-view="slotProps">
325
- <slot name="scroll-view" v-bind="slotProps" />
326
- </template>
327
-
328
- <template v-if="$slots.feather" #feather>
329
- <slot name="feather" />
330
- </template>
331
-
332
306
  <template
333
- v-if="$slots['scroll-to-bottom-button']"
334
- #scroll-to-bottom-button="slotProps"
307
+ v-for="slotName in forwardedSlotNames($slots, OWN_SLOTS)"
308
+ :key="slotName"
309
+ #[slotName]="slotProps"
335
310
  >
336
- <slot name="scroll-to-bottom-button" v-bind="slotProps" />
337
- </template>
338
-
339
- <template v-if="$slots.input" #input="slotProps">
340
- <slot name="input" v-bind="slotProps" />
341
- </template>
342
-
343
- <template
344
- v-if="$slots['suggestion-view']"
345
- #suggestion-view="slotProps"
346
- >
347
- <slot name="suggestion-view" v-bind="slotProps" />
348
- </template>
349
-
350
- <template v-if="$slots['welcome-screen']" #welcome-screen="slotProps">
351
- <slot name="welcome-screen" v-bind="slotProps" />
352
- </template>
353
-
354
- <template v-if="$slots['welcome-message']" #welcome-message>
355
- <slot name="welcome-message" />
311
+ <slot :name="slotName" v-bind="slotProps" />
356
312
  </template>
357
313
  </CopilotChatView>
358
314
  </div>
@@ -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,
@@ -22,7 +21,13 @@ import type {
22
21
  // lands and is published; declared locally here because the built element types
23
22
  // in this worktree predate it.
24
23
  type CollapseChangeDetail = { collapsed: boolean };
25
- import { DEFAULT_AGENT_ID } from "@copilotkit/shared";
24
+ import {
25
+ ɵcreateThreadsDrawerActions,
26
+ ɵgetThreadsDrawerElementProps,
27
+ ɵresolveAgentId,
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,18 +76,17 @@ 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
- const resolvedAgentId = computed(
85
- () => props.agentId ?? config.value?.agentId ?? DEFAULT_AGENT_ID,
85
+ const resolvedAgentId = computed(() =>
86
+ ɵresolveAgentId({
87
+ agentId: props.agentId,
88
+ chatAgentId: config.value?.agentId,
89
+ }),
86
90
  );
87
91
  const activeThreadId = computed(() => config.value?.threadId ?? null);
88
92
 
@@ -107,18 +111,8 @@ const threadsApi = useThreads({
107
111
  limit: () => props.limit,
108
112
  });
109
113
 
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
114
  const drawerThreads = computed(() =>
121
- threadsApi.threads.value.map(toDrawerThread),
115
+ threadsApi.threads.value.map(ɵtoDrawerThread),
122
116
  );
123
117
 
124
118
  // Client-only element registration (SSR-safe). The element module is imported
@@ -144,10 +138,15 @@ watchEffect(
144
138
  const el = elRef.value;
145
139
  if (!el) return;
146
140
  el.threads = drawerThreads.value;
147
- el.loading = threadsApi.isLoading.value || licensePending.value;
141
+ const elementProps = ɵgetThreadsDrawerElementProps({
142
+ loading: threadsApi.isLoading.value,
143
+ licensed: licensed.value,
144
+ licensePending: licensePending.value,
145
+ });
146
+ el.loading = elementProps.loading;
148
147
  el.error = threadsApi.listError.value?.message ?? null;
149
148
  el.activeThreadId = activeThreadId.value;
150
- el.licensed = licensed.value || licensePending.value;
149
+ el.licensed = elementProps.licensed;
151
150
  el.hasMore = threadsApi.hasMoreThreads.value;
152
151
  el.fetchingMore = threadsApi.isFetchingMoreThreads.value;
153
152
  // Dedicated fetch-more error channel: drives the element's inline
@@ -177,101 +176,40 @@ const unregisterDrawer = config.value?.registerDrawer?.();
177
176
  if (unregisterDrawer) onScopeDispose(unregisterDrawer);
178
177
 
179
178
  // --- 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
- }
179
+ // Core owns the drawer actions; they read the latest values at call time.
180
+ const actions = ɵcreateThreadsDrawerActions({
181
+ getThreads: () => threadsApi,
182
+ getConfig: () => config.value,
183
+ getCallbacks: () => ({
184
+ onThreadSelect: props.onThreadSelect,
185
+ onNewThread: props.onNewThread,
186
+ }),
187
+ getElement: () => elRef.value,
188
+ });
218
189
 
219
190
  function onThreadSelected(event: Event) {
220
191
  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?.();
192
+ actions.selectThread(threadId);
229
193
  }
194
+ const handleNewThread = actions.newThread;
230
195
  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
- );
196
+ actions.archive((event as CustomEvent<ArchiveDetail>).detail.threadId);
237
197
  }
238
198
  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
- );
199
+ actions.unarchive((event as CustomEvent<UnarchiveDetail>).detail.threadId);
245
200
  }
246
201
  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();
202
+ actions.remove((event as CustomEvent<DeleteDetail>).detail.threadId);
262
203
  }
204
+ const onFilterChange = actions.refetch;
263
205
  function onCollapseChange(event: Event) {
264
206
  const { collapsed } = (event as CustomEvent<CollapseChangeDetail>).detail;
265
207
  emit("collapse-change", collapsed);
266
208
  }
267
209
  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();
210
+ actions.retry((event as CustomEvent<RetryDetail>).detail.scope);
274
211
  }
212
+ const onLoadMore = actions.loadMore;
275
213
  function onOpenChange(event: Event) {
276
214
  const { open } = (event as CustomEvent<OpenChangeDetail>).detail;
277
215
  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
  });