@copilotkit/vue 2.0.0-rc.1 → 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
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
- import { computed, onMounted, ref, useSlots, watch } from "vue";
3
- import type { Component, FunctionalComponent, VNodeChild } from "vue";
2
+ import { computed, h, onMounted, provide, ref, useSlots, watch } from "vue";
3
+ import type { Component, FunctionalComponent, VNode, VNodeChild } from "vue";
4
4
  import type {
5
5
  ActivityMessage,
6
6
  AssistantMessage,
@@ -24,6 +24,28 @@ import { useCopilotChatConfiguration } from "../../providers/useCopilotChatConfi
24
24
  import CopilotChatAssistantMessage from "./CopilotChatAssistantMessage.vue";
25
25
  import CopilotChatReasoningMessage from "./CopilotChatReasoningMessage.vue";
26
26
  import CopilotChatUserMessage from "./CopilotChatUserMessage.vue";
27
+ import CopilotChatWorkSummary from "./CopilotChatWorkSummary.vue";
28
+ import { CopilotChatCollapsible } from "./tool-call-group-parts";
29
+ import { TurnWorkFold } from "./turn-work";
30
+ import {
31
+ MessageFeedbackScopeKey,
32
+ useLearningFeedbackEnabled,
33
+ } from "./message-feedback";
34
+ import type { MessageFeedbackScope } from "./message-feedback";
35
+ import { ToolCallDisplayContextKey } from "./tool-call-display-context";
36
+ import type { ToolCallDisplayContextValue } from "./tool-call-display-context";
37
+ import {
38
+ getToolCallLayouts,
39
+ getToolCallRendererNames,
40
+ getTurnWork,
41
+ } from "./tool-call-layout";
42
+ import type {
43
+ CopilotChatToolCallDisplay,
44
+ ToolCallEntry,
45
+ ToolCallLayout,
46
+ TurnWork,
47
+ } from "./tool-call-layout";
48
+ import type { CopilotChatWorkSummarySlotProps } from "./types";
27
49
 
28
50
  interface MessageMetaProps {
29
51
  message: Message;
@@ -56,10 +78,26 @@ const props = withDefaults(
56
78
  defineProps<{
57
79
  messages?: Message[];
58
80
  isRunning?: boolean;
81
+ /**
82
+ * How tool calls show. Defaults to `"grouped"`: calls made in a row
83
+ * share one card that opens to a row per call. `"line"` and `"stacked"`
84
+ * group them too; `"turn"` folds a reply's whole working phase into
85
+ * "Worked for 9s" once it's done; `"separate"` gives every call its own
86
+ * card. Calls with a renderer of their own always show on their own.
87
+ */
88
+ toolCallDisplay?: CopilotChatToolCallDisplay;
89
+ /**
90
+ * While Learning records this chat, the assistant thumbs record ratings
91
+ * and ask for a comment. Set `false` to leave the thumbs to the app's own
92
+ * handlers.
93
+ */
94
+ messageFeedback?: boolean;
59
95
  }>(),
60
96
  {
61
97
  messages: () => [],
62
98
  isRunning: false,
99
+ toolCallDisplay: "grouped",
100
+ messageFeedback: true,
63
101
  },
64
102
  );
65
103
 
@@ -81,6 +119,8 @@ defineSlots<{
81
119
  "activity-message"?: (props: ActivitySlotProps) => unknown;
82
120
  [key: string]: ((props: any) => unknown) | undefined;
83
121
  cursor?: () => unknown;
122
+ /** The "Working… / Worked for 9s" line of the `"turn"` tool-call display. */
123
+ "work-summary"?: (props: CopilotChatWorkSummarySlotProps) => unknown;
84
124
  "tool-call"?: (props: {
85
125
  name: string;
86
126
  args: unknown;
@@ -191,6 +231,169 @@ const deduplicatedMessages = computed(() =>
191
231
  deduplicateMessages(props.messages),
192
232
  );
193
233
 
234
+ // Groups of calls can span messages (an agent often sends each call as its
235
+ // own message), so they're laid out here for the whole list and handed to
236
+ // each message's tool calls view through provide/inject.
237
+ const toolCallLayouts = computed<ReadonlyMap<string, ToolCallLayout>>(() =>
238
+ props.toolCallDisplay === "separate"
239
+ ? new Map()
240
+ : getToolCallLayouts(
241
+ deduplicatedMessages.value,
242
+ props.messages,
243
+ getToolCallRendererNames(
244
+ copilotkit.value.renderToolCalls,
245
+ forwardedSlotNames.value,
246
+ ),
247
+ ),
248
+ );
249
+ const learningFeedbackEnabled = useLearningFeedbackEnabled(copilotkit);
250
+ provide(
251
+ MessageFeedbackScopeKey,
252
+ computed<MessageFeedbackScope | null>(() =>
253
+ props.messageFeedback &&
254
+ learningFeedbackEnabled.value &&
255
+ config.value?.agentId !== undefined &&
256
+ config.value?.threadId !== undefined
257
+ ? {
258
+ copilotkit: copilotkit.value,
259
+ agentId: config.value.agentId,
260
+ threadId: config.value.threadId,
261
+ }
262
+ : null,
263
+ ),
264
+ );
265
+
266
+ const turnWork = computed(() =>
267
+ props.toolCallDisplay === "turn"
268
+ ? getTurnWork(deduplicatedMessages.value, toolCallLayouts.value)
269
+ : undefined,
270
+ );
271
+ const turnByFirstMessage = computed(() => {
272
+ const byFirst = new Map<string, TurnWork>();
273
+ for (const turn of turnWork.value?.values() ?? []) {
274
+ byFirst.set(turn.firstMessageId, turn);
275
+ }
276
+ return byFirst;
277
+ });
278
+
279
+ const lastRenderedMessage = computed(
280
+ () => deduplicatedMessages.value[deduplicatedMessages.value.length - 1],
281
+ );
282
+ // The latest reply is keyed by the user message it answers (see getTurnWork).
283
+ const latestTurnKey = computed(() => {
284
+ const rendered = deduplicatedMessages.value;
285
+ for (let i = rendered.length - 1; i >= 0; i--) {
286
+ if (rendered[i]!.role === "user") return rendered[i]!.id;
287
+ }
288
+ return "start";
289
+ });
290
+ const isWorkingOn = (turnKey: string) =>
291
+ props.isRunning && turnKey === latestTurnKey.value;
292
+
293
+ // Work shows while the agent is on it and folds once the reply is done,
294
+ // unless the user has opened or closed it themselves.
295
+ const toggledTurns = ref<ReadonlyMap<string, boolean>>(new Map());
296
+ const isWorkOpen = (turnKey: string) =>
297
+ toggledTurns.value.get(turnKey) ?? isWorkingOn(turnKey);
298
+
299
+ // How long the agent worked, for "Worked for 9s": the sum of its runs on the
300
+ // reply, so waiting between them (say, for an approval) doesn't count. Only
301
+ // known for replies this client watched start from the user's message; a
302
+ // restored thread shows the tool count instead.
303
+ const workTimes = new Map<
304
+ string,
305
+ { elapsedMs: number; workingSince?: number }
306
+ >();
307
+ const workTimesVersion = ref(0);
308
+ watch(
309
+ [
310
+ () => props.toolCallDisplay,
311
+ () => props.isRunning,
312
+ latestTurnKey,
313
+ () => lastRenderedMessage.value?.role,
314
+ ],
315
+ ([display, isRunning, turnKey, lastRole]) => {
316
+ if (display !== "turn") return;
317
+ const now = Date.now();
318
+ if (isRunning) {
319
+ const times = workTimes.get(turnKey);
320
+ if (times) times.workingSince ??= now;
321
+ else if (lastRole === "user")
322
+ workTimes.set(turnKey, { elapsedMs: 0, workingSince: now });
323
+ } else {
324
+ for (const times of workTimes.values()) {
325
+ if (times.workingSince === undefined) continue;
326
+ times.elapsedMs += now - times.workingSince;
327
+ times.workingSince = undefined;
328
+ }
329
+ }
330
+ workTimesVersion.value++;
331
+ },
332
+ { immediate: true },
333
+ );
334
+
335
+ // Whether each working-phase message's work shows. Text that ends the reply
336
+ // stays out even when its message also calls a tool: it's the answer.
337
+ const workOpenState = computed(() => {
338
+ const open = new Map<string, boolean>();
339
+ const textOpen = new Map<string, boolean>();
340
+ for (const turn of turnWork.value?.values() ?? []) {
341
+ const turnOpen = isWorkOpen(turn.key);
342
+ for (const id of turn.workMessageIds) {
343
+ open.set(id, turnOpen);
344
+ if (id !== turn.replyTextMessageId) textOpen.set(id, turnOpen);
345
+ }
346
+ }
347
+ return { workOpen: open, workTextOpen: textOpen };
348
+ });
349
+
350
+ provide(
351
+ ToolCallDisplayContextKey,
352
+ computed<ToolCallDisplayContextValue>(() => ({
353
+ display: props.toolCallDisplay,
354
+ isRunning: props.isRunning,
355
+ layouts: toolCallLayouts.value,
356
+ workOpen: workOpenState.value.workOpen,
357
+ workTextOpen: workOpenState.value.workTextOpen,
358
+ })),
359
+ );
360
+
361
+ /** The `"turn"` display's summary line for a reply, or its slot. */
362
+ const WorkSummaryRow: FunctionalComponent<{
363
+ turnKey: string;
364
+ calls: ToolCallEntry[];
365
+ }> = ({ turnKey, calls }) => {
366
+ void workTimesVersion.value;
367
+ const isWorking = isWorkingOn(turnKey);
368
+ const isOpen = isWorkOpen(turnKey);
369
+ const times = workTimes.get(turnKey);
370
+ const summaryProps: CopilotChatWorkSummarySlotProps = {
371
+ isWorking,
372
+ isOpen,
373
+ calls,
374
+ elapsedMs: times?.elapsedMs,
375
+ workingSince: times?.workingSince,
376
+ onClick: () => {
377
+ toggledTurns.value = new Map(toggledTurns.value).set(turnKey, !isOpen);
378
+ },
379
+ };
380
+ const slot = componentSlots["work-summary"];
381
+ return h(
382
+ CopilotChatCollapsible,
383
+ { open: isWorking || calls.length > 0 },
384
+ () => [
385
+ h(
386
+ "div",
387
+ { class: "cpk-message-view-work-summary" },
388
+ slot
389
+ ? (slot(summaryProps) as VNode[])
390
+ : [h(CopilotChatWorkSummary, summaryProps)],
391
+ ),
392
+ ],
393
+ );
394
+ };
395
+ WorkSummaryRow.props = ["turnKey", "calls"];
396
+
194
397
  // Stable per-row keys. Backends can re-key a message mid-stream, and keying
195
398
  // rows by the canonical id tears the row down on that swap (the HITL chat
196
399
  // flash). See @copilotkit/shared row-render-keys for the mechanism.
@@ -209,8 +412,20 @@ watch(
209
412
  { flush: "post" },
210
413
  );
211
414
  const lastMessage = computed(() => props.messages[props.messages.length - 1]);
415
+ // In the "turn" display the "Working" line at the top of the reply is the
416
+ // progress indicator; before the reply's first message it sits where the
417
+ // cursor would.
212
418
  const showCursor = computed(
213
- () => props.isRunning && lastMessage.value?.role !== "reasoning",
419
+ () =>
420
+ props.isRunning &&
421
+ lastMessage.value?.role !== "reasoning" &&
422
+ props.toolCallDisplay !== "turn",
423
+ );
424
+ const pendingWorkSummary = computed(
425
+ () =>
426
+ props.toolCallDisplay === "turn" &&
427
+ props.isRunning &&
428
+ lastRenderedMessage.value?.role === "user",
214
429
  );
215
430
 
216
431
  watch(
@@ -390,11 +605,20 @@ function resolveToolMessage(
390
605
  </script>
391
606
 
392
607
  <template>
393
- <div data-copilotkit class="cpk:flex cpk:flex-col" v-bind="$attrs">
608
+ <div
609
+ data-copilotkit
610
+ class="copilotKitMessages cpk-message-view"
611
+ v-bind="$attrs"
612
+ >
394
613
  <template
395
614
  v-for="message in deduplicatedMessages"
396
615
  :key="rowRenderKeys.get(message.id) ?? message.id"
397
616
  >
617
+ <WorkSummaryRow
618
+ v-if="turnByFirstMessage.get(message.id)"
619
+ :turn-key="turnByFirstMessage.get(message.id)!.key"
620
+ :calls="turnByFirstMessage.get(message.id)!.calls"
621
+ />
398
622
  <MessageMetaSlot
399
623
  v-if="componentSlots['message-before']"
400
624
  :render="componentSlots['message-before']"
@@ -444,19 +668,30 @@ function resolveToolMessage(
444
668
  </CopilotChatUserMessage>
445
669
  </slot>
446
670
 
447
- <slot
671
+ <!-- Reasoning during a reply's working phase folds away with the work.
672
+ Always wrapped in this display, so reasoning that turns into work
673
+ keeps its node (and its "Thought for" timer) instead of remounting. -->
674
+ <TurnWorkFold
448
675
  v-else-if="message.role === 'reasoning'"
449
- name="reasoning-message"
450
- :message="message"
451
- :messages="messages"
452
- :is-running="isRunning"
676
+ :open="
677
+ toolCallDisplay === 'turn'
678
+ ? (workOpenState.workOpen.get(message.id) ?? true)
679
+ : undefined
680
+ "
453
681
  >
454
- <CopilotChatReasoningMessage
682
+ <slot
683
+ name="reasoning-message"
455
684
  :message="message"
456
685
  :messages="messages"
457
686
  :is-running="isRunning"
458
- />
459
- </slot>
687
+ >
688
+ <CopilotChatReasoningMessage
689
+ :message="message"
690
+ :messages="messages"
691
+ :is-running="isRunning"
692
+ />
693
+ </slot>
694
+ </TurnWorkFold>
460
695
 
461
696
  <slot
462
697
  v-else-if="message.role === 'activity'"
@@ -504,11 +739,19 @@ function resolveToolMessage(
504
739
  :cancel="interruptState.cancel"
505
740
  />
506
741
 
507
- <slot v-if="showCursor" name="cursor">
508
- <div
509
- class="cpk:w-[11px] cpk:h-[11px] cpk:rounded-full cpk:bg-foreground cpk:animate-pulse cpk:ml-1"
510
- data-testid="copilot-loading-cursor"
511
- />
512
- </slot>
742
+ <WorkSummaryRow
743
+ v-if="pendingWorkSummary"
744
+ :turn-key="latestTurnKey"
745
+ :calls="[]"
746
+ />
747
+
748
+ <div v-if="showCursor" class="cpk-message-view-cursor-container">
749
+ <slot name="cursor">
750
+ <div
751
+ class="cpk-message-view-cursor"
752
+ data-testid="copilot-loading-cursor"
753
+ />
754
+ </slot>
755
+ </div>
513
756
  </div>
514
757
  </template>
@@ -150,7 +150,11 @@ function toggleOpen() {
150
150
  </script>
151
151
 
152
152
  <template>
153
- <div data-copilotkit class="cpk:my-1" :data-message-id="message.id">
153
+ <div
154
+ data-copilotkit
155
+ class="cpk-reasoning-message"
156
+ :data-message-id="message.id"
157
+ >
154
158
  <slot
155
159
  name="layout"
156
160
  :message="message"
@@ -189,28 +193,22 @@ function toggleOpen() {
189
193
  >
190
194
  <button
191
195
  type="button"
192
- class="cpk:inline-flex cpk:items-center cpk:gap-1 cpk:py-1 cpk:text-sm cpk:text-muted-foreground cpk:transition-colors cpk:select-none"
193
- :class="
194
- hasContent
195
- ? 'cpk:hover:text-foreground cpk:cursor-pointer'
196
- : 'cpk:cursor-default'
197
- "
196
+ class="cpk-reasoning-message-header"
197
+ :class="{ 'cpk-reasoning-message-header-expandable': hasContent }"
198
198
  :aria-expanded="hasContent ? isOpen : undefined"
199
199
  @click="hasContent ? toggleOpen() : undefined"
200
200
  >
201
- <span class="cpk:font-medium">{{ label }}</span>
201
+ <span class="cpk-reasoning-message-label">{{ label }}</span>
202
202
  <span
203
203
  v-if="isStreaming && !hasContent"
204
- class="cpk:inline-flex cpk:items-center cpk:ml-1"
204
+ class="cpk-reasoning-message-indicator"
205
205
  >
206
- <span
207
- class="cpk:w-1.5 cpk:h-1.5 cpk:rounded-full cpk:bg-muted-foreground cpk:animate-pulse"
208
- />
206
+ <span class="cpk-reasoning-message-indicator-dot" />
209
207
  </span>
210
208
  <IconChevronRight
211
209
  v-if="hasContent"
212
- class="cpk:size-3.5 cpk:shrink-0 cpk:transition-transform cpk:duration-200"
213
- :class="{ 'cpk:rotate-90': isOpen }"
210
+ class="cpk-reasoning-message-chevron"
211
+ :class="{ 'cpk-reasoning-message-chevron-open': isOpen }"
214
212
  />
215
213
  </button>
216
214
  </slot>
@@ -225,18 +223,21 @@ function toggleOpen() {
225
223
  }"
226
224
  >
227
225
  <div
228
- class="cpk:grid cpk:transition-[grid-template-rows] cpk:duration-200 cpk:ease-in-out"
226
+ class="cpk-reasoning-message-toggle"
229
227
  :style="{ gridTemplateRows: isOpen ? '1fr' : '0fr' }"
230
228
  >
231
- <div class="cpk:overflow-hidden">
229
+ <div class="cpk-reasoning-message-toggle-content">
232
230
  <slot
233
231
  name="content-view"
234
232
  :is-streaming="isStreaming"
235
233
  :has-content="hasContent"
236
234
  :content="normalizedContent"
237
235
  >
238
- <div v-if="hasContent || isStreaming" class="cpk:pb-2 cpk:pt-1">
239
- <div class="cpk:text-sm cpk:text-muted-foreground">
236
+ <div
237
+ v-if="hasContent || isStreaming"
238
+ class="cpk-reasoning-message-content"
239
+ >
240
+ <div class="cpk-reasoning-message-text">
240
241
  <!-- Reasoning content uses the streaming renderer (same as assistant);
241
242
  the pluggable provider renderer applies to assistant messages only. -->
242
243
  <StreamingMarkdownDefault
@@ -245,11 +246,9 @@ function toggleOpen() {
245
246
  />
246
247
  <span
247
248
  v-if="isStreaming && hasContent"
248
- class="cpk:inline-flex cpk:items-center cpk:ml-1 cpk:align-middle"
249
+ class="cpk-reasoning-message-cursor"
249
250
  >
250
- <span
251
- class="cpk:w-2 cpk:h-2 cpk:rounded-full cpk:bg-muted-foreground cpk:animate-pulse-cursor"
252
- />
251
+ <span class="cpk-reasoning-message-cursor-dot" />
253
252
  </span>
254
253
  </div>
255
254
  </div>
@@ -29,27 +29,18 @@ const isDisabled = computed(() => props.isLoading || props.disabled);
29
29
  :type="type"
30
30
  :aria-busy="isLoading ? 'true' : undefined"
31
31
  :disabled="isDisabled"
32
- class="cpk:group cpk:inline-flex cpk:h-7 cpk:w-fit cpk:items-center cpk:gap-1 cpk:rounded-full cpk:border cpk:border-border/60 cpk:bg-background cpk:px-2.5 cpk:text-[11px] cpk:leading-none cpk:text-foreground cpk:transition-colors cpk:cursor-pointer cpk:hover:bg-accent/60 cpk:hover:text-foreground cpk:focus-visible:outline-none cpk:focus-visible:ring-2 cpk:focus-visible:ring-ring cpk:focus-visible:ring-offset-2 cpk:focus-visible:ring-offset-background cpk:disabled:cursor-not-allowed cpk:disabled:text-muted-foreground cpk:disabled:hover:bg-background cpk:disabled:hover:text-muted-foreground cpk:pointer-events-auto cpk:sm:h-8 cpk:sm:gap-1.5 cpk:sm:px-3 cpk:sm:text-xs"
32
+ class="cpk-suggestion-pill"
33
33
  v-bind="$attrs"
34
34
  >
35
- <span
36
- v-if="isLoading"
37
- class="cpk:flex cpk:h-3.5 cpk:w-3.5 cpk:items-center cpk:justify-center cpk:text-muted-foreground cpk:sm:h-4 cpk:sm:w-4"
38
- >
39
- <IconLoader2
40
- class="cpk:h-3.5 cpk:w-3.5 cpk:animate-spin cpk:sm:h-4 cpk:sm:w-4"
41
- aria-hidden="true"
42
- />
35
+ <span v-if="isLoading" class="cpk-suggestion-pill-icon">
36
+ <IconLoader2 class="cpk-suggestion-pill-spinner" aria-hidden="true" />
43
37
  </span>
44
- <span
45
- v-else-if="$slots.icon || icon"
46
- class="cpk:flex cpk:h-3.5 cpk:w-3.5 cpk:items-center cpk:justify-center cpk:text-muted-foreground cpk:sm:h-4 cpk:sm:w-4"
47
- >
38
+ <span v-else-if="$slots.icon || icon" class="cpk-suggestion-pill-icon">
48
39
  <slot name="icon">
49
40
  <component :is="icon" />
50
41
  </slot>
51
42
  </span>
52
- <span class="cpk:whitespace-nowrap cpk:font-medium cpk:leading-none">
43
+ <span class="cpk-suggestion-pill-label">
53
44
  <slot />
54
45
  </span>
55
46
  </button>
@@ -32,10 +32,7 @@ const emit = defineEmits<{
32
32
 
33
33
  const attrs = useAttrs();
34
34
  const loadingSet = computed(() => new Set(props.loadingIndexes));
35
- const containerClass = computed(() => [
36
- "cpk:flex cpk:flex-wrap cpk:items-center cpk:gap-1.5 cpk:pl-0 cpk:pr-4 cpk:pointer-events-none cpk:sm:gap-2 cpk:@3xl:px-0",
37
- attrs.class,
38
- ]);
35
+ const containerClass = computed(() => ["cpk-suggestion-view", attrs.class]);
39
36
  const containerAttrs = computed(() => {
40
37
  const { class: _className, ...rest } = attrs;
41
38
  return rest;
@@ -33,12 +33,7 @@ const ariaLabel = computed(() =>
33
33
  : labels.value.chatToggleOpenLabel,
34
34
  );
35
35
  const buttonClass = computed(() => [
36
- "cpk:fixed cpk:bottom-6 cpk:right-6 cpk:z-[1100] cpk:flex cpk:h-14 cpk:w-14 cpk:items-center cpk:justify-center",
37
- "cpk:rounded-full cpk:border cpk:border-primary cpk:bg-primary cpk:text-primary-foreground",
38
- "cpk:shadow-sm cpk:transition-all cpk:duration-200 cpk:ease-out",
39
- "cpk:hover:scale-[1.04] cpk:hover:shadow-md cpk:cursor-pointer cpk:active:scale-[0.96]",
40
- "cpk:focus-visible:outline-none cpk:focus-visible:ring-2 cpk:focus-visible:ring-primary/50 cpk:focus-visible:ring-offset-2 cpk:focus-visible:ring-offset-background",
41
- "cpk:disabled:pointer-events-none cpk:disabled:opacity-60",
36
+ "copilotKitButton cpk-chat-toggle-button",
42
37
  attrs.class,
43
38
  ]);
44
39
  const buttonAttrs = computed(() => {
@@ -46,13 +41,12 @@ const buttonAttrs = computed(() => {
46
41
  return rest;
47
42
  });
48
43
 
49
- const iconClass = "cpk:h-6 cpk:w-6";
44
+ const iconClass = "cpk-chat-toggle-button-icon";
50
45
  const iconTransitionStyle = Object.freeze({
51
46
  transition:
52
47
  "opacity 120ms ease-out, transform 260ms cubic-bezier(0.22, 1, 0.36, 1)",
53
48
  });
54
- const iconWrapperBase =
55
- "cpk:pointer-events-none cpk:absolute cpk:inset-0 cpk:flex cpk:items-center cpk:justify-center cpk:will-change-transform";
49
+ const iconWrapperBase = "cpk-chat-toggle-button-icon-wrapper";
56
50
 
57
51
  function setModalOpen(open: boolean) {
58
52
  if (config.value?.setModalOpen) {
@@ -9,7 +9,7 @@ export default defineComponent({
9
9
  const { class: className, ...rest } = attrs as Record<string, unknown>;
10
10
  return h(IconX, {
11
11
  ...rest,
12
- class: ["cpk:h-6 cpk:w-6", className],
12
+ class: ["cpk-chat-toggle-button-icon", className],
13
13
  strokeWidth: 1.75,
14
14
  });
15
15
  };
@@ -9,7 +9,7 @@ export default defineComponent({
9
9
  const { class: className, ...rest } = attrs as Record<string, unknown>;
10
10
  return h(IconMessageCircle, {
11
11
  ...rest,
12
- class: ["cpk:h-6 cpk:w-6", className],
12
+ class: ["cpk-chat-toggle-button-icon", className],
13
13
  strokeWidth: 1.75,
14
14
  fill: "currentColor",
15
15
  });