@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,39 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import {
3
- normalizeAutoScroll,
4
- type AutoScrollMode,
5
- } from "../normalize-auto-scroll";
6
-
7
- // Strict counterpart of React `normalize-auto-scroll.test.ts`.
8
- // Keep case order and wording aligned 1:1 with the React suite.
9
- describe("normalizeAutoScroll", () => {
10
- it("returns 'pin-to-bottom' for undefined (default)", () => {
11
- expect(normalizeAutoScroll(undefined)).toBe("pin-to-bottom");
12
- });
13
-
14
- it("maps true -> 'pin-to-bottom'", () => {
15
- expect(normalizeAutoScroll(true)).toBe("pin-to-bottom");
16
- });
17
-
18
- it("maps false -> 'none'", () => {
19
- expect(normalizeAutoScroll(false)).toBe("none");
20
- });
21
-
22
- it("passes 'pin-to-bottom' through", () => {
23
- expect(normalizeAutoScroll("pin-to-bottom")).toBe("pin-to-bottom");
24
- });
25
-
26
- it("passes 'pin-to-send' through", () => {
27
- expect(normalizeAutoScroll("pin-to-send")).toBe("pin-to-send");
28
- });
29
-
30
- it("passes 'none' through", () => {
31
- expect(normalizeAutoScroll("none")).toBe("none");
32
- });
33
-
34
- it("falls back to 'pin-to-bottom' for unknown strings", () => {
35
- expect(normalizeAutoScroll("bogus" as AutoScrollMode)).toBe(
36
- "pin-to-bottom",
37
- );
38
- });
39
- });
@@ -1,304 +0,0 @@
1
- import type { Message, ToolCall, ToolMessage } from "@ag-ui/core";
2
-
3
- /**
4
- * How the chat shows tool calls.
5
- *
6
- * - `"grouped"` (default): calls made in a row share one card, collapsed to a
7
- * summary ("Used 3 tools") that opens to a row per call.
8
- * - `"line"`: the same grouping as a quiet line of text, like the reasoning
9
- * message's "Thought for 4 seconds".
10
- * - `"stacked"`: the latest call on top of a stack of the earlier ones; click
11
- * to fan the stack out into its cards.
12
- * - `"turn"`: the agent works in the open (narration, then a row per call),
13
- * and when the reply is done everything before it folds into "Worked for 9s".
14
- * - `"separate"`: every call gets its own card, as before grouping existed.
15
- *
16
- * Only calls drawn by a renderer that opts into grouping (`group: true`) are
17
- * grouped; CopilotKit's built-in card from `useDefaultRenderTool()` does. Any
18
- * other call always shows on its own and splits the group around it.
19
- */
20
- export type CopilotChatToolCallDisplay =
21
- | "grouped"
22
- | "line"
23
- | "stacked"
24
- | "turn"
25
- | "separate";
26
-
27
- /** One tool call and, once it has finished, the message carrying its result. */
28
- export interface ToolCallEntry {
29
- toolCall: ToolCall;
30
- toolMessage?: ToolMessage;
31
- }
32
-
33
- export type ToolCallSegment =
34
- /** Consecutive calls drawn by renderers that opted into grouping. */
35
- | {
36
- kind: "group";
37
- id: string;
38
- calls: ToolCallEntry[];
39
- /** Nothing renders after this group yet, so a running agent may add to it. */
40
- trailing: boolean;
41
- }
42
- /**
43
- * A call drawn by a renderer that didn't opt into grouping, or with no
44
- * renderer at all. The latter renders nothing (and warns in development)
45
- * without breaking a group.
46
- */
47
- | { kind: "call"; id: string; call: ToolCallEntry; rendered: boolean };
48
-
49
- /** What one assistant message's tool-call area renders. */
50
- export interface ToolCallLayout {
51
- segments: ToolCallSegment[];
52
- /** Changes whenever anything this layout renders changes; for memoization. */
53
- signature: string;
54
- }
55
-
56
- /** Which tool-call renderers are registered. */
57
- export interface ToolCallRendererNames {
58
- /** Tool names with a renderer of their own. */
59
- named: ReadonlySet<string>;
60
- /** Of those, the ones whose renderer opted into grouping. */
61
- groupedNames: ReadonlySet<string>;
62
- /** A wildcard (`"*"`) renderer is registered. */
63
- wildcard: boolean;
64
- /** The wildcard renderer opted into grouping (the built-in card does). */
65
- wildcardGroups: boolean;
66
- }
67
-
68
- function contentLength(content: ToolMessage["content"]): number {
69
- return typeof content === "string"
70
- ? content.length
71
- : JSON.stringify(content ?? "").length;
72
- }
73
-
74
- const entrySignature = ({ toolCall, toolMessage }: ToolCallEntry) =>
75
- [
76
- toolCall.id,
77
- toolCall.function.name,
78
- toolCall.function.arguments.length,
79
- toolMessage
80
- ? `${contentLength(toolMessage.content)}${toolMessage.error ? "!" : ""}`
81
- : "-",
82
- ].join(":");
83
-
84
- function signatureOf(segments: ToolCallSegment[]): string {
85
- return segments
86
- .map((segment) =>
87
- segment.kind === "call"
88
- ? `c(${entrySignature(segment.call)})`
89
- : `g${segment.trailing ? "*" : ""}(${segment.calls.map(entrySignature).join(",")})`,
90
- )
91
- .join("|");
92
- }
93
-
94
- /** Index of tool results by the call they answer. */
95
- export function getToolResults(messages: Message[]): Map<string, ToolMessage> {
96
- const results = new Map<string, ToolMessage>();
97
- for (const message of messages) {
98
- if (message.role === "tool") results.set(message.toolCallId, message);
99
- }
100
- return results;
101
- }
102
-
103
- /**
104
- * Lays out the tool calls of every assistant message in `rendered`.
105
- *
106
- * Calls drawn by a renderer that opted into grouping join the group that's
107
- * open; anything else that shows between them closes it: assistant text, a
108
- * user, reasoning or activity message, or a call drawn by any other renderer. A group belongs to
109
- * the message where it starts, so later messages whose calls joined it render
110
- * no tool calls themselves.
111
- *
112
- * @param rendered - The messages as the chat renders them, in order.
113
- * @param all - Every message, for finding tool results (a transform may hide them).
114
- * @param renderers - The registered renderers.
115
- */
116
- export function getToolCallLayouts(
117
- rendered: Message[],
118
- all: Message[],
119
- renderers: ToolCallRendererNames,
120
- ): Map<string, ToolCallLayout> {
121
- const results = getToolResults(all);
122
- const layouts = new Map<string, ToolCallSegment[]>();
123
- let open: Extract<ToolCallSegment, { kind: "group" }> | undefined;
124
-
125
- for (const message of rendered) {
126
- if (message.role === "tool") continue;
127
- if (message.role !== "assistant") {
128
- open = undefined;
129
- continue;
130
- }
131
- if (typeof message.content === "string" && message.content.trim()) {
132
- open = undefined;
133
- }
134
-
135
- const segments: ToolCallSegment[] = [];
136
- layouts.set(message.id, segments);
137
- // Streaming can repeat a call: keep its first position, last content.
138
- const toolCalls = new Map<string, ToolCall>();
139
- for (const toolCall of message.toolCalls ?? []) {
140
- toolCalls.set(toolCall.id, toolCall);
141
- }
142
- for (const toolCall of toolCalls.values()) {
143
- const entry = { toolCall, toolMessage: results.get(toolCall.id) };
144
-
145
- const name = toolCall.function.name;
146
- const named = renderers.named.has(name);
147
- const rendered = named || renderers.wildcard;
148
- const groups = named
149
- ? renderers.groupedNames.has(name)
150
- : renderers.wildcardGroups;
151
-
152
- if (!rendered || !groups) {
153
- if (rendered) open = undefined;
154
- segments.push({ kind: "call", id: toolCall.id, call: entry, rendered });
155
- } else if (open) {
156
- open.calls.push(entry);
157
- } else {
158
- open = {
159
- kind: "group",
160
- id: toolCall.id,
161
- calls: [entry],
162
- trailing: false,
163
- };
164
- segments.push(open);
165
- }
166
- }
167
- }
168
- if (open) open.trailing = true;
169
-
170
- const layout = new Map<string, ToolCallLayout>();
171
- for (const [id, segments] of layouts) {
172
- layout.set(id, { segments, signature: signatureOf(segments) });
173
- }
174
- return layout;
175
- }
176
-
177
- const TOOL_CALL_SLOT_PREFIX = "tool-call-";
178
-
179
- /**
180
- * Which renderers draw tool calls, from the registered renderers and the
181
- * view's tool-call slots. A slot wins over a registered renderer and never
182
- * groups, since the chat can't tell what it draws: `#tool-call-<name>` takes
183
- * that tool, and `#tool-call` takes every tool.
184
- *
185
- * @param renderers - The registered renderers (`copilotkit.renderToolCalls`).
186
- * @param slotNames - The names of the slots the view was given.
187
- */
188
- export function getToolCallRendererNames(
189
- renderers: readonly { name: string; group?: boolean }[],
190
- slotNames: readonly string[] = [],
191
- ): ToolCallRendererNames {
192
- const wildcardSlot = slotNames.includes("tool-call");
193
- const slotTools = slotNames
194
- .filter((name) => name.startsWith(TOOL_CALL_SLOT_PREFIX))
195
- .map((name) => name.slice(TOOL_CALL_SLOT_PREFIX.length));
196
- const named = renderers.filter((renderer) => renderer.name !== "*");
197
- const wildcards = renderers.filter((renderer) => renderer.name === "*");
198
- return {
199
- named: new Set([...named.map((renderer) => renderer.name), ...slotTools]),
200
- groupedNames: new Set(
201
- wildcardSlot
202
- ? []
203
- : named
204
- .filter(
205
- (renderer) =>
206
- renderer.group && !slotTools.includes(renderer.name),
207
- )
208
- .map((renderer) => renderer.name),
209
- ),
210
- wildcard: wildcards.length > 0 || wildcardSlot,
211
- wildcardGroups:
212
- !wildcardSlot && wildcards.some((renderer) => renderer.group),
213
- };
214
- }
215
-
216
- /** A reply's working phase, for the `"turn"` display. */
217
- export interface TurnWork {
218
- /** Stable across the turn's life: the id of the user message it answers. */
219
- key: string;
220
- /** The first assistant-side message, where the "Worked for" line goes. */
221
- firstMessageId: string;
222
- /** Everything up to and including the last message with a tool call. */
223
- workMessageIds: ReadonlySet<string>;
224
- /**
225
- * The reply's last assistant message, when it has text and is part of the
226
- * work (it also calls a tool). Its text is the answer, so it stays out.
227
- */
228
- replyTextMessageId?: string;
229
- calls: ToolCallEntry[];
230
- /** No user message follows, so the agent may still be working on it. */
231
- isLatest: boolean;
232
- }
233
-
234
- /**
235
- * Finds the working phase of every reply in `rendered`: its messages up to the
236
- * last one that calls a tool. Text in there was narration; what follows is the
237
- * reply itself. Replies that called no tools are omitted, except the latest,
238
- * which may be about to.
239
- */
240
- export function getTurnWork(
241
- rendered: Message[],
242
- layouts: ReadonlyMap<string, ToolCallLayout>,
243
- ): Map<string, TurnWork> {
244
- const turns = new Map<string, TurnWork>();
245
- let start = 0;
246
- while (start < rendered.length) {
247
- let end = start;
248
- while (end < rendered.length && rendered[end]!.role !== "user") end++;
249
- const key = start > 0 ? rendered[start - 1]!.id : "start";
250
- const visible = rendered
251
- .slice(start, end)
252
- .filter((message) => message.role !== "tool");
253
- const isLatest = end === rendered.length;
254
-
255
- // A message's calls may sit in a group an earlier message owns, so
256
- // collect every shown call first, then find the last message making one.
257
- const calls: ToolCallEntry[] = [];
258
- for (const message of visible) {
259
- for (const segment of layouts.get(message.id)?.segments ?? []) {
260
- if (segment.kind === "group") calls.push(...segment.calls);
261
- else if (segment.rendered) calls.push(segment.call);
262
- }
263
- }
264
- const shown = new Set(calls.map((entry) => entry.toolCall.id));
265
- let lastWork = -1;
266
- visible.forEach((message, index) => {
267
- if (
268
- message.role === "assistant" &&
269
- message.toolCalls?.some((call) => shown.has(call.id))
270
- ) {
271
- lastWork = index;
272
- }
273
- });
274
-
275
- const first = visible[0];
276
- if (first && (calls.length > 0 || isLatest)) {
277
- let lastAssistant = -1;
278
- visible.forEach((message, index) => {
279
- if (message.role === "assistant") lastAssistant = index;
280
- });
281
- const replyText = visible[lastAssistant]?.content;
282
- const endsWithWork =
283
- lastAssistant >= 0 &&
284
- lastAssistant <= lastWork &&
285
- typeof replyText === "string" &&
286
- replyText.trim().length > 0;
287
-
288
- turns.set(key, {
289
- key,
290
- firstMessageId: first.id,
291
- workMessageIds: new Set(
292
- visible.slice(0, lastWork + 1).map((message) => message.id),
293
- ),
294
- replyTextMessageId: endsWithWork
295
- ? visible[lastAssistant]!.id
296
- : undefined,
297
- calls,
298
- isLatest,
299
- });
300
- }
301
- start = end + 1;
302
- }
303
- return turns;
304
- }
@@ -1,48 +0,0 @@
1
- import { afterEach, describe, expect, it, vi } from "vitest";
2
- import { isMobileViewport } from "../is-mobile-viewport";
3
-
4
- describe("isMobileViewport", () => {
5
- const originalMatchMedia = window.matchMedia;
6
-
7
- afterEach(() => {
8
- window.matchMedia = originalMatchMedia;
9
- vi.restoreAllMocks();
10
- });
11
-
12
- it("returns false when window.matchMedia is undefined", () => {
13
- // @ts-expect-error - simulating an environment without matchMedia support.
14
- delete window.matchMedia;
15
-
16
- expect(isMobileViewport()).toBe(false);
17
- });
18
-
19
- it("returns true when the mobile media query matches", () => {
20
- window.matchMedia = vi.fn().mockReturnValue({
21
- matches: true,
22
- media: "(max-width: 767px)",
23
- onchange: null,
24
- addEventListener: vi.fn(),
25
- removeEventListener: vi.fn(),
26
- addListener: vi.fn(),
27
- removeListener: vi.fn(),
28
- dispatchEvent: vi.fn(),
29
- } as unknown as MediaQueryList);
30
-
31
- expect(isMobileViewport()).toBe(true);
32
- });
33
-
34
- it("returns false when the mobile media query does not match", () => {
35
- window.matchMedia = vi.fn().mockReturnValue({
36
- matches: false,
37
- media: "(max-width: 767px)",
38
- onchange: null,
39
- addEventListener: vi.fn(),
40
- removeEventListener: vi.fn(),
41
- addListener: vi.fn(),
42
- removeListener: vi.fn(),
43
- dispatchEvent: vi.fn(),
44
- } as unknown as MediaQueryList);
45
-
46
- expect(isMobileViewport()).toBe(false);
47
- });
48
- });
@@ -1,152 +0,0 @@
1
- import { CopilotKitCore } from "@copilotkit/core";
2
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
- import {
4
- getMessageFeedback,
5
- subscribeToMessageFeedback,
6
- MESSAGE_FEEDBACK_EVENT_NAME,
7
- setMessageFeedback,
8
- ɵresetMessageFeedbackCache,
9
- } from "../message-feedback";
10
-
11
- const emoji = "👍";
12
-
13
- /** A Core that records what it emits, with its agent-text choice stubbed. */
14
- function capturingCore({ agentText = true } = {}) {
15
- const copilotkit = new CopilotKitCore({});
16
- vi.spyOn(copilotkit, "ɵlearningCapturesAgentText", "get").mockReturnValue(
17
- agentText,
18
- );
19
- const emit = vi
20
- .spyOn(copilotkit, "emitTrajectoryEvent")
21
- .mockImplementation(() => {});
22
- return { copilotkit, emit };
23
- }
24
-
25
- const reply = { id: "m1", role: "assistant" as const, content: "Approved." };
26
-
27
- const rate = (
28
- copilotkit: CopilotKitCore,
29
- feedback: { rating: "up" | "down"; comment?: string } | null,
30
- message: { id: string; role: "assistant"; content: string } = reply,
31
- ) =>
32
- setMessageFeedback({
33
- copilotkit,
34
- agentId: "agent",
35
- threadId: "thread",
36
- message,
37
- feedback,
38
- });
39
-
40
- describe("message feedback store", () => {
41
- beforeEach(() => ɵresetMessageFeedbackCache());
42
- afterEach(() => vi.restoreAllMocks());
43
-
44
- it("cuts long text without splitting a character", () => {
45
- const { copilotkit, emit } = capturingCore();
46
-
47
- rate(
48
- copilotkit,
49
- { rating: "up", comment: emoji.repeat(1200) },
50
- { id: "m1", role: "assistant", content: emoji.repeat(600) },
51
- );
52
-
53
- const [name, value] = emit.mock.calls[0]!;
54
- expect(name).toBe(MESSAGE_FEEDBACK_EVENT_NAME);
55
- expect(value).toMatchObject({
56
- response: emoji.repeat(500),
57
- comment: emoji.repeat(1000),
58
- });
59
- });
60
-
61
- it("keeps the rating and sends each change, a removal as null", () => {
62
- const { copilotkit, emit } = capturingCore();
63
-
64
- rate(copilotkit, { rating: "up" });
65
- expect(getMessageFeedback("agent", "thread", "m1")).toEqual({
66
- rating: "up",
67
- });
68
- rate(copilotkit, null);
69
-
70
- expect(getMessageFeedback("agent", "thread", "m1")).toBeUndefined();
71
- expect(emit.mock.calls.map(([, value]) => value)).toEqual([
72
- expect.objectContaining({ feedbackId: "thread:m1", rating: "up" }),
73
- expect.objectContaining({ feedbackId: "thread:m1", rating: null }),
74
- ]);
75
- });
76
-
77
- it("trims a comment and drops a blank one", () => {
78
- const { copilotkit } = capturingCore();
79
-
80
- rate(copilotkit, { rating: "down", comment: " " });
81
- expect(getMessageFeedback("agent", "thread", "m1")).toEqual({
82
- rating: "down",
83
- });
84
- rate(copilotkit, { rating: "down", comment: " padded " });
85
-
86
- expect(getMessageFeedback("agent", "thread", "m1")).toEqual({
87
- rating: "down",
88
- comment: "padded",
89
- });
90
- });
91
-
92
- it("tells only the rated Thread's listeners", () => {
93
- const { copilotkit } = capturingCore();
94
- const rated = vi.fn();
95
- const other = vi.fn();
96
- subscribeToMessageFeedback("agent", "thread", rated);
97
- subscribeToMessageFeedback("agent", "other", other);
98
-
99
- rate(copilotkit, { rating: "up" });
100
-
101
- expect(rated).toHaveBeenCalledTimes(1);
102
- expect(other).not.toHaveBeenCalled();
103
- });
104
-
105
- it("keeps the object of a rating that did not change", () => {
106
- const { copilotkit } = capturingCore();
107
- rate(copilotkit, { rating: "up" });
108
- const before = getMessageFeedback("agent", "thread", "m1");
109
-
110
- rate(
111
- copilotkit,
112
- { rating: "down" },
113
- { id: "m2", role: "assistant", content: "No." },
114
- );
115
-
116
- expect(getMessageFeedback("agent", "thread", "m1")).toBe(before);
117
- });
118
-
119
- it("treats message ids like object keys as plain ids", () => {
120
- const { copilotkit } = capturingCore();
121
-
122
- rate(
123
- copilotkit,
124
- { rating: "up" },
125
- { id: "__proto__", role: "assistant", content: "" },
126
- );
127
-
128
- expect(getMessageFeedback("agent", "thread", "__proto__")).toEqual({
129
- rating: "up",
130
- });
131
- expect(
132
- getMessageFeedback("agent", "thread", "constructor"),
133
- ).toBeUndefined();
134
- });
135
-
136
- it("leaves out the reply text when capture omits agent text", () => {
137
- const { copilotkit, emit } = capturingCore({ agentText: false });
138
-
139
- rate(copilotkit, { rating: "up" });
140
-
141
- expect(emit.mock.calls[0]![1]).not.toHaveProperty("response");
142
- });
143
-
144
- it("names the reply's run when Core knows it", () => {
145
- const { copilotkit, emit } = capturingCore();
146
- vi.spyOn(copilotkit, "getRunIdForMessage").mockReturnValue("run-9");
147
-
148
- rate(copilotkit, { rating: "up" });
149
-
150
- expect(emit.mock.calls[0]![1]).toMatchObject({ runId: "run-9" });
151
- });
152
- });
@@ -1,84 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import {
3
- processPartialHtml,
4
- extractCompleteStyles,
5
- } from "../processPartialHtml";
6
-
7
- describe("processPartialHtml", () => {
8
- it("returns empty string for empty input", () => {
9
- expect(processPartialHtml("")).toBe("");
10
- });
11
-
12
- it("strips incomplete tag at end", () => {
13
- expect(processPartialHtml('<div>Hello<span class="fo')).toBe("<div>Hello");
14
- });
15
-
16
- it("strips complete <style> blocks", () => {
17
- const input =
18
- "<div>Hello</div><style>.foo { color: red; }</style><p>World</p>";
19
- expect(processPartialHtml(input)).toBe("<div>Hello</div><p>World</p>");
20
- });
21
-
22
- it("strips complete <script> blocks", () => {
23
- const input = '<div>Hello</div><script>alert("hi")</script><p>World</p>';
24
- expect(processPartialHtml(input)).toBe("<div>Hello</div><p>World</p>");
25
- });
26
-
27
- it("strips incomplete <style> block", () => {
28
- const input = "<div>Hello</div><style>.foo { color:";
29
- expect(processPartialHtml(input)).toBe("<div>Hello</div>");
30
- });
31
-
32
- it("strips incomplete <script> block", () => {
33
- const input = '<div>Hello</div><script>const x = "val';
34
- expect(processPartialHtml(input)).toBe("<div>Hello</div>");
35
- });
36
-
37
- it("strips incomplete HTML entities", () => {
38
- expect(processPartialHtml("<p>Hello &amp")).toBe("<p>Hello ");
39
- expect(processPartialHtml("<p>Hello &#123")).toBe("<p>Hello ");
40
- });
41
-
42
- it("preserves complete entities", () => {
43
- expect(processPartialHtml("<p>Hello &amp; World</p>")).toBe(
44
- "<p>Hello &amp; World</p>",
45
- );
46
- });
47
-
48
- it("extracts body content from full HTML document", () => {
49
- const input =
50
- "<html><head><title>Test</title></head><body><p>Content</p></body></html>";
51
- expect(processPartialHtml(input)).toBe("<p>Content</p>");
52
- });
53
-
54
- it("handles <body> with attributes", () => {
55
- const input = '<body class="dark"><p>Content</p></body>';
56
- expect(processPartialHtml(input)).toBe("<p>Content</p>");
57
- });
58
-
59
- it("handles no <body> tag", () => {
60
- const input = "<div><p>Just content</p></div>";
61
- expect(processPartialHtml(input)).toBe("<div><p>Just content</p></div>");
62
- });
63
- });
64
-
65
- describe("extractCompleteStyles", () => {
66
- it("returns empty string for no styles", () => {
67
- expect(extractCompleteStyles("<div>Hello</div>")).toBe("");
68
- });
69
-
70
- it("extracts a single complete style block", () => {
71
- const input =
72
- "<div>Hello</div><style>.foo { color: red; }</style><p>World</p>";
73
- expect(extractCompleteStyles(input)).toBe(
74
- "<style>.foo { color: red; }</style>",
75
- );
76
- });
77
-
78
- it("extracts multiple complete style blocks", () => {
79
- const input = "<style>a{}</style><div>X</div><style>b{}</style>";
80
- expect(extractCompleteStyles(input)).toBe(
81
- "<style>a{}</style><style>b{}</style>",
82
- );
83
- });
84
- });
@@ -1,67 +0,0 @@
1
- import { afterEach, describe, expect, it, vi } from "vitest";
2
- import { TranscriptionErrorCode } from "@copilotkit/shared";
3
- import type { TranscriptionError } from "../transcription-client";
4
- import { transcribeAudio } from "../transcription-client";
5
- import type { CopilotKitCoreVue } from "../vue-core";
6
-
7
- describe("transcription-client", () => {
8
- const originalFetch = globalThis.fetch;
9
-
10
- afterEach(() => {
11
- globalThis.fetch = originalFetch;
12
- });
13
-
14
- it("transcribes audio in REST mode", async () => {
15
- globalThis.fetch = vi.fn().mockResolvedValue({
16
- ok: true,
17
- json: async () => ({
18
- text: "Transcribed text",
19
- size: 12,
20
- type: "audio/webm",
21
- }),
22
- } satisfies Partial<Response>) as typeof fetch;
23
-
24
- const result = await transcribeAudio(
25
- {
26
- runtimeUrl: "/api/copilotkit",
27
- runtimeTransport: "rest",
28
- headers: {},
29
- resolveHeaders: async () => ({}),
30
- } as CopilotKitCoreVue,
31
- new Blob(["audio"], { type: "audio/webm" }),
32
- );
33
-
34
- expect(globalThis.fetch).toHaveBeenCalledTimes(1);
35
- expect(result.text).toBe("Transcribed text");
36
- });
37
-
38
- it("maps structured error responses to TranscriptionError", async () => {
39
- globalThis.fetch = vi.fn().mockResolvedValue({
40
- ok: false,
41
- status: 429,
42
- statusText: "Too Many Requests",
43
- json: async () => ({
44
- error: TranscriptionErrorCode.RATE_LIMITED,
45
- message: "Rate limited",
46
- retryable: true,
47
- }),
48
- } satisfies Partial<Response>) as typeof fetch;
49
-
50
- await expect(
51
- transcribeAudio(
52
- {
53
- runtimeUrl: "/api/copilotkit",
54
- runtimeTransport: "rest",
55
- headers: {},
56
- resolveHeaders: async () => ({}),
57
- } as CopilotKitCoreVue,
58
- new Blob(["audio"], { type: "audio/webm" }),
59
- ),
60
- ).rejects.toMatchObject({
61
- info: {
62
- code: TranscriptionErrorCode.RATE_LIMITED,
63
- retryable: true,
64
- },
65
- } satisfies Partial<TranscriptionError>);
66
- });
67
- });