@copilotkit/vue 2.0.0-rc.0 → 2.0.0-rc.10

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-CTR_ziWV.js +18097 -0
  15. package/dist/use-render-activity-message-CTR_ziWV.js.map +1 -0
  16. package/dist/use-render-activity-message-Dky9_GRG.cjs +92 -0
  17. package/dist/use-render-activity-message-Dky9_GRG.cjs.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,444 @@
1
+ import { defineComponent, h, onBeforeUnmount, ref, watch } from "vue";
2
+ import type { PropType, VNodeChild } from "vue";
3
+ import * as z from "zod";
4
+
5
+ /**
6
+ * Shared pre-paint lifecycle states for the A2UI surface renderer, ported from
7
+ * React's `A2UIRecoveryStates`.
8
+ *
9
+ * The A2UI middleware drives the WHOLE generative-UI lifecycle on a single
10
+ * `a2ui-surface` activity (one stable messageId, `replace: true`), so the states
11
+ * below swap IN PLACE and the painted surface ultimately replaces them:
12
+ *
13
+ * building → animated skeleton + "Building interface" (+ optional ~N tokens)
14
+ * retrying → same skeleton; once perceptible, the sub-label becomes
15
+ * "Retrying generation… (N/M attempts)" (threshold-gated so a fast
16
+ * transient retry never flashes), with debug detail per debugExposure
17
+ * failed → a clean hard-failure card (replacing the skeleton), developer
18
+ * detail tucked into an expander gated by debugExposure
19
+ * painted → the surface renderer owns the UI (these states render nothing)
20
+ *
21
+ * Timing (`showAfterMs` / `showAfterAttempts`) and how much debug detail to
22
+ * surface (`debugExposure`) are client concerns; the server can override
23
+ * `debugExposure` by stamping it onto the activity content (it wins over the
24
+ * client option).
25
+ */
26
+ export type A2UIRecoveryRendererOptions = {
27
+ /** Delay (ms) before the "Retrying…" sub-label becomes visible. Default 2000. */
28
+ showAfterMs?: number;
29
+ /** Show the "Retrying…" sub-label immediately once `attempt` reaches this. Default 2. */
30
+ showAfterAttempts?: number;
31
+ /** How much retry/debug detail to surface. Default "collapsed". */
32
+ debugExposure?: "hidden" | "collapsed" | "verbose";
33
+ };
34
+
35
+ export type DebugExposure = "hidden" | "collapsed" | "verbose";
36
+
37
+ /**
38
+ * The pre-paint lifecycle fields the middleware stamps onto the `a2ui-surface`
39
+ * activity content (alongside `a2ui_operations` on paint).
40
+ */
41
+ export const A2UILifecycleFields = {
42
+ status: z.enum(["building", "retrying", "failed"]).optional(),
43
+ attempt: z.number().optional(),
44
+ maxAttempts: z.number().optional(),
45
+ progressTokens: z.number().optional(),
46
+ error: z.string().optional(),
47
+ errors: z.array(z.any()).optional(),
48
+ attempts: z.array(z.any()).optional(),
49
+ // Server-side knob (stamped by the A2UI middleware).
50
+ debugExposure: z.enum(["hidden", "collapsed", "verbose"]).optional(),
51
+ };
52
+
53
+ /** Server-stamped debugExposure wins; else the client option. */
54
+ export function resolveDebugExposure(
55
+ content: any,
56
+ optionDebugExposure: DebugExposure,
57
+ ): DebugExposure {
58
+ return content?.debugExposure ?? optionDebugExposure;
59
+ }
60
+
61
+ const tokensOf = (content: any): number | undefined =>
62
+ typeof content?.progressTokens === "number"
63
+ ? content.progressTokens
64
+ : undefined;
65
+
66
+ // --- Skeleton + primitives ---------------------------------------------------
67
+
68
+ const dot = () =>
69
+ h("div", {
70
+ style: {
71
+ width: "7px",
72
+ height: "7px",
73
+ borderRadius: "50%",
74
+ backgroundColor: "#d4d4d8",
75
+ flexShrink: 0,
76
+ },
77
+ });
78
+
79
+ const spacer = () => h("div", { style: { width: "12px" } });
80
+
81
+ const bar = (
82
+ w: number,
83
+ ht: number,
84
+ bg: string,
85
+ anim?: number,
86
+ opacity?: number,
87
+ transition?: string,
88
+ ) =>
89
+ h("div", {
90
+ style: {
91
+ width: `${w}px`,
92
+ height: `${ht}px`,
93
+ borderRadius: "9999px",
94
+ backgroundColor: bg,
95
+ ...(anim !== undefined
96
+ ? {
97
+ animation: `cpk-a2ui-fade 2.4s ease-in-out ${anim}s infinite`,
98
+ }
99
+ : {}),
100
+ ...(opacity !== undefined ? { opacity } : {}),
101
+ ...(transition ? { transition } : {}),
102
+ },
103
+ });
104
+
105
+ const row = (show: boolean, delay: number, children: VNodeChild[]) =>
106
+ h(
107
+ "div",
108
+ {
109
+ style: {
110
+ display: "flex",
111
+ alignItems: "center",
112
+ gap: "6px",
113
+ opacity: show ? 1 : 0,
114
+ transition: `opacity 0.4s ${delay}s`,
115
+ },
116
+ },
117
+ children,
118
+ );
119
+
120
+ /**
121
+ * Animated wireframe skeleton with a label, an optional live token count, and
122
+ * optional debug detail below it. The `tokens` count drives a progressive
123
+ * reveal of skeleton rows.
124
+ */
125
+ export function renderA2UIGeneratingSkeleton(
126
+ label: string,
127
+ tokens?: number,
128
+ children?: VNodeChild[],
129
+ ): VNodeChild {
130
+ // No count yet → show the fuller skeleton rather than an empty box.
131
+ const phase =
132
+ tokens == null
133
+ ? 3
134
+ : tokens < 50
135
+ ? 0
136
+ : tokens < 200
137
+ ? 1
138
+ : tokens < 400
139
+ ? 2
140
+ : 3;
141
+
142
+ return h("div", { style: { margin: "12px 0", maxWidth: "320px" } }, [
143
+ h(
144
+ "div",
145
+ {
146
+ style: {
147
+ position: "relative",
148
+ overflow: "hidden",
149
+ borderRadius: "12px",
150
+ border: "1px solid rgba(228,228,231,0.8)",
151
+ backgroundColor: "#fff",
152
+ boxShadow: "0 1px 2px rgba(0,0,0,0.04)",
153
+ padding: "16px 18px 14px",
154
+ },
155
+ },
156
+ [
157
+ // Top bar
158
+ h(
159
+ "div",
160
+ {
161
+ style: {
162
+ display: "flex",
163
+ alignItems: "center",
164
+ gap: "8px",
165
+ marginBottom: "12px",
166
+ },
167
+ },
168
+ [
169
+ h("div", { style: { display: "flex", gap: "4px" } }, [
170
+ dot(),
171
+ dot(),
172
+ dot(),
173
+ ]),
174
+ bar(
175
+ 64,
176
+ 6,
177
+ "#e4e4e7",
178
+ undefined,
179
+ phase >= 1 ? 1 : 0.4,
180
+ "opacity 0.5s",
181
+ ),
182
+ ],
183
+ ),
184
+ // Skeleton lines
185
+ h("div", { style: { display: "grid", gap: "7px" } }, [
186
+ row(phase >= 0, 0, [
187
+ bar(36, 7, "rgba(147,197,253,0.7)", 0),
188
+ bar(80, 7, "rgba(219,234,254,0.8)", 0.2),
189
+ ]),
190
+ row(phase >= 0, 0.1, [
191
+ spacer(),
192
+ dot(),
193
+ bar(100, 7, "rgba(24,24,27,0.2)", 0.3),
194
+ ]),
195
+ row(phase >= 1, 0.15, [
196
+ spacer(),
197
+ bar(48, 7, "rgba(24,24,27,0.15)", 0.1),
198
+ bar(40, 7, "rgba(153,246,228,0.6)", 0.5),
199
+ bar(56, 7, "rgba(147,197,253,0.6)", 0.3),
200
+ ]),
201
+ row(phase >= 1, 0.2, [
202
+ spacer(),
203
+ dot(),
204
+ bar(60, 7, "rgba(24,24,27,0.15)", 0.4),
205
+ ]),
206
+ row(phase >= 2, 0.25, [
207
+ bar(40, 7, "rgba(153,246,228,0.5)", 0.2),
208
+ dot(),
209
+ bar(48, 7, "rgba(24,24,27,0.15)", 0.6),
210
+ bar(64, 7, "rgba(147,197,253,0.5)", 0.1),
211
+ ]),
212
+ row(phase >= 2, 0.3, [
213
+ bar(36, 7, "rgba(147,197,253,0.6)", 0.5),
214
+ bar(36, 7, "rgba(24,24,27,0.12)", 0.7),
215
+ ]),
216
+ row(phase >= 3, 0.35, [
217
+ dot(),
218
+ bar(44, 7, "rgba(24,24,27,0.18)", 0.3),
219
+ dot(),
220
+ bar(56, 7, "rgba(153,246,228,0.5)", 0.8),
221
+ bar(48, 7, "rgba(147,197,253,0.5)", 0.4),
222
+ ]),
223
+ ]),
224
+ // Shimmer
225
+ h("div", {
226
+ style: {
227
+ pointerEvents: "none",
228
+ position: "absolute",
229
+ inset: "0",
230
+ background:
231
+ "linear-gradient(105deg, transparent 0%, transparent 40%, rgba(255,255,255,0.6) 50%, transparent 60%, transparent 100%)",
232
+ backgroundSize: "250% 100%",
233
+ animation: "cpk-a2ui-sweep 3s ease-in-out infinite",
234
+ },
235
+ }),
236
+ ],
237
+ ),
238
+ // Label
239
+ h(
240
+ "div",
241
+ {
242
+ style: {
243
+ display: "flex",
244
+ alignItems: "center",
245
+ justifyContent: "center",
246
+ gap: "8px",
247
+ marginTop: "8px",
248
+ },
249
+ },
250
+ [
251
+ h(
252
+ "span",
253
+ {
254
+ style: {
255
+ fontSize: "12px",
256
+ color: "#a1a1aa",
257
+ letterSpacing: "0.025em",
258
+ },
259
+ },
260
+ label,
261
+ ),
262
+ ...(typeof tokens === "number" && tokens > 0
263
+ ? [
264
+ h(
265
+ "span",
266
+ {
267
+ style: {
268
+ fontSize: "11px",
269
+ color: "#d4d4d8",
270
+ fontVariantNumeric: "tabular-nums",
271
+ },
272
+ },
273
+ `~${tokens.toLocaleString()} tokens`,
274
+ ),
275
+ ]
276
+ : []),
277
+ ],
278
+ ),
279
+ ...(children ?? []),
280
+ // Keyframe styles
281
+ h(
282
+ "style",
283
+ `
284
+ @keyframes cpk-a2ui-fade {
285
+ 0%, 100% { opacity: 1; }
286
+ 50% { opacity: 0.5; }
287
+ }
288
+ @keyframes cpk-a2ui-sweep {
289
+ 0% { background-position: 250% 0; }
290
+ 100% { background-position: -250% 0; }
291
+ }
292
+ `,
293
+ ),
294
+ ]);
295
+ }
296
+
297
+ function renderDebugDetails(
298
+ label: string,
299
+ open: boolean,
300
+ payload: unknown,
301
+ ): VNodeChild {
302
+ return h("details", { open, class: "cpk-a2ui-debug-details" }, [
303
+ h("summary", { class: "cpk-a2ui-debug-details-summary" }, label),
304
+ h(
305
+ "pre",
306
+ { class: "cpk-a2ui-debug-details-payload", style: { fontSize: "11px" } },
307
+ JSON.stringify(payload, null, 2),
308
+ ),
309
+ ]);
310
+ }
311
+
312
+ // --- Lifecycle states ---------------------------------------------------------
313
+
314
+ /** building: the generic skeleton + optional live token count. */
315
+ export const A2UIBuildingState = defineComponent({
316
+ name: "A2UIBuildingState",
317
+ props: {
318
+ content: { type: null as unknown as PropType<any>, default: undefined },
319
+ },
320
+ setup(props) {
321
+ return () =>
322
+ renderA2UIGeneratingSkeleton(
323
+ "Building interface",
324
+ tokensOf(props.content),
325
+ );
326
+ },
327
+ });
328
+
329
+ /**
330
+ * retrying: stays the generic skeleton through fast/transient retries; only
331
+ * once the retry is perceptible (after `showAfterMs`, or once `attempt`
332
+ * crosses `showAfterAttempts`) does the sub-label reveal
333
+ * "Retrying generation… (N/M)".
334
+ */
335
+ export const A2UIRetryingState = defineComponent({
336
+ name: "A2UIRetryingState",
337
+ props: {
338
+ content: { type: null as unknown as PropType<any>, default: undefined },
339
+ showAfterMs: { type: Number, required: true },
340
+ showAfterAttempts: { type: Number, required: true },
341
+ debugExposure: {
342
+ type: String as PropType<DebugExposure>,
343
+ required: true,
344
+ },
345
+ },
346
+ setup(props) {
347
+ const attempt = () =>
348
+ typeof props.content?.attempt === "number"
349
+ ? (props.content.attempt as number)
350
+ : undefined;
351
+ const immediate = () => {
352
+ const current = attempt();
353
+ return current !== undefined && current >= props.showAfterAttempts;
354
+ };
355
+ const revealed = ref(immediate());
356
+ let timer: ReturnType<typeof setTimeout> | undefined;
357
+
358
+ watch(
359
+ [immediate, () => props.showAfterMs],
360
+ ([isImmediate, showAfterMs]) => {
361
+ clearTimeout(timer);
362
+ if (isImmediate) {
363
+ revealed.value = true;
364
+ return;
365
+ }
366
+ timer = setTimeout(() => {
367
+ revealed.value = true;
368
+ }, showAfterMs);
369
+ },
370
+ { immediate: true },
371
+ );
372
+ onBeforeUnmount(() => clearTimeout(timer));
373
+
374
+ return () => {
375
+ const tokens = tokensOf(props.content);
376
+ // Not yet perceptible → indistinguishable from normal building.
377
+ if (!revealed.value) {
378
+ return renderA2UIGeneratingSkeleton("Building interface", tokens);
379
+ }
380
+ const current = attempt();
381
+ const maxAttempts =
382
+ typeof props.content?.maxAttempts === "number"
383
+ ? props.content.maxAttempts
384
+ : undefined;
385
+ const label =
386
+ current !== undefined && maxAttempts !== undefined
387
+ ? `Retrying generation… (${current}/${maxAttempts} attempts)`
388
+ : "Retrying generation…";
389
+ const errors = Array.isArray(props.content?.errors)
390
+ ? props.content.errors
391
+ : [];
392
+ return renderA2UIGeneratingSkeleton(
393
+ label,
394
+ tokens,
395
+ props.debugExposure !== "hidden" && errors.length > 0
396
+ ? [
397
+ renderDebugDetails(
398
+ "validation issues",
399
+ props.debugExposure === "verbose",
400
+ { attempt: props.content?.attempt, errors },
401
+ ),
402
+ ]
403
+ : [],
404
+ );
405
+ };
406
+ },
407
+ });
408
+
409
+ /** failed: a clean hard-failure card that replaces the skeleton in place. */
410
+ export const A2UIRecoveryFailure = defineComponent({
411
+ name: "A2UIRecoveryFailure",
412
+ props: {
413
+ content: { type: null as unknown as PropType<any>, default: undefined },
414
+ debugExposure: {
415
+ type: String as PropType<DebugExposure>,
416
+ required: true,
417
+ },
418
+ },
419
+ setup(props) {
420
+ return () =>
421
+ h("div", { class: "cpk-a2ui-recovery-failure" }, [
422
+ h(
423
+ "div",
424
+ { class: "cpk-a2ui-recovery-failure-title" },
425
+ "Couldn't generate the UI",
426
+ ),
427
+ h(
428
+ "div",
429
+ { class: "cpk-a2ui-recovery-failure-description" },
430
+ "Something went wrong rendering this. You can keep chatting and try again.",
431
+ ),
432
+ props.debugExposure !== "hidden"
433
+ ? renderDebugDetails(
434
+ "developer details",
435
+ props.debugExposure === "verbose",
436
+ {
437
+ error: props.content?.error,
438
+ attempts: props.content?.attempts,
439
+ },
440
+ )
441
+ : null,
442
+ ]);
443
+ },
444
+ });
@@ -0,0 +1,175 @@
1
+ import { describe, it, expect, vi, afterEach } from "vitest";
2
+ import { h, nextTick } from "vue";
3
+ import type { Component } from "vue";
4
+ import { render as renderVue } from "@testing-library/vue";
5
+ import {
6
+ A2UIBuildingState,
7
+ A2UIRetryingState,
8
+ A2UIRecoveryFailure,
9
+ resolveDebugExposure,
10
+ } from "../A2UIRecoveryStates";
11
+
12
+ // Ported from React's A2UIRecoveryStates tests; renders each Vue component
13
+ // with the same props the React tests pass.
14
+ const render = (component: Component, props: Record<string, unknown>) =>
15
+ renderVue({ render: () => h(component, props) });
16
+
17
+ afterEach(() => {
18
+ vi.useRealTimers();
19
+ });
20
+
21
+ describe("A2UI lifecycle states (OSS-162)", () => {
22
+ describe("building", () => {
23
+ it("shows the 'Building interface' skeleton", () => {
24
+ const { container } = render(A2UIBuildingState, {
25
+ content: { status: "building" },
26
+ });
27
+ expect(container.textContent).toContain("Building interface");
28
+ });
29
+
30
+ it("shows a live token count when progressTokens is present", () => {
31
+ const { container } = render(A2UIBuildingState, {
32
+ content: { status: "building", progressTokens: 97 },
33
+ });
34
+ expect(container.textContent).toContain("Building interface");
35
+ expect(container.textContent).toContain("97 tokens");
36
+ });
37
+
38
+ it("omits the token count when progressTokens is absent or zero", () => {
39
+ const { container } = render(A2UIBuildingState, {
40
+ content: { status: "building", progressTokens: 0 },
41
+ });
42
+ expect(container.textContent).not.toContain("tokens");
43
+ });
44
+ });
45
+
46
+ describe("retrying (threshold-gated label)", () => {
47
+ it("stays the generic building skeleton before the delay on a fast first retry", () => {
48
+ vi.useFakeTimers();
49
+ const { container } = render(A2UIRetryingState, {
50
+ content: { status: "retrying", attempt: 1, maxAttempts: 3 },
51
+ showAfterMs: 2000,
52
+ showAfterAttempts: 2,
53
+ debugExposure: "collapsed",
54
+ });
55
+ expect(container.textContent).toContain("Building interface");
56
+ expect(container.textContent).not.toContain("Retrying");
57
+ });
58
+
59
+ it("reveals 'Retrying generation… (N/M attempts)' once the delay elapses", async () => {
60
+ vi.useFakeTimers();
61
+ const { container } = render(A2UIRetryingState, {
62
+ content: { status: "retrying", attempt: 1, maxAttempts: 3 },
63
+ showAfterMs: 2000,
64
+ showAfterAttempts: 2,
65
+ debugExposure: "collapsed",
66
+ });
67
+ vi.advanceTimersByTime(2100);
68
+ await nextTick();
69
+ expect(container.textContent).toContain("Retrying generation");
70
+ expect(container.textContent).toContain("(1/3 attempts)");
71
+ });
72
+
73
+ it("reveals the retry label immediately once attempts cross the threshold", () => {
74
+ vi.useFakeTimers();
75
+ const { container } = render(A2UIRetryingState, {
76
+ content: { status: "retrying", attempt: 2, maxAttempts: 3 },
77
+ showAfterMs: 999999,
78
+ showAfterAttempts: 2,
79
+ debugExposure: "collapsed",
80
+ });
81
+ expect(container.textContent).toContain("Retrying generation");
82
+ expect(container.textContent).toContain("(2/3 attempts)");
83
+ });
84
+
85
+ it("shows validation-issue detail once revealed, unless debugExposure is 'hidden'", () => {
86
+ const shown = render(A2UIRetryingState, {
87
+ content: {
88
+ status: "retrying",
89
+ attempt: 2,
90
+ maxAttempts: 3,
91
+ errors: [{ code: "missing_required_prop" }],
92
+ },
93
+ showAfterMs: 0,
94
+ showAfterAttempts: 1,
95
+ debugExposure: "collapsed",
96
+ });
97
+ expect(shown.container.querySelector("details")).not.toBeNull();
98
+ expect(shown.container.textContent).toContain("missing_required_prop");
99
+
100
+ const hidden = render(A2UIRetryingState, {
101
+ content: {
102
+ status: "retrying",
103
+ attempt: 2,
104
+ maxAttempts: 3,
105
+ errors: [{ code: "missing_required_prop" }],
106
+ },
107
+ showAfterMs: 0,
108
+ showAfterAttempts: 1,
109
+ debugExposure: "hidden",
110
+ });
111
+ expect(hidden.container.querySelector("details")).toBeNull();
112
+ });
113
+ });
114
+
115
+ describe("failed (replaces the skeleton in place)", () => {
116
+ it("renders a clean message with expandable developer detail (collapsed default)", () => {
117
+ const { container } = render(A2UIRecoveryFailure, {
118
+ content: {
119
+ status: "failed",
120
+ error: "Failed to generate valid A2UI after 3 attempt(s)",
121
+ attempts: [
122
+ {
123
+ attempt: 1,
124
+ ok: false,
125
+ errors: [{ code: "missing_required_prop" }],
126
+ },
127
+ ],
128
+ },
129
+ debugExposure: "collapsed",
130
+ });
131
+ expect(container.textContent).toContain("Couldn't generate");
132
+ const details = container.querySelector("details");
133
+ expect(details).not.toBeNull();
134
+ expect(details!.hasAttribute("open")).toBe(false);
135
+ expect(container.textContent).toContain("missing_required_prop");
136
+ });
137
+
138
+ it("hides developer detail entirely when debugExposure is 'hidden'", () => {
139
+ const { container } = render(A2UIRecoveryFailure, {
140
+ content: {
141
+ status: "failed",
142
+ error: "boom",
143
+ attempts: [{ attempt: 1, ok: false }],
144
+ },
145
+ debugExposure: "hidden",
146
+ });
147
+ expect(container.textContent).toContain("Couldn't generate");
148
+ expect(container.querySelector("details")).toBeNull();
149
+ });
150
+
151
+ it("opens the developer detail when debugExposure is 'verbose'", () => {
152
+ const { container } = render(A2UIRecoveryFailure, {
153
+ content: { status: "failed", error: "boom", attempts: [] },
154
+ debugExposure: "verbose",
155
+ });
156
+ const details = container.querySelector("details");
157
+ expect(details).not.toBeNull();
158
+ expect(details!.hasAttribute("open")).toBe(true);
159
+ });
160
+ });
161
+
162
+ describe("resolveDebugExposure precedence", () => {
163
+ it("server-stamped content.debugExposure wins over the client option", () => {
164
+ expect(resolveDebugExposure({ debugExposure: "hidden" }, "verbose")).toBe(
165
+ "hidden",
166
+ );
167
+ });
168
+ it("falls back to the client option when content has none", () => {
169
+ expect(resolveDebugExposure({}, "verbose")).toBe("verbose");
170
+ });
171
+ it("falls back to the resolved default when neither is set", () => {
172
+ expect(resolveDebugExposure(undefined, "collapsed")).toBe("collapsed");
173
+ });
174
+ });
175
+ });
@@ -1,4 +1,4 @@
1
- import { z } from "zod";
1
+ import * as z from "zod";
2
2
 
3
3
  export type A2UIOperation = Record<string, unknown>;
4
4