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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (343) hide show
  1. package/CONTRIBUTOR_GUIDE.md +1 -1
  2. package/PARITY.md +3 -3
  3. package/dist/hooks/use-copilot-action.d.ts.map +1 -1
  4. package/dist/hooks/use-frontend-tool.d.ts +1 -1
  5. package/dist/hooks/use-frontend-tool.d.ts.map +1 -1
  6. package/dist/hooks/zod-parameters.d.ts +14 -0
  7. package/dist/hooks/zod-parameters.d.ts.map +1 -0
  8. package/dist/index.cjs +1 -73
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.mjs +365 -16920
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/use-render-activity-message-BMTHA_P2.js +15901 -0
  13. package/dist/use-render-activity-message-BMTHA_P2.js.map +1 -0
  14. package/dist/use-render-activity-message-CH3beu7z.cjs +113 -0
  15. package/dist/use-render-activity-message-CH3beu7z.cjs.map +1 -0
  16. package/dist/v2/components/A2UIMessageRenderer.d.ts +14 -0
  17. package/dist/v2/components/A2UIMessageRenderer.d.ts.map +1 -1
  18. package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts +10 -3
  19. package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts.map +1 -1
  20. package/dist/v2/components/CopilotKitInspector.vue.d.ts +5 -1
  21. package/dist/v2/components/CopilotKitInspector.vue.d.ts.map +1 -1
  22. package/dist/v2/components/InlineFeatureWarning.vue.d.ts.map +1 -1
  23. package/dist/v2/components/LicenseWarningBanner.vue.d.ts +2 -2
  24. package/dist/v2/components/LicenseWarningBanner.vue.d.ts.map +1 -1
  25. package/dist/v2/components/MCPAppsActivityRenderer.d.ts.map +1 -1
  26. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts +13 -59
  27. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts.map +1 -1
  28. package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts +3 -11
  29. package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts.map +1 -1
  30. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts +10 -15
  31. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts.map +1 -1
  32. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts +14 -130
  33. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts.map +1 -1
  34. package/dist/v2/components/a2ui/catalog.d.ts.map +1 -1
  35. package/dist/v2/components/a2ui/utils.d.ts +3 -15
  36. package/dist/v2/components/a2ui/utils.d.ts.map +1 -1
  37. package/dist/v2/components/a2ui.d.ts +9 -8
  38. package/dist/v2/components/a2ui.d.ts.map +1 -1
  39. package/dist/v2/components/chat/CopilotChat.vue.d.ts +2 -2
  40. package/dist/v2/components/chat/CopilotChat.vue.d.ts.map +1 -1
  41. package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts.map +1 -1
  42. package/dist/v2/components/chat/CopilotChatAttachmentQueue.vue.d.ts.map +1 -1
  43. package/dist/v2/components/chat/CopilotChatAttachmentRenderer.vue.d.ts.map +1 -1
  44. package/dist/v2/components/chat/CopilotChatAudioRecorder.vue.d.ts +4 -8
  45. package/dist/v2/components/chat/CopilotChatAudioRecorder.vue.d.ts.map +1 -1
  46. package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts +1 -1
  47. package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts.map +1 -1
  48. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts +7 -286
  49. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts.map +1 -1
  50. package/dist/v2/components/chat/CopilotChatInspectorButton.vue.d.ts.map +1 -1
  51. package/dist/v2/components/chat/CopilotChatLightbox.vue.d.ts.map +1 -1
  52. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts +1 -1
  53. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts.map +1 -1
  54. package/dist/v2/components/chat/CopilotChatReasoningMessage.vue.d.ts.map +1 -1
  55. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts +1 -1
  56. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts.map +1 -1
  57. package/dist/v2/components/chat/CopilotChatToolCallItem.vue.d.ts.map +1 -1
  58. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts +1 -1
  59. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts.map +1 -1
  60. package/dist/v2/components/chat/CopilotChatUserMessage.vue.d.ts.map +1 -1
  61. package/dist/v2/components/chat/CopilotChatView.vue.d.ts +3 -3
  62. package/dist/v2/components/chat/CopilotChatView.vue.d.ts.map +1 -1
  63. package/dist/v2/components/chat/CopilotChatWorkSummary.vue.d.ts.map +1 -1
  64. package/dist/v2/components/chat/CopilotModalHeader.vue.d.ts.map +1 -1
  65. package/dist/v2/components/chat/CopilotPopup.vue.d.ts +8 -3
  66. package/dist/v2/components/chat/CopilotPopup.vue.d.ts.map +1 -1
  67. package/dist/v2/components/chat/CopilotPopupView.vue.d.ts +5 -3
  68. package/dist/v2/components/chat/CopilotPopupView.vue.d.ts.map +1 -1
  69. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts +5 -3
  70. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts.map +1 -1
  71. package/dist/v2/components/chat/CopilotSidebar.vue.d.ts +8 -3
  72. package/dist/v2/components/chat/CopilotSidebar.vue.d.ts.map +1 -1
  73. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts +6 -4
  74. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts.map +1 -1
  75. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts +6 -4
  76. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts.map +1 -1
  77. package/dist/v2/components/chat/CopilotThreadsDrawer.vue.d.ts.map +1 -1
  78. package/dist/v2/components/chat/StreamingMarkdownDefault.vue.d.ts +1 -0
  79. package/dist/v2/components/chat/StreamingMarkdownDefault.vue.d.ts.map +1 -1
  80. package/dist/v2/components/chat/audioRecorder.d.ts +3 -4
  81. package/dist/v2/components/chat/audioRecorder.d.ts.map +1 -1
  82. package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts +4 -4
  83. package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts.map +1 -1
  84. package/dist/v2/components/chat/forwarded-slots.d.ts +12 -0
  85. package/dist/v2/components/chat/forwarded-slots.d.ts.map +1 -0
  86. package/dist/v2/components/chat/index.d.ts +34 -31
  87. package/dist/v2/components/chat/index.d.ts.map +1 -1
  88. package/dist/v2/components/chat/inspector-shortcuts.d.ts +2 -1
  89. package/dist/v2/components/chat/inspector-shortcuts.d.ts.map +1 -1
  90. package/dist/v2/components/chat/message-feedback.d.ts +38 -49
  91. package/dist/v2/components/chat/message-feedback.d.ts.map +1 -1
  92. package/dist/v2/components/chat/tool-call-display-context.d.ts +4 -19
  93. package/dist/v2/components/chat/tool-call-display-context.d.ts.map +1 -1
  94. package/dist/v2/components/chat/tool-call-group-parts.d.ts +7 -20
  95. package/dist/v2/components/chat/tool-call-group-parts.d.ts.map +1 -1
  96. package/dist/v2/components/chat/turn-work.d.ts +0 -2
  97. package/dist/v2/components/chat/turn-work.d.ts.map +1 -1
  98. package/dist/v2/components/chat/types.d.ts +9 -4
  99. package/dist/v2/components/chat/types.d.ts.map +1 -1
  100. package/dist/v2/components/chat/use-chat-labels.d.ts +8 -0
  101. package/dist/v2/components/chat/use-chat-labels.d.ts.map +1 -0
  102. package/dist/v2/components/chat/use-copy-feedback.d.ts +11 -0
  103. package/dist/v2/components/chat/use-copy-feedback.d.ts.map +1 -0
  104. package/dist/v2/components/chat/use-lightbox.d.ts.map +1 -1
  105. package/dist/v2/components/icons/index.d.ts +968 -1
  106. package/dist/v2/components/icons/index.d.ts.map +1 -1
  107. package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts +1 -1
  108. package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts.map +1 -1
  109. package/dist/v2/hooks/use-agent-context.d.ts +2 -3
  110. package/dist/v2/hooks/use-agent-context.d.ts.map +1 -1
  111. package/dist/v2/hooks/use-agent.d.ts +4 -1
  112. package/dist/v2/hooks/use-agent.d.ts.map +1 -1
  113. package/dist/v2/hooks/use-attachments.d.ts +7 -0
  114. package/dist/v2/hooks/use-attachments.d.ts.map +1 -1
  115. package/dist/v2/hooks/use-capabilities.d.ts.map +1 -1
  116. package/dist/v2/hooks/use-component.d.ts +1 -0
  117. package/dist/v2/hooks/use-component.d.ts.map +1 -1
  118. package/dist/v2/hooks/use-configure-suggestions.d.ts +4 -9
  119. package/dist/v2/hooks/use-configure-suggestions.d.ts.map +1 -1
  120. package/dist/v2/hooks/use-default-render-tool.d.ts +2 -7
  121. package/dist/v2/hooks/use-default-render-tool.d.ts.map +1 -1
  122. package/dist/v2/hooks/use-frontend-tool.d.ts +5 -0
  123. package/dist/v2/hooks/use-frontend-tool.d.ts.map +1 -1
  124. package/dist/v2/hooks/use-human-in-the-loop.d.ts +2 -1
  125. package/dist/v2/hooks/use-human-in-the-loop.d.ts.map +1 -1
  126. package/dist/v2/hooks/use-interrupt.d.ts +0 -1
  127. package/dist/v2/hooks/use-interrupt.d.ts.map +1 -1
  128. package/dist/v2/hooks/use-keyboard-height.d.ts +1 -1
  129. package/dist/v2/hooks/use-keyboard-height.d.ts.map +1 -1
  130. package/dist/v2/hooks/use-pin-to-send.d.ts +4 -12
  131. package/dist/v2/hooks/use-pin-to-send.d.ts.map +1 -1
  132. package/dist/v2/hooks/use-render-activity-message.d.ts +13 -9
  133. package/dist/v2/hooks/use-render-activity-message.d.ts.map +1 -1
  134. package/dist/v2/hooks/use-render-custom-messages.d.ts +5 -7
  135. package/dist/v2/hooks/use-render-custom-messages.d.ts.map +1 -1
  136. package/dist/v2/hooks/use-render-tool.d.ts +1 -1
  137. package/dist/v2/hooks/use-render-tool.d.ts.map +1 -1
  138. package/dist/v2/hooks/use-suggestions.d.ts.map +1 -1
  139. package/dist/v2/hooks/use-threads.d.ts +6 -23
  140. package/dist/v2/hooks/use-threads.d.ts.map +1 -1
  141. package/dist/v2/index.cjs +1 -1
  142. package/dist/v2/index.mjs +197 -200
  143. package/dist/v2/index.mjs.map +1 -1
  144. package/dist/v2/lib/processPartialHtml.d.ts +1 -2
  145. package/dist/v2/lib/processPartialHtml.d.ts.map +1 -1
  146. package/dist/v2/lib/shallow-stable.d.ts.map +1 -1
  147. package/dist/v2/lib/vue-core.d.ts +33 -19
  148. package/dist/v2/lib/vue-core.d.ts.map +1 -1
  149. package/dist/v2/providers/CopilotChatConfigurationProvider.vue.d.ts.map +1 -1
  150. package/dist/v2/providers/CopilotKitProvider.types.d.ts +9 -129
  151. package/dist/v2/providers/CopilotKitProvider.types.d.ts.map +1 -1
  152. package/dist/v2/providers/CopilotKitProvider.vue.d.ts +9 -10
  153. package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
  154. package/dist/v2/providers/chat-configuration-store-key.d.ts +8 -0
  155. package/dist/v2/providers/chat-configuration-store-key.d.ts.map +1 -0
  156. package/dist/v2/providers/markdown-renderer.d.ts +4 -2
  157. package/dist/v2/providers/markdown-renderer.d.ts.map +1 -1
  158. package/dist/v2/providers/types.d.ts +3 -46
  159. package/dist/v2/providers/types.d.ts.map +1 -1
  160. package/dist/v2/providers/use-inspector-thread-override.d.ts +5 -0
  161. package/dist/v2/providers/use-inspector-thread-override.d.ts.map +1 -1
  162. package/dist/v2/types/defineToolCallRenderer.d.ts +1 -1
  163. package/dist/v2/types/defineToolCallRenderer.d.ts.map +1 -1
  164. package/dist/v2/types/human-in-the-loop.d.ts +8 -29
  165. package/dist/v2/types/human-in-the-loop.d.ts.map +1 -1
  166. package/dist/v2/types/interrupt.d.ts +1 -22
  167. package/dist/v2/types/interrupt.d.ts.map +1 -1
  168. package/dist/v2/types/vue-activity-message-renderer.d.ts +16 -15
  169. package/dist/v2/types/vue-activity-message-renderer.d.ts.map +1 -1
  170. package/dist/v2/types/vue-custom-message-renderer.d.ts +7 -16
  171. package/dist/v2/types/vue-custom-message-renderer.d.ts.map +1 -1
  172. package/dist/v2/types/vue-tool-call-renderer.d.ts +16 -35
  173. package/dist/v2/types/vue-tool-call-renderer.d.ts.map +1 -1
  174. package/package.json +12 -13
  175. package/src/__tests__/build-entries.test.ts +29 -0
  176. package/src/hooks/__tests__/zod-parameters.test.ts +520 -0
  177. package/src/hooks/use-copilot-action.ts +2 -1
  178. package/src/hooks/use-frontend-tool.ts +3 -6
  179. package/src/hooks/zod-parameters.ts +162 -0
  180. package/src/v2/__tests__/exports.test.ts +10 -0
  181. package/src/v2/__tests__/mocks/web-inspector.ts +6 -0
  182. package/src/v2/__tests__/utils/test-helpers.ts +34 -4
  183. package/src/v2/components/A2UIMessageRenderer.ts +98 -68
  184. package/src/v2/components/A2UISurfaceActivityRenderer.vue +68 -103
  185. package/src/v2/components/CopilotKitInspector.vue +104 -51
  186. package/src/v2/components/InlineFeatureWarning.vue +20 -21
  187. package/src/v2/components/LicenseWarningBanner.vue +27 -135
  188. package/src/v2/components/MCPAppsActivityRenderer.ts +75 -201
  189. package/src/v2/components/OpenGenerativeUIRenderer.ts +122 -446
  190. package/src/v2/components/__tests__/A2UIMessageRenderer.test.ts +171 -8
  191. package/src/v2/components/__tests__/CopilotKitInspector.test.ts +42 -0
  192. package/src/v2/components/__tests__/LicenseWarningBanner.test.ts +60 -0
  193. package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.ts +64 -8
  194. package/src/v2/components/__tests__/OpenGenerativeUIToolRenderer.test.ts +38 -0
  195. package/src/v2/components/a2ui/A2UIBuiltInToolCallRenderer.ts +6 -26
  196. package/src/v2/components/a2ui/A2UICatalogContext.ts +27 -185
  197. package/src/v2/components/a2ui/A2UIRecoveryStates.ts +127 -327
  198. package/src/v2/components/a2ui/catalog.ts +3 -3
  199. package/src/v2/components/a2ui/utils.ts +13 -65
  200. package/src/v2/components/a2ui.ts +15 -22
  201. package/src/v2/components/chat/CopilotChat.vue +121 -498
  202. package/src/v2/components/chat/CopilotChatAssistantMessage.vue +47 -184
  203. package/src/v2/components/chat/CopilotChatAttachmentQueue.vue +36 -55
  204. package/src/v2/components/chat/CopilotChatAttachmentRenderer.vue +14 -6
  205. package/src/v2/components/chat/CopilotChatAudioRecorder.vue +19 -246
  206. package/src/v2/components/chat/CopilotChatFeedbackCommentPopover.vue +12 -77
  207. package/src/v2/components/chat/CopilotChatInput.vue +139 -654
  208. package/src/v2/components/chat/CopilotChatInspectorButton.vue +45 -108
  209. package/src/v2/components/chat/CopilotChatLightbox.vue +10 -31
  210. package/src/v2/components/chat/CopilotChatMessageView.vue +96 -274
  211. package/src/v2/components/chat/CopilotChatReasoningMessage.vue +27 -62
  212. package/src/v2/components/chat/CopilotChatToolCallGroup.vue +63 -71
  213. package/src/v2/components/chat/CopilotChatToolCallItem.vue +8 -6
  214. package/src/v2/components/chat/CopilotChatToolCallsView.vue +31 -32
  215. package/src/v2/components/chat/CopilotChatUserMessage.vue +24 -112
  216. package/src/v2/components/chat/CopilotChatView.vue +123 -161
  217. package/src/v2/components/chat/CopilotChatWorkSummary.vue +26 -36
  218. package/src/v2/components/chat/CopilotModalHeader.vue +11 -23
  219. package/src/v2/components/chat/CopilotPopup.vue +23 -25
  220. package/src/v2/components/chat/CopilotPopupView.vue +10 -39
  221. package/src/v2/components/chat/CopilotPopupViewInternal.vue +49 -185
  222. package/src/v2/components/chat/CopilotSidebar.vue +23 -25
  223. package/src/v2/components/chat/CopilotSidebarView.vue +10 -39
  224. package/src/v2/components/chat/CopilotSidebarViewInternal.vue +56 -100
  225. package/src/v2/components/chat/CopilotThreadsDrawer.vue +43 -105
  226. package/src/v2/components/chat/StreamingMarkdownDefault.vue +15 -28
  227. package/src/v2/components/chat/__tests__/CopilotChat.labels.test.ts +19 -4
  228. package/src/v2/components/chat/__tests__/CopilotChat.test.ts +12 -10
  229. package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.ts +26 -9
  230. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.learningFeedback.test.ts +5 -5
  231. package/src/v2/components/chat/__tests__/CopilotChatAttachmentQueue.test.ts +28 -0
  232. package/src/v2/components/chat/__tests__/CopilotChatInput.test.ts +132 -1
  233. package/src/v2/components/chat/__tests__/CopilotChatMessageView.test.ts +247 -403
  234. package/src/v2/components/chat/__tests__/CopilotChatMessageView.toolCallDisplay.test.ts +1 -99
  235. package/src/v2/components/chat/__tests__/CopilotChatView.pinToSend.test.ts +43 -1
  236. package/src/v2/components/chat/__tests__/CopilotPopup.test.ts +90 -1
  237. package/src/v2/components/chat/__tests__/CopilotPopupView.test.ts +19 -0
  238. package/src/v2/components/chat/__tests__/CopilotSidebar.test.ts +90 -1
  239. package/src/v2/components/chat/__tests__/CopilotSidebarView.position.test.ts +32 -8
  240. package/src/v2/components/chat/__tests__/CopilotSidebarView.test.ts +2 -1
  241. package/src/v2/components/chat/__tests__/StreamingMarkdownDefault.test.ts +54 -0
  242. package/src/v2/components/chat/audioRecorder.ts +4 -7
  243. package/src/v2/components/chat/copilotChatToolCallItemRender.ts +25 -90
  244. package/src/v2/components/chat/forwarded-slots.ts +17 -0
  245. package/src/v2/components/chat/index.ts +0 -1
  246. package/src/v2/components/chat/inspector-shortcuts.ts +10 -16
  247. package/src/v2/components/chat/message-feedback.ts +92 -195
  248. package/src/v2/components/chat/tool-call-display-context.ts +6 -22
  249. package/src/v2/components/chat/tool-call-group-parts.ts +47 -108
  250. package/src/v2/components/chat/turn-work.ts +0 -9
  251. package/src/v2/components/chat/types.ts +12 -4
  252. package/src/v2/components/chat/use-chat-labels.ts +16 -0
  253. package/src/v2/components/chat/use-copy-feedback.ts +21 -0
  254. package/src/v2/components/chat/use-lightbox.ts +15 -33
  255. package/src/v2/components/icons/__tests__/icons.test.ts +72 -68
  256. package/src/v2/components/icons/index.ts +109 -27
  257. package/src/v2/hooks/__tests__/use-agent-error-state.test.ts +5 -3
  258. package/src/v2/hooks/__tests__/use-agent-stability.test.ts +25 -4
  259. package/src/v2/hooks/__tests__/use-agent-throttle.test.ts +5 -1
  260. package/src/v2/hooks/__tests__/use-agent.test.ts +6 -3
  261. package/src/v2/hooks/__tests__/use-component.test.ts +21 -0
  262. package/src/v2/hooks/__tests__/use-configure-suggestions.test.ts +30 -1
  263. package/src/v2/hooks/__tests__/use-default-render-tool.test.ts +10 -10
  264. package/src/v2/hooks/__tests__/use-frontend-tool.e2e.test.ts +66 -1
  265. package/src/v2/hooks/__tests__/use-human-in-the-loop.e2e.test.ts +6 -1
  266. package/src/v2/hooks/__tests__/use-human-in-the-loop.test.ts +187 -12
  267. package/src/v2/hooks/__tests__/use-interrupt.test.ts +97 -0
  268. package/src/v2/hooks/__tests__/use-render-activity-message.test.ts +106 -0
  269. package/src/v2/hooks/__tests__/use-render-tool.test.ts +3 -6
  270. package/src/v2/hooks/__tests__/use-threads.test.ts +48 -6
  271. package/src/v2/hooks/__tests__/zod-regression.test.ts +5 -4
  272. package/src/v2/hooks/use-agent-context.ts +4 -10
  273. package/src/v2/hooks/use-agent.ts +86 -290
  274. package/src/v2/hooks/use-attachments.ts +48 -168
  275. package/src/v2/hooks/use-capabilities.ts +2 -7
  276. package/src/v2/hooks/use-component.ts +7 -4
  277. package/src/v2/hooks/use-configure-suggestions.ts +29 -220
  278. package/src/v2/hooks/use-default-render-tool.ts +31 -152
  279. package/src/v2/hooks/use-frontend-tool.ts +15 -25
  280. package/src/v2/hooks/use-human-in-the-loop.ts +11 -80
  281. package/src/v2/hooks/use-interrupt.ts +29 -308
  282. package/src/v2/hooks/use-keyboard-height.ts +17 -40
  283. package/src/v2/hooks/use-pin-to-send.ts +15 -99
  284. package/src/v2/hooks/use-render-activity-message.ts +35 -57
  285. package/src/v2/hooks/use-render-custom-messages.ts +24 -88
  286. package/src/v2/hooks/use-render-tool.ts +2 -4
  287. package/src/v2/hooks/use-suggestions.ts +17 -36
  288. package/src/v2/hooks/use-threads.ts +49 -288
  289. package/src/v2/lib/__tests__/shallow-stable.test.ts +54 -0
  290. package/src/v2/lib/__tests__/vue-core-renderers.test.ts +42 -0
  291. package/src/v2/lib/processPartialHtml.ts +6 -21
  292. package/src/v2/lib/shallow-stable.ts +2 -16
  293. package/src/v2/lib/vue-core.ts +90 -85
  294. package/src/v2/providers/CopilotChatConfigurationProvider.vue +48 -186
  295. package/src/v2/providers/CopilotKitProvider.types.ts +12 -132
  296. package/src/v2/providers/CopilotKitProvider.vue +291 -641
  297. package/src/v2/providers/__tests__/CopilotChatConfigurationProvider.test.ts +22 -2
  298. package/src/v2/providers/__tests__/CopilotKitProvider.a2ui.test.ts +38 -2
  299. package/src/v2/providers/__tests__/CopilotKitProvider.config.test.ts +124 -0
  300. package/src/v2/providers/__tests__/CopilotKitProvider.headersAtSendTime.test.ts +3 -3
  301. package/src/v2/providers/__tests__/CopilotKitProvider.learning.test.ts +3 -1
  302. package/src/v2/providers/__tests__/CopilotKitProvider.sandboxFunctions.test.ts +4 -1
  303. package/src/v2/providers/__tests__/CopilotKitProvider.test.ts +88 -28
  304. package/src/v2/providers/chat-configuration-store-key.ts +9 -0
  305. package/src/v2/providers/markdown-renderer.ts +8 -2
  306. package/src/v2/providers/types.ts +3 -49
  307. package/src/v2/providers/use-inspector-thread-override.ts +22 -80
  308. package/src/v2/types/__tests__/defineToolCallRenderer.test.ts +28 -33
  309. package/src/v2/types/defineToolCallRenderer.ts +7 -6
  310. package/src/v2/types/human-in-the-loop.ts +8 -32
  311. package/src/v2/types/interrupt.ts +7 -31
  312. package/src/v2/types/vue-activity-message-renderer.ts +24 -15
  313. package/src/v2/types/vue-custom-message-renderer.ts +12 -16
  314. package/src/v2/types/vue-tool-call-renderer.ts +23 -38
  315. package/tsconfig.json +0 -1
  316. package/vite.config.ts +8 -5
  317. package/vitest.config.ts +12 -7
  318. package/dist/v2/components/chat/BasicMarkdown.vue.d.ts +0 -9
  319. package/dist/v2/components/chat/BasicMarkdown.vue.d.ts.map +0 -1
  320. package/dist/v2/components/chat/normalize-auto-scroll.d.ts +0 -3
  321. package/dist/v2/components/chat/normalize-auto-scroll.d.ts.map +0 -1
  322. package/dist/v2/components/chat/tool-call-layout.d.ts +0 -115
  323. package/dist/v2/components/chat/tool-call-layout.d.ts.map +0 -1
  324. package/dist/v2/lib/is-mobile-viewport.d.ts +0 -15
  325. package/dist/v2/lib/is-mobile-viewport.d.ts.map +0 -1
  326. package/dist/v2/lib/message-feedback.d.ts +0 -33
  327. package/dist/v2/lib/message-feedback.d.ts.map +0 -1
  328. package/dist/v2/lib/transcription-client.d.ts +0 -19
  329. package/dist/v2/lib/transcription-client.d.ts.map +0 -1
  330. package/src/v2/components/__tests__/A2UICatalogContext.test.ts +0 -63
  331. package/src/v2/components/a2ui/__tests__/A2UIRecoveryStates.test.ts +0 -175
  332. package/src/v2/components/chat/BasicMarkdown.vue +0 -160
  333. package/src/v2/components/chat/__tests__/BasicMarkdown.test.ts +0 -69
  334. package/src/v2/components/chat/__tests__/normalize-auto-scroll.test.ts +0 -39
  335. package/src/v2/components/chat/normalize-auto-scroll.ts +0 -17
  336. package/src/v2/components/chat/tool-call-layout.ts +0 -304
  337. package/src/v2/lib/__tests__/is-mobile-viewport.test.ts +0 -48
  338. package/src/v2/lib/__tests__/message-feedback.test.ts +0 -152
  339. package/src/v2/lib/__tests__/processPartialHtml.test.ts +0 -84
  340. package/src/v2/lib/__tests__/transcription-client.test.ts +0 -67
  341. package/src/v2/lib/is-mobile-viewport.ts +0 -23
  342. package/src/v2/lib/message-feedback.ts +0 -120
  343. package/src/v2/lib/transcription-client.ts +0 -151
@@ -1,11 +1,4 @@
1
1
  <script setup lang="ts">
2
- import { AGUIConnectNotImplementedError, AbstractAgent } from "@ag-ui/client";
3
- import {
4
- createAttachmentContent,
5
- DEFAULT_AGENT_ID,
6
- randomUUID,
7
- TranscriptionErrorCode,
8
- } from "@copilotkit/shared";
9
2
  import {
10
3
  computed,
11
4
  onBeforeUnmount,
@@ -17,7 +10,16 @@ import {
17
10
  useSlots,
18
11
  watch,
19
12
  } from "vue";
20
- import { CopilotKitCoreErrorCode, ɵisHttpAgent } from "@copilotkit/core";
13
+ import {
14
+ CopilotChatDefaultLabels,
15
+ ɵChatConnection,
16
+ ɵcreateChatSubmitter,
17
+ ɵcreateLastUserMessageTracker,
18
+ ɵFreshThreadId,
19
+ ɵresolveAgentId,
20
+ ɵresolveChatNotice,
21
+ ɵsubscribeToAgentErrors,
22
+ } from "@copilotkit/core";
21
23
  import type { Suggestion } from "@copilotkit/core";
22
24
  import CopilotChatConfigurationProvider from "../../providers/CopilotChatConfigurationProvider.vue";
23
25
  import { useCopilotChatConfiguration } from "../../providers/useCopilotChatConfiguration";
@@ -28,15 +30,10 @@ import { useAgent } from "../../hooks/use-agent";
28
30
  import { useSuggestions } from "../../hooks/use-suggestions";
29
31
  import { useAttachments } from "../../hooks/use-attachments";
30
32
  import { useShallowStableRef } from "../../lib/shallow-stable";
31
- import {
32
- transcribeAudio,
33
- TranscriptionError,
34
- } from "../../lib/transcription-client";
35
33
  import CopilotChatView from "./CopilotChatView.vue";
36
34
  import { LastUserMessageKey } from "./last-user-message-context";
37
35
  import type { LastUserMessageState } from "./last-user-message-context";
38
36
  import type { Message } from "@ag-ui/core";
39
- import type { InputContent } from "@copilotkit/shared";
40
37
  import { useInspectorThreadOverride } from "../../providers/use-inspector-thread-override";
41
38
  import { CopilotKitStyles } from "../../styles/CopilotKitStyles";
42
39
  import type {
@@ -94,33 +91,35 @@ const forwardedChatViewSlotNames = computed(() =>
94
91
  Object.keys(componentSlots).filter((slotName) => slotName !== "chat-view"),
95
92
  );
96
93
 
97
- const generatedThreadId = ref(randomUUID());
98
94
  const transcribeMode = ref<"input" | "transcribe" | "processing">("input");
99
95
  const inputValue = ref(props.inputValue ?? "");
100
- const transcriptionError = ref<string | null>(null);
101
- const isTranscribing = ref(false);
102
96
  const isMounted = ref(false);
103
- const isUnmounting = ref(false);
104
-
105
- type ActiveConnectCycle = {
106
- core: object;
107
- agent: AbstractAgent;
108
- threadId: string;
109
- inspectorRequestId: string | null;
110
- abortController: AbortController;
111
- detached: boolean;
112
- clearDiscardedBaseline?: () => void;
113
- };
114
-
115
- const activeConnectCycle = shallowRef<ActiveConnectCycle | null>(null);
116
- let lastConnectCycle: ActiveConnectCycle | null = null;
117
- const detachPromises = new WeakMap<AbstractAgent, Promise<void>>();
118
- // Agent clones can share cursors. Finish every old reset before connecting again.
119
- let pendingTeardown = Promise.resolve();
120
- const baselineThreadIds = new WeakMap<AbstractAgent, string>();
121
-
122
- const resolvedAgentId = computed(
123
- () => props.agentId ?? existingConfig.value?.agentId ?? DEFAULT_AGENT_ID,
97
+
98
+ // Loads the thread this chat shows: keeps the agent on it, orders the
99
+ // teardown of the previous thread, owns the connect's abort and detach, and
100
+ // tracks connections a send must wait for.
101
+ const connection = new ɵChatConnection({
102
+ core: {
103
+ connectAgent: (params) => copilotkit.value.connectAgent(params),
104
+ stopAgent: (params) => copilotkit.value.stopAgent(params),
105
+ subscribe: (subscriber) => copilotkit.value.subscribe(subscriber),
106
+ },
107
+ onInspectorOverrideFailed: (requestId) => failInspectorOverride(requestId),
108
+ });
109
+ const { threads } = connection;
110
+ const connectionState = shallowRef(connection.getSnapshot());
111
+ connection.subscribe(() => {
112
+ connectionState.value = connection.getSnapshot();
113
+ });
114
+ // The locally minted thread used while no thread is provided. A new one is
115
+ // minted each time the provided thread goes away.
116
+ const freshThreadId = new ɵFreshThreadId();
117
+
118
+ const resolvedAgentId = computed(() =>
119
+ ɵresolveAgentId({
120
+ agentId: props.agentId,
121
+ chatAgentId: existingConfig.value?.agentId,
122
+ }),
124
123
  );
125
124
  // "Provided" — supplied by either the caller's prop or a wrapping
126
125
  // CopilotChatConfigurationProvider. Distinct from `resolvedThreadId`, which
@@ -130,8 +129,8 @@ const resolvedAgentId = computed(
130
129
  const providedThreadId = computed(
131
130
  () => props.threadId ?? existingConfig.value?.threadId,
132
131
  );
133
- const baseThreadId = computed(
134
- () => providedThreadId.value ?? generatedThreadId.value,
132
+ const baseThreadId = computed(() =>
133
+ freshThreadId.resolve(providedThreadId.value),
135
134
  );
136
135
  // "Explicit" means the caller actually picked this thread — via the
137
136
  // `threadId` prop on CopilotChat or a wrapping provider that flagged its
@@ -151,14 +150,22 @@ const resolvedThreadId = computed(
151
150
  const hasExplicitThreadId = computed(
152
151
  () => inspectorThreadId.value !== null || baseHasExplicitThreadId.value,
153
152
  );
154
- const lastConnectedThreadId = ref<string | null>(null);
155
- const isConnecting = computed(
156
- () =>
157
- hasExplicitThreadId.value &&
158
- lastConnectedThreadId.value !== resolvedThreadId.value,
159
- );
153
+ // An explicit thread shows as connecting until its connect has settled.
154
+ const isConnecting = computed(() => {
155
+ void connectionState.value;
156
+ return connection.isConnecting({
157
+ threadId: resolvedThreadId.value,
158
+ explicit: hasExplicitThreadId.value,
159
+ });
160
+ });
160
161
  const stableLabels = useShallowStableRef(computed(() => props.labels));
161
162
  const resolvedLabels = computed(() => stableLabels.value);
163
+ // The labels this chat shows, the same merge its configuration provider makes.
164
+ const chatLabels = computed(() => ({
165
+ ...CopilotChatDefaultLabels,
166
+ ...existingConfig.value?.labels,
167
+ ...resolvedLabels.value,
168
+ }));
162
169
 
163
170
  // `useAgent` takes no threadId: it pins one only from a surrounding chat
164
171
  // configuration, and this call sits outside the provider rendered in this
@@ -227,27 +234,11 @@ const shouldAllowStop = computed(
227
234
  // Track the latest user message id so descendants (notably `usePinToSend`
228
235
  // inside `CopilotChatView`) can anchor to the most recent user turn.
229
236
  // Mirrors React `CopilotChat.tsx` `lastUserMessageId` + `sendNonce` state.
230
- const lastUserMessageId = computed<string | null>(() => {
231
- for (let i = messages.value.length - 1; i >= 0; i--) {
232
- const message = messages.value[i];
233
- if (message?.role === "user") return message.id;
234
- }
235
- return null;
236
- });
237
- const sendNonce = ref(0);
238
- // Seed with the current value so restoring a thread with existing messages
239
- // does not count as a new send. Only later id transitions bump.
240
- let prevLastUserMessageId: string | null = lastUserMessageId.value;
241
- watch(lastUserMessageId, (next) => {
242
- if (next && next !== prevLastUserMessageId) {
243
- sendNonce.value += 1;
244
- prevLastUserMessageId = next;
245
- }
246
- });
247
- const lastUserMessageState = computed<LastUserMessageState>(() => ({
248
- id: lastUserMessageId.value,
249
- sendNonce: sendNonce.value,
250
- }));
237
+ // Messages the chat starts with (a restored thread) do not count as a send.
238
+ const lastUserMessageTracker = ɵcreateLastUserMessageTracker(messages.value);
239
+ const lastUserMessageState = computed<LastUserMessageState>(() =>
240
+ lastUserMessageTracker.update(messages.value),
241
+ );
251
242
  provide(LastUserMessageKey, lastUserMessageState);
252
243
 
253
244
  watch(
@@ -279,61 +270,13 @@ watch(
279
270
  },
280
271
  );
281
272
 
282
- watch(
283
- [() => props.threadId, () => existingConfig.value?.threadId],
284
- ([threadId, inheritedThreadId], previousValues) => {
285
- if (threadId || inheritedThreadId) {
286
- return;
287
- }
288
-
289
- if (previousValues && (previousValues[0] || previousValues[1])) {
290
- generatedThreadId.value = randomUUID();
291
- }
292
- },
293
- );
294
-
295
273
  watch(
296
274
  [() => copilotkit.value, resolvedAgentId, () => props.onError],
297
275
  ([core, agentId, onError], _old, onCleanup) => {
298
276
  if (!onError) {
299
277
  return;
300
278
  }
301
-
302
- const subscription = core.subscribe({
303
- onError: (event) => {
304
- if (event.context?.agentId === agentId || !event.context?.agentId) {
305
- void onError({
306
- error: event.error,
307
- code: event.code,
308
- context: event.context,
309
- });
310
- }
311
- },
312
- });
313
-
314
- onCleanup(() => subscription.unsubscribe());
315
- },
316
- { immediate: true },
317
- );
318
-
319
- watch(
320
- [
321
- () => copilotkit.value,
322
- resolvedAgentId,
323
- resolvedThreadId,
324
- inspectorRequestId,
325
- ],
326
- ([core, agentId, threadId, requestId], _old, onCleanup) => {
327
- if (!requestId) return;
328
- const subscription = core.subscribe({
329
- onError: (event) => {
330
- if (event.code !== CopilotKitCoreErrorCode.AGENT_CONNECT_FAILED) return;
331
- if (event.context?.agentId !== agentId) return;
332
- if (event.context?.threadId !== threadId) return;
333
- failInspectorOverride(requestId);
334
- },
335
- });
336
- onCleanup(() => subscription.unsubscribe());
279
+ onCleanup(ɵsubscribeToAgentErrors(core, agentId, onError));
337
280
  },
338
281
  { immediate: true },
339
282
  );
@@ -348,367 +291,95 @@ watch(
348
291
  inspectorRequestId,
349
292
  ],
350
293
  (
351
- [mounted, core, currentAgent, threadId, isExplicit, requestId],
294
+ [mounted, _core, currentAgent, threadId, isExplicit, requestId],
352
295
  _old,
353
296
  onCleanup,
354
297
  ) => {
355
- if (!mounted) {
356
- return;
357
- }
358
- if (typeof window === "undefined") {
359
- return;
360
- }
361
- if (!currentAgent) {
362
- return;
363
- }
364
-
365
- const previousCycle = activeConnectCycle.value;
366
- const inspectorTransition =
367
- previousCycle !== null &&
368
- previousCycle.threadId !== threadId &&
369
- previousCycle.inspectorRequestId !== requestId &&
370
- (previousCycle.inspectorRequestId !== null || requestId !== null);
371
- if (inspectorTransition) {
372
- try {
373
- core.stopAgent({ agent: currentAgent });
374
- } catch {
375
- // No live run to stop.
376
- }
377
- }
378
-
379
- // Pin the thread this chat renders onto its agent, before anything issues a
380
- // request. `CopilotKitCore.connectAgent` reads `agent.threadId` synchronously
381
- // to decide whether this is a fresh restore, so a later assignment would let
382
- // /connect address the previous thread. Assigning inside this callback — as
383
- // React does — makes the ordering unconditional instead of depending on
384
- // watcher scheduling. Non-explicit threads skip /connect below, but the first
385
- // runAgent still has to ship the thread the UI is rendering.
386
- baselineThreadIds.set(currentAgent, currentAgent.threadId);
387
- currentAgent.threadId = threadId;
388
-
389
- // When the caller hasn't picked a specific thread, resolvedThreadId is
390
- // a UUID minted locally. The backend has never seen it, so /connect
391
- // would always 404 — skip the call. A real thread is only created
392
- // once the user runs the agent for the first time.
393
- if (!isExplicit) {
394
- return;
395
- }
396
-
397
- const abstractAgentPrototype = AbstractAgent.prototype as unknown as {
398
- connect?: unknown;
399
- connectAgent?: unknown;
400
- };
401
- const inspectableAgent = currentAgent as unknown as {
402
- connect?: unknown;
403
- connectAgent?: unknown;
404
- };
405
- const hasCustomConnect =
406
- inspectableAgent.connect !== abstractAgentPrototype.connect;
407
- const hasCustomConnectAgent =
408
- inspectableAgent.connectAgent !== abstractAgentPrototype.connectAgent;
409
- if (!hasCustomConnect && !hasCustomConnectAgent) {
410
- // No custom connect to wait for — mark as connected so the welcome
411
- // suppression / suggestion gating release immediately.
412
- lastConnectedThreadId.value = threadId;
298
+ if (!mounted || typeof window === "undefined" || !currentAgent) {
413
299
  return;
414
300
  }
415
-
416
- const existingCycle = activeConnectCycle.value;
417
- const hasSameDeps =
418
- existingCycle &&
419
- existingCycle.core === (core as object) &&
420
- existingCycle.agent === currentAgent &&
421
- existingCycle.threadId === threadId &&
422
- existingCycle.inspectorRequestId === requestId;
423
-
424
- let cycle: ActiveConnectCycle;
425
- if (hasSameDeps && existingCycle) {
426
- cycle = existingCycle;
427
- } else {
428
- const connectAbortController = new AbortController();
429
- cycle = {
430
- core: core as object,
431
- agent: currentAgent,
432
- threadId,
433
- inspectorRequestId: requestId,
434
- abortController: connectAbortController,
435
- detached: false,
436
- };
437
- activeConnectCycle.value = cycle;
438
- lastConnectCycle = cycle;
439
-
440
- void pendingTeardown
441
- .then(() => {
442
- if (cycle.detached) return;
443
- if (ɵisHttpAgent(currentAgent))
444
- currentAgent.abortController = connectAbortController;
445
- return core.connectAgent({ agent: currentAgent });
446
- })
447
- .catch((error: unknown) => {
448
- if (cycle.detached) {
449
- cycle.clearDiscardedBaseline?.();
450
- return;
451
- }
452
- if (error instanceof AGUIConnectNotImplementedError) {
453
- return;
454
- }
455
- console.error("CopilotChat: connectAgent failed", error);
456
- if (requestId) {
457
- failInspectorOverride(requestId);
458
- }
459
- })
460
- .finally(() => {
461
- // Whether the connect succeeded or failed, we're no longer in
462
- // the transitional "connecting" state for this thread — release
463
- // the welcome / suggestion gating so the view can settle.
464
- //
465
- // Defer one animation frame so any trailing reactive commits
466
- // from the bootstrap replay (final assistant message content)
467
- // paint before isConnecting flips off. Without this, suggestions
468
- // can briefly render against an incompletely-laid-out message
469
- // tree and visibly snap once the last text chunk lands.
470
- if (cycle.detached) {
471
- cycle.clearDiscardedBaseline?.();
472
- return;
473
- }
474
- const raf =
475
- typeof requestAnimationFrame === "function"
476
- ? requestAnimationFrame
477
- : (cb: () => void) => setTimeout(cb, 16);
478
- raf(() => {
479
- if (cycle.detached) return;
480
- lastConnectedThreadId.value = cycle.threadId;
481
- });
482
- });
483
- }
484
-
485
- onCleanup(() => {
486
- const activeCycle = activeConnectCycle.value;
487
- if (!activeCycle || activeCycle !== cycle) {
488
- return;
489
- }
490
-
491
- const shouldDetach =
492
- isUnmounting.value ||
493
- copilotkit.value !== activeCycle.core ||
494
- agent.value !== activeCycle.agent ||
495
- resolvedThreadId.value !== activeCycle.threadId;
496
- if (!shouldDetach) {
497
- return;
498
- }
499
-
500
- activeCycle.detached = true;
501
- activeCycle.abortController.abort();
502
- const detach = activeCycle.agent
503
- .detachActiveRun()
504
- .catch((error: unknown) => {
505
- console.error("CopilotChat: detachActiveRun failed", error);
506
- });
507
- detachPromises.set(activeCycle.agent, detach);
508
- pendingTeardown = Promise.all([pendingTeardown, detach]).then(() => {});
509
- void detach.then(() => {
510
- if (detachPromises.get(activeCycle.agent) === detach)
511
- detachPromises.delete(activeCycle.agent);
512
- });
513
- activeConnectCycle.value = null;
301
+ // Pins the thread on the agent before anything issues a request, and
302
+ // connects a thread the caller picked. A switch to a fresh thread (a
303
+ // "+ New" reset) empties the agent so the welcome screen shows; moving in
304
+ // or out of an Inspector override stops the run.
305
+ const handle = connection.open({
306
+ agent: currentAgent,
307
+ threadId,
308
+ explicit: isExplicit,
309
+ inspectorRequestId: requestId,
514
310
  });
311
+ onCleanup(() => handle.release());
515
312
  },
516
313
  { immediate: true },
517
314
  );
518
315
 
519
- // Clear stale messages when the active thread switches to a fresh,
520
- // non-explicit thread (e.g. a "+ New" reset). Explicit thread switches
521
- // replay their history via the /connect cycle above, and the very first
522
- // resolution (mount) or an agent-store swap that keeps the same thread id
523
- // must never clear — only a real fresh-thread transition does.
524
- let lastFreshSelection:
525
- | { threadId: string; agent: AbstractAgent | null }
526
- | undefined;
527
- watch(
528
- [resolvedThreadId, hasExplicitThreadId, () => agent.value],
529
- ([threadId, isExplicit, currentAgent], _old, onCleanup) => {
530
- const previous = lastFreshSelection;
531
- const selection = { threadId, agent: currentAgent };
532
- lastFreshSelection = selection;
533
- if (!currentAgent) return;
534
- if (isExplicit) return;
535
- if (previous === undefined) return;
536
- if (threadId === previous.threadId) return;
537
- let active = true;
538
- let resetPending = true;
539
- onCleanup(() => {
540
- active = false;
541
- });
542
- const discardedThreadId =
543
- previous.agent === currentAgent
544
- ? previous.threadId
545
- : baselineThreadIds.get(currentAgent);
546
- const clearCursor = () => {
547
- if (!discardedThreadId) return;
548
- if (
549
- "clearReplayCursor" in currentAgent &&
550
- typeof currentAgent.clearReplayCursor === "function"
551
- )
552
- currentAgent.clearReplayCursor(discardedThreadId);
553
- if (
554
- "clearReconnectCursor" in currentAgent &&
555
- typeof currentAgent.clearReconnectCursor === "function"
556
- )
557
- currentAgent.clearReconnectCursor(discardedThreadId);
558
- };
559
- const clearDiscardedBaseline = () => {
560
- if (
561
- !active ||
562
- !resetPending ||
563
- isUnmounting.value ||
564
- lastFreshSelection !== selection ||
565
- agent.value !== currentAgent
566
- )
567
- return;
568
- currentAgent.setMessages([]);
569
- currentAgent.setState({});
570
- currentAgent.pendingInterrupts = [];
571
- clearCursor();
572
- };
573
- if (
574
- lastConnectCycle?.agent === currentAgent &&
575
- lastConnectCycle.threadId === discardedThreadId
576
- )
577
- lastConnectCycle.clearDiscardedBaseline = clearDiscardedBaseline;
578
- const detach =
579
- detachPromises.get(currentAgent) ?? currentAgent.detachActiveRun();
580
- detachPromises.set(currentAgent, detach);
581
- const finishReset = () => {
582
- if (!resetPending) return;
583
- // The cursor belongs to the discarded view, even after a fast reopen.
584
- clearCursor();
585
- clearDiscardedBaseline();
586
- resetPending = false;
587
- };
588
- clearDiscardedBaseline();
589
- pendingTeardown = Promise.all([pendingTeardown, detach])
590
- .then(finishReset)
591
- .catch((error: unknown) => {
592
- console.error("CopilotChat: detachActiveRun failed", error);
593
- })
594
- .finally(() => {
595
- if (detachPromises.get(currentAgent) === detach)
596
- detachPromises.delete(currentAgent);
597
- });
316
+ // The send side — queueing behind the run in flight and the thread's
317
+ // connection, the upload guard, stop, and transcription — lives in core.
318
+ const submitter = ɵcreateChatSubmitter({
319
+ core: {
320
+ get runtimeUrl() {
321
+ return copilotkit.value.runtimeUrl;
322
+ },
323
+ get runtimeTransport() {
324
+ return copilotkit.value.runtimeTransport;
325
+ },
326
+ get credentials() {
327
+ return copilotkit.value.credentials;
328
+ },
329
+ resolveHeaders: () => copilotkit.value.resolveHeaders(),
330
+ runAgent: (params) => copilotkit.value.runAgent(params),
331
+ stopAgent: (params) => copilotkit.value.stopAgent(params),
598
332
  },
599
- { immediate: true },
600
- );
333
+ getAgent: () => agent.value ?? undefined,
334
+ input: {
335
+ get: () => inputValue.value,
336
+ set: (value) => {
337
+ inputValue.value = value;
338
+ },
339
+ },
340
+ attachments: {
341
+ isUploading: () =>
342
+ attachments.value.some((attachment) => attachment.status === "uploading"),
343
+ consumeReady: consumeAttachments,
344
+ },
345
+ threads,
346
+ });
347
+ const submitterState = shallowRef(submitter.getSnapshot());
348
+ const unsubscribeSubmitter = submitter.subscribe(() => {
349
+ submitterState.value = submitter.getSnapshot();
350
+ });
351
+ const isTranscribing = computed(() => submitterState.value.isTranscribing);
352
+ const transcriptionError = computed(() => {
353
+ const { notice } = submitterState.value;
354
+ return notice ? ɵresolveChatNotice(notice, chatLabels.value) : null;
355
+ });
601
356
 
602
357
  onBeforeUnmount(() => {
603
- isUnmounting.value = true;
358
+ unsubscribeSubmitter();
359
+ submitter.dispose();
360
+ connection.dispose();
604
361
  });
605
362
 
606
363
  onMounted(() => {
607
364
  isMounted.value = true;
608
365
  });
609
366
 
610
- watch(transcriptionError, (next, _old, onCleanup) => {
611
- if (!next) {
612
- return;
613
- }
614
- const timer = setTimeout(() => {
615
- transcriptionError.value = null;
616
- }, 5000);
617
- onCleanup(() => clearTimeout(timer));
618
- });
619
-
620
- async function runCurrentAgent() {
621
- const currentAgent = agent.value;
622
- if (!currentAgent) {
623
- return;
624
- }
625
-
626
- try {
627
- const activeCycle = activeConnectCycle.value;
628
- if (
629
- activeCycle &&
630
- activeCycle.agent === currentAgent &&
631
- activeCycle.threadId === resolvedThreadId.value
632
- ) {
633
- activeCycle.detached = true;
634
- activeCycle.abortController.abort();
635
- activeConnectCycle.value = null;
636
- await activeCycle.agent.detachActiveRun?.();
637
- }
638
- await copilotkit.value.runAgent({ agent: currentAgent });
639
- } catch (error) {
640
- console.error("CopilotChat: runAgent failed", error);
641
- }
642
- }
643
-
644
367
  async function handleSubmitMessage(value: string) {
645
- const hasUploading = attachments.value.some(
368
+ // A send blocked by an upload shows its notice but is not reported.
369
+ const isBlockedByUpload = attachments.value.some(
646
370
  (attachment) => attachment.status === "uploading",
647
371
  );
648
- if (hasUploading) {
649
- console.error("[CopilotKit] Cannot send while attachments are uploading");
650
- return;
651
- }
652
-
653
- emit("submit-message", value);
654
-
655
- if (!agent.value) {
656
- console.error("[CopilotKit] Cannot send message: no agent available");
657
- return;
658
- }
659
-
660
- const readyAttachments = consumeAttachments();
661
- if (readyAttachments.length > 0) {
662
- const contentParts: InputContent[] = [];
663
- if (value.trim()) {
664
- contentParts.push({ type: "text", text: value });
665
- }
666
- for (const attachment of readyAttachments) {
667
- contentParts.push(createAttachmentContent(attachment));
668
- }
669
- agent.value.addMessage({
670
- id: randomUUID(),
671
- role: "user",
672
- content: contentParts,
673
- });
674
- } else {
675
- agent.value.addMessage({
676
- id: randomUUID(),
677
- role: "user",
678
- content: value,
679
- });
680
- }
681
-
682
- inputValue.value = "";
683
- await runCurrentAgent();
372
+ if (!isBlockedByUpload) emit("submit-message", value);
373
+ await submitter.submit(value);
684
374
  }
685
375
 
686
376
  async function handleSelectSuggestion(suggestion: Suggestion, index: number) {
687
377
  emit("select-suggestion", suggestion, index);
688
- agent.value?.addMessage({
689
- id: randomUUID(),
690
- role: "user",
691
- content: suggestion.message,
692
- });
693
- await runCurrentAgent();
378
+ await submitter.selectSuggestion(suggestion);
694
379
  }
695
380
 
696
381
  function stopCurrentRun() {
697
- const currentAgent = agent.value;
698
- if (!currentAgent) {
699
- return;
700
- }
701
-
702
- try {
703
- copilotkit.value.stopAgent({ agent: currentAgent });
704
- } catch (error) {
705
- console.error("CopilotChat: stopAgent failed", error);
706
- try {
707
- currentAgent.abortRun();
708
- } catch (abortError) {
709
- console.error("CopilotChat: abortRun fallback failed", abortError);
710
- }
711
- }
382
+ submitter.stop();
712
383
  }
713
384
 
714
385
  function handleStop() {
@@ -737,7 +408,7 @@ function handleStartTranscribe() {
737
408
  if (!showTranscription.value) {
738
409
  return;
739
410
  }
740
- transcriptionError.value = null;
411
+ submitter.showNotice(null);
741
412
  transcribeMode.value = "transcribe";
742
413
  emit("start-transcribe");
743
414
  }
@@ -746,7 +417,7 @@ function handleCancelTranscribe() {
746
417
  if (!showTranscription.value) {
747
418
  return;
748
419
  }
749
- transcriptionError.value = null;
420
+ submitter.showNotice(null);
750
421
  transcribeMode.value = "input";
751
422
  emit("cancel-transcribe");
752
423
  }
@@ -768,55 +439,7 @@ async function handleFinishTranscribeWithAudio(audioBlob: Blob) {
768
439
  return;
769
440
  }
770
441
 
771
- isTranscribing.value = true;
772
- try {
773
- transcriptionError.value = null;
774
- const result = await transcribeAudio(copilotkit.value, audioBlob);
775
- const trimmedPrevious = inputValue.value.trim();
776
- inputValue.value = trimmedPrevious
777
- ? `${trimmedPrevious} ${result.text}`
778
- : result.text;
779
- } catch (error) {
780
- console.error("CopilotChat: Transcription failed", error);
781
- if (error instanceof TranscriptionError) {
782
- const { code, retryable, message } = error.info;
783
- switch (code) {
784
- case TranscriptionErrorCode.RATE_LIMITED:
785
- transcriptionError.value = "Too many requests. Please wait a moment.";
786
- break;
787
- case TranscriptionErrorCode.AUTH_FAILED:
788
- transcriptionError.value =
789
- "Authentication error. Please check your configuration.";
790
- break;
791
- case TranscriptionErrorCode.AUDIO_TOO_LONG:
792
- transcriptionError.value =
793
- "Recording is too long. Please try a shorter recording.";
794
- break;
795
- case TranscriptionErrorCode.AUDIO_TOO_SHORT:
796
- transcriptionError.value =
797
- "Recording is too short. Please try again.";
798
- break;
799
- case TranscriptionErrorCode.INVALID_AUDIO_FORMAT:
800
- transcriptionError.value = "Audio format not supported.";
801
- break;
802
- case TranscriptionErrorCode.SERVICE_NOT_CONFIGURED:
803
- transcriptionError.value = "Transcription service is not available.";
804
- break;
805
- case TranscriptionErrorCode.NETWORK_ERROR:
806
- transcriptionError.value =
807
- "Network error. Please check your connection.";
808
- break;
809
- default:
810
- transcriptionError.value = retryable
811
- ? "Transcription failed. Please try again."
812
- : message;
813
- }
814
- } else {
815
- transcriptionError.value = "Transcription failed. Please try again.";
816
- }
817
- } finally {
818
- isTranscribing.value = false;
819
- }
442
+ await submitter.transcribe(audioBlob);
820
443
  }
821
444
 
822
445
  const chatViewSlotProps = computed<CopilotChatViewOverrideSlotProps>(() => ({