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

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 (241) hide show
  1. package/PARITY.md +3 -3
  2. package/dist/hooks/use-copilot-action.d.ts.map +1 -1
  3. package/dist/hooks/use-frontend-tool.d.ts +1 -1
  4. package/dist/hooks/use-frontend-tool.d.ts.map +1 -1
  5. package/dist/hooks/zod-parameters.d.ts +14 -0
  6. package/dist/hooks/zod-parameters.d.ts.map +1 -0
  7. package/dist/index.cjs +1 -73
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.mjs +353 -16908
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/use-render-activity-message-CsWYyd6r.cjs +91 -0
  12. package/dist/use-render-activity-message-CsWYyd6r.cjs.map +1 -0
  13. package/dist/use-render-activity-message-DntKKNdd.js +17418 -0
  14. package/dist/use-render-activity-message-DntKKNdd.js.map +1 -0
  15. package/dist/v2/components/InlineFeatureWarning.vue.d.ts.map +1 -1
  16. package/dist/v2/components/LicenseWarningBanner.vue.d.ts +2 -2
  17. package/dist/v2/components/LicenseWarningBanner.vue.d.ts.map +1 -1
  18. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts +13 -45
  19. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts.map +1 -1
  20. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts +1 -1
  21. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts.map +1 -1
  22. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts +13 -5
  23. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts.map +1 -1
  24. package/dist/v2/components/a2ui/catalog.d.ts.map +1 -1
  25. package/dist/v2/components/a2ui/utils.d.ts.map +1 -1
  26. package/dist/v2/components/a2ui.d.ts +3 -7
  27. package/dist/v2/components/a2ui.d.ts.map +1 -1
  28. package/dist/v2/components/chat/CopilotChat.vue.d.ts +2 -2
  29. package/dist/v2/components/chat/CopilotChat.vue.d.ts.map +1 -1
  30. package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts.map +1 -1
  31. package/dist/v2/components/chat/CopilotChatAttachmentQueue.vue.d.ts.map +1 -1
  32. package/dist/v2/components/chat/CopilotChatAttachmentRenderer.vue.d.ts.map +1 -1
  33. package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts +1 -1
  34. package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts.map +1 -1
  35. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts +6 -270
  36. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts.map +1 -1
  37. package/dist/v2/components/chat/CopilotChatInspectorButton.vue.d.ts.map +1 -1
  38. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts +1 -1
  39. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts.map +1 -1
  40. package/dist/v2/components/chat/CopilotChatReasoningMessage.vue.d.ts.map +1 -1
  41. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts +1 -1
  42. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts.map +1 -1
  43. package/dist/v2/components/chat/CopilotChatToolCallItem.vue.d.ts.map +1 -1
  44. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts +1 -1
  45. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts.map +1 -1
  46. package/dist/v2/components/chat/CopilotChatUserMessage.vue.d.ts.map +1 -1
  47. package/dist/v2/components/chat/CopilotChatView.vue.d.ts +2 -2
  48. package/dist/v2/components/chat/CopilotChatView.vue.d.ts.map +1 -1
  49. package/dist/v2/components/chat/CopilotChatWorkSummary.vue.d.ts.map +1 -1
  50. package/dist/v2/components/chat/CopilotModalHeader.vue.d.ts.map +1 -1
  51. package/dist/v2/components/chat/CopilotPopup.vue.d.ts +8 -3
  52. package/dist/v2/components/chat/CopilotPopup.vue.d.ts.map +1 -1
  53. package/dist/v2/components/chat/CopilotPopupView.vue.d.ts +5 -3
  54. package/dist/v2/components/chat/CopilotPopupView.vue.d.ts.map +1 -1
  55. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts +5 -3
  56. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts.map +1 -1
  57. package/dist/v2/components/chat/CopilotSidebar.vue.d.ts +8 -3
  58. package/dist/v2/components/chat/CopilotSidebar.vue.d.ts.map +1 -1
  59. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts +5 -3
  60. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts.map +1 -1
  61. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts +5 -3
  62. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts.map +1 -1
  63. package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts +0 -1
  64. package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts.map +1 -1
  65. package/dist/v2/components/chat/forwarded-slots.d.ts +12 -0
  66. package/dist/v2/components/chat/forwarded-slots.d.ts.map +1 -0
  67. package/dist/v2/components/chat/index.d.ts +28 -25
  68. package/dist/v2/components/chat/index.d.ts.map +1 -1
  69. package/dist/v2/components/chat/inspector-shortcuts.d.ts +2 -1
  70. package/dist/v2/components/chat/inspector-shortcuts.d.ts.map +1 -1
  71. package/dist/v2/components/chat/message-feedback.d.ts +18 -49
  72. package/dist/v2/components/chat/message-feedback.d.ts.map +1 -1
  73. package/dist/v2/components/chat/normalize-auto-scroll.d.ts +2 -2
  74. package/dist/v2/components/chat/normalize-auto-scroll.d.ts.map +1 -1
  75. package/dist/v2/components/chat/tool-call-display-context.d.ts +2 -19
  76. package/dist/v2/components/chat/tool-call-display-context.d.ts.map +1 -1
  77. package/dist/v2/components/chat/tool-call-group-parts.d.ts +7 -20
  78. package/dist/v2/components/chat/tool-call-group-parts.d.ts.map +1 -1
  79. package/dist/v2/components/chat/turn-work.d.ts +0 -2
  80. package/dist/v2/components/chat/turn-work.d.ts.map +1 -1
  81. package/dist/v2/components/chat/types.d.ts +8 -3
  82. package/dist/v2/components/chat/types.d.ts.map +1 -1
  83. package/dist/v2/components/chat/use-chat-labels.d.ts +8 -0
  84. package/dist/v2/components/chat/use-chat-labels.d.ts.map +1 -0
  85. package/dist/v2/components/chat/use-copy-feedback.d.ts +11 -0
  86. package/dist/v2/components/chat/use-copy-feedback.d.ts.map +1 -0
  87. package/dist/v2/components/icons/index.d.ts +968 -1
  88. package/dist/v2/components/icons/index.d.ts.map +1 -1
  89. package/dist/v2/hooks/use-attachments.d.ts.map +1 -1
  90. package/dist/v2/hooks/use-frontend-tool.d.ts +5 -0
  91. package/dist/v2/hooks/use-frontend-tool.d.ts.map +1 -1
  92. package/dist/v2/hooks/use-keyboard-height.d.ts +1 -1
  93. package/dist/v2/hooks/use-keyboard-height.d.ts.map +1 -1
  94. package/dist/v2/hooks/use-pin-to-send.d.ts +4 -12
  95. package/dist/v2/hooks/use-pin-to-send.d.ts.map +1 -1
  96. package/dist/v2/hooks/use-render-activity-message.d.ts +13 -9
  97. package/dist/v2/hooks/use-render-activity-message.d.ts.map +1 -1
  98. package/dist/v2/hooks/use-render-custom-messages.d.ts +5 -7
  99. package/dist/v2/hooks/use-render-custom-messages.d.ts.map +1 -1
  100. package/dist/v2/index.cjs +1 -1
  101. package/dist/v2/index.mjs +197 -200
  102. package/dist/v2/index.mjs.map +1 -1
  103. package/dist/v2/lib/is-mobile-viewport.d.ts +1 -14
  104. package/dist/v2/lib/is-mobile-viewport.d.ts.map +1 -1
  105. package/dist/v2/lib/processPartialHtml.d.ts +1 -2
  106. package/dist/v2/lib/processPartialHtml.d.ts.map +1 -1
  107. package/dist/v2/lib/shallow-stable.d.ts.map +1 -1
  108. package/dist/v2/lib/vue-core.d.ts +0 -1
  109. package/dist/v2/lib/vue-core.d.ts.map +1 -1
  110. package/dist/v2/providers/CopilotKitProvider.types.d.ts +0 -5
  111. package/dist/v2/providers/CopilotKitProvider.types.d.ts.map +1 -1
  112. package/dist/v2/providers/CopilotKitProvider.vue.d.ts +1 -1
  113. package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
  114. package/dist/v2/providers/markdown-renderer.d.ts +2 -2
  115. package/dist/v2/providers/markdown-renderer.d.ts.map +1 -1
  116. package/dist/v2/providers/types.d.ts +3 -46
  117. package/dist/v2/providers/types.d.ts.map +1 -1
  118. package/dist/v2/types/human-in-the-loop.d.ts +8 -29
  119. package/dist/v2/types/human-in-the-loop.d.ts.map +1 -1
  120. package/dist/v2/types/interrupt.d.ts +1 -22
  121. package/dist/v2/types/interrupt.d.ts.map +1 -1
  122. package/dist/v2/types/vue-activity-message-renderer.d.ts +16 -15
  123. package/dist/v2/types/vue-activity-message-renderer.d.ts.map +1 -1
  124. package/dist/v2/types/vue-custom-message-renderer.d.ts +7 -16
  125. package/dist/v2/types/vue-custom-message-renderer.d.ts.map +1 -1
  126. package/dist/v2/types/vue-tool-call-renderer.d.ts +16 -35
  127. package/dist/v2/types/vue-tool-call-renderer.d.ts.map +1 -1
  128. package/package.json +10 -11
  129. package/src/__tests__/build-entries.test.ts +27 -0
  130. package/src/hooks/__tests__/zod-parameters.test.ts +520 -0
  131. package/src/hooks/use-copilot-action.ts +2 -1
  132. package/src/hooks/use-frontend-tool.ts +3 -6
  133. package/src/hooks/zod-parameters.ts +162 -0
  134. package/src/v2/components/A2UIMessageRenderer.ts +3 -3
  135. package/src/v2/components/InlineFeatureWarning.vue +20 -21
  136. package/src/v2/components/LicenseWarningBanner.vue +27 -135
  137. package/src/v2/components/OpenGenerativeUIRenderer.ts +51 -373
  138. package/src/v2/components/__tests__/A2UICatalogContext.test.ts +1 -1
  139. package/src/v2/components/__tests__/LicenseWarningBanner.test.ts +60 -0
  140. package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.ts +55 -6
  141. package/src/v2/components/a2ui/A2UIBuiltInToolCallRenderer.ts +1 -1
  142. package/src/v2/components/a2ui/A2UICatalogContext.ts +10 -102
  143. package/src/v2/components/a2ui/A2UIRecoveryStates.ts +1 -1
  144. package/src/v2/components/a2ui/catalog.ts +1 -0
  145. package/src/v2/components/a2ui/utils.ts +2 -0
  146. package/src/v2/components/a2ui.ts +1 -1
  147. package/src/v2/components/chat/CopilotChat.vue +19 -40
  148. package/src/v2/components/chat/CopilotChatAssistantMessage.vue +19 -43
  149. package/src/v2/components/chat/CopilotChatAttachmentQueue.vue +14 -10
  150. package/src/v2/components/chat/CopilotChatAttachmentRenderer.vue +14 -6
  151. package/src/v2/components/chat/CopilotChatFeedbackCommentPopover.vue +2 -2
  152. package/src/v2/components/chat/CopilotChatInput.vue +40 -30
  153. package/src/v2/components/chat/CopilotChatInspectorButton.vue +45 -108
  154. package/src/v2/components/chat/CopilotChatMessageView.vue +72 -140
  155. package/src/v2/components/chat/CopilotChatReasoningMessage.vue +7 -15
  156. package/src/v2/components/chat/CopilotChatToolCallGroup.vue +60 -37
  157. package/src/v2/components/chat/CopilotChatToolCallItem.vue +3 -3
  158. package/src/v2/components/chat/CopilotChatToolCallsView.vue +15 -13
  159. package/src/v2/components/chat/CopilotChatUserMessage.vue +24 -112
  160. package/src/v2/components/chat/CopilotChatView.vue +5 -5
  161. package/src/v2/components/chat/CopilotChatWorkSummary.vue +26 -36
  162. package/src/v2/components/chat/CopilotModalHeader.vue +11 -23
  163. package/src/v2/components/chat/CopilotPopup.vue +23 -25
  164. package/src/v2/components/chat/CopilotPopupView.vue +10 -39
  165. package/src/v2/components/chat/CopilotPopupViewInternal.vue +14 -34
  166. package/src/v2/components/chat/CopilotSidebar.vue +23 -25
  167. package/src/v2/components/chat/CopilotSidebarView.vue +10 -39
  168. package/src/v2/components/chat/CopilotSidebarViewInternal.vue +14 -34
  169. package/src/v2/components/chat/StreamingMarkdownDefault.vue +4 -4
  170. package/src/v2/components/chat/__tests__/CopilotChat.labels.test.ts +19 -4
  171. package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.ts +26 -9
  172. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.learningFeedback.test.ts +5 -5
  173. package/src/v2/components/chat/__tests__/CopilotChatInput.test.ts +33 -1
  174. package/src/v2/components/chat/__tests__/CopilotChatMessageView.test.ts +247 -403
  175. package/src/v2/components/chat/__tests__/CopilotChatMessageView.toolCallDisplay.test.ts +1 -99
  176. package/src/v2/components/chat/__tests__/CopilotPopup.test.ts +90 -1
  177. package/src/v2/components/chat/__tests__/CopilotSidebar.test.ts +90 -1
  178. package/src/v2/components/chat/copilotChatToolCallItemRender.ts +3 -19
  179. package/src/v2/components/chat/forwarded-slots.ts +17 -0
  180. package/src/v2/components/chat/index.ts +0 -1
  181. package/src/v2/components/chat/inspector-shortcuts.ts +10 -16
  182. package/src/v2/components/chat/message-feedback.ts +62 -197
  183. package/src/v2/components/chat/normalize-auto-scroll.ts +3 -17
  184. package/src/v2/components/chat/tool-call-display-context.ts +2 -23
  185. package/src/v2/components/chat/tool-call-group-parts.ts +44 -85
  186. package/src/v2/components/chat/turn-work.ts +0 -9
  187. package/src/v2/components/chat/types.ts +12 -4
  188. package/src/v2/components/chat/use-chat-labels.ts +16 -0
  189. package/src/v2/components/chat/use-copy-feedback.ts +21 -0
  190. package/src/v2/components/icons/__tests__/icons.test.ts +72 -68
  191. package/src/v2/components/icons/index.ts +109 -27
  192. package/src/v2/hooks/__tests__/use-frontend-tool.e2e.test.ts +62 -1
  193. package/src/v2/hooks/__tests__/use-render-activity-message.test.ts +105 -0
  194. package/src/v2/hooks/__tests__/use-render-tool.test.ts +3 -6
  195. package/src/v2/hooks/__tests__/zod-regression.test.ts +5 -4
  196. package/src/v2/hooks/use-attachments.ts +6 -2
  197. package/src/v2/hooks/use-frontend-tool.ts +10 -10
  198. package/src/v2/hooks/use-keyboard-height.ts +17 -40
  199. package/src/v2/hooks/use-pin-to-send.ts +15 -99
  200. package/src/v2/hooks/use-render-activity-message.ts +27 -48
  201. package/src/v2/hooks/use-render-custom-messages.ts +14 -35
  202. package/src/v2/lib/__tests__/shallow-stable.test.ts +54 -0
  203. package/src/v2/lib/is-mobile-viewport.ts +5 -23
  204. package/src/v2/lib/processPartialHtml.ts +6 -21
  205. package/src/v2/lib/shallow-stable.ts +2 -16
  206. package/src/v2/lib/vue-core.ts +9 -13
  207. package/src/v2/providers/CopilotKitProvider.types.ts +0 -5
  208. package/src/v2/providers/CopilotKitProvider.vue +53 -112
  209. package/src/v2/providers/__tests__/CopilotKitProvider.a2ui.test.ts +1 -1
  210. package/src/v2/providers/__tests__/CopilotKitProvider.headersAtSendTime.test.ts +3 -3
  211. package/src/v2/providers/__tests__/CopilotKitProvider.learning.test.ts +3 -1
  212. package/src/v2/providers/__tests__/CopilotKitProvider.test.ts +17 -33
  213. package/src/v2/providers/markdown-renderer.ts +2 -2
  214. package/src/v2/providers/types.ts +3 -49
  215. package/src/v2/types/__tests__/defineToolCallRenderer.test.ts +28 -33
  216. package/src/v2/types/defineToolCallRenderer.ts +5 -4
  217. package/src/v2/types/human-in-the-loop.ts +8 -32
  218. package/src/v2/types/interrupt.ts +7 -31
  219. package/src/v2/types/vue-activity-message-renderer.ts +24 -15
  220. package/src/v2/types/vue-custom-message-renderer.ts +12 -16
  221. package/src/v2/types/vue-tool-call-renderer.ts +23 -38
  222. package/tsconfig.json +0 -1
  223. package/vite.config.ts +3 -4
  224. package/dist/v2/components/chat/BasicMarkdown.vue.d.ts +0 -9
  225. package/dist/v2/components/chat/BasicMarkdown.vue.d.ts.map +0 -1
  226. package/dist/v2/components/chat/tool-call-layout.d.ts +0 -115
  227. package/dist/v2/components/chat/tool-call-layout.d.ts.map +0 -1
  228. package/dist/v2/lib/message-feedback.d.ts +0 -33
  229. package/dist/v2/lib/message-feedback.d.ts.map +0 -1
  230. package/dist/v2/lib/transcription-client.d.ts +0 -19
  231. package/dist/v2/lib/transcription-client.d.ts.map +0 -1
  232. package/src/v2/components/chat/BasicMarkdown.vue +0 -160
  233. package/src/v2/components/chat/__tests__/BasicMarkdown.test.ts +0 -69
  234. package/src/v2/components/chat/__tests__/normalize-auto-scroll.test.ts +0 -39
  235. package/src/v2/components/chat/tool-call-layout.ts +0 -304
  236. package/src/v2/lib/__tests__/is-mobile-viewport.test.ts +0 -48
  237. package/src/v2/lib/__tests__/message-feedback.test.ts +0 -152
  238. package/src/v2/lib/__tests__/processPartialHtml.test.ts +0 -84
  239. package/src/v2/lib/__tests__/transcription-client.test.ts +0 -67
  240. package/src/v2/lib/message-feedback.ts +0 -120
  241. package/src/v2/lib/transcription-client.ts +0 -151
@@ -1,4 +1,6 @@
1
- import { onBeforeUnmount, onMounted, readonly, ref, type Ref } from "vue";
1
+ import { onBeforeUnmount, onMounted, readonly, ref } from "vue";
2
+ import type { Ref } from "vue";
3
+ import { ɵinitialKeyboardState, ɵwatchKeyboardState } from "@copilotkit/core";
2
4
 
3
5
  /**
4
6
  * Vue-idiomatic result of {@link useKeyboardHeight}. Fields mirror the React
@@ -32,50 +34,25 @@ export interface KeyboardState {
32
34
  * ```
33
35
  */
34
36
  export function useKeyboardHeight(): KeyboardState {
35
- const initialHeight = typeof window !== "undefined" ? window.innerHeight : 0;
36
- const isKeyboardOpen = ref(false);
37
- const keyboardHeight = ref(0);
38
- const availableHeight = ref(initialHeight);
39
- const viewportHeight = ref(initialHeight);
40
-
41
- const updateKeyboardState = () => {
42
- if (typeof window === "undefined") return;
43
- const visualViewport = window.visualViewport;
44
- if (!visualViewport) return;
45
-
46
- const layoutHeight = window.innerHeight;
47
- const visualHeight = visualViewport.height;
48
-
49
- // Keyboard height = layout viewport minus visual viewport, clamped to 0.
50
- const nextKeyboardHeight = Math.max(0, layoutHeight - visualHeight);
51
- // Only treat the keyboard as open past the 150px threshold, matching
52
- // the React implementation's mobile heuristic.
53
- const nextIsOpen = nextKeyboardHeight > 150;
54
-
55
- keyboardHeight.value = nextKeyboardHeight;
56
- isKeyboardOpen.value = nextIsOpen;
57
- availableHeight.value = visualHeight;
58
- viewportHeight.value = layoutHeight;
59
- };
60
-
61
- let visualViewport: VisualViewport | null = null;
37
+ const initial = ɵinitialKeyboardState();
38
+ const isKeyboardOpen = ref(initial.isKeyboardOpen);
39
+ const keyboardHeight = ref(initial.keyboardHeight);
40
+ const availableHeight = ref(initial.availableHeight);
41
+ const viewportHeight = ref(initial.viewportHeight);
42
+ let stopWatching: (() => void) | undefined;
62
43
 
63
44
  onMounted(() => {
64
- if (typeof window === "undefined") return;
65
- visualViewport = window.visualViewport ?? null;
66
- if (!visualViewport) return;
67
-
68
- updateKeyboardState();
69
-
70
- visualViewport.addEventListener("resize", updateKeyboardState);
71
- visualViewport.addEventListener("scroll", updateKeyboardState);
45
+ stopWatching = ɵwatchKeyboardState((state) => {
46
+ keyboardHeight.value = state.keyboardHeight;
47
+ isKeyboardOpen.value = state.isKeyboardOpen;
48
+ availableHeight.value = state.availableHeight;
49
+ viewportHeight.value = state.viewportHeight;
50
+ });
72
51
  });
73
52
 
74
53
  onBeforeUnmount(() => {
75
- if (!visualViewport) return;
76
- visualViewport.removeEventListener("resize", updateKeyboardState);
77
- visualViewport.removeEventListener("scroll", updateKeyboardState);
78
- visualViewport = null;
54
+ stopWatching?.();
55
+ stopWatching = undefined;
79
56
  });
80
57
 
81
58
  return {
@@ -1,5 +1,6 @@
1
1
  import { inject, watch } from "vue";
2
2
  import type { Ref } from "vue";
3
+ import { ɵpinMessageToTop } from "@copilotkit/core";
3
4
  import {
4
5
  LastUserMessageKey,
5
6
  createDefaultLastUserMessageRef,
@@ -19,18 +20,10 @@ export interface UsePinToSendOptions {
19
20
  * pinned near the top of the viewport while the assistant streams a
20
21
  * response beneath it.
21
22
  *
22
- * Implementation parity with React:
23
- * - Reads the latest user message via the `LastUserMessageContext`
24
- * equivalent (`LastUserMessageKey` + `Ref<LastUserMessageState>`).
25
- * - On each `sendNonce` increment, sizes the spacer to
26
- * `viewportHeight - bubbleHeight - topOffset` and scrolls so the bubble
27
- * sits `topOffset` from the viewport top (padding above the bubble is
28
- * pushed off-screen).
29
- * - Installs a `ResizeObserver` on `contentRef` that adjusts the spacer in
30
- * both directions as content below the anchored message changes, keeping
31
- * the bubble pinned.
32
- * - Cancels the scheduled `requestAnimationFrame` and disconnects the
33
- * `ResizeObserver` on subsequent re-runs and on scope dispose.
23
+ * Reads the latest user message via `LastUserMessageKey` and, on each
24
+ * `sendNonce` increment, runs core's `ɵpinMessageToTop`, which sizes the
25
+ * spacer, scrolls, and follows the reply's growth. The previous pin stops on
26
+ * the next run and on scope dispose.
34
27
  */
35
28
  export function usePinToSend({
36
29
  scrollRef,
@@ -45,17 +38,6 @@ export function usePinToSend({
45
38
  );
46
39
 
47
40
  let lastNonce = -1;
48
- let raf: number | null = null;
49
- let ro: ResizeObserver | null = null;
50
-
51
- function teardown() {
52
- if (raf !== null && typeof cancelAnimationFrame === "function") {
53
- cancelAnimationFrame(raf);
54
- }
55
- raf = null;
56
- ro?.disconnect();
57
- ro = null;
58
- }
59
41
 
60
42
  watch(
61
43
  [
@@ -67,90 +49,24 @@ export function usePinToSend({
67
49
  () => topOffset,
68
50
  ],
69
51
  ([id, sendNonce, scrollEl, contentEl, spacerEl], _old, onCleanup) => {
70
- // Always tear down the previous run's RAF / ResizeObserver before
71
- // evaluating any of the early-exit guards below. Mirrors React
72
- // `useEffect` cleanup semantics: the prior run's cleanup runs before
73
- // the next callback executes regardless of why the deps changed.
74
- // Without this, a reactive `autoScroll` mode change (e.g. switching
75
- // away from `"pin-to-send"`) or a `ref` swap that doesn't bump
76
- // `sendNonce` would leak the stale content-element observer because
77
- // the nonce guard skips the body. Registering via `onCleanup` also
78
- // covers watcher stop on scope dispose, so an explicit
79
- // `onScopeDispose(teardown)` is no longer required.
80
- onCleanup(teardown);
81
-
82
52
  if (sendNonce === lastNonce) return;
83
53
  lastNonce = sendNonce;
84
54
 
85
55
  if (!id) return;
86
56
  if (!scrollEl || !contentEl || !spacerEl) return;
87
57
 
88
- const escaped =
89
- typeof CSS !== "undefined" && typeof CSS.escape === "function"
90
- ? CSS.escape(id)
91
- : id.replace(/[!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g, "\\$&");
92
- const targetEl = contentEl.querySelector<HTMLElement>(
93
- `[data-message-id="${escaped}"]`,
58
+ // Registered through `onCleanup`, so the previous pin stops before the
59
+ // next run and when the watcher stops on scope dispose.
60
+ onCleanup(
61
+ ɵpinMessageToTop({
62
+ scrollEl,
63
+ contentEl,
64
+ spacerEl,
65
+ messageId: id,
66
+ topOffset,
67
+ }),
94
68
  );
95
- if (!targetEl) return;
96
-
97
- // The target message's element has a top padding (e.g. `pt-10`) that
98
- // creates breathing room above the visible bubble. When we "anchor at
99
- // the top", we mean anchor the *bubble*, not the element's padded box.
100
- // So we scroll past the padding (it goes above the viewport, hiding
101
- // whatever was above the element too — including the previous message's
102
- // trailing copy button).
103
- const viewportHeight = scrollEl.clientHeight;
104
- const userMessageHeight = targetEl.getBoundingClientRect().height;
105
- const paddingTop = parseFloat(getComputedStyle(targetEl).paddingTop) || 0;
106
- const bubbleHeight = Math.max(0, userMessageHeight - paddingTop);
107
- const spacerHeight = Math.max(
108
- 0,
109
- viewportHeight - bubbleHeight - topOffset,
110
- );
111
-
112
- spacerEl.style.height = `${spacerHeight}px`;
113
-
114
- if (typeof requestAnimationFrame === "function") {
115
- raf = requestAnimationFrame(() => {
116
- // Scroll so the BUBBLE is `topOffset` from the viewport top — the
117
- // padding above the bubble ends up scrolled off-screen.
118
- const targetTop =
119
- computeOffsetTop(targetEl, scrollEl) + paddingTop - topOffset;
120
- scrollEl.scrollTo({
121
- top: Math.max(0, targetTop),
122
- behavior: "smooth",
123
- });
124
- });
125
- }
126
-
127
- // As content below the anchored user message changes, adjust the spacer
128
- // by the same amount so total scrollable space below the bubble stays
129
- // constant and the bubble stays pinned.
130
- if (typeof ResizeObserver !== "undefined") {
131
- ro = new ResizeObserver(() => {
132
- if (!contentEl || !spacerEl || !scrollEl) return;
133
- const contentHeight = contentEl.getBoundingClientRect().height;
134
- const targetOffsetWithinContent = computeOffsetTop(
135
- targetEl,
136
- contentEl,
137
- );
138
- const consumedBelow =
139
- contentHeight - targetOffsetWithinContent - userMessageHeight;
140
- const remaining = Math.max(0, spacerHeight - consumedBelow);
141
- spacerEl.style.height = `${remaining}px`;
142
- });
143
- ro.observe(contentEl);
144
- }
145
69
  },
146
70
  { immediate: true, flush: "post" },
147
71
  );
148
72
  }
149
-
150
- // Compute the offset of el relative to stopAt, accounting for stopAt's current scrollTop.
151
- // Uses getBoundingClientRect so it works regardless of CSS positioning (including position:static).
152
- function computeOffsetTop(el: HTMLElement, stopAt: HTMLElement): number {
153
- const elRect = el.getBoundingClientRect();
154
- const stopRect = stopAt.getBoundingClientRect();
155
- return elRect.top - stopRect.top + stopAt.scrollTop;
156
- }
@@ -1,19 +1,11 @@
1
1
  import { computed } from "vue";
2
2
  import type { Component } from "vue";
3
3
  import type { ActivityMessage } from "@ag-ui/core";
4
- import type { AbstractAgent } from "@ag-ui/client";
4
+ import { ɵresolveActivityRenderer } from "@copilotkit/core";
5
5
  import { DEFAULT_AGENT_ID } from "@copilotkit/shared";
6
6
  import { useCopilotKit } from "../providers/useCopilotKit";
7
7
  import { useCopilotChatConfiguration } from "../providers/useCopilotChatConfiguration";
8
- import type {
9
- VueActivityMessageRenderer,
10
- VueActivityMessageRendererProps,
11
- } from "../types";
12
-
13
- interface ActivityRendererResult {
14
- renderer: Component<VueActivityMessageRendererProps<unknown>>;
15
- props: VueActivityMessageRendererProps<unknown>;
16
- }
8
+ import type { VueActivityMessageRendererProps } from "../types";
17
9
 
18
10
  /**
19
11
  * Returns helpers for rendering activity messages.
@@ -21,70 +13,57 @@ interface ActivityRendererResult {
21
13
  * Matches the React `useRenderActivityMessage` API: `findRenderer` locates a
22
14
  * registered renderer by activity type (preferring agent-scoped over global,
23
15
  * with `"*"` as a wildcard fallback), and `renderActivityMessage` resolves the
24
- * renderer and validates the content schema.
16
+ * renderer and validates the content with the renderer's `content` schema
17
+ * (any Standard Schema, such as zod).
25
18
  */
26
19
  export function useRenderActivityMessage() {
27
20
  const { copilotkit } = useCopilotKit();
28
21
  const config = useCopilotChatConfiguration();
29
22
  const agentId = computed(() => config.value?.agentId ?? DEFAULT_AGENT_ID);
30
23
 
31
- const renderers = computed(() => [
32
- ...copilotkit.value.renderActivityMessages,
33
- ]);
34
-
35
- function findRenderer(
36
- activityType: string,
37
- ): VueActivityMessageRenderer<unknown> | null {
38
- const list = renderers.value;
39
- if (!list.length) {
40
- return null;
41
- }
42
-
43
- const matches = list.filter(
24
+ function findRenderer(activityType: string) {
25
+ const renderers = copilotkit.value.renderActivityMessages;
26
+ const matches = renderers.filter(
44
27
  (renderer) => renderer.activityType === activityType,
45
28
  );
46
29
 
47
30
  return (
48
31
  matches.find((candidate) => candidate.agentId === agentId.value) ??
49
32
  matches.find((candidate) => candidate.agentId === undefined) ??
50
- list.find((candidate) => candidate.activityType === "*") ??
33
+ renderers.find((candidate) => candidate.activityType === "*") ??
51
34
  null
52
35
  );
53
36
  }
54
37
 
55
- function renderActivityMessage(
56
- message: ActivityMessage,
57
- ): ActivityRendererResult | null {
58
- const renderer = findRenderer(message.activityType);
59
-
60
- if (!renderer) {
61
- return null;
62
- }
63
-
64
- const parseResult = renderer.content.safeParse(message.content);
38
+ function renderActivityMessage(message: ActivityMessage) {
39
+ const match = ɵresolveActivityRenderer(
40
+ copilotkit.value.renderActivityMessages,
41
+ {
42
+ activityType: message.activityType,
43
+ agentId: agentId.value,
44
+ content: message.content,
45
+ },
46
+ );
65
47
 
66
- if (!parseResult.success) {
67
- console.warn(
68
- `Failed to parse content for activity message ` +
69
- `'${message.activityType}':`,
70
- parseResult.error,
71
- );
48
+ if (!match) {
49
+ if (findRenderer(message.activityType)) {
50
+ console.warn(
51
+ `Failed to validate content for activity message ` +
52
+ `'${message.activityType}'.`,
53
+ );
54
+ }
72
55
  return null;
73
56
  }
74
57
 
75
- const agent: AbstractAgent | undefined = copilotkit.value.getAgent(
76
- agentId.value,
77
- );
78
-
79
58
  return {
80
- renderer: renderer.render as Component<
59
+ renderer: match.renderer.render as Component<
81
60
  VueActivityMessageRendererProps<unknown>
82
61
  >,
83
62
  props: {
84
63
  activityType: message.activityType,
85
- content: parseResult.data,
64
+ content: match.content,
86
65
  message,
87
- agent,
66
+ agent: copilotkit.value.getAgent(agentId.value),
88
67
  },
89
68
  };
90
69
  }
@@ -1,5 +1,5 @@
1
- import type { Component, VNodeChild } from "vue";
2
1
  import type { Message } from "@ag-ui/core";
2
+ import { ɵresolveCustomMessageRenderers } from "@copilotkit/core";
3
3
  import { DEFAULT_AGENT_ID } from "@copilotkit/shared";
4
4
  import { useCopilotKit } from "../providers/useCopilotKit";
5
5
  import { useCopilotChatConfiguration } from "../providers/useCopilotChatConfiguration";
@@ -13,13 +13,6 @@ interface UseRenderCustomMessagesParams {
13
13
  position: VueCustomMessageRendererPosition;
14
14
  }
15
15
 
16
- interface CustomMessageRendererResult {
17
- renderer:
18
- | Component<VueCustomMessageRendererProps>
19
- | ((props: VueCustomMessageRendererProps) => VNodeChild);
20
- props: VueCustomMessageRendererProps;
21
- }
22
-
23
16
  /**
24
17
  * Returns a function that resolves the appropriate custom message renderer for
25
18
  * a given message and position.
@@ -37,9 +30,7 @@ export function useRenderCustomMessages() {
37
30
  const { copilotkit } = useCopilotKit();
38
31
  const config = useCopilotChatConfiguration();
39
32
 
40
- return function renderCustomMessage(
41
- params: UseRenderCustomMessagesParams,
42
- ): CustomMessageRendererResult | null {
33
+ return function renderCustomMessage(params: UseRenderCustomMessagesParams) {
43
34
  const configValue = config.value;
44
35
  if (!configValue) return null;
45
36
 
@@ -47,17 +38,10 @@ export function useRenderCustomMessages() {
47
38
  const { threadId } = configValue;
48
39
  const core = copilotkit.value;
49
40
 
50
- const customMessageRenderers = [...core.renderCustomMessages]
51
- .filter(
52
- (renderer) =>
53
- renderer.agentId === undefined || renderer.agentId === agentId,
54
- )
55
- .sort((a, b) => {
56
- const aHasAgent = a.agentId !== undefined;
57
- const bHasAgent = b.agentId !== undefined;
58
- if (aHasAgent === bHasAgent) return 0;
59
- return aHasAgent ? -1 : 1;
60
- });
41
+ const customMessageRenderers = ɵresolveCustomMessageRenderers(
42
+ core.renderCustomMessages,
43
+ agentId,
44
+ );
61
45
 
62
46
  if (!customMessageRenderers.length) {
63
47
  return null;
@@ -101,7 +85,7 @@ export function useRenderCustomMessages() {
101
85
  ? core.getStateByRun(agentId, threadId, resolvedRunId)
102
86
  : undefined;
103
87
 
104
- const props: CustomMessageRendererResult["props"] = {
88
+ const props: VueCustomMessageRendererProps = {
105
89
  message,
106
90
  position,
107
91
  runId,
@@ -112,18 +96,13 @@ export function useRenderCustomMessages() {
112
96
  stateSnapshot,
113
97
  };
114
98
 
115
- // Iterate renderers like React: try each one and use the first that
116
- // returns a non-null render function.
117
- for (const candidate of customMessageRenderers) {
118
- if (!candidate.render) {
119
- continue;
120
- }
121
- return {
122
- renderer: candidate.render as CustomMessageRendererResult["renderer"],
123
- props,
124
- };
125
- }
99
+ // Agent-scoped renderers come first. Use the first one that has a
100
+ // render function.
101
+ const selected = customMessageRenderers.find(
102
+ (candidate) => candidate.render,
103
+ );
104
+ if (!selected) return null;
126
105
 
127
- return null;
106
+ return { renderer: selected.render, props };
128
107
  };
129
108
  }
@@ -0,0 +1,54 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { nextTick, shallowRef } from "vue";
3
+ import { useShallowStableRef } from "../shallow-stable";
4
+
5
+ /** A stable ref over a source the test replaces with `set(next)`. */
6
+ function stableOver<T>(initial: T) {
7
+ const source = shallowRef(initial);
8
+ const stable = useShallowStableRef(source);
9
+ const set = async (next: T) => {
10
+ source.value = next;
11
+ await nextTick();
12
+ };
13
+ return { stable, set };
14
+ }
15
+
16
+ describe("useShallowStableRef", () => {
17
+ it("keeps the reference for a shallowly equal plain object", async () => {
18
+ const { stable, set } = stableOver({ a: 1 });
19
+ const first = stable.value;
20
+
21
+ await set({ a: 1 });
22
+
23
+ expect(stable.value).toBe(first);
24
+ });
25
+
26
+ it("updates the reference when a value changes", async () => {
27
+ const { stable, set } = stableOver({ a: 1 });
28
+
29
+ await set({ a: 2 });
30
+
31
+ expect(stable.value).toEqual({ a: 2 });
32
+ });
33
+
34
+ it("updates the reference when a different key holds undefined", async () => {
35
+ const { stable, set } = stableOver<{ a?: number; b?: number }>({
36
+ a: undefined,
37
+ });
38
+ const first = stable.value;
39
+
40
+ await set({ b: undefined });
41
+
42
+ expect(stable.value).not.toBe(first);
43
+ expect(stable.value).toEqual({ b: undefined });
44
+ });
45
+
46
+ it("compares arrays by reference", async () => {
47
+ const { stable, set } = stableOver([1, 2]);
48
+ const first = stable.value;
49
+
50
+ await set([1, 2]);
51
+
52
+ expect(stable.value).not.toBe(first);
53
+ });
54
+ });
@@ -1,23 +1,5 @@
1
- /**
2
- * Media query for the mobile breakpoint, shared so the string literal isn't
3
- * duplicated across call sites within this package (e.g. `CopilotModalHeader`,
4
- * which needs a live `matchMedia` change-listener and so can't call
5
- * `isMobileViewport()` directly).
6
- */
7
- export const MOBILE_MAX_WIDTH_QUERY = "(max-width: 767px)";
8
-
9
- /**
10
- * Reports whether the viewport is in the mobile range (`<768px`), where the
11
- * drawer and chat modal are mutually exclusive. SSR-safe (returns `false`
12
- * when `window` is absent) and guards environments where `window` exists but
13
- * `window.matchMedia` does not (some test runners, embedded webviews).
14
- */
15
- export function isMobileViewport(): boolean {
16
- if (
17
- typeof window === "undefined" ||
18
- typeof window.matchMedia !== "function"
19
- ) {
20
- return false;
21
- }
22
- return window.matchMedia(MOBILE_MAX_WIDTH_QUERY).matches;
23
- }
1
+ // The mobile breakpoint lives in core. This module keeps the import path stable.
2
+ export {
3
+ ɵMOBILE_MAX_WIDTH_QUERY as MOBILE_MAX_WIDTH_QUERY,
4
+ ɵisMobileViewport as isMobileViewport,
5
+ } from "@copilotkit/core";
@@ -1,21 +1,6 @@
1
- export function extractCompleteStyles(html: string): string {
2
- const matches = html.match(/<style\b[^>]*>[\s\S]*?<\/style>/gi);
3
- return matches ? matches.join("") : "";
4
- }
5
-
6
- export function processPartialHtml(html: string): string {
7
- let result = html;
8
-
9
- result = result.replace(/<[^>]*$/, "");
10
- result = result.replace(/<(style|script|head)\b[^>]*>[\s\S]*?<\/\1>/gi, "");
11
- result = result.replace(/<(style|script|head)\b[^>]*>[\s\S]*$/gi, "");
12
- result = result.replace(/&[a-zA-Z0-9#]*$/, "");
13
-
14
- const bodyMatch = result.match(/<body[^>]*>([\s\S]*)/i);
15
- if (bodyMatch) {
16
- result = bodyMatch[1]!;
17
- result = result.replace(/<\/body>[\s\S]*/i, "");
18
- }
19
-
20
- return result;
21
- }
1
+ // The partial-HTML helpers live in @copilotkit/core; these names stay for
2
+ // existing imports.
3
+ export {
4
+ ɵextractCompleteStyles as extractCompleteStyles,
5
+ ɵprocessPartialHtml as processPartialHtml,
6
+ } from "@copilotkit/core";
@@ -1,21 +1,7 @@
1
+ import { ɵshallowEqualRecord } from "@copilotkit/core";
1
2
  import { shallowRef, toValue, watch } from "vue";
2
3
  import type { MaybeRefOrGetter, ShallowRef } from "vue";
3
4
 
4
- function shallowEqualObjects(
5
- first: Record<string, unknown>,
6
- second: Record<string, unknown>,
7
- ): boolean {
8
- const firstKeys = Object.keys(first);
9
- const secondKeys = Object.keys(second);
10
- if (firstKeys.length !== secondKeys.length) return false;
11
-
12
- for (const key of firstKeys) {
13
- if (first[key] !== second[key]) return false;
14
- }
15
-
16
- return true;
17
- }
18
-
19
5
  function isPlainObject(value: unknown): value is Record<string, unknown> {
20
6
  return (
21
7
  value !== null &&
@@ -40,7 +26,7 @@ export function useShallowStableRef<T>(
40
26
  if (previous === next) return;
41
27
 
42
28
  if (isPlainObject(previous) && isPlainObject(next)) {
43
- if (shallowEqualObjects(previous, next)) {
29
+ if (ɵshallowEqualRecord(previous, next)) {
44
30
  return;
45
31
  }
46
32
  }
@@ -44,7 +44,9 @@ export class CopilotKitCoreVue extends CopilotKitCore {
44
44
  private _interruptState: InterruptRenderProps<unknown, unknown> | null = null;
45
45
 
46
46
  constructor(config: CopilotKitCoreVueConfig) {
47
- super(config);
47
+ // Tool handlers can change reactive state. `nextTick` lets Vue flush those
48
+ // updates before core starts the follow-up run.
49
+ super({ ...config, ɵwaitForFrameworkUpdates: () => nextTick() });
48
50
  this._renderToolCalls = config.renderToolCalls ?? [];
49
51
  this._renderCustomMessages = config.renderCustomMessages ?? [];
50
52
  this._renderActivityMessages = config.renderActivityMessages ?? [];
@@ -70,7 +72,7 @@ export class CopilotKitCoreVue extends CopilotKitCore {
70
72
  this._renderCustomMessages = [...renderers];
71
73
  void this.notifySubscribers((subscriber) => {
72
74
  const vueSubscriber = subscriber as CopilotKitCoreVueSubscriber;
73
- vueSubscriber.onRenderCustomMessagesChanged?.({
75
+ return vueSubscriber.onRenderCustomMessagesChanged?.({
74
76
  copilotkit: this,
75
77
  renderCustomMessages: [...this.renderCustomMessages],
76
78
  });
@@ -127,12 +129,10 @@ export class CopilotKitCoreVue extends CopilotKitCore {
127
129
  private _notifyRenderToolCallsChanged(): void {
128
130
  void this.notifySubscribers((subscriber) => {
129
131
  const vueSubscriber = subscriber as CopilotKitCoreVueSubscriber;
130
- if (vueSubscriber.onRenderToolCallsChanged) {
131
- vueSubscriber.onRenderToolCallsChanged({
132
- copilotkit: this,
133
- renderToolCalls: [...this.renderToolCalls],
134
- });
135
- }
132
+ return vueSubscriber.onRenderToolCallsChanged?.({
133
+ copilotkit: this,
134
+ renderToolCalls: [...this.renderToolCalls],
135
+ });
136
136
  }, "Subscriber onRenderToolCallsChanged error:");
137
137
  }
138
138
 
@@ -142,7 +142,7 @@ export class CopilotKitCoreVue extends CopilotKitCore {
142
142
  this._interruptState = interruptState;
143
143
  void this.notifySubscribers((subscriber) => {
144
144
  const vueSubscriber = subscriber as CopilotKitCoreVueSubscriber;
145
- vueSubscriber.onInterruptStateChanged?.({
145
+ return vueSubscriber.onInterruptStateChanged?.({
146
146
  copilotkit: this,
147
147
  interruptState: this._interruptState,
148
148
  });
@@ -154,8 +154,4 @@ export class CopilotKitCoreVue extends CopilotKitCore {
154
154
  ): CopilotKitCoreSubscription {
155
155
  return super.subscribe(subscriber);
156
156
  }
157
-
158
- async waitForPendingFrameworkUpdates(): Promise<void> {
159
- await nextTick();
160
- }
161
157
  }
@@ -84,11 +84,6 @@ export interface CopilotKitProviderProps {
84
84
  sandboxFunctions?: SandboxFunction[];
85
85
  designSkill?: string;
86
86
  };
87
- /**
88
- * @deprecated This prop no longer controls the Inspector. Use
89
- * `enableInspector` instead.
90
- */
91
- showDevConsole?: boolean | "auto";
92
87
  /**
93
88
  * Disable the CopilotKit Inspector in development.
94
89
  * The Inspector is enabled by default in development browser builds and is