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

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 (239) hide show
  1. package/PARITY.md +13 -12
  2. package/README.md +1 -2
  3. package/dist/components/copilot-provider/CopilotKit.vue.d.ts +3 -1
  4. package/dist/components/copilot-provider/CopilotKit.vue.d.ts.map +1 -1
  5. package/dist/index.cjs +43 -46
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.mjs +10170 -7506
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/v2/components/A2UIMessageRenderer.d.ts +7 -0
  10. package/dist/v2/components/A2UIMessageRenderer.d.ts.map +1 -1
  11. package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts.map +1 -1
  12. package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts +11 -2
  13. package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts.map +1 -1
  14. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts +136 -0
  15. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts.map +1 -0
  16. package/dist/v2/components/chat/BasicMarkdown.vue.d.ts.map +1 -1
  17. package/dist/v2/components/chat/CopilotChat.vue.d.ts +1 -0
  18. package/dist/v2/components/chat/CopilotChat.vue.d.ts.map +1 -1
  19. package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts +3 -1
  20. package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts.map +1 -1
  21. package/dist/v2/components/chat/CopilotChatAssistantToolbarButton.vue.d.ts +16 -0
  22. package/dist/v2/components/chat/CopilotChatAssistantToolbarButton.vue.d.ts.map +1 -0
  23. package/dist/v2/components/chat/CopilotChatAttachmentQueue.vue.d.ts.map +1 -1
  24. package/dist/v2/components/chat/CopilotChatAttachmentRenderer.vue.d.ts.map +1 -1
  25. package/dist/v2/components/chat/CopilotChatAudioRecorder.vue.d.ts.map +1 -1
  26. package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts +22 -0
  27. package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts.map +1 -0
  28. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts +69 -16
  29. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts.map +1 -1
  30. package/dist/v2/components/chat/CopilotChatInspectorButton.vue.d.ts +12 -0
  31. package/dist/v2/components/chat/CopilotChatInspectorButton.vue.d.ts.map +1 -0
  32. package/dist/v2/components/chat/CopilotChatLightbox.vue.d.ts +22 -0
  33. package/dist/v2/components/chat/CopilotChatLightbox.vue.d.ts.map +1 -0
  34. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts +20 -0
  35. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts.map +1 -1
  36. package/dist/v2/components/chat/CopilotChatReasoningMessage.vue.d.ts.map +1 -1
  37. package/dist/v2/components/chat/CopilotChatSuggestionPill.vue.d.ts.map +1 -1
  38. package/dist/v2/components/chat/CopilotChatSuggestionView.vue.d.ts.map +1 -1
  39. package/dist/v2/components/chat/CopilotChatToggleButton.vue.d.ts.map +1 -1
  40. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts +32 -0
  41. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts.map +1 -0
  42. package/dist/v2/components/chat/CopilotChatToolCallItem.vue.d.ts.map +1 -1
  43. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts +11 -1
  44. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts.map +1 -1
  45. package/dist/v2/components/chat/CopilotChatUserMessage.vue.d.ts.map +1 -1
  46. package/dist/v2/components/chat/CopilotChatView.vue.d.ts +1 -0
  47. package/dist/v2/components/chat/CopilotChatView.vue.d.ts.map +1 -1
  48. package/dist/v2/components/chat/CopilotChatWorkSummary.vue.d.ts +5 -0
  49. package/dist/v2/components/chat/CopilotChatWorkSummary.vue.d.ts.map +1 -0
  50. package/dist/v2/components/chat/CopilotModalHeader.vue.d.ts.map +1 -1
  51. package/dist/v2/components/chat/CopilotModalHeaderCloseButton.d.ts.map +1 -1
  52. package/dist/v2/components/chat/CopilotModalHeaderTitle.d.ts.map +1 -1
  53. package/dist/v2/components/chat/CopilotPopup.vue.d.ts +1 -0
  54. package/dist/v2/components/chat/CopilotPopup.vue.d.ts.map +1 -1
  55. package/dist/v2/components/chat/CopilotPopupView.vue.d.ts +1 -0
  56. package/dist/v2/components/chat/CopilotPopupView.vue.d.ts.map +1 -1
  57. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts +1 -0
  58. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts.map +1 -1
  59. package/dist/v2/components/chat/CopilotPopupWelcomeScreen.vue.d.ts.map +1 -1
  60. package/dist/v2/components/chat/CopilotSidebar.vue.d.ts +2 -0
  61. package/dist/v2/components/chat/CopilotSidebar.vue.d.ts.map +1 -1
  62. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts +2 -0
  63. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts.map +1 -1
  64. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts +2 -0
  65. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts.map +1 -1
  66. package/dist/v2/components/chat/CopilotSidebarWelcomeScreen.vue.d.ts.map +1 -1
  67. package/dist/v2/components/chat/StreamingMarkdownDefault.vue.d.ts.map +1 -1
  68. package/dist/v2/components/chat/index.d.ts +17 -0
  69. package/dist/v2/components/chat/index.d.ts.map +1 -1
  70. package/dist/v2/components/chat/inspector-shortcuts.d.ts +12 -0
  71. package/dist/v2/components/chat/inspector-shortcuts.d.ts.map +1 -0
  72. package/dist/v2/components/chat/message-feedback.d.ts +89 -0
  73. package/dist/v2/components/chat/message-feedback.d.ts.map +1 -0
  74. package/dist/v2/components/chat/tool-call-capture.d.ts +39 -0
  75. package/dist/v2/components/chat/tool-call-capture.d.ts.map +1 -0
  76. package/dist/v2/components/chat/tool-call-display-context.d.ts +39 -0
  77. package/dist/v2/components/chat/tool-call-display-context.d.ts.map +1 -0
  78. package/dist/v2/components/chat/tool-call-group-parts.d.ts +144 -0
  79. package/dist/v2/components/chat/tool-call-group-parts.d.ts.map +1 -0
  80. package/dist/v2/components/chat/tool-call-layout.d.ts +115 -0
  81. package/dist/v2/components/chat/tool-call-layout.d.ts.map +1 -0
  82. package/dist/v2/components/chat/turn-work.d.ts +35 -0
  83. package/dist/v2/components/chat/turn-work.d.ts.map +1 -0
  84. package/dist/v2/components/chat/types.d.ts +104 -4
  85. package/dist/v2/components/chat/types.d.ts.map +1 -1
  86. package/dist/v2/components/chat/use-lightbox.d.ts +18 -0
  87. package/dist/v2/components/chat/use-lightbox.d.ts.map +1 -0
  88. package/dist/v2/components/icons/index.d.ts +1 -1
  89. package/dist/v2/components/icons/index.d.ts.map +1 -1
  90. package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts +55 -0
  91. package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts.map +1 -0
  92. package/dist/v2/components/ui/CopilotPopover.vue.d.ts +40 -0
  93. package/dist/v2/components/ui/CopilotPopover.vue.d.ts.map +1 -0
  94. package/dist/v2/components/ui/CopilotTooltip.vue.d.ts +37 -0
  95. package/dist/v2/components/ui/CopilotTooltip.vue.d.ts.map +1 -0
  96. package/dist/v2/components/ui/dropdown-menu.d.ts +14 -0
  97. package/dist/v2/components/ui/dropdown-menu.d.ts.map +1 -0
  98. package/dist/v2/components/ui/floating.d.ts +84 -0
  99. package/dist/v2/components/ui/floating.d.ts.map +1 -0
  100. package/dist/v2/components/ui/presence.d.ts +9 -0
  101. package/dist/v2/components/ui/presence.d.ts.map +1 -0
  102. package/dist/v2/components/ui/use-id.d.ts +9 -0
  103. package/dist/v2/components/ui/use-id.d.ts.map +1 -0
  104. package/dist/v2/hooks/use-default-render-tool.d.ts +6 -0
  105. package/dist/v2/hooks/use-default-render-tool.d.ts.map +1 -1
  106. package/dist/v2/hooks/use-render-tool.d.ts +4 -0
  107. package/dist/v2/hooks/use-render-tool.d.ts.map +1 -1
  108. package/dist/v2/index.cjs +1 -1
  109. package/dist/v2/index.d.cts +3 -0
  110. package/dist/v2/index.d.mts +3 -0
  111. package/dist/v2/index.d.ts +3 -0
  112. package/dist/v2/index.d.ts.map +1 -1
  113. package/dist/v2/index.mjs +165 -162
  114. package/dist/v2/lib/message-feedback.d.ts +33 -0
  115. package/dist/v2/lib/message-feedback.d.ts.map +1 -0
  116. package/dist/v2/providers/CopilotChatConfigurationProvider.vue.d.ts.map +1 -1
  117. package/dist/v2/providers/CopilotKitProvider.types.d.ts +56 -1
  118. package/dist/v2/providers/CopilotKitProvider.types.d.ts.map +1 -1
  119. package/dist/v2/providers/CopilotKitProvider.vue.d.ts +5 -1
  120. package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
  121. package/dist/v2/providers/index.d.ts +1 -1
  122. package/dist/v2/providers/index.d.ts.map +1 -1
  123. package/dist/v2/providers/keys.d.ts +8 -0
  124. package/dist/v2/providers/keys.d.ts.map +1 -1
  125. package/dist/v2/providers/types.d.ts +9 -0
  126. package/dist/v2/providers/types.d.ts.map +1 -1
  127. package/dist/v2/styles/CopilotKitStyles.d.ts +18 -0
  128. package/dist/v2/styles/CopilotKitStyles.d.ts.map +1 -0
  129. package/dist/v2/types/defineToolCallRenderer.d.ts +2 -0
  130. package/dist/v2/types/defineToolCallRenderer.d.ts.map +1 -1
  131. package/dist/v2/types/vue-tool-call-renderer.d.ts +7 -0
  132. package/dist/v2/types/vue-tool-call-renderer.d.ts.map +1 -1
  133. package/package.json +11 -23
  134. package/src/components/copilot-provider/CopilotKit.vue +4 -1
  135. package/src/v2/__tests__/exports.test.ts +4 -2
  136. package/src/v2/components/A2UIMessageRenderer.ts +55 -67
  137. package/src/v2/components/A2UISurfaceActivityRenderer.vue +11 -23
  138. package/src/v2/components/__tests__/A2UIBasicCatalogColors.test.ts +8 -9
  139. package/src/v2/components/__tests__/A2UIMessageRenderer.test.ts +63 -36
  140. package/src/v2/components/a2ui/A2UIBuiltInToolCallRenderer.ts +14 -257
  141. package/src/v2/components/a2ui/A2UIRecoveryStates.ts +444 -0
  142. package/src/v2/components/a2ui/__tests__/A2UIRecoveryStates.test.ts +175 -0
  143. package/src/v2/components/chat/BasicMarkdown.vue +8 -6
  144. package/src/v2/components/chat/CopilotChat.vue +7 -0
  145. package/src/v2/components/chat/CopilotChatAssistantMessage.vue +267 -67
  146. package/src/v2/components/chat/CopilotChatAssistantToolbarButton.vue +46 -0
  147. package/src/v2/components/chat/CopilotChatAttachmentQueue.vue +141 -168
  148. package/src/v2/components/chat/CopilotChatAttachmentRenderer.vue +67 -18
  149. package/src/v2/components/chat/CopilotChatAudioRecorder.vue +2 -2
  150. package/src/v2/components/chat/CopilotChatFeedbackCommentPopover.vue +240 -0
  151. package/src/v2/components/chat/CopilotChatInput.vue +210 -161
  152. package/src/v2/components/chat/CopilotChatInspectorButton.vue +331 -0
  153. package/src/v2/components/chat/CopilotChatLightbox.vue +105 -0
  154. package/src/v2/components/chat/CopilotChatMessageView.vue +261 -18
  155. package/src/v2/components/chat/CopilotChatReasoningMessage.vue +21 -22
  156. package/src/v2/components/chat/CopilotChatSuggestionPill.vue +5 -14
  157. package/src/v2/components/chat/CopilotChatSuggestionView.vue +1 -4
  158. package/src/v2/components/chat/CopilotChatToggleButton.vue +3 -9
  159. package/src/v2/components/chat/CopilotChatToggleButtonCloseIcon.ts +1 -1
  160. package/src/v2/components/chat/CopilotChatToggleButtonOpenIcon.ts +1 -1
  161. package/src/v2/components/chat/CopilotChatToolCallGroup.vue +330 -0
  162. package/src/v2/components/chat/CopilotChatToolCallItem.vue +21 -11
  163. package/src/v2/components/chat/CopilotChatToolCallsView.vue +192 -21
  164. package/src/v2/components/chat/CopilotChatUserMessage.vue +105 -42
  165. package/src/v2/components/chat/CopilotChatView.vue +33 -38
  166. package/src/v2/components/chat/CopilotChatWorkSummary.vue +85 -0
  167. package/src/v2/components/chat/CopilotModalHeader.vue +10 -8
  168. package/src/v2/components/chat/CopilotModalHeaderCloseButton.ts +7 -6
  169. package/src/v2/components/chat/CopilotModalHeaderTitle.ts +1 -4
  170. package/src/v2/components/chat/CopilotPopup.vue +3 -0
  171. package/src/v2/components/chat/CopilotPopupView.vue +1 -0
  172. package/src/v2/components/chat/CopilotPopupViewInternal.vue +9 -19
  173. package/src/v2/components/chat/CopilotPopupWelcomeScreen.vue +5 -8
  174. package/src/v2/components/chat/CopilotSidebar.vue +5 -0
  175. package/src/v2/components/chat/CopilotSidebarView.vue +2 -0
  176. package/src/v2/components/chat/CopilotSidebarViewInternal.vue +24 -17
  177. package/src/v2/components/chat/CopilotSidebarWelcomeScreen.vue +7 -10
  178. package/src/v2/components/chat/StreamingMarkdownDefault.vue +3 -5
  179. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.inspector.test.ts +269 -0
  180. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.learningFeedback.test.ts +760 -0
  181. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.slots.e2e.test.ts +3 -5
  182. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.test.ts +2 -2
  183. package/src/v2/components/chat/__tests__/CopilotChatInput.addMenu.test.ts +328 -0
  184. package/src/v2/components/chat/__tests__/CopilotChatInput.slots.e2e.test.ts +6 -3
  185. package/src/v2/components/chat/__tests__/CopilotChatInput.test.ts +22 -13
  186. package/src/v2/components/chat/__tests__/CopilotChatLightbox.test.ts +160 -0
  187. package/src/v2/components/chat/__tests__/CopilotChatMessageView.toolCallDisplay.test.ts +735 -0
  188. package/src/v2/components/chat/__tests__/CopilotChatSuggestionPill.test.ts +1 -1
  189. package/src/v2/components/chat/__tests__/CopilotChatSuggestionView.slots.e2e.test.ts +3 -1
  190. package/src/v2/components/chat/__tests__/CopilotChatToolCallsView.learning.test.ts +75 -0
  191. package/src/v2/components/chat/__tests__/CopilotChatUserMessage.attachments.test.ts +143 -0
  192. package/src/v2/components/chat/__tests__/CopilotChatView.inputOverlay.test.ts +5 -4
  193. package/src/v2/components/chat/__tests__/CopilotChatView.rootWidth.test.ts +7 -33
  194. package/src/v2/components/chat/__tests__/CopilotModalHeader.slots.e2e.test.ts +1 -1
  195. package/src/v2/components/chat/__tests__/CopilotPopupView.slots.e2e.test.ts +3 -3
  196. package/src/v2/components/chat/__tests__/CopilotSidebarView.position.test.ts +126 -0
  197. package/src/v2/components/chat/__tests__/messageFeedbackDefaults.test.ts +33 -0
  198. package/src/v2/components/chat/__tests__/modalChatDisplayProps.test.ts +44 -0
  199. package/src/v2/components/chat/index.ts +2 -0
  200. package/src/v2/components/chat/inspector-shortcuts.ts +34 -0
  201. package/src/v2/components/chat/message-feedback.ts +291 -0
  202. package/src/v2/components/chat/tool-call-capture.ts +55 -0
  203. package/src/v2/components/chat/tool-call-display-context.ts +49 -0
  204. package/src/v2/components/chat/tool-call-group-parts.ts +292 -0
  205. package/src/v2/components/chat/tool-call-layout.ts +304 -0
  206. package/src/v2/components/chat/turn-work.ts +61 -0
  207. package/src/v2/components/chat/types.ts +113 -3
  208. package/src/v2/components/chat/use-lightbox.ts +64 -0
  209. package/src/v2/components/icons/index.ts +4 -0
  210. package/src/v2/components/ui/CopilotDropdownMenuContent.vue +465 -0
  211. package/src/v2/components/ui/CopilotPopover.vue +138 -0
  212. package/src/v2/components/ui/CopilotTooltip.vue +237 -0
  213. package/src/v2/components/ui/__tests__/CopilotTooltip.test.ts +168 -0
  214. package/src/v2/components/ui/dropdown-menu.ts +15 -0
  215. package/src/v2/components/ui/floating.ts +321 -0
  216. package/src/v2/components/ui/presence.ts +54 -0
  217. package/src/v2/components/ui/use-id.ts +16 -0
  218. package/src/v2/hooks/use-default-render-tool.ts +123 -62
  219. package/src/v2/hooks/use-render-tool.ts +8 -0
  220. package/src/v2/index.ts +3 -0
  221. package/src/v2/lib/__tests__/message-feedback.test.ts +152 -0
  222. package/src/v2/lib/message-feedback.ts +120 -0
  223. package/src/v2/providers/CopilotChatConfigurationProvider.vue +29 -2
  224. package/src/v2/providers/CopilotKitProvider.types.ts +57 -0
  225. package/src/v2/providers/CopilotKitProvider.vue +125 -3
  226. package/src/v2/providers/__tests__/CopilotChatConfigurationProvider.openThread.test.ts +69 -0
  227. package/src/v2/providers/__tests__/CopilotKitProvider.learning.test.ts +534 -0
  228. package/src/v2/providers/index.ts +4 -1
  229. package/src/v2/providers/keys.ts +12 -0
  230. package/src/v2/providers/types.ts +11 -0
  231. package/src/v2/styles/CopilotKitStyles.ts +95 -0
  232. package/src/v2/styles/__tests__/CopilotKitStyles.client.test.ts +149 -0
  233. package/src/v2/styles/__tests__/CopilotKitStyles.ssr.test.ts +71 -0
  234. package/src/v2/types/defineToolCallRenderer.ts +4 -0
  235. package/src/v2/types/vue-tool-call-renderer.ts +7 -0
  236. package/vite.config.ts +2 -1
  237. package/dist/styles.css +0 -2
  238. package/scripts/scope-preflight.mjs +0 -100
  239. package/src/styles/globals.css +0 -233
@@ -0,0 +1,330 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Tool calls made in a row, collapsed into one summary. While a call runs the
4
+ * summary names it ("Running read_file src/app.ts"); once they're all done it
5
+ * reads "Used 3 tools" and opens to the calls.
6
+ *
7
+ * Each call is drawn by the `call` slot, which the tool calls view fills with
8
+ * the registered renderers. CopilotKit's built-in card (`useDefaultRenderTool`)
9
+ * draws a compact row inside the card and line appearances and an open stack;
10
+ * a custom wildcard renderer draws whatever it draws.
11
+ */
12
+ import { computed, provide, ref } from "vue";
13
+ import { useCopilotId } from "../ui/use-id";
14
+ import type { ToolCallEntry } from "./tool-call-layout";
15
+ import { ToolCallGroupContextKey } from "./tool-call-display-context";
16
+ import type { ToolCallGroupContextValue } from "./tool-call-display-context";
17
+ import {
18
+ CopilotChatCollapsible,
19
+ ToolCallChevron,
20
+ ToolCallFailedCount,
21
+ ToolCallStatusIcon,
22
+ entryPreview,
23
+ entryStatus,
24
+ pluralize,
25
+ statusLabels,
26
+ toolNames,
27
+ } from "./tool-call-group-parts";
28
+ import type { ToolCallStatusName } from "./tool-call-group-parts";
29
+ import type { CopilotChatToolCallGroupAppearance } from "./types";
30
+
31
+ const props = withDefaults(
32
+ defineProps<{
33
+ /** The calls in the group, in order. */
34
+ calls: ToolCallEntry[];
35
+ /**
36
+ * - `"card"` (default): one card with a summary header and a row per call.
37
+ * - `"line"`: a quiet line of text that opens to a list of rows.
38
+ * - `"stack"`: the latest call on a stack of the earlier ones.
39
+ */
40
+ appearance?: CopilotChatToolCallGroupAppearance;
41
+ /** The agent is running and nothing follows the group, so more calls may join it. */
42
+ isActive?: boolean;
43
+ }>(),
44
+ { appearance: "card", isActive: false },
45
+ );
46
+
47
+ defineSlots<{
48
+ /** Draws one call. */
49
+ call(props: { call: ToolCallEntry }): unknown;
50
+ }>();
51
+
52
+ const open = ref(false);
53
+ const bodyId = useCopilotId("cpk-tool-call-group");
54
+ const toggle = () => {
55
+ open.value = !open.value;
56
+ };
57
+
58
+ const latest = computed(() => props.calls[props.calls.length - 1]);
59
+ // Only an active group has a call in progress. Between calls nothing is
60
+ // running, so the latest call stays the subject (or the label flickers).
61
+ const current = computed(() =>
62
+ props.isActive
63
+ ? (props.calls.find((call) => !call.toolMessage) ?? latest.value)
64
+ : undefined,
65
+ );
66
+ const preview = computed(() =>
67
+ current.value ? entryPreview(current.value) : undefined,
68
+ );
69
+ const done = computed(
70
+ () => props.calls.filter((call) => call.toolMessage).length,
71
+ );
72
+ const statuses = computed(() =>
73
+ props.calls.map((call) => entryStatus(call, props.isActive)),
74
+ );
75
+ const failedIds = computed(
76
+ () =>
77
+ new Set(
78
+ props.calls
79
+ .filter((_, index) => statuses.value[index] === "failed")
80
+ .map((call) => call.toolCall.id),
81
+ ),
82
+ );
83
+ const status = computed<ToolCallStatusName>(() =>
84
+ current.value
85
+ ? "running"
86
+ : failedIds.value.size > 0
87
+ ? "failed"
88
+ : statuses.value.includes("stopped")
89
+ ? "stopped"
90
+ : "done",
91
+ );
92
+ const single = computed(
93
+ () =>
94
+ props.appearance === "line" && props.calls.length === 1 && !current.value,
95
+ );
96
+
97
+ provide(
98
+ ToolCallGroupContextKey,
99
+ computed<ToolCallGroupContextValue>(() => ({
100
+ appearance: props.appearance,
101
+ failedIds: failedIds.value,
102
+ active: props.isActive,
103
+ })),
104
+ );
105
+
106
+ // Stack: a lone call is the top card of a stack with nothing behind it yet.
107
+ const behind = computed(() =>
108
+ open.value ? 0 : Math.min(props.calls.length - 1, 2),
109
+ );
110
+ const latestStatus = computed(() =>
111
+ latest.value ? entryStatus(latest.value, props.isActive) : "done",
112
+ );
113
+ const latestPreview = computed(() =>
114
+ latest.value ? entryPreview(latest.value) : undefined,
115
+ );
116
+ const layer = "cpk-tool-call-group-stack-layer";
117
+ </script>
118
+
119
+ <template>
120
+ <div
121
+ v-if="latest && single"
122
+ data-copilotkit
123
+ data-testid="copilot-tool-call-group"
124
+ :data-appearance="appearance"
125
+ :data-state="status"
126
+ class="cpk-tool-call-group cpk-tool-call-group-line cpk-tool-call-group-single"
127
+ >
128
+ <slot name="call" :call="latest" />
129
+ </div>
130
+
131
+ <div
132
+ v-else-if="latest && appearance === 'line'"
133
+ data-copilotkit
134
+ data-testid="copilot-tool-call-group"
135
+ :data-appearance="appearance"
136
+ :data-state="status"
137
+ class="cpk-tool-call-group cpk-tool-call-group-line"
138
+ >
139
+ <button
140
+ type="button"
141
+ :aria-expanded="open ? 'true' : 'false'"
142
+ :aria-controls="bodyId"
143
+ class="cpk-tool-call-group-line-toggle"
144
+ @click="toggle"
145
+ >
146
+ <template v-if="current">
147
+ <span class="cpk-tool-call-group-running cpk-shimmer"
148
+ >Running {{ current.toolCall.function.name }}</span
149
+ >
150
+ <span v-if="preview" class="cpk-tool-call-group-preview">{{
151
+ preview
152
+ }}</span>
153
+ </template>
154
+ <template v-else>
155
+ <span class="cpk-tool-call-group-line-summary"
156
+ >Used {{ pluralize(calls.length, "tool") }}</span
157
+ >
158
+ <span class="cpk-tool-call-group-line-names">{{
159
+ toolNames(calls)
160
+ }}</span>
161
+ <ToolCallFailedCount :calls="calls" />
162
+ </template>
163
+ <ToolCallChevron :open="open" />
164
+ </button>
165
+ <CopilotChatCollapsible :id="bodyId" :open="open">
166
+ <div class="cpk-tool-call-group-line-body">
167
+ <template v-for="call in calls" :key="call.toolCall.id">
168
+ <slot name="call" :call="call" />
169
+ </template>
170
+ </div>
171
+ </CopilotChatCollapsible>
172
+ </div>
173
+
174
+ <div
175
+ v-else-if="latest && appearance === 'stack'"
176
+ data-copilotkit
177
+ data-testid="copilot-tool-call-group"
178
+ :data-appearance="appearance"
179
+ :data-state="status"
180
+ class="cpk-tool-call-group cpk-tool-call-group-stack"
181
+ :style="{ paddingBottom: `${behind * 6}px` }"
182
+ >
183
+ <div class="cpk-tool-call-group-stack-pile">
184
+ <div
185
+ v-for="index in behind"
186
+ :key="index"
187
+ aria-hidden="true"
188
+ :class="[layer, 'cpk-tool-call-group-stack-behind']"
189
+ :style="{
190
+ transform: `translateY(${index * 6}px) scaleX(${1 - index * 0.045})`,
191
+ zIndex: -index,
192
+ opacity: 1 - index * 0.28,
193
+ }"
194
+ />
195
+ <!-- One toggle in both states, so it keeps keyboard focus when pressed. -->
196
+ <button
197
+ type="button"
198
+ :aria-expanded="open ? 'true' : 'false'"
199
+ :aria-controls="open ? bodyId : undefined"
200
+ :class="[
201
+ 'cpk-tool-call-group-stack-toggle',
202
+ open
203
+ ? 'cpk-tool-call-group-stack-toggle-open'
204
+ : [layer, 'cpk-tool-call-group-stack-toggle-closed'],
205
+ ]"
206
+ @click="toggle"
207
+ >
208
+ <template v-if="open">
209
+ {{ pluralize(calls.length, "tool call") }}
210
+ <ToolCallFailedCount :calls="calls" />
211
+ <span class="cpk-tool-call-group-stack-collapse">
212
+ Collapse
213
+ <ToolCallChevron
214
+ :open="true"
215
+ class="cpk-tool-call-group-stack-collapse-icon"
216
+ />
217
+ </span>
218
+ </template>
219
+ <template v-else>
220
+ <span
221
+ :key="latest.toolCall.id"
222
+ class="cpk-tool-call-group-stack-latest"
223
+ >
224
+ <ToolCallStatusIcon :status="latestStatus" />
225
+ <span
226
+ :class="[
227
+ 'cpk-tool-call-group-stack-name',
228
+ latestStatus === 'running' && 'cpk-shimmer',
229
+ ]"
230
+ >{{ latest.toolCall.function.name }}</span
231
+ >
232
+ <span
233
+ v-if="latestPreview"
234
+ class="cpk-tool-call-group-stack-preview"
235
+ >{{ latestPreview }}</span
236
+ >
237
+ <!-- The status icon is decorative, so say the status. -->
238
+ <span class="cpk-tool-call-group-stack-status">{{
239
+ statusLabels[latestStatus]
240
+ }}</span>
241
+ </span>
242
+ <span class="cpk-tool-call-group-stack-meta">
243
+ <ToolCallFailedCount :calls="calls" />
244
+ <span class="cpk-tool-call-group-stack-count">{{
245
+ pluralize(calls.length, "call")
246
+ }}</span>
247
+ <ToolCallChevron
248
+ :open="false"
249
+ class="cpk-tool-call-group-stack-expand-icon"
250
+ />
251
+ </span>
252
+ </template>
253
+ </button>
254
+ <!-- Always mounted, so screen readers hear the closed stack's latest
255
+ call change ("read_file: Running", then "read_file: Done"); the
256
+ button only names it. -->
257
+ <span aria-live="polite" class="cpk-tool-call-group-stack-live">{{
258
+ open
259
+ ? ""
260
+ : `${latest.toolCall.function.name}: ${statusLabels[latestStatus]}`
261
+ }}</span>
262
+ </div>
263
+ <!-- Each call gets the collapsed stack's card, easing out of the stack. -->
264
+ <div v-if="open" :id="bodyId" class="cpk-tool-call-group-stack-items">
265
+ <div
266
+ v-for="(call, index) in calls"
267
+ :key="call.toolCall.id"
268
+ :class="[layer, 'cpk-tool-call-group-stack-item']"
269
+ :style="{ animationDelay: `${index * 30}ms` }"
270
+ >
271
+ <slot name="call" :call="call" />
272
+ </div>
273
+ </div>
274
+ </div>
275
+
276
+ <!-- card: one call gets the same card as several, so the card a run
277
+ starts with doesn't change style when the next call joins it. -->
278
+ <div
279
+ v-else-if="latest"
280
+ data-copilotkit
281
+ data-testid="copilot-tool-call-group"
282
+ :data-appearance="appearance"
283
+ :data-state="status"
284
+ class="cpk-tool-call-group cpk-tool-call-group-card"
285
+ >
286
+ <button
287
+ type="button"
288
+ :aria-expanded="open ? 'true' : 'false'"
289
+ :aria-controls="bodyId"
290
+ class="cpk-tool-call-group-card-toggle"
291
+ @click="toggle"
292
+ >
293
+ <ToolCallStatusIcon :status="status" />
294
+ <template v-if="current">
295
+ <span class="cpk-tool-call-group-running cpk-shimmer"
296
+ >Running {{ current.toolCall.function.name }}</span
297
+ >
298
+ <span v-if="preview" class="cpk-tool-call-group-preview">{{
299
+ preview
300
+ }}</span>
301
+ </template>
302
+ <template v-else>
303
+ <span class="cpk-tool-call-group-card-summary"
304
+ >Used {{ pluralize(calls.length, "tool") }}</span
305
+ >
306
+ <span class="cpk-tool-call-group-card-names">{{
307
+ toolNames(calls)
308
+ }}</span>
309
+ </template>
310
+ <span class="cpk-tool-call-group-card-meta">
311
+ <ToolCallFailedCount v-if="status === 'failed'" :calls="calls" />
312
+ <span v-else class="cpk-tool-call-group-card-status">{{
313
+ status !== "running"
314
+ ? statusLabels[status]
315
+ : done > 0
316
+ ? `${done} done`
317
+ : ""
318
+ }}</span>
319
+ <ToolCallChevron :open="open" />
320
+ </span>
321
+ </button>
322
+ <CopilotChatCollapsible :id="bodyId" :open="open">
323
+ <div>
324
+ <template v-for="call in calls" :key="call.toolCall.id">
325
+ <slot name="call" :call="call" />
326
+ </template>
327
+ </div>
328
+ </CopilotChatCollapsible>
329
+ </div>
330
+ </template>
@@ -11,6 +11,10 @@ import {
11
11
  getToolCallRenderProps,
12
12
  getToolCallSlotName,
13
13
  } from "./copilotChatToolCallItemRender";
14
+ import {
15
+ ToolCallCaptureScope,
16
+ useLearningConfigured,
17
+ } from "./tool-call-capture";
14
18
 
15
19
  const props = withDefaults(
16
20
  defineProps<{
@@ -31,6 +35,7 @@ defineSlots<{
31
35
 
32
36
  const { copilotkit, executingToolCallIds } = useCopilotKit();
33
37
  const config = useCopilotChatConfiguration();
38
+ const learningConfigured = useLearningConfigured(copilotkit);
34
39
 
35
40
  function getRenderProps(): CopilotChatToolCallRenderSlotProps {
36
41
  return getToolCallRenderProps(
@@ -70,17 +75,22 @@ function getMemoDeps() {
70
75
  </script>
71
76
 
72
77
  <template>
73
- <slot
74
- :name="getToolCallSlotName(toolCall.function.name)"
75
- v-bind="getRenderProps()"
78
+ <ToolCallCaptureScope
79
+ :tool-call-id="toolCall.id"
80
+ :enabled="learningConfigured"
76
81
  >
77
- <slot name="tool-call" v-bind="getRenderProps()">
78
- <component
79
- :is="getRenderConfig()?.render"
80
- v-if="getRenderConfig()"
81
- v-memo="getMemoDeps()"
82
- v-bind="getCoreProps()"
83
- />
82
+ <slot
83
+ :name="getToolCallSlotName(toolCall.function.name)"
84
+ v-bind="getRenderProps()"
85
+ >
86
+ <slot name="tool-call" v-bind="getRenderProps()">
87
+ <component
88
+ :is="getRenderConfig()?.render"
89
+ v-if="getRenderConfig()"
90
+ v-memo="getMemoDeps()"
91
+ v-bind="getCoreProps()"
92
+ />
93
+ </slot>
84
94
  </slot>
85
- </slot>
95
+ </ToolCallCaptureScope>
86
96
  </template>
@@ -1,49 +1,220 @@
1
1
  <script setup lang="ts">
2
- import { useSlots } from "vue";
2
+ import { computed, defineComponent, h, inject, provide, useSlots } from "vue";
3
+ import type { PropType } from "vue";
4
+ import type { Slots, VNode } from "vue";
3
5
  import type { AssistantMessage, Message } from "@ag-ui/core";
4
- import type { CopilotChatToolCallRenderSlotProps } from "./types";
6
+ import { useCopilotKit } from "../../providers/useCopilotKit";
7
+ import type {
8
+ CopilotChatToolCallGroupAppearance,
9
+ CopilotChatToolCallRenderSlotProps,
10
+ CopilotChatToolCallsGroupSlotProps,
11
+ } from "./types";
5
12
  import CopilotChatToolCallItem from "./CopilotChatToolCallItem.vue";
13
+ import CopilotChatToolCallGroup from "./CopilotChatToolCallGroup.vue";
14
+ import { CopilotChatCollapsible } from "./tool-call-group-parts";
15
+ import {
16
+ ToolCallDisplayContextKey,
17
+ ToolCallGroupContextKey,
18
+ } from "./tool-call-display-context";
19
+ import type { ToolCallGroupContextValue } from "./tool-call-display-context";
20
+ import {
21
+ getToolCallLayouts,
22
+ getToolCallRendererNames,
23
+ } from "./tool-call-layout";
24
+ import type {
25
+ CopilotChatToolCallDisplay,
26
+ ToolCallEntry,
27
+ } from "./tool-call-layout";
6
28
 
7
- withDefaults(
29
+ const props = withDefaults(
8
30
  defineProps<{
9
31
  message: AssistantMessage;
10
32
  messages?: Message[];
33
+ /**
34
+ * How to show the calls (see `CopilotChatToolCallDisplay`). Inside a
35
+ * message view it follows the view's `toolCallDisplay`; on its own it
36
+ * defaults to `"grouped"`.
37
+ */
38
+ display?: CopilotChatToolCallDisplay;
11
39
  }>(),
12
40
  {
13
41
  messages: () => [],
42
+ display: undefined,
14
43
  },
15
44
  );
16
45
 
17
46
  defineSlots<{
18
47
  "tool-call"?: (props: CopilotChatToolCallRenderSlotProps) => unknown;
48
+ /** Replaces a group of calls made in a row. */
49
+ "tool-calls-group"?: (props: CopilotChatToolCallsGroupSlotProps) => unknown;
19
50
  [key: `tool-call-${string}`]: (
20
51
  props: CopilotChatToolCallRenderSlotProps,
21
52
  ) => unknown;
22
53
  }>();
23
54
 
24
55
  type ToolCallSlotName = "tool-call" | `tool-call-${string}`;
25
- const componentSlots = useSlots() as Record<
26
- ToolCallSlotName,
27
- (props?: unknown) => unknown
28
- >;
29
- function getForwardedSlotNames(): ToolCallSlotName[] {
30
- return Object.keys(componentSlots) as ToolCallSlotName[];
56
+
57
+ const appearances: Partial<
58
+ Record<CopilotChatToolCallDisplay, CopilotChatToolCallGroupAppearance>
59
+ > = {
60
+ grouped: "card",
61
+ line: "line",
62
+ stacked: "stack",
63
+ };
64
+
65
+ const componentSlots = useSlots() as Slots;
66
+ const { copilotkit } = useCopilotKit();
67
+ const context = inject(ToolCallDisplayContextKey, null);
68
+
69
+ /** The slots that draw tool calls, which each call's item renders. */
70
+ function getToolCallSlotNames(): ToolCallSlotName[] {
71
+ return Object.keys(componentSlots).filter(
72
+ (name): name is ToolCallSlotName =>
73
+ name === "tool-call" || name.startsWith("tool-call-"),
74
+ );
75
+ }
76
+
77
+ const display = computed(
78
+ () => props.display ?? context?.value.display ?? "grouped",
79
+ );
80
+
81
+ // Inside a message view, groups can span messages, so the view lays them out
82
+ // for the whole list; on its own, this message's calls are grouped.
83
+ const layout = computed(() => {
84
+ if (display.value === "separate") return undefined;
85
+ const viewLayout = context?.value.layouts.get(props.message.id);
86
+ if (viewLayout) return viewLayout;
87
+ const rendererNames = getToolCallRendererNames(
88
+ copilotkit.value.renderToolCalls,
89
+ getToolCallSlotNames(),
90
+ );
91
+ return getToolCallLayouts([props.message], props.messages, rendererNames).get(
92
+ props.message.id,
93
+ );
94
+ });
95
+
96
+ // Whether the agent may still finish a trailing group's calls. Without a
97
+ // message view there's no run state, so a call with no result is assumed to
98
+ // be running, as the built-in card has always shown it.
99
+ const groupActive = (trailing: boolean) =>
100
+ trailing && (context ? context.value.isRunning : true);
101
+
102
+ const appearance = computed(() => appearances[display.value] ?? "card");
103
+
104
+ const workOpen = computed(() => context?.value.workOpen.get(props.message.id));
105
+
106
+ /**
107
+ * `"turn"` display: draws the built-in card's calls as compact rows, the way
108
+ * an open line group does, without a group around them.
109
+ */
110
+ const TurnRows = defineComponent({
111
+ props: {
112
+ calls: { type: Array as PropType<ToolCallEntry[]>, required: true },
113
+ active: { type: Boolean, required: true },
114
+ },
115
+ setup(rowProps, { slots }) {
116
+ provide(
117
+ ToolCallGroupContextKey,
118
+ computed<ToolCallGroupContextValue>(() => ({
119
+ appearance: "line",
120
+ failedIds: new Set(
121
+ rowProps.calls
122
+ .filter((call) => call.toolMessage?.error)
123
+ .map((call) => call.toolCall.id),
124
+ ),
125
+ active: rowProps.active,
126
+ })),
127
+ );
128
+ return () => slots.default?.();
129
+ },
130
+ });
131
+
132
+ /** Draws one call through the registered renderers and tool-call slots. */
133
+ function renderCall(call: ToolCallEntry): VNode {
134
+ const slots: Record<string, Slots[string]> = {};
135
+ for (const name of getToolCallSlotNames()) slots[name] = componentSlots[name];
136
+ return h(
137
+ CopilotChatToolCallItem,
138
+ {
139
+ key: call.toolCall.id,
140
+ toolCall: call.toolCall,
141
+ messages: props.messages,
142
+ },
143
+ slots,
144
+ );
31
145
  }
32
146
  </script>
33
147
 
34
148
  <template>
35
- <CopilotChatToolCallItem
36
- v-for="toolCall in message.toolCalls ?? []"
37
- :key="toolCall.id"
38
- :tool-call="toolCall"
39
- :messages="messages"
40
- >
41
- <template
42
- v-for="slotName in getForwardedSlotNames()"
43
- :key="slotName"
44
- #[slotName]="slotProps"
149
+ <template v-if="!layout">
150
+ <CopilotChatToolCallItem
151
+ v-for="toolCall in message.toolCalls ?? []"
152
+ :key="toolCall.id"
153
+ :tool-call="toolCall"
154
+ :messages="messages"
45
155
  >
46
- <slot :name="slotName" v-bind="slotProps ?? {}" />
156
+ <template
157
+ v-for="slotName in getToolCallSlotNames()"
158
+ :key="slotName"
159
+ #[slotName]="slotProps"
160
+ >
161
+ <slot :name="slotName" v-bind="slotProps ?? {}" />
162
+ </template>
163
+ </CopilotChatToolCallItem>
164
+ </template>
165
+ <template v-else>
166
+ <template v-for="segment in layout.segments" :key="segment.id">
167
+ <CopilotChatToolCallItem
168
+ v-if="segment.kind === 'call'"
169
+ :tool-call="segment.call.toolCall"
170
+ :messages="messages"
171
+ >
172
+ <template
173
+ v-for="slotName in getToolCallSlotNames()"
174
+ :key="slotName"
175
+ #[slotName]="slotProps"
176
+ >
177
+ <slot :name="slotName" v-bind="slotProps ?? {}" />
178
+ </template>
179
+ </CopilotChatToolCallItem>
180
+ <!-- A row per call, in the open while the agent works; the message view
181
+ folds them away with the rest of the work once it's done. -->
182
+ <CopilotChatCollapsible
183
+ v-else-if="display === 'turn'"
184
+ :open="workOpen ?? true"
185
+ class="cpk-tool-calls-view-turn"
186
+ >
187
+ <div class="cpk-tool-calls-view-turn-rows">
188
+ <TurnRows
189
+ :calls="segment.calls"
190
+ :active="groupActive(segment.trailing)"
191
+ >
192
+ <component
193
+ :is="renderCall(call)"
194
+ v-for="call in segment.calls"
195
+ :key="call.toolCall.id"
196
+ />
197
+ </TurnRows>
198
+ </div>
199
+ </CopilotChatCollapsible>
200
+ <slot
201
+ v-else
202
+ name="tool-calls-group"
203
+ :calls="segment.calls"
204
+ :appearance="appearance"
205
+ :is-active="groupActive(segment.trailing)"
206
+ :render-call="renderCall"
207
+ >
208
+ <CopilotChatToolCallGroup
209
+ :calls="segment.calls"
210
+ :appearance="appearance"
211
+ :is-active="groupActive(segment.trailing)"
212
+ >
213
+ <template #call="{ call }">
214
+ <component :is="renderCall(call)" />
215
+ </template>
216
+ </CopilotChatToolCallGroup>
217
+ </slot>
47
218
  </template>
48
- </CopilotChatToolCallItem>
219
+ </template>
49
220
  </template>