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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (335) hide show
  1. package/PARITY.md +3 -3
  2. package/dist/hooks/use-copilot-action.d.ts.map +1 -1
  3. package/dist/hooks/use-frontend-tool.d.ts +1 -1
  4. package/dist/hooks/use-frontend-tool.d.ts.map +1 -1
  5. package/dist/hooks/zod-parameters.d.ts +14 -0
  6. package/dist/hooks/zod-parameters.d.ts.map +1 -0
  7. package/dist/index.cjs +1 -73
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.mjs +365 -16920
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/use-render-activity-message-BAhbpSDh.js +16200 -0
  12. package/dist/use-render-activity-message-BAhbpSDh.js.map +1 -0
  13. package/dist/use-render-activity-message-DJ6q1qHV.cjs +114 -0
  14. package/dist/use-render-activity-message-DJ6q1qHV.cjs.map +1 -0
  15. package/dist/v2/components/A2UIMessageRenderer.d.ts +14 -0
  16. package/dist/v2/components/A2UIMessageRenderer.d.ts.map +1 -1
  17. package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts +10 -3
  18. package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts.map +1 -1
  19. package/dist/v2/components/CopilotKitInspector.vue.d.ts +5 -1
  20. package/dist/v2/components/CopilotKitInspector.vue.d.ts.map +1 -1
  21. package/dist/v2/components/InlineFeatureWarning.vue.d.ts.map +1 -1
  22. package/dist/v2/components/LicenseWarningBanner.vue.d.ts +2 -2
  23. package/dist/v2/components/LicenseWarningBanner.vue.d.ts.map +1 -1
  24. package/dist/v2/components/MCPAppsActivityRenderer.d.ts.map +1 -1
  25. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts +13 -59
  26. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts.map +1 -1
  27. package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts +0 -5
  28. package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts.map +1 -1
  29. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts +10 -15
  30. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts.map +1 -1
  31. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts +14 -130
  32. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts.map +1 -1
  33. package/dist/v2/components/a2ui/catalog.d.ts.map +1 -1
  34. package/dist/v2/components/a2ui/utils.d.ts +3 -15
  35. package/dist/v2/components/a2ui/utils.d.ts.map +1 -1
  36. package/dist/v2/components/a2ui.d.ts +9 -8
  37. package/dist/v2/components/a2ui.d.ts.map +1 -1
  38. package/dist/v2/components/chat/CopilotChat.vue.d.ts +2 -2
  39. package/dist/v2/components/chat/CopilotChat.vue.d.ts.map +1 -1
  40. package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts.map +1 -1
  41. package/dist/v2/components/chat/CopilotChatAttachmentQueue.vue.d.ts.map +1 -1
  42. package/dist/v2/components/chat/CopilotChatAttachmentRenderer.vue.d.ts.map +1 -1
  43. package/dist/v2/components/chat/CopilotChatAudioRecorder.vue.d.ts +4 -8
  44. package/dist/v2/components/chat/CopilotChatAudioRecorder.vue.d.ts.map +1 -1
  45. package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts +1 -1
  46. package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts.map +1 -1
  47. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts +6 -270
  48. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts.map +1 -1
  49. package/dist/v2/components/chat/CopilotChatInspectorButton.vue.d.ts.map +1 -1
  50. package/dist/v2/components/chat/CopilotChatLightbox.vue.d.ts.map +1 -1
  51. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts +1 -1
  52. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts.map +1 -1
  53. package/dist/v2/components/chat/CopilotChatReasoningMessage.vue.d.ts.map +1 -1
  54. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts +1 -1
  55. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts.map +1 -1
  56. package/dist/v2/components/chat/CopilotChatToolCallItem.vue.d.ts.map +1 -1
  57. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts +1 -1
  58. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts.map +1 -1
  59. package/dist/v2/components/chat/CopilotChatUserMessage.vue.d.ts.map +1 -1
  60. package/dist/v2/components/chat/CopilotChatView.vue.d.ts +3 -3
  61. package/dist/v2/components/chat/CopilotChatView.vue.d.ts.map +1 -1
  62. package/dist/v2/components/chat/CopilotChatWorkSummary.vue.d.ts.map +1 -1
  63. package/dist/v2/components/chat/CopilotModalHeader.vue.d.ts.map +1 -1
  64. package/dist/v2/components/chat/CopilotPopup.vue.d.ts +8 -3
  65. package/dist/v2/components/chat/CopilotPopup.vue.d.ts.map +1 -1
  66. package/dist/v2/components/chat/CopilotPopupView.vue.d.ts +5 -3
  67. package/dist/v2/components/chat/CopilotPopupView.vue.d.ts.map +1 -1
  68. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts +5 -3
  69. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts.map +1 -1
  70. package/dist/v2/components/chat/CopilotSidebar.vue.d.ts +8 -3
  71. package/dist/v2/components/chat/CopilotSidebar.vue.d.ts.map +1 -1
  72. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts +6 -4
  73. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts.map +1 -1
  74. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts +6 -4
  75. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts.map +1 -1
  76. package/dist/v2/components/chat/CopilotThreadsDrawer.vue.d.ts.map +1 -1
  77. package/dist/v2/components/chat/StreamingMarkdownDefault.vue.d.ts +1 -0
  78. package/dist/v2/components/chat/StreamingMarkdownDefault.vue.d.ts.map +1 -1
  79. package/dist/v2/components/chat/audioRecorder.d.ts +3 -4
  80. package/dist/v2/components/chat/audioRecorder.d.ts.map +1 -1
  81. package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts +3 -3
  82. package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts.map +1 -1
  83. package/dist/v2/components/chat/forwarded-slots.d.ts +12 -0
  84. package/dist/v2/components/chat/forwarded-slots.d.ts.map +1 -0
  85. package/dist/v2/components/chat/index.d.ts +34 -31
  86. package/dist/v2/components/chat/index.d.ts.map +1 -1
  87. package/dist/v2/components/chat/inspector-shortcuts.d.ts +2 -1
  88. package/dist/v2/components/chat/inspector-shortcuts.d.ts.map +1 -1
  89. package/dist/v2/components/chat/message-feedback.d.ts +18 -49
  90. package/dist/v2/components/chat/message-feedback.d.ts.map +1 -1
  91. package/dist/v2/components/chat/tool-call-display-context.d.ts +4 -19
  92. package/dist/v2/components/chat/tool-call-display-context.d.ts.map +1 -1
  93. package/dist/v2/components/chat/tool-call-group-parts.d.ts +7 -20
  94. package/dist/v2/components/chat/tool-call-group-parts.d.ts.map +1 -1
  95. package/dist/v2/components/chat/turn-work.d.ts +0 -2
  96. package/dist/v2/components/chat/turn-work.d.ts.map +1 -1
  97. package/dist/v2/components/chat/types.d.ts +9 -4
  98. package/dist/v2/components/chat/types.d.ts.map +1 -1
  99. package/dist/v2/components/chat/use-chat-labels.d.ts +8 -0
  100. package/dist/v2/components/chat/use-chat-labels.d.ts.map +1 -0
  101. package/dist/v2/components/chat/use-copy-feedback.d.ts +11 -0
  102. package/dist/v2/components/chat/use-copy-feedback.d.ts.map +1 -0
  103. package/dist/v2/components/chat/use-lightbox.d.ts.map +1 -1
  104. package/dist/v2/components/icons/index.d.ts +968 -1
  105. package/dist/v2/components/icons/index.d.ts.map +1 -1
  106. package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts +1 -1
  107. package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts.map +1 -1
  108. package/dist/v2/hooks/use-agent-context.d.ts +2 -3
  109. package/dist/v2/hooks/use-agent-context.d.ts.map +1 -1
  110. package/dist/v2/hooks/use-agent.d.ts +4 -1
  111. package/dist/v2/hooks/use-agent.d.ts.map +1 -1
  112. package/dist/v2/hooks/use-attachments.d.ts +7 -0
  113. package/dist/v2/hooks/use-attachments.d.ts.map +1 -1
  114. package/dist/v2/hooks/use-capabilities.d.ts.map +1 -1
  115. package/dist/v2/hooks/use-component.d.ts +1 -0
  116. package/dist/v2/hooks/use-component.d.ts.map +1 -1
  117. package/dist/v2/hooks/use-configure-suggestions.d.ts +4 -9
  118. package/dist/v2/hooks/use-configure-suggestions.d.ts.map +1 -1
  119. package/dist/v2/hooks/use-default-render-tool.d.ts.map +1 -1
  120. package/dist/v2/hooks/use-frontend-tool.d.ts +5 -0
  121. package/dist/v2/hooks/use-frontend-tool.d.ts.map +1 -1
  122. package/dist/v2/hooks/use-human-in-the-loop.d.ts +2 -1
  123. package/dist/v2/hooks/use-human-in-the-loop.d.ts.map +1 -1
  124. package/dist/v2/hooks/use-interrupt.d.ts +0 -1
  125. package/dist/v2/hooks/use-interrupt.d.ts.map +1 -1
  126. package/dist/v2/hooks/use-keyboard-height.d.ts +1 -1
  127. package/dist/v2/hooks/use-keyboard-height.d.ts.map +1 -1
  128. package/dist/v2/hooks/use-pin-to-send.d.ts +4 -12
  129. package/dist/v2/hooks/use-pin-to-send.d.ts.map +1 -1
  130. package/dist/v2/hooks/use-render-activity-message.d.ts +13 -9
  131. package/dist/v2/hooks/use-render-activity-message.d.ts.map +1 -1
  132. package/dist/v2/hooks/use-render-custom-messages.d.ts +5 -7
  133. package/dist/v2/hooks/use-render-custom-messages.d.ts.map +1 -1
  134. package/dist/v2/hooks/use-suggestions.d.ts.map +1 -1
  135. package/dist/v2/hooks/use-threads.d.ts +0 -8
  136. package/dist/v2/hooks/use-threads.d.ts.map +1 -1
  137. package/dist/v2/index.cjs +1 -1
  138. package/dist/v2/index.mjs +197 -200
  139. package/dist/v2/index.mjs.map +1 -1
  140. package/dist/v2/lib/processPartialHtml.d.ts +1 -2
  141. package/dist/v2/lib/processPartialHtml.d.ts.map +1 -1
  142. package/dist/v2/lib/shallow-stable.d.ts.map +1 -1
  143. package/dist/v2/lib/vue-core.d.ts +12 -12
  144. package/dist/v2/lib/vue-core.d.ts.map +1 -1
  145. package/dist/v2/providers/CopilotChatConfigurationProvider.vue.d.ts.map +1 -1
  146. package/dist/v2/providers/CopilotKitProvider.types.d.ts +9 -129
  147. package/dist/v2/providers/CopilotKitProvider.types.d.ts.map +1 -1
  148. package/dist/v2/providers/CopilotKitProvider.vue.d.ts +9 -10
  149. package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
  150. package/dist/v2/providers/chat-configuration-store-key.d.ts +8 -0
  151. package/dist/v2/providers/chat-configuration-store-key.d.ts.map +1 -0
  152. package/dist/v2/providers/markdown-renderer.d.ts +4 -2
  153. package/dist/v2/providers/markdown-renderer.d.ts.map +1 -1
  154. package/dist/v2/providers/types.d.ts +3 -46
  155. package/dist/v2/providers/types.d.ts.map +1 -1
  156. package/dist/v2/providers/use-inspector-thread-override.d.ts +5 -0
  157. package/dist/v2/providers/use-inspector-thread-override.d.ts.map +1 -1
  158. package/dist/v2/types/human-in-the-loop.d.ts +8 -29
  159. package/dist/v2/types/human-in-the-loop.d.ts.map +1 -1
  160. package/dist/v2/types/interrupt.d.ts +1 -22
  161. package/dist/v2/types/interrupt.d.ts.map +1 -1
  162. package/dist/v2/types/vue-activity-message-renderer.d.ts +16 -15
  163. package/dist/v2/types/vue-activity-message-renderer.d.ts.map +1 -1
  164. package/dist/v2/types/vue-custom-message-renderer.d.ts +7 -16
  165. package/dist/v2/types/vue-custom-message-renderer.d.ts.map +1 -1
  166. package/dist/v2/types/vue-tool-call-renderer.d.ts +16 -35
  167. package/dist/v2/types/vue-tool-call-renderer.d.ts.map +1 -1
  168. package/package.json +10 -11
  169. package/src/__tests__/build-entries.test.ts +27 -0
  170. package/src/hooks/__tests__/zod-parameters.test.ts +520 -0
  171. package/src/hooks/use-copilot-action.ts +2 -1
  172. package/src/hooks/use-frontend-tool.ts +3 -6
  173. package/src/hooks/zod-parameters.ts +162 -0
  174. package/src/v2/__tests__/exports.test.ts +10 -0
  175. package/src/v2/__tests__/mocks/web-inspector.ts +6 -0
  176. package/src/v2/__tests__/utils/test-helpers.ts +34 -4
  177. package/src/v2/components/A2UIMessageRenderer.ts +98 -68
  178. package/src/v2/components/A2UISurfaceActivityRenderer.vue +68 -103
  179. package/src/v2/components/CopilotKitInspector.vue +104 -51
  180. package/src/v2/components/InlineFeatureWarning.vue +20 -21
  181. package/src/v2/components/LicenseWarningBanner.vue +27 -135
  182. package/src/v2/components/MCPAppsActivityRenderer.ts +75 -201
  183. package/src/v2/components/OpenGenerativeUIRenderer.ts +122 -446
  184. package/src/v2/components/__tests__/A2UIMessageRenderer.test.ts +171 -8
  185. package/src/v2/components/__tests__/CopilotKitInspector.test.ts +42 -0
  186. package/src/v2/components/__tests__/LicenseWarningBanner.test.ts +60 -0
  187. package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.ts +64 -8
  188. package/src/v2/components/__tests__/OpenGenerativeUIToolRenderer.test.ts +38 -0
  189. package/src/v2/components/a2ui/A2UIBuiltInToolCallRenderer.ts +2 -7
  190. package/src/v2/components/a2ui/A2UICatalogContext.ts +27 -185
  191. package/src/v2/components/a2ui/A2UIRecoveryStates.ts +127 -327
  192. package/src/v2/components/a2ui/catalog.ts +3 -3
  193. package/src/v2/components/a2ui/utils.ts +13 -65
  194. package/src/v2/components/a2ui.ts +15 -22
  195. package/src/v2/components/chat/CopilotChat.vue +147 -356
  196. package/src/v2/components/chat/CopilotChatAssistantMessage.vue +19 -43
  197. package/src/v2/components/chat/CopilotChatAttachmentQueue.vue +36 -55
  198. package/src/v2/components/chat/CopilotChatAttachmentRenderer.vue +14 -6
  199. package/src/v2/components/chat/CopilotChatAudioRecorder.vue +19 -246
  200. package/src/v2/components/chat/CopilotChatFeedbackCommentPopover.vue +2 -2
  201. package/src/v2/components/chat/CopilotChatInput.vue +108 -436
  202. package/src/v2/components/chat/CopilotChatInspectorButton.vue +45 -108
  203. package/src/v2/components/chat/CopilotChatLightbox.vue +10 -31
  204. package/src/v2/components/chat/CopilotChatMessageView.vue +82 -210
  205. package/src/v2/components/chat/CopilotChatReasoningMessage.vue +7 -15
  206. package/src/v2/components/chat/CopilotChatToolCallGroup.vue +63 -71
  207. package/src/v2/components/chat/CopilotChatToolCallItem.vue +8 -6
  208. package/src/v2/components/chat/CopilotChatToolCallsView.vue +31 -32
  209. package/src/v2/components/chat/CopilotChatUserMessage.vue +24 -112
  210. package/src/v2/components/chat/CopilotChatView.vue +33 -28
  211. package/src/v2/components/chat/CopilotChatWorkSummary.vue +26 -36
  212. package/src/v2/components/chat/CopilotModalHeader.vue +11 -23
  213. package/src/v2/components/chat/CopilotPopup.vue +23 -25
  214. package/src/v2/components/chat/CopilotPopupView.vue +10 -39
  215. package/src/v2/components/chat/CopilotPopupViewInternal.vue +35 -131
  216. package/src/v2/components/chat/CopilotSidebar.vue +23 -25
  217. package/src/v2/components/chat/CopilotSidebarView.vue +10 -39
  218. package/src/v2/components/chat/CopilotSidebarViewInternal.vue +38 -59
  219. package/src/v2/components/chat/CopilotThreadsDrawer.vue +37 -102
  220. package/src/v2/components/chat/StreamingMarkdownDefault.vue +15 -28
  221. package/src/v2/components/chat/__tests__/CopilotChat.labels.test.ts +19 -4
  222. package/src/v2/components/chat/__tests__/CopilotChat.test.ts +12 -10
  223. package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.ts +26 -9
  224. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.learningFeedback.test.ts +5 -5
  225. package/src/v2/components/chat/__tests__/CopilotChatAttachmentQueue.test.ts +28 -0
  226. package/src/v2/components/chat/__tests__/CopilotChatInput.test.ts +89 -1
  227. package/src/v2/components/chat/__tests__/CopilotChatMessageView.test.ts +247 -403
  228. package/src/v2/components/chat/__tests__/CopilotChatMessageView.toolCallDisplay.test.ts +1 -99
  229. package/src/v2/components/chat/__tests__/CopilotPopup.test.ts +90 -1
  230. package/src/v2/components/chat/__tests__/CopilotPopupView.test.ts +19 -0
  231. package/src/v2/components/chat/__tests__/CopilotSidebar.test.ts +90 -1
  232. package/src/v2/components/chat/__tests__/CopilotSidebarView.position.test.ts +32 -8
  233. package/src/v2/components/chat/__tests__/CopilotSidebarView.test.ts +2 -1
  234. package/src/v2/components/chat/__tests__/StreamingMarkdownDefault.test.ts +54 -0
  235. package/src/v2/components/chat/audioRecorder.ts +4 -7
  236. package/src/v2/components/chat/copilotChatToolCallItemRender.ts +24 -89
  237. package/src/v2/components/chat/forwarded-slots.ts +17 -0
  238. package/src/v2/components/chat/index.ts +0 -1
  239. package/src/v2/components/chat/inspector-shortcuts.ts +10 -16
  240. package/src/v2/components/chat/message-feedback.ts +62 -197
  241. package/src/v2/components/chat/tool-call-display-context.ts +6 -22
  242. package/src/v2/components/chat/tool-call-group-parts.ts +47 -108
  243. package/src/v2/components/chat/turn-work.ts +0 -9
  244. package/src/v2/components/chat/types.ts +12 -4
  245. package/src/v2/components/chat/use-chat-labels.ts +16 -0
  246. package/src/v2/components/chat/use-copy-feedback.ts +21 -0
  247. package/src/v2/components/chat/use-lightbox.ts +15 -33
  248. package/src/v2/components/icons/__tests__/icons.test.ts +72 -68
  249. package/src/v2/components/icons/index.ts +109 -27
  250. package/src/v2/hooks/__tests__/use-agent-error-state.test.ts +5 -3
  251. package/src/v2/hooks/__tests__/use-agent-stability.test.ts +25 -4
  252. package/src/v2/hooks/__tests__/use-agent-throttle.test.ts +5 -1
  253. package/src/v2/hooks/__tests__/use-agent.test.ts +6 -3
  254. package/src/v2/hooks/__tests__/use-component.test.ts +21 -0
  255. package/src/v2/hooks/__tests__/use-configure-suggestions.test.ts +30 -1
  256. package/src/v2/hooks/__tests__/use-default-render-tool.test.ts +10 -10
  257. package/src/v2/hooks/__tests__/use-frontend-tool.e2e.test.ts +66 -1
  258. package/src/v2/hooks/__tests__/use-human-in-the-loop.e2e.test.ts +6 -1
  259. package/src/v2/hooks/__tests__/use-human-in-the-loop.test.ts +187 -12
  260. package/src/v2/hooks/__tests__/use-interrupt.test.ts +97 -0
  261. package/src/v2/hooks/__tests__/use-render-activity-message.test.ts +106 -0
  262. package/src/v2/hooks/__tests__/use-render-tool.test.ts +3 -6
  263. package/src/v2/hooks/__tests__/use-threads.test.ts +48 -6
  264. package/src/v2/hooks/__tests__/zod-regression.test.ts +5 -4
  265. package/src/v2/hooks/use-agent-context.ts +4 -10
  266. package/src/v2/hooks/use-agent.ts +86 -290
  267. package/src/v2/hooks/use-attachments.ts +48 -168
  268. package/src/v2/hooks/use-capabilities.ts +2 -7
  269. package/src/v2/hooks/use-component.ts +7 -4
  270. package/src/v2/hooks/use-configure-suggestions.ts +28 -218
  271. package/src/v2/hooks/use-default-render-tool.ts +34 -94
  272. package/src/v2/hooks/use-frontend-tool.ts +10 -10
  273. package/src/v2/hooks/use-human-in-the-loop.ts +11 -80
  274. package/src/v2/hooks/use-interrupt.ts +29 -308
  275. package/src/v2/hooks/use-keyboard-height.ts +17 -40
  276. package/src/v2/hooks/use-pin-to-send.ts +15 -99
  277. package/src/v2/hooks/use-render-activity-message.ts +31 -55
  278. package/src/v2/hooks/use-render-custom-messages.ts +24 -88
  279. package/src/v2/hooks/use-suggestions.ts +9 -33
  280. package/src/v2/hooks/use-threads.ts +43 -273
  281. package/src/v2/lib/__tests__/shallow-stable.test.ts +54 -0
  282. package/src/v2/lib/__tests__/vue-core-renderers.test.ts +42 -0
  283. package/src/v2/lib/processPartialHtml.ts +6 -21
  284. package/src/v2/lib/shallow-stable.ts +2 -16
  285. package/src/v2/lib/vue-core.ts +69 -78
  286. package/src/v2/providers/CopilotChatConfigurationProvider.vue +48 -186
  287. package/src/v2/providers/CopilotKitProvider.types.ts +12 -132
  288. package/src/v2/providers/CopilotKitProvider.vue +237 -510
  289. package/src/v2/providers/__tests__/CopilotChatConfigurationProvider.test.ts +22 -2
  290. package/src/v2/providers/__tests__/CopilotKitProvider.a2ui.test.ts +20 -2
  291. package/src/v2/providers/__tests__/CopilotKitProvider.config.test.ts +124 -0
  292. package/src/v2/providers/__tests__/CopilotKitProvider.headersAtSendTime.test.ts +3 -3
  293. package/src/v2/providers/__tests__/CopilotKitProvider.learning.test.ts +3 -1
  294. package/src/v2/providers/__tests__/CopilotKitProvider.sandboxFunctions.test.ts +4 -1
  295. package/src/v2/providers/__tests__/CopilotKitProvider.test.ts +53 -26
  296. package/src/v2/providers/chat-configuration-store-key.ts +9 -0
  297. package/src/v2/providers/markdown-renderer.ts +8 -2
  298. package/src/v2/providers/types.ts +3 -49
  299. package/src/v2/providers/use-inspector-thread-override.ts +22 -80
  300. package/src/v2/types/__tests__/defineToolCallRenderer.test.ts +28 -33
  301. package/src/v2/types/defineToolCallRenderer.ts +5 -4
  302. package/src/v2/types/human-in-the-loop.ts +8 -32
  303. package/src/v2/types/interrupt.ts +7 -31
  304. package/src/v2/types/vue-activity-message-renderer.ts +24 -15
  305. package/src/v2/types/vue-custom-message-renderer.ts +12 -16
  306. package/src/v2/types/vue-tool-call-renderer.ts +23 -38
  307. package/tsconfig.json +0 -1
  308. package/vite.config.ts +8 -5
  309. package/vitest.config.ts +12 -7
  310. package/dist/v2/components/chat/BasicMarkdown.vue.d.ts +0 -9
  311. package/dist/v2/components/chat/BasicMarkdown.vue.d.ts.map +0 -1
  312. package/dist/v2/components/chat/normalize-auto-scroll.d.ts +0 -3
  313. package/dist/v2/components/chat/normalize-auto-scroll.d.ts.map +0 -1
  314. package/dist/v2/components/chat/tool-call-layout.d.ts +0 -115
  315. package/dist/v2/components/chat/tool-call-layout.d.ts.map +0 -1
  316. package/dist/v2/lib/is-mobile-viewport.d.ts +0 -15
  317. package/dist/v2/lib/is-mobile-viewport.d.ts.map +0 -1
  318. package/dist/v2/lib/message-feedback.d.ts +0 -33
  319. package/dist/v2/lib/message-feedback.d.ts.map +0 -1
  320. package/dist/v2/lib/transcription-client.d.ts +0 -19
  321. package/dist/v2/lib/transcription-client.d.ts.map +0 -1
  322. package/src/v2/components/__tests__/A2UICatalogContext.test.ts +0 -63
  323. package/src/v2/components/a2ui/__tests__/A2UIRecoveryStates.test.ts +0 -175
  324. package/src/v2/components/chat/BasicMarkdown.vue +0 -160
  325. package/src/v2/components/chat/__tests__/BasicMarkdown.test.ts +0 -69
  326. package/src/v2/components/chat/__tests__/normalize-auto-scroll.test.ts +0 -39
  327. package/src/v2/components/chat/normalize-auto-scroll.ts +0 -17
  328. package/src/v2/components/chat/tool-call-layout.ts +0 -304
  329. package/src/v2/lib/__tests__/is-mobile-viewport.test.ts +0 -48
  330. package/src/v2/lib/__tests__/message-feedback.test.ts +0 -152
  331. package/src/v2/lib/__tests__/processPartialHtml.test.ts +0 -84
  332. package/src/v2/lib/__tests__/transcription-client.test.ts +0 -67
  333. package/src/v2/lib/is-mobile-viewport.ts +0 -23
  334. package/src/v2/lib/message-feedback.ts +0 -120
  335. package/src/v2/lib/transcription-client.ts +0 -151
@@ -20,6 +20,11 @@ import type {
20
20
  import CopilotTooltip from "../ui/CopilotTooltip.vue";
21
21
  import { useCopilotId } from "../ui/use-id";
22
22
  import { hideInspectorShortcuts } from "./inspector-shortcuts";
23
+ import {
24
+ ɵHoverMenuController,
25
+ ɵinspectorKiteFill,
26
+ ɵinspectorKiteIcon,
27
+ } from "@copilotkit/core";
23
28
 
24
29
  defineOptions({ inheritAttrs: false });
25
30
 
@@ -37,32 +42,20 @@ const menuId = useCopilotId("cpk-inspector-menu");
37
42
  const triggerId = useCopilotId("cpk-inspector-button");
38
43
  const kiteId = useCopilotId("cpk-inspector-kite");
39
44
  const trigger = shallowRef<HTMLButtonElement | null>(null);
40
- const open = ref(false);
41
- const dark = ref(false);
42
45
  const initialFocus = ref<"first" | "none">("none");
43
- let closeTimer: ReturnType<typeof setTimeout> | null = null;
44
- // Hover opens it without moving focus, and leaving closes it again.
45
- let openedByHover = false;
46
-
47
- const cancelClose = () => {
48
- if (closeTimer !== null) clearTimeout(closeTimer);
49
- closeTimer = null;
50
- };
51
- onBeforeUnmount(cancelClose);
52
-
53
- const changeOpen = (next: boolean) => {
54
- cancelClose();
55
- if (next) dark.value = !!trigger.value?.closest(".dark");
56
- open.value = next;
57
- };
58
-
59
- const scheduleClose = () => {
60
- cancelClose();
61
- closeTimer = setTimeout(() => {
62
- // Keep the panel available while the keyboard is interacting with it.
63
- if (openedByHover) open.value = false;
64
- }, 180);
65
- };
46
+ const menu = new ɵHoverMenuController();
47
+ const menuState = shallowRef(menu.getSnapshot());
48
+ const unsubscribeMenu = menu.subscribe(() => {
49
+ menuState.value = menu.getSnapshot();
50
+ });
51
+ onBeforeUnmount(() => {
52
+ unsubscribeMenu();
53
+ menu.dispose();
54
+ });
55
+ const open = computed(() => menuState.value.open);
56
+ const dark = computed(() => menuState.value.dark);
57
+ const { cancelClose, scheduleClose, keyboardUsed } = menu;
58
+ const changeOpen = (next: boolean) => menu.setOpen(next, trigger.value);
66
59
 
67
60
  const items = computed<CopilotDropdownMenuEntry[]>(() => [
68
61
  {
@@ -82,9 +75,8 @@ const isInspectItem = (item: CopilotDropdownMenuItem) =>
82
75
 
83
76
  function onPointerEnter(event: PointerEvent) {
84
77
  if (props.disabled || event.pointerType === "touch") return;
85
- openedByHover = true;
86
78
  initialFocus.value = "none";
87
- changeOpen(true);
79
+ menu.pointerEnter({ pointerType: event.pointerType, trigger: trigger.value });
88
80
  }
89
81
 
90
82
  function onClick() {
@@ -93,7 +85,7 @@ function onClick() {
93
85
  }
94
86
 
95
87
  function onKeyDown(event: KeyboardEvent) {
96
- openedByHover = false;
88
+ keyboardUsed();
97
89
  if (event.key === "Enter" || event.key === " ") {
98
90
  // Enter and Space inspect, as a click does, instead of opening the menu.
99
91
  event.preventDefault();
@@ -103,7 +95,7 @@ function onKeyDown(event: KeyboardEvent) {
103
95
  initialFocus.value = "first";
104
96
  if (open.value) {
105
97
  // Open already from hover: move into it.
106
- open.value = false;
98
+ changeOpen(false);
107
99
  queueMicrotask(() => changeOpen(true));
108
100
  } else {
109
101
  changeOpen(true);
@@ -112,14 +104,14 @@ function onKeyDown(event: KeyboardEvent) {
112
104
  }
113
105
 
114
106
  function onSelect(item: CopilotDropdownMenuItem) {
115
- const returnFocus = !openedByHover;
107
+ const returnFocus = !menu.openedByHover;
116
108
  changeOpen(false);
117
109
  item.action?.();
118
110
  if (returnFocus && !isInspectItem(item)) trigger.value?.focus();
119
111
  }
120
112
 
121
113
  function onDismiss(reason: CopilotDropdownMenuDismissReason) {
122
- const returnFocus = !openedByHover && reason !== "outside";
114
+ const returnFocus = !menu.openedByHover && reason !== "outside";
123
115
  changeOpen(false);
124
116
  if (returnFocus) trigger.value?.focus();
125
117
  }
@@ -178,7 +170,7 @@ const descriptionFor = (item: CopilotDropdownMenuItem) =>
178
170
  @dismiss="onDismiss"
179
171
  @pointer-enter="cancelClose"
180
172
  @pointer-leave="scheduleClose"
181
- @keydown="openedByHover = false"
173
+ @keydown="keyboardUsed"
182
174
  >
183
175
  <template #header>
184
176
  <div
@@ -226,90 +218,35 @@ const descriptionFor = (item: CopilotDropdownMenuItem) =>
226
218
  v-if="isInspectItem(item)"
227
219
  aria-hidden="true"
228
220
  class="cpk-inspector-button-kite-icon cpk-inspector-button-menu-item-icon"
229
- viewBox="4.57 3.36 17.8 17.8"
221
+ :viewBox="ɵinspectorKiteIcon.viewBox"
230
222
  fill="none"
231
223
  >
232
224
  <path
233
- d="M6.36084 10.9855C8.34277 8.393 9.98843 5.82939 10.6204 3.75914C10.6382 3.70281 10.7043 3.67888 10.7534 3.7114C12.9536 5.16894 16.9635 6.12833 20.5086 6.15085C20.5703 6.15124 20.6124 6.2114 20.5895 6.26829C19.4109 9.25938 17.9705 14.6189 17.9148 20.7392C17.9148 20.8301 17.7873 20.8627 17.7419 20.7837C15.7236 17.2522 9.26021 12.2898 6.39414 11.1186C6.34112 11.0968 6.32556 11.0313 6.36084 10.9855Z"
234
- :fill="`url(#${kiteId}-paint0_linear)`"
235
- />
236
- <path
237
- d="M13.0475 9.39974C9.95016 10.3806 7.11935 10.9259 6.44331 11.0498C6.40027 11.0577 6.39115 11.1172 6.43152 11.134C9.3203 12.3347 15.7516 17.2826 17.7511 20.7998C17.7551 20.8075 17.7647 20.8103 17.7728 20.8068C17.7809 20.803 17.7853 20.793 17.7819 20.7844L13.0475 9.39974Z"
238
- :fill="`url(#${kiteId}-paint1_linear)`"
239
- />
240
- <path
241
- d="M10.762 3.705C13.4137 5.15161 16.4787 5.80132 20.545 6.14367C20.5703 6.14585 20.5787 6.18008 20.5557 6.19197C20.0359 6.45923 17.0574 7.97512 14.8455 8.78701C14.2524 9.00453 13.6564 9.20632 13.0692 9.39249C13.0562 9.39656 13.0419 9.39015 13.0369 9.37774L10.7005 3.75979C10.6849 3.72196 10.7257 3.68538 10.762 3.705Z"
242
- :fill="`url(#${kiteId}-paint2_linear)`"
243
- />
244
- <path
245
- d="M10.7145 3.79041L17.8305 20.7659"
246
- stroke="#513C9F"
247
- stroke-width="0.17284"
248
- stroke-linecap="round"
249
- />
250
- <path
251
- d="M6.44531 11.0476C6.44531 11.0476 10.375 10.3422 14.0686 9.06804C17.7623 7.7939 20.5122 6.23373 20.5122 6.23373"
252
- stroke="#513C9F"
253
- stroke-width="0.17284"
254
- stroke-linecap="round"
255
- />
256
- <path
257
- d="M11.6914 5.93518L9.05534 14.7068M9.05534 14.7068H15.3203M9.05534 14.7068L0.15625 26.3646"
258
- stroke="#ABABAB"
259
- stroke-width="0.302474"
260
- stroke-linecap="round"
261
- />
262
- <path
263
- d="M6.02539 23.9646L4.85806 24.1287C5.46272 25.7287 6.70381 26.4276 8.18528 26.4276C11.8147 26.4276 10.707 22.3227 12.8103 22.3227C14.3358 22.3227 13.7155 25.6498 16.9992 25.6498C19.0029 25.6498 19.2028 23.631 18.8607 22.7625C18.8589 22.7572 18.8568 22.7524 18.8538 22.7476L18.3166 21.9253C18.2817 21.8706 18.1968 21.8912 18.1907 21.9562L18.0908 22.9529C18.0838 23.0222 18.0857 23.0913 18.0936 23.1605C18.1764 23.8491 18.2291 25.5202 16.9992 25.5202C15.7015 25.5202 15.3895 22.2362 12.8103 22.2362C9.78393 22.2362 10.1726 26.298 8.31487 26.298C7.08938 26.298 6.15447 24.9153 6.02539 23.9646Z"
264
- :fill="`url(#${kiteId}-paint3_linear)`"
225
+ v-for="path in ɵinspectorKiteIcon.paths"
226
+ :key="path.d"
227
+ :d="path.d"
228
+ :fill="ɵinspectorKiteFill(kiteId, path)"
229
+ :stroke="path.stroke"
230
+ :stroke-width="path.strokeWidth"
231
+ :stroke-linecap="path.strokeLinecap"
265
232
  />
266
233
  <defs>
267
234
  <linearGradient
268
- :id="`${kiteId}-paint0_linear`"
269
- x1="15.5372"
270
- y1="5.0278"
271
- x2="12.0802"
272
- y2="14.534"
273
- gradientUnits="userSpaceOnUse"
274
- >
275
- <stop stop-color="#6430AB" />
276
- <stop offset="1" stop-color="#AA89D8" />
277
- </linearGradient>
278
- <linearGradient
279
- :id="`${kiteId}-paint1_linear`"
280
- x1="12.8583"
281
- y1="10.3858"
282
- x2="8.40764"
283
- y2="18.9846"
284
- gradientUnits="userSpaceOnUse"
285
- >
286
- <stop stop-color="#005DBB" />
287
- <stop offset="1" stop-color="#3D92E8" />
288
- </linearGradient>
289
- <linearGradient
290
- :id="`${kiteId}-paint2_linear`"
291
- x1="14.8452"
292
- y1="5.02774"
293
- x2="13.5047"
294
- y2="9.21911"
295
- gradientUnits="userSpaceOnUse"
296
- >
297
- <stop stop-color="#1B70C4" />
298
- <stop offset="1" stop-color="#54A4F2" />
299
- </linearGradient>
300
- <linearGradient
301
- :id="`${kiteId}-paint3_linear`"
302
- x1="4.85806"
303
- y1="24.2455"
304
- x2="18.9963"
305
- y2="24.2455"
235
+ v-for="gradient in ɵinspectorKiteIcon.gradients"
236
+ :id="`${kiteId}-${gradient.id}`"
237
+ :key="gradient.id"
238
+ :x1="gradient.x1"
239
+ :y1="gradient.y1"
240
+ :x2="gradient.x2"
241
+ :y2="gradient.y2"
306
242
  gradientUnits="userSpaceOnUse"
307
243
  >
308
- <stop stop-color="#4497EA" />
309
- <stop offset="0.254755" stop-color="#1463B2" />
310
- <stop offset="0.498725" stop-color="#0A437D" />
311
- <stop offset="0.666667" stop-color="#2476C8" />
312
- <stop offset="0.972542" stop-color="#0C549A" />
244
+ <stop
245
+ v-for="stop in gradient.stops"
246
+ :key="`${stop.offset ?? '0'}-${stop.color}`"
247
+ :offset="stop.offset"
248
+ :stop-color="stop.color"
249
+ />
313
250
  </linearGradient>
314
251
  </defs>
315
252
  </svg>
@@ -9,6 +9,7 @@
9
9
  * the element that opened it (or `returnFocusTo`) when it closes.
10
10
  */
11
11
  import { computed, nextTick, onBeforeUnmount, onMounted, ref } from "vue";
12
+ import { ɵbindDialogFocus } from "@copilotkit/core";
12
13
  import { IconX } from "../icons";
13
14
  import { useCopilotChatConfiguration } from "../../providers/useCopilotChatConfiguration";
14
15
  import { CopilotChatDefaultLabels } from "../../providers/types";
@@ -29,49 +30,28 @@ const labels = computed(() => config.value?.labels ?? CopilotChatDefaultLabels);
29
30
 
30
31
  const root = ref<HTMLElement | null>(null);
31
32
  const closeButton = ref<HTMLButtonElement | null>(null);
32
- let previouslyFocused: HTMLElement | null = null;
33
-
34
- const FOCUSABLE =
35
- 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), audio[controls], video[controls], iframe, [tabindex]:not([tabindex="-1"])';
33
+ let releaseFocus: (() => void) | undefined;
36
34
 
37
35
  function handleKeydown(event: KeyboardEvent) {
38
36
  if (event.key === "Escape") emit("close");
39
37
  }
40
38
 
41
- /** Keeps Tab inside the lightbox while it is open. */
42
- function handleTab(event: KeyboardEvent) {
43
- if (event.key !== "Tab" || !root.value) return;
44
- const focusables = Array.from(
45
- root.value.querySelectorAll<HTMLElement>(FOCUSABLE),
46
- );
47
- const first = focusables[0];
48
- const last = focusables[focusables.length - 1];
49
- if (!first || !last) return;
50
- const active = document.activeElement;
51
- if (event.shiftKey && (active === first || !root.value.contains(active))) {
52
- event.preventDefault();
53
- last.focus();
54
- } else if (!event.shiftKey && active === last) {
55
- event.preventDefault();
56
- first.focus();
57
- }
58
- }
59
-
60
39
  onMounted(() => {
61
40
  if (typeof document === "undefined") return;
62
- previouslyFocused =
63
- document.activeElement instanceof HTMLElement
64
- ? document.activeElement
65
- : null;
66
41
  document.addEventListener("keydown", handleKeydown);
67
- void nextTick(() => closeButton.value?.focus());
42
+ void nextTick(() => {
43
+ if (!root.value) return;
44
+ releaseFocus = ɵbindDialogFocus(root.value, {
45
+ initialFocus: closeButton.value,
46
+ returnFocusTo: props.returnFocusTo,
47
+ });
48
+ });
68
49
  });
69
50
 
70
51
  onBeforeUnmount(() => {
71
52
  if (typeof document === "undefined") return;
72
53
  document.removeEventListener("keydown", handleKeydown);
73
- const target = props.returnFocusTo ?? previouslyFocused;
74
- if (target?.isConnected) target.focus();
54
+ releaseFocus?.();
75
55
  });
76
56
  </script>
77
57
 
@@ -85,7 +65,6 @@ onBeforeUnmount(() => {
85
65
  :aria-label="label"
86
66
  data-testid="copilot-chat-attachment-lightbox"
87
67
  @click="emit('close')"
88
- @keydown="handleTab"
89
68
  >
90
69
  <button
91
70
  ref="closeButton"
@@ -1,5 +1,15 @@
1
1
  <script setup lang="ts">
2
- import { computed, h, onMounted, provide, ref, useSlots, watch } from "vue";
2
+ import {
3
+ computed,
4
+ h,
5
+ onBeforeUnmount,
6
+ onMounted,
7
+ provide,
8
+ ref,
9
+ shallowRef,
10
+ useSlots,
11
+ watch,
12
+ } from "vue";
3
13
  import type { Component, FunctionalComponent, VNode, VNodeChild } from "vue";
4
14
  import type {
5
15
  ActivityMessage,
@@ -15,6 +25,19 @@ import {
15
25
  createRowKeyStore,
16
26
  resolveRowRenderKeysById,
17
27
  } from "@copilotkit/shared";
28
+ import {
29
+ ɵdeduplicateMessages,
30
+ ɵcreateMessageViewModel,
31
+ ɵduplicateMessagesWarning,
32
+ ɵgetToolCallRendererNames,
33
+ ɵresolveActivityRenderer,
34
+ ɵresolveCustomMessageRenderers,
35
+ } from "@copilotkit/core";
36
+ import type {
37
+ CopilotChatToolCallDisplay,
38
+ ToolCallEntry,
39
+ ɵToolCallDisplayContextValue,
40
+ } from "@copilotkit/core";
18
41
  import type {
19
42
  InterruptRenderProps,
20
43
  VueCustomMessageRendererProps,
@@ -33,18 +56,6 @@ import {
33
56
  } from "./message-feedback";
34
57
  import type { MessageFeedbackScope } from "./message-feedback";
35
58
  import { ToolCallDisplayContextKey } from "./tool-call-display-context";
36
- import type { ToolCallDisplayContextValue } from "./tool-call-display-context";
37
- import {
38
- getToolCallLayouts,
39
- getToolCallRendererNames,
40
- getTurnWork,
41
- } from "./tool-call-layout";
42
- import type {
43
- CopilotChatToolCallDisplay,
44
- ToolCallEntry,
45
- ToolCallLayout,
46
- TurnWork,
47
- } from "./tool-call-layout";
48
59
  import type { CopilotChatWorkSummarySlotProps } from "./types";
49
60
 
50
61
  interface MessageMetaProps {
@@ -203,49 +214,37 @@ watch(
203
214
  { immediate: true },
204
215
  );
205
216
 
206
- function deduplicateMessages(messages: Message[]): Message[] {
207
- const byId = new Map<string, Message>();
208
- for (const message of messages) {
209
- const existing = byId.get(message.id);
210
- if (
211
- existing &&
212
- message.role === "assistant" &&
213
- existing.role === "assistant"
214
- ) {
215
- const content = message.content || existing.content;
216
- const toolCalls = message.toolCalls ?? existing.toolCalls;
217
- byId.set(message.id, {
218
- ...existing,
219
- ...message,
220
- content,
221
- toolCalls,
222
- } as AssistantMessage);
223
- } else {
224
- byId.set(message.id, message);
225
- }
226
- }
227
- return [...byId.values()];
228
- }
229
-
230
217
  const deduplicatedMessages = computed(() =>
231
- deduplicateMessages(props.messages),
218
+ ɵdeduplicateMessages(props.messages),
232
219
  );
233
220
 
234
221
  // Groups of calls can span messages (an agent often sends each call as its
235
222
  // own message), so they're laid out here for the whole list and handed to
236
223
  // each message's tool calls view through provide/inject.
237
- const toolCallLayouts = computed<ReadonlyMap<string, ToolCallLayout>>(() =>
238
- props.toolCallDisplay === "separate"
239
- ? new Map()
240
- : getToolCallLayouts(
241
- deduplicatedMessages.value,
242
- props.messages,
243
- getToolCallRendererNames(
244
- copilotkit.value.renderToolCalls,
245
- forwardedSlotNames.value,
246
- ),
247
- ),
224
+ const rendererNames = computed(() =>
225
+ ɵgetToolCallRendererNames(copilotkit.value.renderToolCalls, {
226
+ slotNames: forwardedSlotNames.value,
227
+ }),
248
228
  );
229
+ // The list's tool-call layout and turn state live in core. A user's open or
230
+ // close of a reply's work is the only change it reports by itself.
231
+ const viewModel = ɵcreateMessageViewModel();
232
+ const toggledTurns = shallowRef(viewModel.getSnapshot());
233
+ const unsubscribeViewModel = viewModel.subscribe(() => {
234
+ toggledTurns.value = viewModel.getSnapshot();
235
+ });
236
+ onBeforeUnmount(unsubscribeViewModel);
237
+ const viewState = computed(() => {
238
+ void toggledTurns.value;
239
+ return viewModel.update({
240
+ display: props.toolCallDisplay,
241
+ messages: props.messages,
242
+ rendered: deduplicatedMessages.value,
243
+ isRunning: props.isRunning,
244
+ rendererNames: rendererNames.value,
245
+ now: Date.now(),
246
+ });
247
+ });
249
248
  const learningFeedbackEnabled = useLearningFeedbackEnabled(copilotkit);
250
249
  provide(
251
250
  MessageFeedbackScopeKey,
@@ -263,98 +262,18 @@ provide(
263
262
  ),
264
263
  );
265
264
 
266
- const turnWork = computed(() =>
267
- props.toolCallDisplay === "turn"
268
- ? getTurnWork(deduplicatedMessages.value, toolCallLayouts.value)
269
- : undefined,
270
- );
271
- const turnByFirstMessage = computed(() => {
272
- const byFirst = new Map<string, TurnWork>();
273
- for (const turn of turnWork.value?.values() ?? []) {
274
- byFirst.set(turn.firstMessageId, turn);
275
- }
276
- return byFirst;
277
- });
278
-
279
- const lastRenderedMessage = computed(
280
- () => deduplicatedMessages.value[deduplicatedMessages.value.length - 1],
281
- );
265
+ const turnByFirstMessage = computed(() => viewState.value.turnByFirstMessage);
282
266
  // The latest reply is keyed by the user message it answers (see getTurnWork).
283
- const latestTurnKey = computed(() => {
284
- const rendered = deduplicatedMessages.value;
285
- for (let i = rendered.length - 1; i >= 0; i--) {
286
- if (rendered[i]!.role === "user") return rendered[i]!.id;
287
- }
288
- return "start";
289
- });
290
- const isWorkingOn = (turnKey: string) =>
291
- props.isRunning && turnKey === latestTurnKey.value;
292
-
293
- // Work shows while the agent is on it and folds once the reply is done,
294
- // unless the user has opened or closed it themselves.
295
- const toggledTurns = ref<ReadonlyMap<string, boolean>>(new Map());
296
- const isWorkOpen = (turnKey: string) =>
297
- toggledTurns.value.get(turnKey) ?? isWorkingOn(turnKey);
298
-
299
- // How long the agent worked, for "Worked for 9s": the sum of its runs on the
300
- // reply, so waiting between them (say, for an approval) doesn't count. Only
301
- // known for replies this client watched start from the user's message; a
302
- // restored thread shows the tool count instead.
303
- const workTimes = new Map<
304
- string,
305
- { elapsedMs: number; workingSince?: number }
306
- >();
307
- const workTimesVersion = ref(0);
308
- watch(
309
- [
310
- () => props.toolCallDisplay,
311
- () => props.isRunning,
312
- latestTurnKey,
313
- () => lastRenderedMessage.value?.role,
314
- ],
315
- ([display, isRunning, turnKey, lastRole]) => {
316
- if (display !== "turn") return;
317
- const now = Date.now();
318
- if (isRunning) {
319
- const times = workTimes.get(turnKey);
320
- if (times) times.workingSince ??= now;
321
- else if (lastRole === "user")
322
- workTimes.set(turnKey, { elapsedMs: 0, workingSince: now });
323
- } else {
324
- for (const times of workTimes.values()) {
325
- if (times.workingSince === undefined) continue;
326
- times.elapsedMs += now - times.workingSince;
327
- times.workingSince = undefined;
328
- }
329
- }
330
- workTimesVersion.value++;
331
- },
332
- { immediate: true },
333
- );
334
-
335
- // Whether each working-phase message's work shows. Text that ends the reply
336
- // stays out even when its message also calls a tool: it's the answer.
337
- const workOpenState = computed(() => {
338
- const open = new Map<string, boolean>();
339
- const textOpen = new Map<string, boolean>();
340
- for (const turn of turnWork.value?.values() ?? []) {
341
- const turnOpen = isWorkOpen(turn.key);
342
- for (const id of turn.workMessageIds) {
343
- open.set(id, turnOpen);
344
- if (id !== turn.replyTextMessageId) textOpen.set(id, turnOpen);
345
- }
346
- }
347
- return { workOpen: open, workTextOpen: textOpen };
348
- });
267
+ const latestTurnKey = computed(() => viewState.value.latestTurnKey);
349
268
 
350
269
  provide(
351
270
  ToolCallDisplayContextKey,
352
- computed<ToolCallDisplayContextValue>(() => ({
271
+ computed<ɵToolCallDisplayContextValue>(() => ({
353
272
  display: props.toolCallDisplay,
354
273
  isRunning: props.isRunning,
355
- layouts: toolCallLayouts.value,
356
- workOpen: workOpenState.value.workOpen,
357
- workTextOpen: workOpenState.value.workTextOpen,
274
+ layouts: viewState.value.layouts,
275
+ workOpen: viewState.value.workOpen,
276
+ workTextOpen: viewState.value.workTextOpen,
358
277
  })),
359
278
  );
360
279
 
@@ -363,10 +282,10 @@ const WorkSummaryRow: FunctionalComponent<{
363
282
  turnKey: string;
364
283
  calls: ToolCallEntry[];
365
284
  }> = ({ turnKey, calls }) => {
366
- void workTimesVersion.value;
367
- const isWorking = isWorkingOn(turnKey);
368
- const isOpen = isWorkOpen(turnKey);
369
- const times = workTimes.get(turnKey);
285
+ void viewState.value;
286
+ const isWorking = viewModel.isTurnWorking(turnKey);
287
+ const isOpen = viewModel.isTurnOpen(turnKey);
288
+ const times = viewModel.getWorkTime(turnKey);
370
289
  const summaryProps: CopilotChatWorkSummarySlotProps = {
371
290
  isWorking,
372
291
  isOpen,
@@ -374,7 +293,7 @@ const WorkSummaryRow: FunctionalComponent<{
374
293
  elapsedMs: times?.elapsedMs,
375
294
  workingSince: times?.workingSince,
376
295
  onClick: () => {
377
- toggledTurns.value = new Map(toggledTurns.value).set(turnKey, !isOpen);
296
+ viewModel.toggleTurn(turnKey);
378
297
  },
379
298
  };
380
299
  const slot = componentSlots["work-summary"];
@@ -411,34 +330,15 @@ watch(
411
330
  (messages) => commitRowKeyStore(rowKeyStore, messages),
412
331
  { flush: "post" },
413
332
  );
414
- const lastMessage = computed(() => props.messages[props.messages.length - 1]);
415
- // In the "turn" display the "Working" line at the top of the reply is the
416
- // progress indicator; before the reply's first message it sits where the
417
- // cursor would.
418
- const showCursor = computed(
419
- () =>
420
- props.isRunning &&
421
- lastMessage.value?.role !== "reasoning" &&
422
- props.toolCallDisplay !== "turn",
423
- );
424
- const pendingWorkSummary = computed(
425
- () =>
426
- props.toolCallDisplay === "turn" &&
427
- props.isRunning &&
428
- lastRenderedMessage.value?.role === "user",
429
- );
333
+ const showCursor = computed(() => viewState.value.showCursor);
334
+ const pendingWorkSummary = computed(() => viewState.value.pendingWorkSummary);
430
335
 
431
336
  watch(
432
337
  [() => props.messages.length, () => deduplicatedMessages.value.length],
433
338
  ([messageCount, deduplicatedCount]) => {
434
- if (
435
- process.env.NODE_ENV === "development" &&
436
- deduplicatedCount < messageCount
437
- ) {
438
- console.warn(
439
- `CopilotChatMessageView: Deduplicated ${messageCount - deduplicatedCount} message(s) with duplicate IDs.`,
440
- );
441
- }
339
+ if (process.env.NODE_ENV !== "development") return;
340
+ const warning = ɵduplicateMessagesWarning(messageCount, deduplicatedCount);
341
+ if (warning) console.warn(warning);
442
342
  },
443
343
  { immediate: true },
444
344
  );
@@ -534,21 +434,12 @@ function resolveCustomMessageRenderer(
534
434
  return null;
535
435
  }
536
436
 
537
- const agentId = resolvedAgentId.value;
538
- const renderers = [...copilotkit.value.renderCustomMessages]
539
- .filter(
540
- (renderer) =>
541
- renderer.agentId === undefined || renderer.agentId === agentId,
542
- )
543
- .sort((a, b) => {
544
- const aHasAgent = a.agentId !== undefined;
545
- const bHasAgent = b.agentId !== undefined;
546
- if (aHasAgent === bHasAgent) return 0;
547
- return aHasAgent ? -1 : 1;
548
- });
549
-
550
- const selected = renderers[0];
551
- if (!selected?.render) {
437
+ // Try each renderer in order and use the first that has something to draw.
438
+ const selected = ɵresolveCustomMessageRenderers(
439
+ copilotkit.value.renderCustomMessages,
440
+ resolvedAgentId.value,
441
+ ).find((renderer) => renderer.render);
442
+ if (!selected) {
552
443
  return null;
553
444
  }
554
445
 
@@ -563,45 +454,26 @@ function resolveActivityRenderer(
563
454
  ): { renderer: Component; props: ActivitySlotProps } | null {
564
455
  stateTick.value += 0;
565
456
 
566
- const agentId = resolvedAgentId.value;
567
- const renderer = [...copilotkit.value.renderActivityMessages]
568
- .filter(
569
- (entry) =>
570
- entry.activityType === message.activityType &&
571
- (entry.agentId === undefined || entry.agentId === agentId),
572
- )
573
- .sort((a, b) => {
574
- const aScoped = a.agentId !== undefined;
575
- const bScoped = b.agentId !== undefined;
576
- if (aScoped === bScoped) return 0;
577
- return aScoped ? -1 : 1;
578
- })[0];
579
-
580
- if (!renderer) return null;
581
- const parsed = renderer.content.safeParse(message.content);
582
- if (!parsed.success) return null;
457
+ const match = ɵresolveActivityRenderer(
458
+ copilotkit.value.renderActivityMessages,
459
+ {
460
+ activityType: message.activityType,
461
+ agentId: resolvedAgentId.value,
462
+ content: message.content,
463
+ },
464
+ );
465
+ if (!match) return null;
583
466
 
584
467
  return {
585
- renderer: renderer.render as Component,
468
+ renderer: match.renderer.render as Component,
586
469
  props: {
587
470
  activityType: message.activityType,
588
- content: parsed.data,
471
+ content: match.content,
589
472
  message,
590
473
  agent: resolvedThreadAgent.value,
591
474
  },
592
475
  };
593
476
  }
594
-
595
- function resolveToolMessage(
596
- message: Message,
597
- toolCallId: string,
598
- ): ToolMessage | undefined {
599
- return props.messages.find(
600
- (candidate) =>
601
- candidate.role === "tool" &&
602
- (candidate as ToolMessage).toolCallId === toolCallId,
603
- ) as ToolMessage | undefined;
604
- }
605
477
  </script>
606
478
 
607
479
  <template>
@@ -675,7 +547,7 @@ function resolveToolMessage(
675
547
  v-else-if="message.role === 'reasoning'"
676
548
  :open="
677
549
  toolCallDisplay === 'turn'
678
- ? (workOpenState.workOpen.get(message.id) ?? true)
550
+ ? (viewState.workOpen.get(message.id) ?? true)
679
551
  : undefined
680
552
  "
681
553
  >