@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
@@ -31,10 +31,10 @@ describe("useAgent error state", () => {
31
31
 
32
32
  const TestComponent = defineComponent({
33
33
  setup() {
34
- const { agent } = useAgent({ agentId: "nonexistent" });
35
- return { agent };
34
+ const { agent, isReady } = useAgent({ agentId: "nonexistent" });
35
+ return { agent, isReady };
36
36
  },
37
- template: `<div data-testid="agent-id">{{ agent.agentId }}</div>`,
37
+ template: `<div data-testid="agent-id">{{ agent.agentId }}</div><div data-testid="ready">{{ isReady }}</div>`,
38
38
  });
39
39
 
40
40
  const Host = defineComponent({
@@ -59,6 +59,8 @@ describe("useAgent error state", () => {
59
59
  // Should render without crashing — agent is provisional
60
60
  const el = await screen.findByTestId("agent-id");
61
61
  expect(el.textContent).toBe("nonexistent");
62
+ // A provisional stand-in is not the real agent.
63
+ expect(screen.getByTestId("ready").textContent).toBe("false");
62
64
  expect(capturedErrors).toEqual([]);
63
65
  });
64
66
  });
@@ -6,7 +6,23 @@ import type { AbstractAgent } from "@ag-ui/client";
6
6
  import { useCopilotKit } from "../../providers/useCopilotKit";
7
7
  import { MockStepwiseAgent } from "../../__tests__/utils/test-helpers";
8
8
  import { useAgent } from "../use-agent";
9
- import { CopilotKitCoreRuntimeConnectionStatus } from "@copilotkit/core";
9
+ import {
10
+ CopilotKitCoreRuntimeConnectionStatus,
11
+ ProxiedCopilotRuntimeAgent,
12
+ } from "@copilotkit/core";
13
+
14
+ /** Core's `ɵruntimeInfo` snapshot, built from a fake core's runtime fields. */
15
+ function runtimeInfoOf(core: {
16
+ runtimeConnectionStatus: CopilotKitCoreRuntimeConnectionStatus;
17
+ threadEndpoints?: unknown;
18
+ intelligence?: unknown;
19
+ }) {
20
+ return {
21
+ status: core.runtimeConnectionStatus,
22
+ threadEndpoints: core.threadEndpoints,
23
+ intelligence: core.intelligence,
24
+ };
25
+ }
10
26
 
11
27
  // Mock the CopilotKitProvider to control copilotkit state directly
12
28
  vi.mock("../../providers/useCopilotKit", () => ({
@@ -26,6 +42,7 @@ describe("useAgent stability during runtime connection", () => {
26
42
  type MockCopilotkit = {
27
43
  getAgent: ReturnType<typeof vi.fn>;
28
44
  runtimeUrl: string | undefined;
45
+ readonly ɵruntimeInfo: unknown;
29
46
  runtimeConnectionStatus: CopilotKitCoreRuntimeConnectionStatus;
30
47
  runtimeTransport: string;
31
48
  headers: Record<string, string>;
@@ -45,6 +62,9 @@ describe("useAgent stability during runtime connection", () => {
45
62
  copilotkitRef = ref({
46
63
  getAgent: vi.fn(() => undefined),
47
64
  runtimeUrl: "http://localhost:3000/api/copilotkit",
65
+ get ɵruntimeInfo() {
66
+ return runtimeInfoOf(this);
67
+ },
48
68
  runtimeConnectionStatus:
49
69
  CopilotKitCoreRuntimeConnectionStatus.Disconnected,
50
70
  runtimeTransport: "rest",
@@ -198,7 +218,6 @@ describe("useAgent stability during runtime connection", () => {
198
218
  // Phase 1: Disconnected — provisional created
199
219
  const { rerender } = render(AgentTracker, { props: { tick: 0 } });
200
220
  await nextTick();
201
- const provisionalThreadId = agentInstances[0]!.threadId;
202
221
 
203
222
  // Phase 2: Connecting
204
223
  mockCopilotkit.runtimeConnectionStatus =
@@ -232,8 +251,10 @@ describe("useAgent stability during runtime connection", () => {
232
251
  // CopilotChat's connect guard ensures connect fires only once (when Connected),
233
252
  // so the agent reference change doesn't cause a duplicate connect.
234
253
  expect(agentInstances.length).toBe(2);
235
- // First instance was the provisional
236
- expect(agentInstances[0]!.threadId).toBe(provisionalThreadId);
254
+ // First instance was the provisional. The hand-off then syncs it with
255
+ // the registered agent, so its threadId follows the registered one.
256
+ expect(agentInstances[0]).toBeInstanceOf(ProxiedCopilotRuntimeAgent);
257
+ expect(agentInstances[0]!.threadId).toBe(registeredAgent.threadId);
237
258
  // Second instance is the registered agent
238
259
  expect(agentInstances[1]).toBe(registeredAgent);
239
260
  });
@@ -541,6 +541,8 @@ describe("useAgent throttleMs", () => {
541
541
  it("single notification within window does not trigger a trailing re-render", async () => {
542
542
  const renderCount = { current: 0 };
543
543
  mountHookComponent({ agent, throttleMs: 100, renderCount });
544
+ // The provider connects on mount, and the status change re-renders once.
545
+ await flushVue();
544
546
  const afterMount = renderCount.current;
545
547
  agent.setMessages([userMsg("1", "a")]);
546
548
  agent.notifyMessagesChanged();
@@ -692,8 +694,10 @@ describe("useAgent defaultThrottleMs from provider", () => {
692
694
  agent,
693
695
  defaultThrottleMs: value,
694
696
  });
697
+ // Core validates the value (the provider no longer logs its own copy).
695
698
  expect(errorSpy).toHaveBeenCalledWith(
696
- expect.stringContaining("CopilotKitProvider: defaultThrottleMs"),
699
+ expect.stringContaining("CopilotKitCore.setDefaultThrottleMs"),
700
+ expect.any(Error),
697
701
  );
698
702
  agent.setMessages([userMsg("1", "a")]);
699
703
  agent.notifyMessagesChanged();
@@ -21,13 +21,15 @@ describe("useAgent", () => {
21
21
 
22
22
  const Child = defineComponent({
23
23
  setup() {
24
- const { agent } = useAgent({ agentId: "test-agent" });
25
- return () =>
24
+ const { agent, isReady } = useAgent({ agentId: "test-agent" });
25
+ return () => [
26
26
  h(
27
27
  "span",
28
28
  { "data-testid": "agent-id" },
29
29
  agent.value?.agentId ?? "none",
30
- );
30
+ ),
31
+ h("span", { "data-testid": "ready" }, String(isReady.value)),
32
+ ];
31
33
  },
32
34
  });
33
35
 
@@ -38,6 +40,7 @@ describe("useAgent", () => {
38
40
  });
39
41
 
40
42
  expect(wrapper.find("[data-testid=agent-id]").text()).toBe("test-agent");
43
+ expect(wrapper.find("[data-testid=ready]").text()).toBe("true");
41
44
  });
42
45
 
43
46
  it("uses agentId from chat configuration when no agentId prop is provided", () => {
@@ -106,6 +106,27 @@ describe("useComponent", () => {
106
106
  expect(forwardedDeps).toBe(deps);
107
107
  });
108
108
 
109
+ it("forwards followUp, as React and Angular do", () => {
110
+ const Harness = defineComponent({
111
+ setup() {
112
+ useComponent({
113
+ name: "showWeatherCard",
114
+ render: defineComponent({ template: `<div />` }),
115
+ followUp: false,
116
+ });
117
+ return {};
118
+ },
119
+ template: `<div />`,
120
+ });
121
+
122
+ render(Harness);
123
+
124
+ const [toolConfig] = mockUseFrontendTool.mock.calls[0] as [
125
+ { followUp?: boolean },
126
+ ];
127
+ expect(toolConfig.followUp).toBe(false);
128
+ });
129
+
109
130
  it("creates a render function that passes args into the component", () => {
110
131
  const DemoComponent = defineComponent({
111
132
  props: {
@@ -12,7 +12,10 @@ import type { Observable } from "rxjs";
12
12
  import { useConfigureSuggestions } from "../use-configure-suggestions";
13
13
  import { useSuggestions } from "../use-suggestions";
14
14
  import { useCopilotKit } from "../../providers/useCopilotKit";
15
- import { mountWithProvider } from "../../__tests__/utils/mount";
15
+ import {
16
+ mountWithProvider,
17
+ renderWithCopilotKit,
18
+ } from "../../__tests__/utils/mount";
16
19
  import {
17
20
  StateCapturingAgent,
18
21
  SuggestionsProviderAgent,
@@ -396,4 +399,30 @@ describe("useConfigureSuggestions", () => {
396
399
 
397
400
  expect(wrapper.find("[data-testid=json]").text()).toContain("Deferred");
398
401
  });
402
+
403
+ it("loads a global static config for the chat's agent before any agent registers", async () => {
404
+ const Harness = defineComponent({
405
+ setup() {
406
+ useConfigureSuggestions({
407
+ suggestions: [{ title: "Welcome", message: "Say hi" }],
408
+ available: "always",
409
+ });
410
+ const { suggestions } = useSuggestions({ agentId: "support" });
411
+ return () =>
412
+ h(
413
+ "span",
414
+ { "data-testid": "titles" },
415
+ suggestions.value.map((suggestion) => suggestion.title).join(","),
416
+ );
417
+ },
418
+ });
419
+
420
+ const { wrapper } = renderWithCopilotKit(() => h(Harness), {
421
+ agentId: "support",
422
+ agents: {},
423
+ });
424
+ await nextTick();
425
+
426
+ expect(wrapper.find("[data-testid=titles]").text()).toBe("Welcome");
427
+ });
399
428
  });
@@ -530,10 +530,8 @@ describe("useDefaultRenderTool", () => {
530
530
  expect(forwarded.result).toBe("ok");
531
531
  });
532
532
 
533
- // Fix #5: circular-ref parameters must not crash the vue render; log.
534
- it("default renderer survives circular-ref parameters and logs", async () => {
535
- const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
536
-
533
+ // Fix #5: circular-ref parameters must not crash the vue render.
534
+ it("default renderer survives circular-ref parameters", async () => {
537
535
  const Harness = defineComponent({
538
536
  setup() {
539
537
  useDefaultRenderTool();
@@ -567,14 +565,16 @@ describe("useDefaultRenderTool", () => {
567
565
  }),
568
566
  ).not.toThrow();
569
567
 
568
+ const wrapper = screen.getByTestId("copilot-tool-render");
569
+ expect(wrapper.getAttribute("data-args")).toBe(
570
+ '{"a":1,"self":"[Circular]"}',
571
+ );
572
+
570
573
  const headerButton = screen
571
574
  .getByTestId("copilot-tool-render-name")
572
575
  .closest("button");
573
- if (headerButton) {
574
- await expect(fireEvent.click(headerButton)).resolves.not.toThrow();
575
- }
576
-
577
- expect(warnSpy).toHaveBeenCalled();
578
- warnSpy.mockRestore();
576
+ expect(headerButton).not.toBeNull();
577
+ await fireEvent.click(headerButton!);
578
+ expect(wrapper.textContent).toContain('"self": "[Circular]"');
579
579
  });
580
580
  });
@@ -1,4 +1,12 @@
1
- import { computed, defineComponent, onMounted, ref, watch } from "vue";
1
+ import {
2
+ computed,
3
+ defineComponent,
4
+ h,
5
+ nextTick,
6
+ onMounted,
7
+ ref,
8
+ watch,
9
+ } from "vue";
2
10
  import type { PropType } from "vue";
3
11
  import { screen, fireEvent, waitFor, cleanup } from "@testing-library/vue";
4
12
  import { afterEach, describe, expect, it } from "vitest";
@@ -27,6 +35,11 @@ import {
27
35
  textChunkEvent,
28
36
  testId,
29
37
  } from "../../__tests__/utils/test-helpers";
38
+ import { mountWithProvider } from "../../__tests__/utils/mount";
39
+ import {
40
+ StateCapturingAgent,
41
+ toolCallMessage,
42
+ } from "../../__tests__/utils/agents";
30
43
 
31
44
  afterEach(() => {
32
45
  cleanup();
@@ -874,6 +887,10 @@ describe("useFrontendTool E2E - Dynamic Registration", () => {
874
887
  expect(firstVersion.textContent).toContain("before override");
875
888
  });
876
889
 
890
+ await agent.emit(runFinishedEvent());
891
+ // The tool call starts a follow-up run. A send waits for the run in
892
+ // flight (#5195), so finish the follow-up before the next message.
893
+ await agent.emit(runStartedEvent());
877
894
  await agent.emit(runFinishedEvent());
878
895
 
879
896
  const overrideButton = screen.getByTestId("activate-override");
@@ -912,6 +929,54 @@ describe("useFrontendTool E2E - Dynamic Registration", () => {
912
929
  });
913
930
  });
914
931
 
932
+ describe("Overriding a provider tool", () => {
933
+ it("brings the provider tool back after the overriding component unmounts", async () => {
934
+ const calls: string[] = [];
935
+ const lookupTool = (owner: string): VueFrontendTool => ({
936
+ name: "lookup",
937
+ parameters: z.object({}),
938
+ followUp: false,
939
+ handler: async () => {
940
+ calls.push(owner);
941
+ return owner;
942
+ },
943
+ });
944
+
945
+ const OverridingTool = defineComponent({
946
+ setup() {
947
+ useFrontendTool(lookupTool("component"));
948
+ return () => null;
949
+ },
950
+ });
951
+
952
+ const showOverride = ref(true);
953
+ const agent = new StateCapturingAgent(
954
+ [
955
+ { newMessages: [toolCallMessage("lookup")] },
956
+ { newMessages: [toolCallMessage("lookup")] },
957
+ ],
958
+ "test-agent",
959
+ );
960
+ const { getCore, wrapper } = mountWithProvider(
961
+ () => (showOverride.value ? h(OverridingTool) : h("div")),
962
+ {
963
+ frontendTools: [lookupTool("provider")],
964
+ agents__unsafe_dev_only: { "test-agent": agent },
965
+ },
966
+ );
967
+
968
+ await nextTick();
969
+ await getCore().runAgent({ agent });
970
+
971
+ showOverride.value = false;
972
+ await nextTick();
973
+ await getCore().runAgent({ agent });
974
+
975
+ expect(calls).toEqual(["component", "provider"]);
976
+ wrapper.unmount();
977
+ });
978
+ });
979
+
915
980
  describe("Integration with Chat UI", () => {
916
981
  it("should render tool output correctly in chat interface", async () => {
917
982
  const agent = new MockStepwiseAgent();
@@ -720,7 +720,12 @@ describe("useHumanInTheLoop E2E - HITL Tool Rendering", () => {
720
720
  expect(screen.queryByTestId("hitl-enabled")).toBeNull();
721
721
  });
722
722
 
723
- await submitMessage("Test after disable");
723
+ // The first run still waits for the unanswered HITL prompt, and a send
724
+ // waits for the run in flight (#5195), so this message stays queued.
725
+ // What this test pins is that the unregistered tool no longer renders.
726
+ const input = await screen.findByRole("textbox");
727
+ await fireEvent.update(input, "Test after disable");
728
+ await fireEvent.keyDown(input, { key: "Enter", code: "Enter" });
724
729
 
725
730
  const messageId2 = testId("msg2");
726
731
  const toolCallId2 = testId("tc2");
@@ -4,7 +4,22 @@ import { z } from "zod";
4
4
  import type { AbstractAgent } from "@ag-ui/client";
5
5
  import { useHumanInTheLoop } from "../use-human-in-the-loop";
6
6
  import { mountWithProvider } from "../../__tests__/utils/mount";
7
- import { StateCapturingAgent } from "../../__tests__/utils/agents";
7
+ import {
8
+ SequencedRunAgent,
9
+ StateCapturingAgent,
10
+ toolCallMessage,
11
+ } from "../../__tests__/utils/agents";
12
+
13
+ /** Handler context for one tool call; core always passes the call. */
14
+ function callContext(id: string, name = "tool") {
15
+ return {
16
+ toolCall: {
17
+ id,
18
+ type: "function" as const,
19
+ function: { name, arguments: "{}" },
20
+ },
21
+ };
22
+ }
8
23
 
9
24
  describe("useHumanInTheLoop", () => {
10
25
  beforeEach(() => {
@@ -53,7 +68,7 @@ describe("useHumanInTheLoop", () => {
53
68
 
54
69
  const pending = registeredTool!.handler!(
55
70
  { question: "Proceed?" },
56
- {} as never,
71
+ callContext("tc-approve"),
57
72
  );
58
73
 
59
74
  const executingVNode = renderer!.render({
@@ -107,8 +122,8 @@ describe("useHumanInTheLoop", () => {
107
122
  const renderA = getCore().renderToolCalls.find((rc) => rc.name === "toolA");
108
123
  const renderB = getCore().renderToolCalls.find((rc) => rc.name === "toolB");
109
124
 
110
- const pA = toolA!.handler!({}, {} as never);
111
- const pB = toolB!.handler!({}, {} as never);
125
+ const pA = toolA!.handler!({}, callContext("tc-a"));
126
+ const pB = toolB!.handler!({}, callContext("tc-b"));
112
127
 
113
128
  const respondA = (
114
129
  renderA!.render({
@@ -140,6 +155,72 @@ describe("useHumanInTheLoop", () => {
140
155
  await expect(pB).resolves.toBe("B");
141
156
  });
142
157
 
158
+ it("gives parallel calls of one tool their own respond", async () => {
159
+ const RenderComp = defineComponent({
160
+ props: ["respond"],
161
+ setup() {
162
+ return () => h("div");
163
+ },
164
+ });
165
+ const Child = defineComponent({
166
+ setup() {
167
+ useHumanInTheLoop({
168
+ name: "parallelTool",
169
+ parameters: z.object({}),
170
+ render: RenderComp,
171
+ });
172
+ return () => null;
173
+ },
174
+ });
175
+ const { getCore } = mountWithProvider(() => h(Child));
176
+ const handler = getCore().getTool({ toolName: "parallelTool" })!.handler!;
177
+ const renderer = getCore().renderToolCalls.find(
178
+ (rc) => rc.name === "parallelTool",
179
+ )!;
180
+ const respondFor = (toolCallId: string) =>
181
+ (
182
+ renderer.render({
183
+ name: "parallelTool",
184
+ toolCallId,
185
+ args: {},
186
+ status: "executing",
187
+ result: undefined,
188
+ }) as { props?: { respond?: (result: unknown) => Promise<void> } }
189
+ ).props!.respond!;
190
+
191
+ const first = handler({}, callContext("call-1"));
192
+ const second = handler({}, callContext("call-2"));
193
+ await respondFor("call-2")("second");
194
+ await respondFor("call-1")("first");
195
+
196
+ await expect(first).resolves.toBe("first");
197
+ await expect(second).resolves.toBe("second");
198
+ });
199
+
200
+ it("passes the called tool's name to a catch-all render", () => {
201
+ const RenderComp = defineComponent({
202
+ setup() {
203
+ return () => h("div");
204
+ },
205
+ });
206
+ const Child = defineComponent({
207
+ setup() {
208
+ useHumanInTheLoop({ name: "*", render: RenderComp });
209
+ return () => null;
210
+ },
211
+ });
212
+ const { getCore } = mountWithProvider(() => h(Child));
213
+ const renderer = getCore().renderToolCalls.find((rc) => rc.name === "*")!;
214
+ const vnode = renderer.render({
215
+ name: "deleteFile",
216
+ toolCallId: "tc-any",
217
+ args: {},
218
+ status: "inProgress",
219
+ result: undefined,
220
+ }) as { props?: Record<string, unknown> };
221
+ expect(vnode.props?.name).toBe("deleteFile");
222
+ });
223
+
143
224
  it("only exposes respond during executing status", () => {
144
225
  const RenderComp = defineComponent({
145
226
  props: ["respond"],
@@ -323,9 +404,9 @@ describe("useHumanInTheLoop", () => {
323
404
  const controller = new AbortController();
324
405
  controller.abort();
325
406
 
326
- await expect(handler!({}, { signal: controller.signal })).rejects.toEqual(
327
- new Error("Human-in-the-loop interaction aborted"),
328
- );
407
+ await expect(
408
+ handler!({}, { ...callContext("tc-x"), signal: controller.signal }),
409
+ ).rejects.toEqual(new Error("Human-in-the-loop interaction aborted"));
329
410
  });
330
411
 
331
412
  it("rejects once on abort, clears pending refs, and installs a one-shot listener", async () => {
@@ -344,7 +425,7 @@ describe("useHumanInTheLoop", () => {
344
425
  }),
345
426
  } as unknown as AbortSignal;
346
427
 
347
- const pending = handler!({}, { signal });
428
+ const pending = handler!({}, { ...callContext("tc-aborted"), signal });
348
429
  expect(listeners.size).toBe(1);
349
430
  const onAbort = [...listeners][0];
350
431
  onAbort();
@@ -379,7 +460,13 @@ describe("useHumanInTheLoop", () => {
379
460
  }),
380
461
  } as unknown as AbortSignal;
381
462
 
382
- const pending = handler!({}, { signal }).then((result) => {
463
+ const pending = handler!(
464
+ {},
465
+ {
466
+ ...callContext("tc-respond"),
467
+ signal,
468
+ },
469
+ ).then((result) => {
383
470
  events.push(`resolved:${String(result)}`);
384
471
  return result;
385
472
  });
@@ -511,10 +598,98 @@ describe("useHumanInTheLoop", () => {
511
598
  expect(vnode.props?.agentId).toBeUndefined();
512
599
  });
513
600
 
601
+ it("lets a message queued behind an unanswered prompt send after the prompt unmounts", async () => {
602
+ const prompt = toolCallMessage("unmountApproval");
603
+ const toolCallId = (prompt as { toolCalls: { id: string }[] })
604
+ .toolCalls[0]!.id;
605
+ const agent = new SequencedRunAgent(
606
+ [
607
+ () => ({ result: undefined, newMessages: [prompt] }),
608
+ () => ({
609
+ result: undefined,
610
+ newMessages: [{ id: "reply", role: "assistant", content: "ok" }],
611
+ }),
612
+ ],
613
+ "default",
614
+ );
615
+ const RenderComp = defineComponent({
616
+ setup() {
617
+ return () => h("div");
618
+ },
619
+ });
620
+ const shown = ref(true);
621
+ const Child = defineComponent({
622
+ setup() {
623
+ useHumanInTheLoop({
624
+ name: "unmountApproval",
625
+ parameters: z.object({}),
626
+ render: RenderComp,
627
+ });
628
+ return () => null;
629
+ },
630
+ });
631
+ const { getCore } = mountWithProvider(
632
+ () => (shown.value ? h(Child) : null),
633
+ {
634
+ agents__unsafe_dev_only: {
635
+ default: agent as unknown as AbstractAgent,
636
+ },
637
+ },
638
+ );
639
+ const core = getCore();
640
+ const sendMessage = async (content: string) => {
641
+ agent.addMessage({ id: content, role: "user", content });
642
+ await core.runAgent({ agent: agent as unknown as AbstractAgent });
643
+ };
644
+
645
+ const first = sendMessage("approve this");
646
+ const queued = first.then(() => sendMessage("next question"));
647
+ await vi.waitFor(() =>
648
+ expect(core.ɵhumanInTheLoop.isPending(toolCallId)).toBe(true),
649
+ );
650
+
651
+ shown.value = false;
652
+ await nextTick();
653
+
654
+ await expect(queued).resolves.toBeUndefined();
655
+ expect(agent.messages).toEqual(
656
+ expect.arrayContaining([
657
+ expect.objectContaining({
658
+ role: "tool",
659
+ toolCallId,
660
+ error: "Human-in-the-loop interaction aborted",
661
+ }),
662
+ expect.objectContaining({ id: "reply", content: "ok" }),
663
+ ]),
664
+ );
665
+ });
666
+
514
667
  it("does not settle a pending HITL promise when its renderer unmounts", async () => {
515
- const mounted = mountHitlTool();
516
- const pending = mounted.handler({}, {});
517
- mounted.wrapper.unmount();
668
+ const RenderComp = defineComponent({
669
+ setup() {
670
+ return () => h("div");
671
+ },
672
+ });
673
+ const shown = ref(true);
674
+ const Child = defineComponent({
675
+ setup() {
676
+ useHumanInTheLoop({
677
+ name: "unmountTool",
678
+ parameters: z.object({}),
679
+ render: RenderComp,
680
+ });
681
+ return () => null;
682
+ },
683
+ });
684
+ const { getCore } = mountWithProvider(() =>
685
+ shown.value ? h(Child) : null,
686
+ );
687
+ const pending = getCore().getTool({ toolName: "unmountTool" })!.handler!(
688
+ {},
689
+ callContext("tc-unmount"),
690
+ );
691
+ shown.value = false;
692
+ await nextTick();
518
693
 
519
694
  const outcome = await Promise.race([
520
695
  pending.then(