@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
@@ -1,14 +1,28 @@
1
- import { computed, defineComponent, h, onBeforeUnmount, ref, watch } from "vue";
1
+ import {
2
+ defineComponent,
3
+ h,
4
+ onBeforeUnmount,
5
+ onMounted,
6
+ ref,
7
+ shallowRef,
8
+ watch,
9
+ } from "vue";
2
10
  import type { PropType } from "vue";
3
- import { z } from "zod";
4
- import { ToolCallStatus } from "@copilotkit/core";
11
+ import * as z from "zod";
5
12
  import {
6
- processPartialHtml,
7
- extractCompleteStyles,
8
- } from "../lib/processPartialHtml";
13
+ OPEN_GENERATIVE_UI_ACTIVITY_TYPE,
14
+ ToolCallStatus,
15
+ ɵOpenGenerativeUIController,
16
+ } from "@copilotkit/core";
17
+ import type {
18
+ GenerateSandboxedUiArgs,
19
+ OpenGenerativeUIContent,
20
+ } from "@copilotkit/core";
9
21
  import { useSandboxFunctions } from "../providers/SandboxFunctionsContext";
10
22
 
11
- export const OpenGenerativeUIActivityType = "open-generative-ui";
23
+ export type { GenerateSandboxedUiArgs, OpenGenerativeUIContent };
24
+
25
+ export const OpenGenerativeUIActivityType = OPEN_GENERATIVE_UI_ACTIVITY_TYPE;
12
26
 
13
27
  export const OpenGenerativeUIContentSchema = z.object({
14
28
  initialHeight: z.number().optional(),
@@ -21,11 +35,7 @@ export const OpenGenerativeUIContentSchema = z.object({
21
35
  jsFunctionsComplete: z.boolean().optional(),
22
36
  jsExpressions: z.array(z.string()).optional(),
23
37
  jsExpressionsComplete: z.boolean().optional(),
24
- });
25
-
26
- export type OpenGenerativeUIContent = z.infer<
27
- typeof OpenGenerativeUIContentSchema
28
- >;
38
+ }) satisfies z.ZodType<OpenGenerativeUIContent>;
29
39
 
30
40
  export const GenerateSandboxedUiArgsSchema = z.object({
31
41
  initialHeight: z.number().optional(),
@@ -34,68 +44,12 @@ export const GenerateSandboxedUiArgsSchema = z.object({
34
44
  html: z.string().optional(),
35
45
  jsFunctions: z.string().optional(),
36
46
  jsExpressions: z.array(z.string()).optional(),
37
- });
38
-
39
- export type GenerateSandboxedUiArgs = z.infer<
40
- typeof GenerateSandboxedUiArgsSchema
41
- >;
42
-
43
- function shouldFlushImmediately(
44
- previous: OpenGenerativeUIContent | null,
45
- next: OpenGenerativeUIContent,
46
- ): boolean {
47
- if (next.cssComplete && (!previous || !previous.cssComplete)) return true;
48
- if (next.htmlComplete) return true;
49
- if (next.generating === false) return true;
50
- if (next.jsFunctions && (!previous || !previous.jsFunctions)) return true;
51
- if (
52
- (next.jsExpressions?.length ?? 0) > (previous?.jsExpressions?.length ?? 0)
53
- )
54
- return true;
55
- if (next.html?.length && (!previous || !previous.html?.length)) return true;
56
- return false;
57
- }
58
-
59
- function ensureHead(html: string): string {
60
- if (/<head[\s>]/i.test(html)) return html;
61
- return `<head></head>${html}`;
62
- }
63
-
64
- function injectCssIntoHtml(html: string, css: string): string {
65
- const headCloseIdx = html.indexOf("</head>");
66
- if (headCloseIdx !== -1) {
67
- return (
68
- html.slice(0, headCloseIdx) +
69
- `<style>${css}</style>` +
70
- html.slice(headCloseIdx)
71
- );
72
- }
73
- return `<head><style>${css}</style></head>${html}`;
74
- }
75
-
76
- type SandboxInstance = {
77
- iframe: HTMLIFrameElement;
78
- promise: Promise<unknown>;
79
- run: (code: string | Function) => Promise<unknown>;
80
- destroy: () => void;
81
- };
82
-
83
- type WebsandboxModule = {
84
- create: (
85
- localApi: Record<string, unknown>,
86
- options: {
87
- frameContainer: HTMLElement;
88
- frameContent: string;
89
- allowAdditionalAttributes: string;
90
- },
91
- ) => SandboxInstance;
92
- };
93
-
94
- async function loadWebsandbox(): Promise<WebsandboxModule> {
95
- const mod = (await import("@jetbrains/websandbox")) as any;
96
- return (mod.default?.default ?? mod.default) as WebsandboxModule;
97
- }
47
+ }) satisfies z.ZodType<GenerateSandboxedUiArgs>;
98
48
 
49
+ /**
50
+ * Renders Open Generative UI content. The core controller throttles the
51
+ * content and runs the websandbox iframes inside the container div.
52
+ */
99
53
  export const OpenGenerativeUIRenderer = defineComponent({
100
54
  name: "OpenGenerativeUIRenderer",
101
55
  props: {
@@ -107,307 +61,32 @@ export const OpenGenerativeUIRenderer = defineComponent({
107
61
  setup(props) {
108
62
  const sandboxFunctions = useSandboxFunctions();
109
63
  const containerRef = ref<HTMLElement | null>(null);
110
- const throttledContent = ref<OpenGenerativeUIContent>(props.content);
111
- const latestContent = ref<OpenGenerativeUIContent>(props.content);
112
- const throttleTimer = ref<number | null>(null);
113
- const sandboxRef = ref<SandboxInstance | null>(null);
114
- const previewSandboxRef = ref<SandboxInstance | null>(null);
115
- const sandboxReady = ref(false);
116
- const previewReady = ref(false);
117
- const executedExpressionIndex = ref(0);
118
- const jsFunctionsInjected = ref(false);
119
- const pendingQueue = ref<string[]>([]);
120
-
121
- const localApi = computed(() => {
122
- const api: Record<string, unknown> = {};
123
- for (const fn of sandboxFunctions.value) {
124
- api[fn.name] = fn.handler;
125
- }
126
- return api;
64
+ const controller = new ɵOpenGenerativeUIController();
65
+ controller.setContent(props.content);
66
+ const state = shallowRef(controller.getState());
67
+ const unsubscribe = controller.subscribe(() => {
68
+ state.value = controller.getState();
127
69
  });
128
70
 
129
71
  watch(
130
72
  () => props.content,
131
- (next) => {
132
- latestContent.value = next;
133
- if (shouldFlushImmediately(throttledContent.value, next)) {
134
- if (throttleTimer.value !== null) {
135
- window.clearTimeout(throttleTimer.value);
136
- throttleTimer.value = null;
137
- }
138
- throttledContent.value = next;
139
- return;
140
- }
141
- if (throttleTimer.value === null) {
142
- throttleTimer.value = window.setTimeout(() => {
143
- throttledContent.value = latestContent.value;
144
- throttleTimer.value = null;
145
- }, 1000);
146
- }
147
- },
148
- { immediate: true },
73
+ (content) => controller.setContent(content),
149
74
  );
150
-
151
- onBeforeUnmount(() => {
152
- if (throttleTimer.value !== null) {
153
- window.clearTimeout(throttleTimer.value);
154
- }
155
- });
156
-
157
- const partialHtml = computed(() => {
158
- if (throttledContent.value.htmlComplete) return undefined;
159
- if (!throttledContent.value.html?.length) return undefined;
160
- return throttledContent.value.html.join("");
161
- });
162
- const previewBody = computed(() =>
163
- partialHtml.value ? processPartialHtml(partialHtml.value) : undefined,
164
- );
165
- const previewStyles = computed(() =>
166
- partialHtml.value ? extractCompleteStyles(partialHtml.value) : "",
167
- );
168
- const fullHtml = computed(() =>
169
- throttledContent.value.htmlComplete && throttledContent.value.html?.length
170
- ? throttledContent.value.html.join("")
171
- : undefined,
172
- );
173
- const css = computed(() =>
174
- throttledContent.value.cssComplete
175
- ? throttledContent.value.css
176
- : undefined,
177
- );
178
- const hasPreview = computed(
179
- () =>
180
- !!throttledContent.value.cssComplete &&
181
- !!previewBody.value &&
182
- previewBody.value.trim().length > 0,
183
- );
184
- const hasVisibleSandbox = computed(
185
- () => !!fullHtml.value || hasPreview.value,
186
- );
187
- const resolvedHeight = computed(
188
- () => `${throttledContent.value.initialHeight ?? 200}px`,
189
- );
190
-
191
- const destroyPreview = () => {
192
- if (previewSandboxRef.value) {
193
- previewSandboxRef.value.destroy();
194
- previewSandboxRef.value = null;
195
- }
196
- previewReady.value = false;
197
- };
198
-
199
- const destroyFinal = () => {
200
- if (sandboxRef.value) {
201
- sandboxRef.value.destroy();
202
- sandboxRef.value = null;
203
- }
204
- sandboxReady.value = false;
205
- pendingQueue.value = [];
206
- executedExpressionIndex.value = 0;
207
- jsFunctionsInjected.value = false;
208
- };
209
-
210
75
  watch(
211
- [
212
- hasPreview,
213
- fullHtml,
214
- css,
215
- previewBody,
216
- previewStyles,
217
- () => containerRef.value,
218
- ],
219
- async ([previewVisible, htmlComplete], _previous, onCleanup) => {
220
- if (!previewVisible || htmlComplete || !containerRef.value) return;
221
- if (previewSandboxRef.value) return;
222
-
223
- let cancelled = false;
224
- try {
225
- const Websandbox = await loadWebsandbox();
226
- if (cancelled || !containerRef.value) return;
227
-
228
- const sandbox = Websandbox.create(
229
- {},
230
- {
231
- frameContainer: containerRef.value,
232
- frameContent: "<head></head><body></body>",
233
- allowAdditionalAttributes: "",
234
- },
235
- );
236
- previewSandboxRef.value = sandbox;
237
- sandbox.iframe.setAttribute(
238
- "data-testid",
239
- "open-generative-ui-preview-sandbox",
240
- );
241
- sandbox.iframe.style.width = "100%";
242
- sandbox.iframe.style.height = "100%";
243
- sandbox.iframe.style.border = "none";
244
- sandbox.iframe.style.backgroundColor = "transparent";
245
-
246
- sandbox.promise.then(() => {
247
- if (cancelled || !previewSandboxRef.value) return;
248
- previewReady.value = true;
249
- void sandbox.run(
250
- "var s=document.createElement('style');s.textContent='html, body { overflow: hidden !important; }';document.head.appendChild(s);",
251
- );
252
- });
253
- } catch (error) {
254
- console.error(
255
- "[OpenGenerativeUI] Failed to load sandbox module:",
256
- error,
257
- );
258
- }
259
-
260
- onCleanup(() => {
261
- cancelled = true;
262
- });
263
- },
264
- { immediate: true },
265
- );
266
-
267
- watch(
268
- [previewBody, previewStyles, css, previewReady],
269
- ([body, styles, cssText, ready]) => {
270
- if (!previewSandboxRef.value || !ready) return;
271
- const headParts: string[] = [];
272
- if (cssText) headParts.push(`<style>${cssText}</style>`);
273
- if (styles) headParts.push(styles);
274
- if (headParts.length) {
275
- void previewSandboxRef.value.run(
276
- `document.head.innerHTML = ${JSON.stringify(headParts.join(""))}`,
277
- );
278
- }
279
- if (body) {
280
- void previewSandboxRef.value.run(
281
- `document.body.innerHTML = ${JSON.stringify(body)}`,
282
- );
283
- }
284
- },
76
+ sandboxFunctions,
77
+ (functions) => controller.setSandboxFunctions(functions),
285
78
  { immediate: true },
286
79
  );
287
-
288
- watch(
289
- [fullHtml, css, localApi, () => containerRef.value],
290
- async ([html, cssText, api], _previous, onCleanup) => {
291
- destroyFinal();
292
- if (!html || !containerRef.value) return;
293
- destroyPreview();
294
-
295
- let cancelled = false;
296
- try {
297
- const Websandbox = await loadWebsandbox();
298
- if (cancelled || !containerRef.value) return;
299
- const htmlWithHead = ensureHead(html);
300
- const htmlWithCss = cssText
301
- ? injectCssIntoHtml(htmlWithHead, cssText)
302
- : htmlWithHead;
303
- const sandbox = Websandbox.create(api, {
304
- frameContainer: containerRef.value,
305
- frameContent: htmlWithCss,
306
- allowAdditionalAttributes: "",
307
- });
308
- sandboxRef.value = sandbox;
309
- sandbox.iframe.setAttribute(
310
- "data-testid",
311
- "open-generative-ui-final-sandbox",
312
- );
313
- sandbox.iframe.style.width = "100%";
314
- sandbox.iframe.style.height = "100%";
315
- sandbox.iframe.style.border = "none";
316
- sandbox.iframe.style.backgroundColor = "transparent";
317
-
318
- sandbox.promise.then(() => {
319
- if (cancelled || !sandboxRef.value) return;
320
- sandboxReady.value = true;
321
- void sandbox.run(
322
- "var s=document.createElement('style');s.textContent='html, body { overflow: hidden !important; }';document.head.appendChild(s);",
323
- );
324
- const functionsCode = throttledContent.value.jsFunctions;
325
- if (functionsCode && !jsFunctionsInjected.value) {
326
- jsFunctionsInjected.value = true;
327
- pendingQueue.value.unshift(functionsCode);
328
- }
329
- const expressions = throttledContent.value.jsExpressions;
330
- if (expressions?.length) {
331
- const startIndex = executedExpressionIndex.value;
332
- if (startIndex < expressions.length) {
333
- pendingQueue.value.push(...expressions.slice(startIndex));
334
- executedExpressionIndex.value = expressions.length;
335
- }
336
- }
337
- const queue = [...pendingQueue.value];
338
- pendingQueue.value = [];
339
- for (const code of queue) {
340
- void sandbox.run(code);
341
- }
342
- });
343
- } catch (error) {
344
- console.error(
345
- "[OpenGenerativeUI] Failed to load sandbox module:",
346
- error,
347
- );
348
- }
349
-
350
- onCleanup(() => {
351
- cancelled = true;
352
- });
353
- },
354
- { immediate: true },
355
- );
356
-
357
- watch(
358
- () => throttledContent.value.jsFunctions,
359
- (functionsCode) => {
360
- if (!functionsCode || jsFunctionsInjected.value) return;
361
- jsFunctionsInjected.value = true;
362
- if (sandboxReady.value && sandboxRef.value) {
363
- void sandboxRef.value.run(functionsCode);
364
- } else {
365
- pendingQueue.value.push(functionsCode);
366
- }
367
- },
368
- );
369
-
370
- watch(
371
- () => throttledContent.value.jsExpressions,
372
- (expressions) => {
373
- if (!expressions?.length) return;
374
- const startIndex = executedExpressionIndex.value;
375
- if (startIndex >= expressions.length) return;
376
- const newExpressions = expressions.slice(startIndex);
377
- executedExpressionIndex.value = expressions.length;
378
- if (sandboxReady.value && sandboxRef.value) {
379
- for (const expression of newExpressions) {
380
- void sandboxRef.value.run(expression);
381
- }
382
- } else {
383
- pendingQueue.value.push(...newExpressions);
384
- }
385
- },
386
- { deep: true },
387
- );
388
-
389
- const isGenerating = computed(
390
- () => throttledContent.value.generating !== false,
391
- );
392
- watch(
393
- [hasPreview, fullHtml],
394
- ([previewVisible, html]) => {
395
- if (html) destroyPreview();
396
- if (!previewVisible) destroyPreview();
397
- },
398
- { immediate: true },
399
- );
400
-
80
+ onMounted(() => controller.setHost(containerRef.value));
401
81
  onBeforeUnmount(() => {
402
- if (throttleTimer.value !== null) {
403
- window.clearTimeout(throttleTimer.value);
404
- }
405
- destroyPreview();
406
- destroyFinal();
82
+ unsubscribe();
83
+ controller.destroy();
407
84
  });
408
85
 
409
- return () =>
410
- h(
86
+ return () => {
87
+ const { phase, generating, height } = state.value;
88
+ const hasVisibleSandbox = phase !== "placeholder";
89
+ return h(
411
90
  "div",
412
91
  {
413
92
  ref: containerRef,
@@ -415,20 +94,18 @@ export const OpenGenerativeUIRenderer = defineComponent({
415
94
  style: {
416
95
  position: "relative",
417
96
  width: "100%",
418
- height: resolvedHeight.value,
97
+ height: `${height}px`,
419
98
  borderRadius: "8px",
420
- backgroundColor: hasVisibleSandbox.value
421
- ? "transparent"
422
- : "#f5f5f5",
423
- border: hasVisibleSandbox.value ? "none" : "1px solid #e0e0e0",
99
+ backgroundColor: hasVisibleSandbox ? "transparent" : "#f5f5f5",
100
+ border: hasVisibleSandbox ? "none" : "1px solid #e0e0e0",
424
101
  overflow: "hidden",
425
- display: hasVisibleSandbox.value ? "block" : "flex",
426
- alignItems: hasVisibleSandbox.value ? undefined : "center",
427
- justifyContent: hasVisibleSandbox.value ? undefined : "center",
102
+ display: hasVisibleSandbox ? "block" : "flex",
103
+ alignItems: hasVisibleSandbox ? undefined : "center",
104
+ justifyContent: hasVisibleSandbox ? undefined : "center",
428
105
  },
429
106
  },
430
107
  [
431
- !hasVisibleSandbox.value
108
+ !hasVisibleSandbox
432
109
  ? h("div", { "data-testid": "open-generative-ui-placeholder" }, [
433
110
  h(
434
111
  "svg",
@@ -461,7 +138,7 @@ export const OpenGenerativeUIRenderer = defineComponent({
461
138
  ),
462
139
  ])
463
140
  : null,
464
- isGenerating.value
141
+ generating
465
142
  ? h("div", {
466
143
  "data-testid": "open-generative-ui-progress-overlay",
467
144
  style: {
@@ -473,6 +150,7 @@ export const OpenGenerativeUIRenderer = defineComponent({
473
150
  : null,
474
151
  ],
475
152
  );
153
+ };
476
154
  },
477
155
  });
478
156
 
@@ -1,7 +1,7 @@
1
- import { readFileSync } from "node:fs";
2
1
  import { describe, expect, it } from "vitest";
3
2
  import { ref } from "vue";
4
3
  import { render, waitFor } from "@testing-library/vue";
4
+ import { stylesheet } from "@copilotkit/core/styles";
5
5
  import { createA2UIMessageRenderer } from "../A2UIMessageRenderer";
6
6
  import { CopilotKitKey } from "../../providers/keys";
7
7
 
@@ -173,16 +173,15 @@ describe("A2UI basic catalog colours", () => {
173
173
  );
174
174
  });
175
175
 
176
- it("sets the variables from the dark theme in the chat stylesheet", () => {
177
- const globalsCss = readFileSync("src/styles/globals.css", "utf8");
176
+ it("sets the variables from the dark theme in the injected stylesheet", () => {
178
177
  const darkBlock =
179
- globalsCss.match(
180
- /\.dark \[data-copilotkit\],\s*\[data-copilotkit\]\.dark \{([^}]*)\}/,
178
+ stylesheet.match(
179
+ /:where\(\.dark \[data-copilotkit\],\[data-copilotkit\]\.dark\)\{([^}]*)\}/,
181
180
  )?.[1] ?? "";
182
181
 
183
- expect(darkBlock).toContain("--a2ui-color-surface: var(--card);");
184
- expect(darkBlock).toContain("--a2ui-color-border: oklch(0.371 0 0);");
185
- expect(darkBlock).toContain("--a2ui-color-muted: var(--muted-foreground);");
186
- expect(darkBlock).toContain("--a2ui-color-error: #f87171;");
182
+ expect(darkBlock).toContain("--a2ui-color-surface: var(--card)");
183
+ expect(darkBlock).toContain("--a2ui-color-border: oklch(.371 0 0)");
184
+ expect(darkBlock).toContain("--a2ui-color-muted: var(--muted-foreground)");
185
+ expect(darkBlock).toContain("--a2ui-color-error: #f87171");
187
186
  });
188
187
  });
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { z } from "zod";
2
+ import { z } from "zod-v3";
3
3
  import { Catalog } from "@a2ui/web_core/v0_9";
4
4
  import type { ComponentApi } from "@a2ui/web_core/v0_9";
5
5
  import { buildCatalogContextValue } from "../a2ui/A2UICatalogContext";
@@ -22,52 +22,79 @@ function copilotKitProvide() {
22
22
  }
23
23
 
24
24
  describe("createA2UIMessageRenderer", () => {
25
- it("returns loading state when no operations exist", () => {
26
- const renderer = createA2UIMessageRenderer({ theme: {} });
27
- const { getByTestId } = render(renderer.render, {
28
- props: {
29
- activityType: "a2ui-surface",
30
- content: {},
31
- message: {},
32
- agent: {},
33
- },
25
+ const renderLifecycle = (
26
+ content: Record<string, unknown>,
27
+ options: Partial<Parameters<typeof createA2UIMessageRenderer>[0]> = {},
28
+ ) => {
29
+ const renderer = createA2UIMessageRenderer({ theme: {}, ...options });
30
+ return render(renderer.render, {
31
+ props: { activityType: "a2ui-surface", content, message: {}, agent: {} },
34
32
  });
35
- expect(getByTestId("a2ui-loading")).not.toBeNull();
33
+ };
34
+
35
+ it("shows the 'Building interface' skeleton while there are no operations", () => {
36
+ const { container } = renderLifecycle({});
37
+ expect(container.textContent).toContain("Building interface");
38
+ expect(container.textContent).not.toContain("Generating UI");
36
39
  });
37
40
 
38
- it("default loading fallback renders header dot, 'Generating UI...' label, and three pulsing skeleton bars", () => {
39
- const renderer = createA2UIMessageRenderer({ theme: {} });
40
- const { getByTestId, getAllByTestId, container } = render(renderer.render, {
41
- props: {
42
- activityType: "a2ui-surface",
43
- content: {},
44
- message: {},
45
- agent: {},
46
- },
41
+ it("shows the live token count while building", () => {
42
+ const { container } = renderLifecycle({
43
+ status: "building",
44
+ progressTokens: 97,
47
45
  });
46
+ expect(container.textContent).toContain("~97 tokens");
47
+ });
48
48
 
49
- const root = getByTestId("a2ui-loading");
50
- expect(root).not.toBeNull();
51
- expect((root as HTMLElement).textContent ?? "").toContain(
52
- "Generating UI...",
49
+ it("shows the retry state for status 'retrying'", () => {
50
+ const { container } = renderLifecycle({
51
+ status: "retrying",
52
+ attempt: 2,
53
+ maxAttempts: 3,
54
+ });
55
+ expect(container.textContent).toContain(
56
+ "Retrying generation… (2/3 attempts)",
53
57
  );
58
+ });
54
59
 
55
- const dot = getByTestId("a2ui-loading-dot") as HTMLElement;
56
- expect(dot.getAttribute("style") ?? "").toMatch(/cpk-a2ui-pulse/);
60
+ it("honours recovery.showAfterAttempts", () => {
61
+ const { container } = renderLifecycle(
62
+ { status: "retrying", attempt: 2, maxAttempts: 3 },
63
+ { recovery: { showAfterAttempts: 5, showAfterMs: 999999 } },
64
+ );
65
+ expect(container.textContent).toContain("Building interface");
66
+ expect(container.textContent).not.toContain("Retrying");
67
+ });
57
68
 
58
- const bars = getAllByTestId("a2ui-loading-bar") as HTMLElement[];
59
- expect(bars).toHaveLength(3);
69
+ it("shows the failure card for status 'failed', with details per recovery.debugExposure", () => {
70
+ const { container } = renderLifecycle(
71
+ { status: "failed", error: "boom", attempts: [] },
72
+ { recovery: { debugExposure: "hidden" } },
73
+ );
74
+ expect(
75
+ container.querySelector(".cpk-a2ui-recovery-failure")?.textContent,
76
+ ).toContain("Couldn't generate the UI");
77
+ expect(container.querySelector("details")).toBeNull();
78
+ });
60
79
 
61
- const widthMatches = bars.map((bar) => {
62
- const style = bar.getAttribute("style") ?? "";
63
- const match = style.match(/width:\s*([\d.]+)%/);
64
- expect(style).toMatch(/cpk-a2ui-pulse/);
65
- return match ? Number(match[1]) : null;
66
- });
67
- expect(widthMatches).toEqual([80, 60, 40]);
80
+ it("lets a server-stamped debugExposure win over the option", () => {
81
+ const { container } = renderLifecycle(
82
+ { status: "failed", error: "boom", debugExposure: "verbose" },
83
+ { recovery: { debugExposure: "hidden" } },
84
+ );
85
+ expect(container.querySelector("details")?.hasAttribute("open")).toBe(true);
86
+ });
68
87
 
69
- const styleTag = container.querySelector("style");
70
- expect(styleTag?.textContent ?? "").toContain("@keyframes cpk-a2ui-pulse");
88
+ it("shows the failure card instead of a custom loading component", () => {
89
+ const CustomLoading = defineComponent({
90
+ setup: () => () => h("div", { "data-testid": "custom-loading" }),
91
+ });
92
+ const { container, queryByTestId } = renderLifecycle(
93
+ { status: "failed" },
94
+ { loadingComponent: CustomLoading },
95
+ );
96
+ expect(queryByTestId("custom-loading")).toBeNull();
97
+ expect(container.textContent).toContain("Couldn't generate the UI");
71
98
  });
72
99
 
73
100
  it("renders custom loading component when provided", () => {
@@ -20,4 +20,24 @@ describe("LicenseWarningBanner", () => {
20
20
 
21
21
  expect(wrapper.find("button").exists()).toBe(false);
22
22
  });
23
+
24
+ it("says the license expires soon when the day count is unknown", () => {
25
+ const wrapper = mount(LicenseWarningBanner, {
26
+ props: { type: "expiring" },
27
+ });
28
+
29
+ expect(wrapper.get("span").text()).toBe(
30
+ "Your CopilotKit license expires soon. Please renew.",
31
+ );
32
+ });
33
+
34
+ it("counts the days left before the license expires", () => {
35
+ const wrapper = mount(LicenseWarningBanner, {
36
+ props: { type: "expiring", graceRemaining: 1 },
37
+ });
38
+
39
+ expect(wrapper.get("span").text()).toBe(
40
+ "Your CopilotKit license expires in 1 day. Please renew.",
41
+ );
42
+ });
23
43
  });