@copilotkit/vue 2.0.0-rc.1 → 2.0.0-rc.11

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 (317) hide show
  1. package/PARITY.md +13 -12
  2. package/README.md +1 -2
  3. package/dist/components/copilot-provider/CopilotKit.vue.d.ts +3 -1
  4. package/dist/components/copilot-provider/CopilotKit.vue.d.ts.map +1 -1
  5. package/dist/hooks/use-copilot-action.d.ts.map +1 -1
  6. package/dist/hooks/use-frontend-tool.d.ts +1 -1
  7. package/dist/hooks/use-frontend-tool.d.ts.map +1 -1
  8. package/dist/hooks/zod-parameters.d.ts +14 -0
  9. package/dist/hooks/zod-parameters.d.ts.map +1 -0
  10. package/dist/index.cjs +1 -76
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.mjs +384 -14275
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/use-render-activity-message-2np7y4Qt.cjs +92 -0
  15. package/dist/use-render-activity-message-2np7y4Qt.cjs.map +1 -0
  16. package/dist/use-render-activity-message-D59E9t0x.js +18097 -0
  17. package/dist/use-render-activity-message-D59E9t0x.js.map +1 -0
  18. package/dist/v2/components/A2UIMessageRenderer.d.ts +7 -0
  19. package/dist/v2/components/A2UIMessageRenderer.d.ts.map +1 -1
  20. package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts.map +1 -1
  21. package/dist/v2/components/LicenseWarningBanner.vue.d.ts.map +1 -1
  22. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts +13 -45
  23. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts.map +1 -1
  24. package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts +11 -2
  25. package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts.map +1 -1
  26. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts +1 -1
  27. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts.map +1 -1
  28. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts +144 -0
  29. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts.map +1 -0
  30. package/dist/v2/components/a2ui.d.ts +3 -7
  31. package/dist/v2/components/a2ui.d.ts.map +1 -1
  32. package/dist/v2/components/chat/CopilotChat.vue.d.ts +1 -0
  33. package/dist/v2/components/chat/CopilotChat.vue.d.ts.map +1 -1
  34. package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts +3 -1
  35. package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts.map +1 -1
  36. package/dist/v2/components/chat/CopilotChatAssistantToolbarButton.vue.d.ts +16 -0
  37. package/dist/v2/components/chat/CopilotChatAssistantToolbarButton.vue.d.ts.map +1 -0
  38. package/dist/v2/components/chat/CopilotChatAttachmentQueue.vue.d.ts.map +1 -1
  39. package/dist/v2/components/chat/CopilotChatAttachmentRenderer.vue.d.ts.map +1 -1
  40. package/dist/v2/components/chat/CopilotChatAudioRecorder.vue.d.ts.map +1 -1
  41. package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts +22 -0
  42. package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts.map +1 -0
  43. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts +21 -232
  44. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts.map +1 -1
  45. package/dist/v2/components/chat/CopilotChatInspectorButton.vue.d.ts +12 -0
  46. package/dist/v2/components/chat/CopilotChatInspectorButton.vue.d.ts.map +1 -0
  47. package/dist/v2/components/chat/CopilotChatLightbox.vue.d.ts +22 -0
  48. package/dist/v2/components/chat/CopilotChatLightbox.vue.d.ts.map +1 -0
  49. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts +20 -0
  50. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts.map +1 -1
  51. package/dist/v2/components/chat/CopilotChatReasoningMessage.vue.d.ts.map +1 -1
  52. package/dist/v2/components/chat/CopilotChatSuggestionPill.vue.d.ts.map +1 -1
  53. package/dist/v2/components/chat/CopilotChatSuggestionView.vue.d.ts.map +1 -1
  54. package/dist/v2/components/chat/CopilotChatToggleButton.vue.d.ts.map +1 -1
  55. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts +32 -0
  56. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts.map +1 -0
  57. package/dist/v2/components/chat/CopilotChatToolCallItem.vue.d.ts.map +1 -1
  58. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts +11 -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 +1 -0
  62. package/dist/v2/components/chat/CopilotChatView.vue.d.ts.map +1 -1
  63. package/dist/v2/components/chat/CopilotChatWorkSummary.vue.d.ts +5 -0
  64. package/dist/v2/components/chat/CopilotChatWorkSummary.vue.d.ts.map +1 -0
  65. package/dist/v2/components/chat/CopilotModalHeader.vue.d.ts.map +1 -1
  66. package/dist/v2/components/chat/CopilotModalHeaderCloseButton.d.ts.map +1 -1
  67. package/dist/v2/components/chat/CopilotModalHeaderTitle.d.ts.map +1 -1
  68. package/dist/v2/components/chat/CopilotPopup.vue.d.ts +1 -0
  69. package/dist/v2/components/chat/CopilotPopup.vue.d.ts.map +1 -1
  70. package/dist/v2/components/chat/CopilotPopupView.vue.d.ts +1 -0
  71. package/dist/v2/components/chat/CopilotPopupView.vue.d.ts.map +1 -1
  72. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts +1 -0
  73. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts.map +1 -1
  74. package/dist/v2/components/chat/CopilotPopupWelcomeScreen.vue.d.ts.map +1 -1
  75. package/dist/v2/components/chat/CopilotSidebar.vue.d.ts +2 -0
  76. package/dist/v2/components/chat/CopilotSidebar.vue.d.ts.map +1 -1
  77. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts +2 -0
  78. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts.map +1 -1
  79. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts +2 -0
  80. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts.map +1 -1
  81. package/dist/v2/components/chat/CopilotSidebarWelcomeScreen.vue.d.ts.map +1 -1
  82. package/dist/v2/components/chat/StreamingMarkdownDefault.vue.d.ts.map +1 -1
  83. package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts +0 -1
  84. package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts.map +1 -1
  85. package/dist/v2/components/chat/index.d.ts +17 -1
  86. package/dist/v2/components/chat/index.d.ts.map +1 -1
  87. package/dist/v2/components/chat/inspector-shortcuts.d.ts +12 -0
  88. package/dist/v2/components/chat/inspector-shortcuts.d.ts.map +1 -0
  89. package/dist/v2/components/chat/message-feedback.d.ts +89 -0
  90. package/dist/v2/components/chat/message-feedback.d.ts.map +1 -0
  91. package/dist/v2/components/chat/tool-call-capture.d.ts +39 -0
  92. package/dist/v2/components/chat/tool-call-capture.d.ts.map +1 -0
  93. package/dist/v2/components/chat/tool-call-display-context.d.ts +22 -0
  94. package/dist/v2/components/chat/tool-call-display-context.d.ts.map +1 -0
  95. package/dist/v2/components/chat/tool-call-group-parts.d.ts +131 -0
  96. package/dist/v2/components/chat/tool-call-group-parts.d.ts.map +1 -0
  97. package/dist/v2/components/chat/turn-work.d.ts +33 -0
  98. package/dist/v2/components/chat/turn-work.d.ts.map +1 -0
  99. package/dist/v2/components/chat/types.d.ts +104 -5
  100. package/dist/v2/components/chat/types.d.ts.map +1 -1
  101. package/dist/v2/components/chat/use-chat-labels.d.ts +8 -0
  102. package/dist/v2/components/chat/use-chat-labels.d.ts.map +1 -0
  103. package/dist/v2/components/chat/use-lightbox.d.ts +18 -0
  104. package/dist/v2/components/chat/use-lightbox.d.ts.map +1 -0
  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 +55 -0
  108. package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts.map +1 -0
  109. package/dist/v2/components/ui/CopilotPopover.vue.d.ts +40 -0
  110. package/dist/v2/components/ui/CopilotPopover.vue.d.ts.map +1 -0
  111. package/dist/v2/components/ui/CopilotTooltip.vue.d.ts +37 -0
  112. package/dist/v2/components/ui/CopilotTooltip.vue.d.ts.map +1 -0
  113. package/dist/v2/components/ui/dropdown-menu.d.ts +14 -0
  114. package/dist/v2/components/ui/dropdown-menu.d.ts.map +1 -0
  115. package/dist/v2/components/ui/floating.d.ts +84 -0
  116. package/dist/v2/components/ui/floating.d.ts.map +1 -0
  117. package/dist/v2/components/ui/presence.d.ts +9 -0
  118. package/dist/v2/components/ui/presence.d.ts.map +1 -0
  119. package/dist/v2/components/ui/use-id.d.ts +9 -0
  120. package/dist/v2/components/ui/use-id.d.ts.map +1 -0
  121. package/dist/v2/hooks/use-default-render-tool.d.ts +6 -0
  122. package/dist/v2/hooks/use-default-render-tool.d.ts.map +1 -1
  123. package/dist/v2/hooks/use-frontend-tool.d.ts +5 -0
  124. package/dist/v2/hooks/use-frontend-tool.d.ts.map +1 -1
  125. package/dist/v2/hooks/use-render-activity-message.d.ts +13 -9
  126. package/dist/v2/hooks/use-render-activity-message.d.ts.map +1 -1
  127. package/dist/v2/hooks/use-render-custom-messages.d.ts +5 -7
  128. package/dist/v2/hooks/use-render-custom-messages.d.ts.map +1 -1
  129. package/dist/v2/hooks/use-render-tool.d.ts +4 -0
  130. package/dist/v2/hooks/use-render-tool.d.ts.map +1 -1
  131. package/dist/v2/index.cjs +1 -1
  132. package/dist/v2/index.d.cts +3 -0
  133. package/dist/v2/index.d.mts +3 -0
  134. package/dist/v2/index.d.ts +3 -0
  135. package/dist/v2/index.d.ts.map +1 -1
  136. package/dist/v2/index.mjs +197 -197
  137. package/dist/v2/index.mjs.map +1 -1
  138. package/dist/v2/lib/message-feedback.d.ts +33 -0
  139. package/dist/v2/lib/message-feedback.d.ts.map +1 -0
  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/vue-core.d.ts +0 -1
  143. package/dist/v2/lib/vue-core.d.ts.map +1 -1
  144. package/dist/v2/providers/CopilotChatConfigurationProvider.vue.d.ts.map +1 -1
  145. package/dist/v2/providers/CopilotKitProvider.types.d.ts +56 -6
  146. package/dist/v2/providers/CopilotKitProvider.types.d.ts.map +1 -1
  147. package/dist/v2/providers/CopilotKitProvider.vue.d.ts +6 -2
  148. package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
  149. package/dist/v2/providers/index.d.ts +1 -1
  150. package/dist/v2/providers/index.d.ts.map +1 -1
  151. package/dist/v2/providers/keys.d.ts +8 -0
  152. package/dist/v2/providers/keys.d.ts.map +1 -1
  153. package/dist/v2/providers/types.d.ts +3 -37
  154. package/dist/v2/providers/types.d.ts.map +1 -1
  155. package/dist/v2/styles/CopilotKitStyles.d.ts +18 -0
  156. package/dist/v2/styles/CopilotKitStyles.d.ts.map +1 -0
  157. package/dist/v2/types/defineToolCallRenderer.d.ts +2 -0
  158. package/dist/v2/types/defineToolCallRenderer.d.ts.map +1 -1
  159. package/dist/v2/types/human-in-the-loop.d.ts +8 -29
  160. package/dist/v2/types/human-in-the-loop.d.ts.map +1 -1
  161. package/dist/v2/types/interrupt.d.ts +1 -22
  162. package/dist/v2/types/interrupt.d.ts.map +1 -1
  163. package/dist/v2/types/vue-activity-message-renderer.d.ts +16 -15
  164. package/dist/v2/types/vue-activity-message-renderer.d.ts.map +1 -1
  165. package/dist/v2/types/vue-custom-message-renderer.d.ts +7 -16
  166. package/dist/v2/types/vue-custom-message-renderer.d.ts.map +1 -1
  167. package/dist/v2/types/vue-tool-call-renderer.d.ts +16 -28
  168. package/dist/v2/types/vue-tool-call-renderer.d.ts.map +1 -1
  169. package/package.json +14 -27
  170. package/src/__tests__/build-entries.test.ts +27 -0
  171. package/src/components/copilot-provider/CopilotKit.vue +4 -1
  172. package/src/hooks/__tests__/zod-parameters.test.ts +520 -0
  173. package/src/hooks/use-copilot-action.ts +2 -1
  174. package/src/hooks/use-frontend-tool.ts +3 -6
  175. package/src/hooks/zod-parameters.ts +162 -0
  176. package/src/v2/__tests__/exports.test.ts +4 -2
  177. package/src/v2/components/A2UIMessageRenderer.ts +56 -68
  178. package/src/v2/components/A2UISurfaceActivityRenderer.vue +11 -23
  179. package/src/v2/components/LicenseWarningBanner.vue +31 -15
  180. package/src/v2/components/OpenGenerativeUIRenderer.ts +51 -373
  181. package/src/v2/components/__tests__/A2UIBasicCatalogColors.test.ts +8 -9
  182. package/src/v2/components/__tests__/A2UICatalogContext.test.ts +1 -1
  183. package/src/v2/components/__tests__/A2UIMessageRenderer.test.ts +63 -36
  184. package/src/v2/components/__tests__/LicenseWarningBanner.test.ts +20 -0
  185. package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.ts +55 -6
  186. package/src/v2/components/a2ui/A2UIBuiltInToolCallRenderer.ts +15 -258
  187. package/src/v2/components/a2ui/A2UICatalogContext.ts +10 -102
  188. package/src/v2/components/a2ui/A2UIRecoveryStates.ts +444 -0
  189. package/src/v2/components/a2ui/__tests__/A2UIRecoveryStates.test.ts +175 -0
  190. package/src/v2/components/a2ui.ts +1 -1
  191. package/src/v2/components/chat/CopilotChat.vue +26 -40
  192. package/src/v2/components/chat/CopilotChatAssistantMessage.vue +267 -67
  193. package/src/v2/components/chat/CopilotChatAssistantToolbarButton.vue +46 -0
  194. package/src/v2/components/chat/CopilotChatAttachmentQueue.vue +150 -173
  195. package/src/v2/components/chat/CopilotChatAttachmentRenderer.vue +77 -20
  196. package/src/v2/components/chat/CopilotChatAudioRecorder.vue +2 -2
  197. package/src/v2/components/chat/CopilotChatFeedbackCommentPopover.vue +240 -0
  198. package/src/v2/components/chat/CopilotChatInput.vue +250 -191
  199. package/src/v2/components/chat/CopilotChatInspectorButton.vue +331 -0
  200. package/src/v2/components/chat/CopilotChatLightbox.vue +105 -0
  201. package/src/v2/components/chat/CopilotChatMessageView.vue +262 -87
  202. package/src/v2/components/chat/CopilotChatReasoningMessage.vue +52 -35
  203. package/src/v2/components/chat/CopilotChatSuggestionPill.vue +5 -14
  204. package/src/v2/components/chat/CopilotChatSuggestionView.vue +1 -4
  205. package/src/v2/components/chat/CopilotChatToggleButton.vue +3 -9
  206. package/src/v2/components/chat/CopilotChatToggleButtonCloseIcon.ts +1 -1
  207. package/src/v2/components/chat/CopilotChatToggleButtonOpenIcon.ts +1 -1
  208. package/src/v2/components/chat/CopilotChatToolCallGroup.vue +353 -0
  209. package/src/v2/components/chat/CopilotChatToolCallItem.vue +24 -14
  210. package/src/v2/components/chat/CopilotChatToolCallsView.vue +194 -21
  211. package/src/v2/components/chat/CopilotChatUserMessage.vue +105 -42
  212. package/src/v2/components/chat/CopilotChatView.vue +37 -42
  213. package/src/v2/components/chat/CopilotChatWorkSummary.vue +111 -0
  214. package/src/v2/components/chat/CopilotModalHeader.vue +10 -8
  215. package/src/v2/components/chat/CopilotModalHeaderCloseButton.ts +7 -6
  216. package/src/v2/components/chat/CopilotModalHeaderTitle.ts +1 -4
  217. package/src/v2/components/chat/CopilotPopup.vue +3 -0
  218. package/src/v2/components/chat/CopilotPopupView.vue +1 -0
  219. package/src/v2/components/chat/CopilotPopupViewInternal.vue +9 -19
  220. package/src/v2/components/chat/CopilotPopupWelcomeScreen.vue +5 -8
  221. package/src/v2/components/chat/CopilotSidebar.vue +5 -0
  222. package/src/v2/components/chat/CopilotSidebarView.vue +2 -0
  223. package/src/v2/components/chat/CopilotSidebarViewInternal.vue +24 -17
  224. package/src/v2/components/chat/CopilotSidebarWelcomeScreen.vue +7 -10
  225. package/src/v2/components/chat/StreamingMarkdownDefault.vue +3 -5
  226. package/src/v2/components/chat/__tests__/CopilotChat.labels.test.ts +19 -4
  227. package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.ts +26 -9
  228. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.inspector.test.ts +269 -0
  229. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.learningFeedback.test.ts +760 -0
  230. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.slots.e2e.test.ts +3 -5
  231. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.test.ts +2 -2
  232. package/src/v2/components/chat/__tests__/CopilotChatInput.addMenu.test.ts +328 -0
  233. package/src/v2/components/chat/__tests__/CopilotChatInput.slots.e2e.test.ts +6 -3
  234. package/src/v2/components/chat/__tests__/CopilotChatInput.test.ts +55 -14
  235. package/src/v2/components/chat/__tests__/CopilotChatLightbox.test.ts +160 -0
  236. package/src/v2/components/chat/__tests__/CopilotChatMessageView.test.ts +247 -403
  237. package/src/v2/components/chat/__tests__/CopilotChatMessageView.toolCallDisplay.test.ts +637 -0
  238. package/src/v2/components/chat/__tests__/CopilotChatSuggestionPill.test.ts +1 -1
  239. package/src/v2/components/chat/__tests__/CopilotChatSuggestionView.slots.e2e.test.ts +3 -1
  240. package/src/v2/components/chat/__tests__/CopilotChatToolCallsView.learning.test.ts +75 -0
  241. package/src/v2/components/chat/__tests__/CopilotChatUserMessage.attachments.test.ts +143 -0
  242. package/src/v2/components/chat/__tests__/CopilotChatView.inputOverlay.test.ts +5 -4
  243. package/src/v2/components/chat/__tests__/CopilotChatView.rootWidth.test.ts +7 -33
  244. package/src/v2/components/chat/__tests__/CopilotModalHeader.slots.e2e.test.ts +1 -1
  245. package/src/v2/components/chat/__tests__/CopilotPopupView.slots.e2e.test.ts +3 -3
  246. package/src/v2/components/chat/__tests__/CopilotSidebarView.position.test.ts +126 -0
  247. package/src/v2/components/chat/__tests__/messageFeedbackDefaults.test.ts +33 -0
  248. package/src/v2/components/chat/__tests__/modalChatDisplayProps.test.ts +44 -0
  249. package/src/v2/components/chat/copilotChatToolCallItemRender.ts +3 -19
  250. package/src/v2/components/chat/index.ts +2 -1
  251. package/src/v2/components/chat/inspector-shortcuts.ts +34 -0
  252. package/src/v2/components/chat/message-feedback.ts +291 -0
  253. package/src/v2/components/chat/tool-call-capture.ts +55 -0
  254. package/src/v2/components/chat/tool-call-display-context.ts +28 -0
  255. package/src/v2/components/chat/tool-call-group-parts.ts +251 -0
  256. package/src/v2/components/chat/turn-work.ts +52 -0
  257. package/src/v2/components/chat/types.ts +114 -4
  258. package/src/v2/components/chat/use-chat-labels.ts +16 -0
  259. package/src/v2/components/chat/use-lightbox.ts +64 -0
  260. package/src/v2/components/icons/__tests__/icons.test.ts +72 -68
  261. package/src/v2/components/icons/index.ts +109 -23
  262. package/src/v2/components/ui/CopilotDropdownMenuContent.vue +465 -0
  263. package/src/v2/components/ui/CopilotPopover.vue +138 -0
  264. package/src/v2/components/ui/CopilotTooltip.vue +237 -0
  265. package/src/v2/components/ui/__tests__/CopilotTooltip.test.ts +168 -0
  266. package/src/v2/components/ui/dropdown-menu.ts +15 -0
  267. package/src/v2/components/ui/floating.ts +321 -0
  268. package/src/v2/components/ui/presence.ts +54 -0
  269. package/src/v2/components/ui/use-id.ts +16 -0
  270. package/src/v2/hooks/__tests__/use-frontend-tool.e2e.test.ts +62 -1
  271. package/src/v2/hooks/__tests__/use-render-activity-message.test.ts +105 -0
  272. package/src/v2/hooks/__tests__/use-render-tool.test.ts +3 -6
  273. package/src/v2/hooks/__tests__/zod-regression.test.ts +5 -4
  274. package/src/v2/hooks/use-default-render-tool.ts +123 -62
  275. package/src/v2/hooks/use-frontend-tool.ts +10 -10
  276. package/src/v2/hooks/use-render-activity-message.ts +27 -48
  277. package/src/v2/hooks/use-render-custom-messages.ts +14 -35
  278. package/src/v2/hooks/use-render-tool.ts +8 -0
  279. package/src/v2/index.ts +3 -0
  280. package/src/v2/lib/__tests__/message-feedback.test.ts +152 -0
  281. package/src/v2/lib/message-feedback.ts +120 -0
  282. package/src/v2/lib/processPartialHtml.ts +6 -21
  283. package/src/v2/lib/vue-core.ts +3 -5
  284. package/src/v2/providers/CopilotChatConfigurationProvider.vue +29 -2
  285. package/src/v2/providers/CopilotKitProvider.types.ts +57 -5
  286. package/src/v2/providers/CopilotKitProvider.vue +177 -114
  287. package/src/v2/providers/__tests__/CopilotChatConfigurationProvider.openThread.test.ts +69 -0
  288. package/src/v2/providers/__tests__/CopilotKitProvider.a2ui.test.ts +1 -1
  289. package/src/v2/providers/__tests__/CopilotKitProvider.headersAtSendTime.test.ts +3 -3
  290. package/src/v2/providers/__tests__/CopilotKitProvider.learning.test.ts +536 -0
  291. package/src/v2/providers/__tests__/CopilotKitProvider.test.ts +17 -33
  292. package/src/v2/providers/index.ts +4 -1
  293. package/src/v2/providers/keys.ts +12 -0
  294. package/src/v2/providers/types.ts +3 -38
  295. package/src/v2/styles/CopilotKitStyles.ts +95 -0
  296. package/src/v2/styles/__tests__/CopilotKitStyles.client.test.ts +149 -0
  297. package/src/v2/styles/__tests__/CopilotKitStyles.ssr.test.ts +71 -0
  298. package/src/v2/types/__tests__/defineToolCallRenderer.test.ts +28 -33
  299. package/src/v2/types/defineToolCallRenderer.ts +9 -4
  300. package/src/v2/types/human-in-the-loop.ts +8 -32
  301. package/src/v2/types/interrupt.ts +7 -31
  302. package/src/v2/types/vue-activity-message-renderer.ts +24 -15
  303. package/src/v2/types/vue-custom-message-renderer.ts +12 -16
  304. package/src/v2/types/vue-tool-call-renderer.ts +23 -31
  305. package/vite.config.ts +5 -5
  306. package/dist/styles.css +0 -2
  307. package/dist/v2/components/chat/BasicMarkdown.vue.d.ts +0 -9
  308. package/dist/v2/components/chat/BasicMarkdown.vue.d.ts.map +0 -1
  309. package/dist/v2/lib/transcription-client.d.ts +0 -19
  310. package/dist/v2/lib/transcription-client.d.ts.map +0 -1
  311. package/scripts/scope-preflight.mjs +0 -100
  312. package/src/styles/globals.css +0 -233
  313. package/src/v2/components/chat/BasicMarkdown.vue +0 -158
  314. package/src/v2/components/chat/__tests__/BasicMarkdown.test.ts +0 -69
  315. package/src/v2/lib/__tests__/processPartialHtml.test.ts +0 -84
  316. package/src/v2/lib/__tests__/transcription-client.test.ts +0 -67
  317. package/src/v2/lib/transcription-client.ts +0 -151
@@ -0,0 +1,637 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { defineComponent, h, nextTick, ref } from "vue";
3
+ import type { Ref } from "vue";
4
+ import { fireEvent, render, screen, within } from "@testing-library/vue";
5
+ import { z } from "zod";
6
+ import type { AssistantMessage, Message, ToolMessage } from "@ag-ui/core";
7
+ import CopilotKitProvider from "../../../providers/CopilotKitProvider.vue";
8
+ import CopilotChatConfigurationProvider from "../../../providers/CopilotChatConfigurationProvider.vue";
9
+ import { defineToolCallRenderer } from "../../../types";
10
+ import type { VueToolCallRenderer } from "../../../types";
11
+ import { useDefaultRenderTool } from "../../../hooks/use-default-render-tool";
12
+ import CopilotChatMessageView from "../CopilotChatMessageView.vue";
13
+ import CopilotChatToolCallsView from "../CopilotChatToolCallsView.vue";
14
+ import type { CopilotChatToolCallDisplay } from "@copilotkit/core";
15
+
16
+ // Ported from React's CopilotChatMessageView.toolCallDisplay tests.
17
+
18
+ const question: Message = { id: "u1", role: "user", content: "Why?" };
19
+
20
+ const callMessage = (id: string, name = "run_command"): AssistantMessage => ({
21
+ id: `m-${id}`,
22
+ role: "assistant",
23
+ content: "",
24
+ toolCalls: [
25
+ {
26
+ id,
27
+ type: "function",
28
+ function: { name, arguments: JSON.stringify({ command: `cmd ${id}` }) },
29
+ },
30
+ ],
31
+ });
32
+
33
+ const result = (id: string, error?: string): ToolMessage => ({
34
+ id: `r-${id}`,
35
+ role: "tool",
36
+ toolCallId: id,
37
+ content: "ok",
38
+ ...(error ? { error } : {}),
39
+ });
40
+
41
+ const say = (id: string, content: string): Message => ({
42
+ id,
43
+ role: "assistant",
44
+ content,
45
+ });
46
+
47
+ const weather = defineToolCallRenderer({
48
+ name: "weather",
49
+ args: z.object({}),
50
+ render: () => h("div", { "data-testid": "weather-card" }, "Weather"),
51
+ });
52
+
53
+ interface ViewState {
54
+ messages: Ref<Message[]>;
55
+ isRunning: Ref<boolean>;
56
+ toolCallDisplay: Ref<CopilotChatToolCallDisplay | undefined>;
57
+ }
58
+
59
+ /**
60
+ * Renders a message view inside the providers. Without `renderers`, the
61
+ * built-in card (`useDefaultRenderTool()`) draws every call but `weather`.
62
+ */
63
+ function renderView(
64
+ messages: Message[],
65
+ props: {
66
+ isRunning?: boolean;
67
+ toolCallDisplay?: CopilotChatToolCallDisplay;
68
+ } = {},
69
+ renderers?: VueToolCallRenderer<unknown>[],
70
+ slots: Record<string, (props: any) => unknown> = {},
71
+ ) {
72
+ const state: ViewState = {
73
+ messages: ref(messages),
74
+ isRunning: ref(props.isRunning ?? false),
75
+ toolCallDisplay: ref(props.toolCallDisplay),
76
+ };
77
+ const Harness = defineComponent({
78
+ setup() {
79
+ if (!renderers) useDefaultRenderTool();
80
+ return () =>
81
+ h(
82
+ CopilotChatMessageView,
83
+ {
84
+ messages: state.messages.value,
85
+ isRunning: state.isRunning.value,
86
+ toolCallDisplay: state.toolCallDisplay.value,
87
+ },
88
+ slots,
89
+ );
90
+ },
91
+ });
92
+ const rendered = render(CopilotKitProvider, {
93
+ props: { renderToolCalls: renderers ?? [weather] },
94
+ slots: {
95
+ default: () =>
96
+ h(
97
+ CopilotChatConfigurationProvider,
98
+ { threadId: "tool-call-display" },
99
+ { default: () => h(Harness) },
100
+ ),
101
+ },
102
+ });
103
+ return { ...rendered, state };
104
+ }
105
+
106
+ const firstButton = (element: HTMLElement) =>
107
+ within(element).getAllByRole("button")[0]!;
108
+
109
+ describe("CopilotChatMessageView toolCallDisplay", () => {
110
+ const burst = [
111
+ question,
112
+ callMessage("a"),
113
+ result("a"),
114
+ callMessage("b"),
115
+ result("b", "boom"),
116
+ say("t", "Done."),
117
+ ];
118
+
119
+ it("groups calls into one collapsed card by default", async () => {
120
+ renderView(burst);
121
+ const group = screen.getByTestId("copilot-tool-call-group");
122
+ expect(group.getAttribute("data-appearance")).toBe("card");
123
+ // The header comes first; the rows (closed, so inert) follow it.
124
+ const toggle = firstButton(group);
125
+ expect(toggle.getAttribute("aria-expanded")).toBe("false");
126
+ expect(toggle.getAttribute("aria-controls")).toBe(
127
+ group.querySelector(".cpk-collapsible")!.id,
128
+ );
129
+ expect(toggle.textContent).toContain("Used 2 tools");
130
+ expect(toggle.textContent).toContain("1 failed");
131
+
132
+ await fireEvent.click(toggle);
133
+ expect(toggle.getAttribute("aria-expanded")).toBe("true");
134
+ expect(within(group).getAllByTestId("copilot-tool-render")).toHaveLength(2);
135
+ });
136
+
137
+ it("names the running call while the group is still going", () => {
138
+ renderView([question, callMessage("a"), result("a"), callMessage("b")], {
139
+ isRunning: true,
140
+ });
141
+ const group = screen.getByTestId("copilot-tool-call-group");
142
+ expect(group.getAttribute("data-state")).toBe("running");
143
+ expect(group.textContent).toContain("Running run_command");
144
+ expect(group.textContent).toContain("1 done");
145
+ });
146
+
147
+ it("draws a lone call in the same card a group uses", async () => {
148
+ const { state } = renderView([question, callMessage("a")], {
149
+ isRunning: true,
150
+ });
151
+ const group = screen.getByTestId("copilot-tool-call-group");
152
+ const toggle = firstButton(group);
153
+ expect(toggle.getAttribute("aria-expanded")).toBe("false");
154
+ expect(toggle.textContent).toContain("Running run_command");
155
+ // Nothing has finished yet, so there's no count.
156
+ expect(toggle.textContent).not.toContain("done");
157
+
158
+ state.messages.value = [question, callMessage("a"), result("a")];
159
+ state.isRunning.value = false;
160
+ await nextTick();
161
+ expect(toggle.textContent).toContain("Used 1 tool");
162
+ expect(toggle.textContent).toContain("Done");
163
+ });
164
+
165
+ it("draws a lone call as the top card of a stack", () => {
166
+ renderView([question, callMessage("a"), result("a")], {
167
+ toolCallDisplay: "stacked",
168
+ });
169
+ const group = screen.getByTestId("copilot-tool-call-group");
170
+ const toggle = firstButton(group);
171
+ expect(toggle.textContent).toContain("run_command");
172
+ expect(toggle.textContent).toContain("1 call");
173
+ // The status icon is decorative; screen readers get the status as text.
174
+ expect(within(toggle).getByText("Done").classList).toContain(
175
+ "cpk-tool-call-group-stack-status",
176
+ );
177
+ });
178
+
179
+ it("announces a closed stack's status as it changes", async () => {
180
+ const { state } = renderView([question, callMessage("a")], {
181
+ toolCallDisplay: "stacked",
182
+ isRunning: true,
183
+ });
184
+ const group = screen.getByTestId("copilot-tool-call-group");
185
+ const live = group.querySelector('[aria-live="polite"]')!;
186
+ expect(live.textContent).toBe("run_command: Running");
187
+
188
+ state.messages.value = [question, callMessage("a"), result("a")];
189
+ state.isRunning.value = false;
190
+ await nextTick();
191
+ // Same region, new text: that's what gets announced.
192
+ expect(group.querySelector('[aria-live="polite"]')).toBe(live);
193
+ expect(live.textContent).toBe("run_command: Done");
194
+ });
195
+
196
+ it("opens a stack into the same compact cards, with Collapse", async () => {
197
+ renderView(burst, { toolCallDisplay: "stacked" });
198
+ const group = screen.getByTestId("copilot-tool-call-group");
199
+ await fireEvent.click(firstButton(group));
200
+ expect(within(group).getByText("Collapse")).toBeTruthy();
201
+ const statuses = within(group).getAllByTestId("copilot-tool-render-status");
202
+ expect(statuses).toHaveLength(2);
203
+ // Compact rows, not the standalone card with its status badge.
204
+ for (const status of statuses) {
205
+ expect(status.classList).toContain("cpk-tool-call-row-status");
206
+ }
207
+ });
208
+
209
+ it.each([
210
+ ["line", "line"],
211
+ ["stacked", "stack"],
212
+ ] as const)("draws %s groups", (display, appearance) => {
213
+ renderView(burst, { toolCallDisplay: display });
214
+ expect(
215
+ screen
216
+ .getByTestId("copilot-tool-call-group")
217
+ .getAttribute("data-appearance"),
218
+ ).toBe(appearance);
219
+ });
220
+
221
+ it("draws a finished lone call in line as its row, without a toggle", () => {
222
+ renderView([question, callMessage("a"), result("a")], {
223
+ toolCallDisplay: "line",
224
+ });
225
+ const group = screen.getByTestId("copilot-tool-call-group");
226
+ expect(group.classList).toContain("cpk-tool-call-group-single");
227
+ expect(
228
+ within(group).getByTestId("copilot-tool-render").classList,
229
+ ).toContain("cpk-tool-call-row-line");
230
+ });
231
+
232
+ it("gives every call its own card with separate", () => {
233
+ renderView(burst, { toolCallDisplay: "separate" });
234
+ expect(screen.queryByTestId("copilot-tool-call-group")).toBeNull();
235
+ const cards = screen.getAllByTestId("copilot-tool-render");
236
+ expect(cards).toHaveLength(2);
237
+ expect(cards[0]!.classList).toContain("cpk-default-tool-call");
238
+ });
239
+
240
+ it("keeps calls with their own renderer visible and outside the group", () => {
241
+ renderView([
242
+ question,
243
+ callMessage("a"),
244
+ callMessage("w", "weather"),
245
+ callMessage("b"),
246
+ ]);
247
+ expect(screen.getByTestId("weather-card")).toBeDefined();
248
+ expect(screen.getAllByTestId("copilot-tool-call-group")).toHaveLength(2);
249
+ });
250
+
251
+ it("keeps calls a tool-call slot draws on their own", () => {
252
+ renderView([question, callMessage("a"), callMessage("b")], {}, undefined, {
253
+ "tool-call-run_command": ({ name }: { name: string }) =>
254
+ h("div", { "data-testid": "slot-call" }, name),
255
+ });
256
+ expect(screen.queryByTestId("copilot-tool-call-group")).toBeNull();
257
+ expect(screen.getAllByTestId("slot-call")).toHaveLength(2);
258
+ });
259
+
260
+ it("lets the tool-calls-group slot replace a group", () => {
261
+ renderView(burst, {}, undefined, {
262
+ "tool-calls-group": ({
263
+ calls,
264
+ appearance,
265
+ renderCall,
266
+ }: {
267
+ calls: { toolCall: { id: string } }[];
268
+ appearance: string;
269
+ renderCall: (call: unknown) => unknown;
270
+ }) =>
271
+ h(
272
+ "section",
273
+ { "data-testid": "custom-group", "data-appearance": appearance },
274
+ [`${calls.length} calls`, ...calls.map((call) => renderCall(call))],
275
+ ),
276
+ });
277
+ expect(screen.queryByTestId("copilot-tool-call-group")).toBeNull();
278
+ const group = screen.getByTestId("custom-group");
279
+ expect(group.getAttribute("data-appearance")).toBe("card");
280
+ expect(group.textContent).toContain("2 calls");
281
+ // Calls drawn outside a group get the standalone card.
282
+ expect(within(group).getAllByTestId("copilot-tool-render")).toHaveLength(2);
283
+ });
284
+
285
+ it("folds a finished reply's work into the summary with turn", async () => {
286
+ renderView([question, say("t1", "Looking."), ...burst.slice(1)], {
287
+ toolCallDisplay: "turn",
288
+ });
289
+ const summary = screen.getByTestId("copilot-work-summary");
290
+ expect(summary.getAttribute("aria-expanded")).toBe("false");
291
+ // No timing for a reply this client didn't watch: it counts the tools.
292
+ expect(summary.textContent).toContain("Used 2 tools");
293
+ expect(summary.textContent).toContain("1 failed");
294
+ expect(
295
+ document.querySelector('[data-work-text="narration"]'),
296
+ ).not.toBeNull();
297
+ expect(document.querySelector('[data-work-text="reply"]')).not.toBeNull();
298
+ // The calls are rows of the work, not a group, and fold away with it.
299
+ expect(screen.queryByTestId("copilot-tool-call-group")).toBeNull();
300
+ const work = document.querySelector(".cpk-tool-calls-view-turn")!;
301
+ expect(work.hasAttribute("inert")).toBe(true);
302
+ expect(
303
+ within(work as HTMLElement).getAllByTestId("copilot-tool-render"),
304
+ ).toHaveLength(2);
305
+
306
+ await fireEvent.click(summary);
307
+ expect(summary.getAttribute("aria-expanded")).toBe("true");
308
+ expect(work.hasAttribute("inert")).toBe(false);
309
+ });
310
+
311
+ it("shows Working while the latest reply runs with turn", () => {
312
+ renderView([question], { toolCallDisplay: "turn", isRunning: true });
313
+ const summary = screen.getByTestId("copilot-work-summary");
314
+ expect(summary.getAttribute("data-state")).toBe("working");
315
+ expect(screen.queryByTestId("copilot-loading-cursor")).toBeNull();
316
+ });
317
+
318
+ it("shows the work in the open while the agent works on it with turn", async () => {
319
+ const { state } = renderView([question, say("t1", "Looking.")], {
320
+ toolCallDisplay: "turn",
321
+ isRunning: true,
322
+ });
323
+ state.messages.value = [...state.messages.value, callMessage("a")];
324
+ await nextTick();
325
+ const summary = screen.getByTestId("copilot-work-summary");
326
+ expect(summary.getAttribute("aria-expanded")).toBe("true");
327
+ expect(
328
+ document
329
+ .querySelector(".cpk-tool-calls-view-turn")!
330
+ .hasAttribute("inert"),
331
+ ).toBe(false);
332
+ expect(screen.getByTestId("copilot-tool-render").textContent).toContain(
333
+ "Running",
334
+ );
335
+
336
+ state.messages.value = [
337
+ ...state.messages.value,
338
+ result("a"),
339
+ say("t2", "Done."),
340
+ ];
341
+ state.isRunning.value = false;
342
+ await nextTick();
343
+ expect(summary.getAttribute("aria-expanded")).toBe("false");
344
+ expect(summary.getAttribute("data-state")).toBe("done");
345
+ });
346
+
347
+ it("lets the work-summary slot replace the summary line", async () => {
348
+ renderView(
349
+ [question, ...burst.slice(1)],
350
+ { toolCallDisplay: "turn" },
351
+ undefined,
352
+ {
353
+ "work-summary": (props: {
354
+ isOpen: boolean;
355
+ calls: unknown[];
356
+ onClick: () => void;
357
+ }) =>
358
+ h(
359
+ "button",
360
+ {
361
+ type: "button",
362
+ "data-testid": "custom-summary",
363
+ "aria-expanded": String(props.isOpen),
364
+ onClick: props.onClick,
365
+ },
366
+ `${props.calls.length} steps`,
367
+ ),
368
+ },
369
+ );
370
+ expect(screen.queryByTestId("copilot-work-summary")).toBeNull();
371
+ const summary = screen.getByTestId("custom-summary");
372
+ expect(summary.textContent).toBe("2 steps");
373
+
374
+ await fireEvent.click(summary);
375
+ expect(summary.getAttribute("aria-expanded")).toBe("true");
376
+ });
377
+
378
+ it("makes a closed group's rows inert", async () => {
379
+ renderView(burst);
380
+ const group = screen.getByTestId("copilot-tool-call-group");
381
+ const body = group.querySelector("[id]")!;
382
+ expect(body.hasAttribute("inert")).toBe(true);
383
+ await fireEvent.click(firstButton(group));
384
+ expect(body.hasAttribute("inert")).toBe(false);
385
+ });
386
+
387
+ it("keeps a reasoning message mounted when a later call makes it work", async () => {
388
+ const reasoning: Message = {
389
+ id: "r1",
390
+ role: "reasoning",
391
+ content: "Thinking about it.",
392
+ };
393
+ const { state } = renderView([question, reasoning], {
394
+ toolCallDisplay: "turn",
395
+ isRunning: true,
396
+ });
397
+ const reasoningNode = () =>
398
+ document.querySelector(".cpk-reasoning-message")!;
399
+ const node = reasoningNode();
400
+ expect(node).not.toBeNull();
401
+
402
+ state.messages.value = [question, reasoning, callMessage("a")];
403
+ await nextTick();
404
+ expect(reasoningNode()).toBe(node);
405
+ // It folds away with the work, which is open while the agent works.
406
+ expect(node.closest(".cpk-collapsible")!.hasAttribute("inert")).toBe(false);
407
+ });
408
+
409
+ it("leaves calls drawn by a custom catch-all on their own unless it opts in", () => {
410
+ const draw = ({ name }: { name: string }) =>
411
+ h("div", { "data-testid": "custom-call" }, name);
412
+ const quiet = defineToolCallRenderer({ name: "*", render: draw });
413
+ const messages = [question, callMessage("a"), callMessage("b")];
414
+
415
+ const { unmount } = renderView(messages, {}, [quiet]);
416
+ expect(screen.queryByTestId("copilot-tool-call-group")).toBeNull();
417
+ expect(screen.getAllByTestId("custom-call")).toHaveLength(2);
418
+ unmount();
419
+
420
+ renderView(messages, {}, [
421
+ defineToolCallRenderer({ name: "*", render: draw, group: true }),
422
+ ]);
423
+ expect(screen.getByTestId("copilot-tool-call-group")).toBeDefined();
424
+ });
425
+
426
+ it("tucks a single opted-in call into a closed group too", async () => {
427
+ const draw = ({ name }: { name: string }) =>
428
+ h("div", { "data-testid": "custom-call" }, name);
429
+ const grouped = defineToolCallRenderer({
430
+ name: "*",
431
+ render: draw,
432
+ group: true,
433
+ });
434
+ const messages = [question, callMessage("a"), result("a")];
435
+
436
+ // Grouped: a closed "Used 1 tool" card, like a bigger group.
437
+ const { unmount } = renderView(messages, {}, [grouped]);
438
+ const toggle = firstButton(screen.getByTestId("copilot-tool-call-group"));
439
+ expect(toggle.textContent).toContain("Used 1 tool");
440
+ expect(toggle.getAttribute("aria-expanded")).toBe("false");
441
+ unmount();
442
+
443
+ // Stacked: the call renders once the stack is opened.
444
+ renderView(messages, { toolCallDisplay: "stacked" }, [grouped]);
445
+ expect(screen.queryByTestId("custom-call")).toBeNull();
446
+ await fireEvent.click(
447
+ firstButton(screen.getByTestId("copilot-tool-call-group")),
448
+ );
449
+ expect(screen.getByTestId("custom-call").textContent).toBe("run_command");
450
+ });
451
+
452
+ it("shows a group the run left unfinished as stopped, not running", () => {
453
+ renderView([question, callMessage("a"), result("a"), callMessage("b")], {
454
+ isRunning: false,
455
+ });
456
+ const group = screen.getByTestId("copilot-tool-call-group");
457
+ expect(group.getAttribute("data-state")).toBe("stopped");
458
+ expect(group.textContent).not.toContain("Running");
459
+ expect(group.textContent).toContain("Stopped");
460
+ });
461
+
462
+ it("says how many calls failed instead of Done", () => {
463
+ renderView(burst);
464
+ const group = screen.getByTestId("copilot-tool-call-group");
465
+ expect(group.getAttribute("data-state")).toBe("failed");
466
+ const header = firstButton(group);
467
+ expect(header.textContent).toContain("1 failed");
468
+ expect(header.textContent).not.toContain("Done");
469
+ });
470
+
471
+ it("marks a failed row inside an open group", async () => {
472
+ renderView(burst);
473
+ const group = screen.getByTestId("copilot-tool-call-group");
474
+ await fireEvent.click(firstButton(group));
475
+ const rows = within(group).getAllByTestId("copilot-tool-render-status");
476
+ expect(rows.map((row) => row.textContent)).toEqual(["Done", "Failed"]);
477
+ });
478
+
479
+ it("keeps keyboard focus on the stack's toggle when it opens and closes", async () => {
480
+ renderView(burst, { toolCallDisplay: "stacked" });
481
+ const toggle = firstButton(screen.getByTestId("copilot-tool-call-group"));
482
+ toggle.focus();
483
+
484
+ await fireEvent.click(toggle);
485
+ expect(toggle.getAttribute("aria-expanded")).toBe("true");
486
+ expect(document.activeElement).toBe(toggle);
487
+ await fireEvent.click(toggle);
488
+ expect(toggle.getAttribute("aria-expanded")).toBe("false");
489
+ expect(document.activeElement).toBe(toggle);
490
+ });
491
+
492
+ it("opens a row to its arguments and result", async () => {
493
+ renderView(burst);
494
+ const group = screen.getByTestId("copilot-tool-call-group");
495
+ await fireEvent.click(firstButton(group));
496
+ const row = within(group).getAllByTestId("copilot-tool-render")[0]!;
497
+ const rowToggle = within(row).getByRole("button");
498
+ const details = document.getElementById(
499
+ rowToggle.getAttribute("aria-controls")!,
500
+ )!;
501
+ expect(details.hasAttribute("inert")).toBe(true);
502
+ await fireEvent.click(rowToggle);
503
+ expect(rowToggle.getAttribute("aria-expanded")).toBe("true");
504
+ expect(details.hasAttribute("inert")).toBe(false);
505
+ expect(details.textContent).toContain("Arguments");
506
+ expect(details.textContent).toContain("cmd a");
507
+ });
508
+ });
509
+
510
+ describe("CopilotChatMessageView toolCallDisplay turn answers", () => {
511
+ it("keeps the answer visible in turn when it shares a message with a call", () => {
512
+ const answer: AssistantMessage = {
513
+ ...callMessage("chart", "show_chart"),
514
+ content: "Revenue grew 12%.",
515
+ };
516
+ renderView([question, say("t1", "Looking."), answer], {
517
+ toolCallDisplay: "turn",
518
+ });
519
+ expect(
520
+ document
521
+ .querySelector('[data-message-id="t1"] [data-work-text]')!
522
+ .getAttribute("data-work-text"),
523
+ ).toBe("narration");
524
+ expect(
525
+ document
526
+ .querySelector(`[data-message-id="${answer.id}"] [data-work-text]`)!
527
+ .getAttribute("data-work-text"),
528
+ ).toBe("reply");
529
+ });
530
+ });
531
+
532
+ describe("CopilotChatWorkSummary timing", () => {
533
+ beforeEach(() => {
534
+ vi.useFakeTimers();
535
+ vi.setSystemTime(0);
536
+ });
537
+ afterEach(() => vi.useRealTimers());
538
+
539
+ const finished = [question, callMessage("a"), result("a"), say("t", "Done.")];
540
+ const summary = () => screen.getByTestId("copilot-work-summary").textContent;
541
+ const finish = async (state: ViewState, isRunning = false) => {
542
+ state.messages.value = finished;
543
+ state.isRunning.value = isRunning;
544
+ await nextTick();
545
+ };
546
+
547
+ it("ticks while working and reports the total once done", async () => {
548
+ const { state } = renderView([question], {
549
+ toolCallDisplay: "turn",
550
+ isRunning: true,
551
+ });
552
+ vi.advanceTimersByTime(125_000);
553
+ await nextTick();
554
+ expect(summary()).toContain("Working2m 5s");
555
+
556
+ vi.setSystemTime(65_000 + 60_000);
557
+ await finish(state);
558
+ expect(summary()).toContain("Worked for 2m 5s");
559
+ expect(summary()).toContain("1 tool");
560
+ });
561
+
562
+ it("reports a 65-second turn as 1m 5s", async () => {
563
+ const { state } = renderView([question], {
564
+ toolCallDisplay: "turn",
565
+ isRunning: true,
566
+ });
567
+ vi.setSystemTime(65_000);
568
+ await finish(state);
569
+ expect(summary()).toContain("Worked for 1m 5s");
570
+ });
571
+
572
+ it("leaves out time spent waiting between runs", async () => {
573
+ const { state } = renderView([question], {
574
+ toolCallDisplay: "turn",
575
+ isRunning: true,
576
+ });
577
+ vi.setSystemTime(5_000);
578
+ await finish(state);
579
+
580
+ vi.setSystemTime(185_000); // three minutes waiting on an approval
581
+ await finish(state, true);
582
+ vi.setSystemTime(190_000);
583
+ await finish(state);
584
+ expect(summary()).toContain("Worked for 10s");
585
+ });
586
+ });
587
+
588
+ describe("CopilotChatToolCallsView on its own", () => {
589
+ it("shows a call without a result as running, with no run state to say otherwise", () => {
590
+ const message: AssistantMessage = {
591
+ id: "standalone",
592
+ role: "assistant",
593
+ content: "",
594
+ toolCalls: [
595
+ ...callMessage("a").toolCalls!,
596
+ ...callMessage("b").toolCalls!,
597
+ ],
598
+ };
599
+ const Harness = defineComponent({
600
+ setup() {
601
+ useDefaultRenderTool();
602
+ return () =>
603
+ h(CopilotChatToolCallsView, { message, messages: [result("a")] });
604
+ },
605
+ });
606
+ render(CopilotKitProvider, { slots: { default: () => h(Harness) } });
607
+ const group = screen.getByTestId("copilot-tool-call-group");
608
+ expect(group.getAttribute("data-state")).toBe("running");
609
+ expect(group.textContent).toContain("Running run_command");
610
+ });
611
+
612
+ it("gives every call its own card with display separate", () => {
613
+ const message: AssistantMessage = {
614
+ id: "standalone",
615
+ role: "assistant",
616
+ content: "",
617
+ toolCalls: [
618
+ ...callMessage("a").toolCalls!,
619
+ ...callMessage("b").toolCalls!,
620
+ ],
621
+ };
622
+ const Harness = defineComponent({
623
+ setup() {
624
+ useDefaultRenderTool();
625
+ return () =>
626
+ h(CopilotChatToolCallsView, {
627
+ message,
628
+ messages: [],
629
+ display: "separate",
630
+ });
631
+ },
632
+ });
633
+ render(CopilotKitProvider, { slots: { default: () => h(Harness) } });
634
+ expect(screen.queryByTestId("copilot-tool-call-group")).toBeNull();
635
+ expect(screen.getAllByTestId("copilot-tool-render")).toHaveLength(2);
636
+ });
637
+ });
@@ -34,7 +34,7 @@ describe("CopilotChatSuggestionPill", () => {
34
34
  );
35
35
  expect(button.attributes("aria-busy")).toBe("true");
36
36
  expect(button.attributes("disabled")).toBeDefined();
37
- expect(wrapper.find(".cpk\\:animate-spin").exists()).toBe(true);
37
+ expect(wrapper.find(".cpk-suggestion-pill-spinner").exists()).toBe(true);
38
38
  });
39
39
 
40
40
  it("renders icon component when provided", () => {
@@ -88,7 +88,9 @@ describe("CopilotChatSuggestionView Slot System E2E Tests", () => {
88
88
  renderInWrapper(Host);
89
89
  const containerEl = document.querySelector(".custom-container-class");
90
90
  expect(containerEl).toBeTruthy();
91
- expect(containerEl?.classList.contains("cpk:flex-wrap")).toBe(true);
91
+ expect(containerEl?.classList.contains("cpk-suggestion-view")).toBe(
92
+ true,
93
+ );
92
94
  });
93
95
  });
94
96