@copilotkit/vue 2.0.0-rc.7 → 2.0.0-rc.9

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 (156) hide show
  1. package/dist/hooks/use-copilot-action.d.ts.map +1 -1
  2. package/dist/hooks/use-frontend-tool.d.ts +1 -1
  3. package/dist/hooks/use-frontend-tool.d.ts.map +1 -1
  4. package/dist/hooks/zod-parameters.d.ts +14 -0
  5. package/dist/hooks/zod-parameters.d.ts.map +1 -0
  6. package/dist/index.cjs +1 -73
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.mjs +353 -16906
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/use-render-activity-message-B59A4R48.js +18097 -0
  11. package/dist/use-render-activity-message-B59A4R48.js.map +1 -0
  12. package/dist/use-render-activity-message-u0OVXjd8.cjs +92 -0
  13. package/dist/use-render-activity-message-u0OVXjd8.cjs.map +1 -0
  14. package/dist/v2/components/LicenseWarningBanner.vue.d.ts.map +1 -1
  15. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts +13 -45
  16. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts.map +1 -1
  17. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts +1 -1
  18. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts.map +1 -1
  19. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts +13 -5
  20. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts.map +1 -1
  21. package/dist/v2/components/a2ui.d.ts +3 -7
  22. package/dist/v2/components/a2ui.d.ts.map +1 -1
  23. package/dist/v2/components/chat/CopilotChat.vue.d.ts.map +1 -1
  24. package/dist/v2/components/chat/CopilotChatAttachmentQueue.vue.d.ts.map +1 -1
  25. package/dist/v2/components/chat/CopilotChatAttachmentRenderer.vue.d.ts.map +1 -1
  26. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts +6 -270
  27. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts.map +1 -1
  28. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts +1 -1
  29. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts.map +1 -1
  30. package/dist/v2/components/chat/CopilotChatReasoningMessage.vue.d.ts.map +1 -1
  31. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts +1 -1
  32. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts.map +1 -1
  33. package/dist/v2/components/chat/CopilotChatToolCallItem.vue.d.ts.map +1 -1
  34. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts +1 -1
  35. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts.map +1 -1
  36. package/dist/v2/components/chat/CopilotChatView.vue.d.ts.map +1 -1
  37. package/dist/v2/components/chat/CopilotChatWorkSummary.vue.d.ts.map +1 -1
  38. package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts +0 -1
  39. package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts.map +1 -1
  40. package/dist/v2/components/chat/index.d.ts +0 -1
  41. package/dist/v2/components/chat/index.d.ts.map +1 -1
  42. package/dist/v2/components/chat/tool-call-display-context.d.ts +2 -19
  43. package/dist/v2/components/chat/tool-call-display-context.d.ts.map +1 -1
  44. package/dist/v2/components/chat/tool-call-group-parts.d.ts +7 -20
  45. package/dist/v2/components/chat/tool-call-group-parts.d.ts.map +1 -1
  46. package/dist/v2/components/chat/turn-work.d.ts +0 -2
  47. package/dist/v2/components/chat/turn-work.d.ts.map +1 -1
  48. package/dist/v2/components/chat/types.d.ts +1 -2
  49. package/dist/v2/components/chat/types.d.ts.map +1 -1
  50. package/dist/v2/components/chat/use-chat-labels.d.ts +8 -0
  51. package/dist/v2/components/chat/use-chat-labels.d.ts.map +1 -0
  52. package/dist/v2/components/icons/index.d.ts +968 -1
  53. package/dist/v2/components/icons/index.d.ts.map +1 -1
  54. package/dist/v2/hooks/use-frontend-tool.d.ts +5 -0
  55. package/dist/v2/hooks/use-frontend-tool.d.ts.map +1 -1
  56. package/dist/v2/hooks/use-render-activity-message.d.ts +13 -9
  57. package/dist/v2/hooks/use-render-activity-message.d.ts.map +1 -1
  58. package/dist/v2/hooks/use-render-custom-messages.d.ts +5 -7
  59. package/dist/v2/hooks/use-render-custom-messages.d.ts.map +1 -1
  60. package/dist/v2/index.cjs +1 -1
  61. package/dist/v2/index.mjs +197 -200
  62. package/dist/v2/index.mjs.map +1 -1
  63. package/dist/v2/lib/processPartialHtml.d.ts +1 -2
  64. package/dist/v2/lib/processPartialHtml.d.ts.map +1 -1
  65. package/dist/v2/lib/vue-core.d.ts +0 -1
  66. package/dist/v2/lib/vue-core.d.ts.map +1 -1
  67. package/dist/v2/providers/CopilotKitProvider.vue.d.ts +1 -1
  68. package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
  69. package/dist/v2/providers/types.d.ts +3 -46
  70. package/dist/v2/providers/types.d.ts.map +1 -1
  71. package/dist/v2/types/human-in-the-loop.d.ts +8 -29
  72. package/dist/v2/types/human-in-the-loop.d.ts.map +1 -1
  73. package/dist/v2/types/interrupt.d.ts +1 -22
  74. package/dist/v2/types/interrupt.d.ts.map +1 -1
  75. package/dist/v2/types/vue-activity-message-renderer.d.ts +16 -15
  76. package/dist/v2/types/vue-activity-message-renderer.d.ts.map +1 -1
  77. package/dist/v2/types/vue-custom-message-renderer.d.ts +7 -16
  78. package/dist/v2/types/vue-custom-message-renderer.d.ts.map +1 -1
  79. package/dist/v2/types/vue-tool-call-renderer.d.ts +16 -35
  80. package/dist/v2/types/vue-tool-call-renderer.d.ts.map +1 -1
  81. package/package.json +10 -11
  82. package/src/__tests__/build-entries.test.ts +27 -0
  83. package/src/hooks/__tests__/zod-parameters.test.ts +520 -0
  84. package/src/hooks/use-copilot-action.ts +2 -1
  85. package/src/hooks/use-frontend-tool.ts +3 -6
  86. package/src/hooks/zod-parameters.ts +162 -0
  87. package/src/v2/components/A2UIMessageRenderer.ts +3 -3
  88. package/src/v2/components/LicenseWarningBanner.vue +31 -15
  89. package/src/v2/components/OpenGenerativeUIRenderer.ts +51 -373
  90. package/src/v2/components/__tests__/A2UICatalogContext.test.ts +1 -1
  91. package/src/v2/components/__tests__/LicenseWarningBanner.test.ts +20 -0
  92. package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.ts +55 -6
  93. package/src/v2/components/a2ui/A2UIBuiltInToolCallRenderer.ts +1 -1
  94. package/src/v2/components/a2ui/A2UICatalogContext.ts +10 -102
  95. package/src/v2/components/a2ui/A2UIRecoveryStates.ts +1 -1
  96. package/src/v2/components/a2ui.ts +1 -1
  97. package/src/v2/components/chat/CopilotChat.vue +19 -40
  98. package/src/v2/components/chat/CopilotChatAttachmentQueue.vue +14 -10
  99. package/src/v2/components/chat/CopilotChatAttachmentRenderer.vue +14 -6
  100. package/src/v2/components/chat/CopilotChatInput.vue +40 -30
  101. package/src/v2/components/chat/CopilotChatMessageView.vue +72 -140
  102. package/src/v2/components/chat/CopilotChatReasoningMessage.vue +31 -13
  103. package/src/v2/components/chat/CopilotChatToolCallGroup.vue +60 -37
  104. package/src/v2/components/chat/CopilotChatToolCallItem.vue +3 -3
  105. package/src/v2/components/chat/CopilotChatToolCallsView.vue +15 -13
  106. package/src/v2/components/chat/CopilotChatView.vue +5 -5
  107. package/src/v2/components/chat/CopilotChatWorkSummary.vue +44 -18
  108. package/src/v2/components/chat/__tests__/CopilotChat.labels.test.ts +19 -4
  109. package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.ts +26 -9
  110. package/src/v2/components/chat/__tests__/CopilotChatInput.test.ts +33 -1
  111. package/src/v2/components/chat/__tests__/CopilotChatMessageView.test.ts +247 -403
  112. package/src/v2/components/chat/__tests__/CopilotChatMessageView.toolCallDisplay.test.ts +1 -99
  113. package/src/v2/components/chat/copilotChatToolCallItemRender.ts +3 -19
  114. package/src/v2/components/chat/index.ts +0 -1
  115. package/src/v2/components/chat/tool-call-display-context.ts +2 -23
  116. package/src/v2/components/chat/tool-call-group-parts.ts +44 -85
  117. package/src/v2/components/chat/turn-work.ts +0 -9
  118. package/src/v2/components/chat/types.ts +4 -4
  119. package/src/v2/components/chat/use-chat-labels.ts +16 -0
  120. package/src/v2/components/icons/__tests__/icons.test.ts +72 -68
  121. package/src/v2/components/icons/index.ts +109 -27
  122. package/src/v2/hooks/__tests__/use-frontend-tool.e2e.test.ts +62 -1
  123. package/src/v2/hooks/__tests__/use-render-activity-message.test.ts +105 -0
  124. package/src/v2/hooks/__tests__/use-render-tool.test.ts +3 -6
  125. package/src/v2/hooks/__tests__/zod-regression.test.ts +5 -4
  126. package/src/v2/hooks/use-frontend-tool.ts +10 -10
  127. package/src/v2/hooks/use-render-activity-message.ts +27 -48
  128. package/src/v2/hooks/use-render-custom-messages.ts +14 -35
  129. package/src/v2/lib/processPartialHtml.ts +6 -21
  130. package/src/v2/lib/vue-core.ts +3 -5
  131. package/src/v2/providers/CopilotKitProvider.vue +53 -112
  132. package/src/v2/providers/__tests__/CopilotKitProvider.a2ui.test.ts +1 -1
  133. package/src/v2/providers/__tests__/CopilotKitProvider.headersAtSendTime.test.ts +3 -3
  134. package/src/v2/providers/__tests__/CopilotKitProvider.learning.test.ts +3 -1
  135. package/src/v2/providers/__tests__/CopilotKitProvider.test.ts +17 -0
  136. package/src/v2/providers/types.ts +3 -49
  137. package/src/v2/types/__tests__/defineToolCallRenderer.test.ts +28 -33
  138. package/src/v2/types/defineToolCallRenderer.ts +5 -4
  139. package/src/v2/types/human-in-the-loop.ts +8 -32
  140. package/src/v2/types/interrupt.ts +7 -31
  141. package/src/v2/types/vue-activity-message-renderer.ts +24 -15
  142. package/src/v2/types/vue-custom-message-renderer.ts +12 -16
  143. package/src/v2/types/vue-tool-call-renderer.ts +23 -38
  144. package/vite.config.ts +3 -4
  145. package/dist/v2/components/chat/BasicMarkdown.vue.d.ts +0 -9
  146. package/dist/v2/components/chat/BasicMarkdown.vue.d.ts.map +0 -1
  147. package/dist/v2/components/chat/tool-call-layout.d.ts +0 -115
  148. package/dist/v2/components/chat/tool-call-layout.d.ts.map +0 -1
  149. package/dist/v2/lib/transcription-client.d.ts +0 -19
  150. package/dist/v2/lib/transcription-client.d.ts.map +0 -1
  151. package/src/v2/components/chat/BasicMarkdown.vue +0 -160
  152. package/src/v2/components/chat/__tests__/BasicMarkdown.test.ts +0 -69
  153. package/src/v2/components/chat/tool-call-layout.ts +0 -304
  154. package/src/v2/lib/__tests__/processPartialHtml.test.ts +0 -84
  155. package/src/v2/lib/__tests__/transcription-client.test.ts +0 -67
  156. package/src/v2/lib/transcription-client.ts +0 -151
@@ -15,6 +15,27 @@ import {
15
15
  createRowKeyStore,
16
16
  resolveRowRenderKeysById,
17
17
  } from "@copilotkit/shared";
18
+ import {
19
+ ɵdeduplicateMessages,
20
+ ɵgetToolCallLayouts,
21
+ ɵgetToolCallRendererNames,
22
+ ɵgetTurnWork,
23
+ ɵgetWorkOpenState,
24
+ ɵisTurnWorkOpen,
25
+ ɵisTurnWorking,
26
+ ɵrecordWorkTime,
27
+ ɵresolveActivityRenderer,
28
+ ɵresolveCustomMessageRenderers,
29
+ ɵgetLatestTurnKey,
30
+ } from "@copilotkit/core";
31
+ import type {
32
+ CopilotChatToolCallDisplay,
33
+ ToolCallEntry,
34
+ ɵToolCallDisplayContextValue,
35
+ ɵToolCallLayout,
36
+ ɵTurnWork,
37
+ ɵWorkTime,
38
+ } from "@copilotkit/core";
18
39
  import type {
19
40
  InterruptRenderProps,
20
41
  VueCustomMessageRendererProps,
@@ -33,18 +54,6 @@ import {
33
54
  } from "./message-feedback";
34
55
  import type { MessageFeedbackScope } from "./message-feedback";
35
56
  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
57
  import type { CopilotChatWorkSummarySlotProps } from "./types";
49
58
 
50
59
  interface MessageMetaProps {
@@ -203,47 +212,22 @@ watch(
203
212
  { immediate: true },
204
213
  );
205
214
 
206
- function deduplicateMessages(messages: Message[]): Message[] {
207
- const byId = new Map<string, Message>();
208
- for (const message of messages) {
209
- const existing = byId.get(message.id);
210
- if (
211
- existing &&
212
- message.role === "assistant" &&
213
- existing.role === "assistant"
214
- ) {
215
- const content = message.content || existing.content;
216
- const toolCalls = message.toolCalls ?? existing.toolCalls;
217
- byId.set(message.id, {
218
- ...existing,
219
- ...message,
220
- content,
221
- toolCalls,
222
- } as AssistantMessage);
223
- } else {
224
- byId.set(message.id, message);
225
- }
226
- }
227
- return [...byId.values()];
228
- }
229
-
230
215
  const deduplicatedMessages = computed(() =>
231
- deduplicateMessages(props.messages),
216
+ ɵdeduplicateMessages(props.messages),
232
217
  );
233
218
 
234
219
  // Groups of calls can span messages (an agent often sends each call as its
235
220
  // own message), so they're laid out here for the whole list and handed to
236
221
  // each message's tool calls view through provide/inject.
237
- const toolCallLayouts = computed<ReadonlyMap<string, ToolCallLayout>>(() =>
222
+ const toolCallLayouts = computed<ReadonlyMap<string, ɵToolCallLayout>>(() =>
238
223
  props.toolCallDisplay === "separate"
239
224
  ? new Map()
240
- : getToolCallLayouts(
225
+ : ɵgetToolCallLayouts(
241
226
  deduplicatedMessages.value,
242
227
  props.messages,
243
- getToolCallRendererNames(
244
- copilotkit.value.renderToolCalls,
245
- forwardedSlotNames.value,
246
- ),
228
+ ɵgetToolCallRendererNames(copilotkit.value.renderToolCalls, {
229
+ slotNames: forwardedSlotNames.value,
230
+ }),
247
231
  ),
248
232
  );
249
233
  const learningFeedbackEnabled = useLearningFeedbackEnabled(copilotkit);
@@ -265,11 +249,11 @@ provide(
265
249
 
266
250
  const turnWork = computed(() =>
267
251
  props.toolCallDisplay === "turn"
268
- ? getTurnWork(deduplicatedMessages.value, toolCallLayouts.value)
252
+ ? ɵgetTurnWork(deduplicatedMessages.value, toolCallLayouts.value)
269
253
  : undefined,
270
254
  );
271
255
  const turnByFirstMessage = computed(() => {
272
- const byFirst = new Map<string, TurnWork>();
256
+ const byFirst = new Map<string, ɵTurnWork>();
273
257
  for (const turn of turnWork.value?.values() ?? []) {
274
258
  byFirst.set(turn.firstMessageId, turn);
275
259
  }
@@ -280,30 +264,23 @@ const lastRenderedMessage = computed(
280
264
  () => deduplicatedMessages.value[deduplicatedMessages.value.length - 1],
281
265
  );
282
266
  // 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;
267
+ const latestTurnKey = computed(() =>
268
+ ɵgetLatestTurnKey(deduplicatedMessages.value),
269
+ );
292
270
 
293
271
  // Work shows while the agent is on it and folds once the reply is done,
294
272
  // unless the user has opened or closed it themselves.
295
273
  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
- >();
274
+ const turnOpenState = computed(() => ({
275
+ toggledTurns: toggledTurns.value,
276
+ isRunning: props.isRunning,
277
+ latestTurnKey: latestTurnKey.value,
278
+ }));
279
+
280
+ // How long the agent worked, for "Worked for 9s". Only known for replies this
281
+ // client watched start from the user's message; a restored thread shows the
282
+ // tool count instead.
283
+ const workTimes = new Map<string, ɵWorkTime>();
307
284
  const workTimesVersion = ref(0);
308
285
  watch(
309
286
  [
@@ -314,42 +291,25 @@ watch(
314
291
  ],
315
292
  ([display, isRunning, turnKey, lastRole]) => {
316
293
  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
- }
294
+ ɵrecordWorkTime(workTimes, {
295
+ isRunning,
296
+ latestTurnKey: turnKey,
297
+ lastMessageRole: lastRole,
298
+ now: Date.now(),
299
+ });
330
300
  workTimesVersion.value++;
331
301
  },
332
302
  { immediate: true },
333
303
  );
334
304
 
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
- });
305
+ // Whether each working-phase message's work, and its text, shows.
306
+ const workOpenState = computed(() =>
307
+ ɵgetWorkOpenState(turnWork.value?.values() ?? [], turnOpenState.value),
308
+ );
349
309
 
350
310
  provide(
351
311
  ToolCallDisplayContextKey,
352
- computed<ToolCallDisplayContextValue>(() => ({
312
+ computed<ɵToolCallDisplayContextValue>(() => ({
353
313
  display: props.toolCallDisplay,
354
314
  isRunning: props.isRunning,
355
315
  layouts: toolCallLayouts.value,
@@ -364,8 +324,8 @@ const WorkSummaryRow: FunctionalComponent<{
364
324
  calls: ToolCallEntry[];
365
325
  }> = ({ turnKey, calls }) => {
366
326
  void workTimesVersion.value;
367
- const isWorking = isWorkingOn(turnKey);
368
- const isOpen = isWorkOpen(turnKey);
327
+ const isWorking = ɵisTurnWorking(turnKey, turnOpenState.value);
328
+ const isOpen = ɵisTurnWorkOpen(turnKey, turnOpenState.value);
369
329
  const times = workTimes.get(turnKey);
370
330
  const summaryProps: CopilotChatWorkSummarySlotProps = {
371
331
  isWorking,
@@ -534,21 +494,12 @@ function resolveCustomMessageRenderer(
534
494
  return null;
535
495
  }
536
496
 
537
- const agentId = resolvedAgentId.value;
538
- const renderers = [...copilotkit.value.renderCustomMessages]
539
- .filter(
540
- (renderer) =>
541
- renderer.agentId === undefined || renderer.agentId === agentId,
542
- )
543
- .sort((a, b) => {
544
- const aHasAgent = a.agentId !== undefined;
545
- const bHasAgent = b.agentId !== undefined;
546
- if (aHasAgent === bHasAgent) return 0;
547
- return aHasAgent ? -1 : 1;
548
- });
549
-
550
- const selected = renderers[0];
551
- if (!selected?.render) {
497
+ // Try each renderer in order and use the first that has something to draw.
498
+ const selected = ɵresolveCustomMessageRenderers(
499
+ copilotkit.value.renderCustomMessages,
500
+ resolvedAgentId.value,
501
+ ).find((renderer) => renderer.render);
502
+ if (!selected) {
552
503
  return null;
553
504
  }
554
505
 
@@ -563,45 +514,26 @@ function resolveActivityRenderer(
563
514
  ): { renderer: Component; props: ActivitySlotProps } | null {
564
515
  stateTick.value += 0;
565
516
 
566
- const agentId = resolvedAgentId.value;
567
- const renderer = [...copilotkit.value.renderActivityMessages]
568
- .filter(
569
- (entry) =>
570
- entry.activityType === message.activityType &&
571
- (entry.agentId === undefined || entry.agentId === agentId),
572
- )
573
- .sort((a, b) => {
574
- const aScoped = a.agentId !== undefined;
575
- const bScoped = b.agentId !== undefined;
576
- if (aScoped === bScoped) return 0;
577
- return aScoped ? -1 : 1;
578
- })[0];
579
-
580
- if (!renderer) return null;
581
- const parsed = renderer.content.safeParse(message.content);
582
- if (!parsed.success) return null;
517
+ const match = ɵresolveActivityRenderer(
518
+ copilotkit.value.renderActivityMessages,
519
+ {
520
+ activityType: message.activityType,
521
+ agentId: resolvedAgentId.value,
522
+ content: message.content,
523
+ },
524
+ );
525
+ if (!match) return null;
583
526
 
584
527
  return {
585
- renderer: renderer.render as Component,
528
+ renderer: match.renderer.render as Component,
586
529
  props: {
587
530
  activityType: message.activityType,
588
- content: parsed.data,
531
+ content: match.content,
589
532
  message,
590
533
  agent: resolvedThreadAgent.value,
591
534
  },
592
535
  };
593
536
  }
594
-
595
- function resolveToolMessage(
596
- message: Message,
597
- toolCallId: string,
598
- ): ToolMessage | undefined {
599
- return props.messages.find(
600
- (candidate) =>
601
- candidate.role === "tool" &&
602
- (candidate as ToolMessage).toolCallId === toolCallId,
603
- ) as ToolMessage | undefined;
604
- }
605
537
  </script>
606
538
 
607
539
  <template>
@@ -3,8 +3,9 @@ import { computed, onBeforeUnmount, ref, watch } from "vue";
3
3
  import type { Message, ReasoningMessage } from "@ag-ui/core";
4
4
  import { IconChevronRight } from "../icons";
5
5
  import StreamingMarkdownDefault from "./StreamingMarkdownDefault.vue";
6
- import { useCopilotChatConfiguration } from "../../providers/useCopilotChatConfiguration";
7
- import { CopilotChatDefaultLabels } from "../../providers/types";
6
+ import { ɵformatLabel, ɵformatReasoningDuration } from "@copilotkit/core";
7
+ import type { CopilotChatLabels } from "@copilotkit/core";
8
+ import { useChatLabels } from "./use-chat-labels";
8
9
 
9
10
  const props = withDefaults(
10
11
  defineProps<{
@@ -69,13 +70,29 @@ defineSlots<{
69
70
  }) => unknown;
70
71
  }>();
71
72
 
72
- function formatDuration(seconds: number): string {
73
- if (seconds < 1) return "a few seconds";
74
- if (seconds < 60) return `${Math.round(seconds)} seconds`;
75
- const mins = Math.floor(seconds / 60);
76
- const secs = Math.round(seconds % 60);
77
- if (secs === 0) return `${mins} minute${mins > 1 ? "s" : ""}`;
78
- return `${mins}m ${secs}s`;
73
+ /** How long the model reasoned, in the chat's labels: "4 seconds", "1m 5s". */
74
+ function formatDuration(labels: Readonly<CopilotChatLabels>, seconds: number) {
75
+ const duration = ɵformatReasoningDuration(seconds);
76
+ switch (duration.unit) {
77
+ case "fewSeconds":
78
+ return labels.reasoningMessageDurationFewSeconds;
79
+ case "seconds":
80
+ return ɵformatLabel(labels.reasoningMessageDurationSeconds, {
81
+ count: duration.seconds,
82
+ });
83
+ case "minutes":
84
+ return ɵformatLabel(
85
+ duration.minutes === 1
86
+ ? labels.reasoningMessageDurationMinutesOne
87
+ : labels.reasoningMessageDurationMinutesOther,
88
+ { count: duration.minutes },
89
+ );
90
+ case "minutesSeconds":
91
+ return ɵformatLabel(labels.reasoningMessageDurationMinutesSeconds, {
92
+ minutes: duration.minutes,
93
+ seconds: duration.seconds,
94
+ });
95
+ }
79
96
  }
80
97
 
81
98
  const normalizedContent = computed(() =>
@@ -133,13 +150,14 @@ onBeforeUnmount(() => {
133
150
  clearElapsedInterval();
134
151
  });
135
152
 
136
- const config = useCopilotChatConfiguration();
153
+ const labels = useChatLabels();
137
154
  /** `labels.reasoningMessageThinkingLabel` while streaming, then "Thought for …". */
138
155
  const label = computed(() =>
139
156
  isStreaming.value
140
- ? (config.value?.labels ?? CopilotChatDefaultLabels)
141
- .reasoningMessageThinkingLabel
142
- : `Thought for ${formatDuration(elapsed.value)}`,
157
+ ? labels.value.reasoningMessageThinkingLabel
158
+ : ɵformatLabel(labels.value.reasoningMessageThoughtForLabel, {
159
+ duration: formatDuration(labels.value, elapsed.value),
160
+ }),
143
161
  );
144
162
 
145
163
  function toggleOpen() {
@@ -10,8 +10,15 @@
10
10
  * a custom wildcard renderer draws whatever it draws.
11
11
  */
12
12
  import { computed, provide, ref } from "vue";
13
+ import {
14
+ ɵformatLabel,
15
+ ɵformatToolNames,
16
+ ɵgetToolCallPreview,
17
+ ɵgetToolCallRowStatus,
18
+ ɵformatCountLabel,
19
+ } from "@copilotkit/core";
20
+ import type { ToolCallEntry, ɵToolCallRowStatus } from "@copilotkit/core";
13
21
  import { useCopilotId } from "../ui/use-id";
14
- import type { ToolCallEntry } from "./tool-call-layout";
15
22
  import { ToolCallGroupContextKey } from "./tool-call-display-context";
16
23
  import type { ToolCallGroupContextValue } from "./tool-call-display-context";
17
24
  import {
@@ -19,13 +26,9 @@ import {
19
26
  ToolCallChevron,
20
27
  ToolCallFailedCount,
21
28
  ToolCallStatusIcon,
22
- entryPreview,
23
- entryStatus,
24
- pluralize,
25
- statusLabels,
26
- toolNames,
29
+ toolCallStatusLabel,
27
30
  } from "./tool-call-group-parts";
28
- import type { ToolCallStatusName } from "./tool-call-group-parts";
31
+ import { useChatLabels } from "./use-chat-labels";
29
32
  import type { CopilotChatToolCallGroupAppearance } from "./types";
30
33
 
31
34
  const props = withDefaults(
@@ -49,6 +52,7 @@ defineSlots<{
49
52
  call(props: { call: ToolCallEntry }): unknown;
50
53
  }>();
51
54
 
55
+ const labels = useChatLabels();
52
56
  const open = ref(false);
53
57
  const bodyId = useCopilotId("cpk-tool-call-group");
54
58
  const toggle = () => {
@@ -64,13 +68,13 @@ const current = computed(() =>
64
68
  : undefined,
65
69
  );
66
70
  const preview = computed(() =>
67
- current.value ? entryPreview(current.value) : undefined,
71
+ current.value ? ɵgetToolCallPreview(current.value) : undefined,
68
72
  );
69
73
  const done = computed(
70
74
  () => props.calls.filter((call) => call.toolMessage).length,
71
75
  );
72
76
  const statuses = computed(() =>
73
- props.calls.map((call) => entryStatus(call, props.isActive)),
77
+ props.calls.map((call) => ɵgetToolCallRowStatus(call, props.isActive)),
74
78
  );
75
79
  const failedIds = computed(
76
80
  () =>
@@ -80,7 +84,7 @@ const failedIds = computed(
80
84
  .map((call) => call.toolCall.id),
81
85
  ),
82
86
  );
83
- const status = computed<ToolCallStatusName>(() =>
87
+ const status = computed<ɵToolCallRowStatus>(() =>
84
88
  current.value
85
89
  ? "running"
86
90
  : failedIds.value.size > 0
@@ -108,10 +112,27 @@ const behind = computed(() =>
108
112
  open.value ? 0 : Math.min(props.calls.length - 1, 2),
109
113
  );
110
114
  const latestStatus = computed(() =>
111
- latest.value ? entryStatus(latest.value, props.isActive) : "done",
115
+ latest.value ? ɵgetToolCallRowStatus(latest.value, props.isActive) : "done",
112
116
  );
113
117
  const latestPreview = computed(() =>
114
- latest.value ? entryPreview(latest.value) : undefined,
118
+ latest.value ? ɵgetToolCallPreview(latest.value) : undefined,
119
+ );
120
+ const runningLabel = computed(() =>
121
+ current.value
122
+ ? ɵformatLabel(labels.value.toolCallRunningLabel, {
123
+ name: current.value.toolCall.function.name,
124
+ })
125
+ : "",
126
+ );
127
+ const usedToolsLabel = computed(() =>
128
+ ɵformatCountLabel(props.calls.length, {
129
+ one: labels.value.toolCallUsedToolsOne,
130
+ other: labels.value.toolCallUsedToolsOther,
131
+ }),
132
+ );
133
+ const toolNames = computed(() => ɵformatToolNames(props.calls));
134
+ const latestStatusLabel = computed(() =>
135
+ toolCallStatusLabel(labels.value, latestStatus.value),
115
136
  );
116
137
  const layer = "cpk-tool-call-group-stack-layer";
117
138
  </script>
@@ -144,20 +165,18 @@ const layer = "cpk-tool-call-group-stack-layer";
144
165
  @click="toggle"
145
166
  >
146
167
  <template v-if="current">
147
- <span class="cpk-tool-call-group-running cpk-shimmer"
148
- >Running {{ current.toolCall.function.name }}</span
149
- >
168
+ <span class="cpk-tool-call-group-running cpk-shimmer">{{
169
+ runningLabel
170
+ }}</span>
150
171
  <span v-if="preview" class="cpk-tool-call-group-preview">{{
151
172
  preview
152
173
  }}</span>
153
174
  </template>
154
175
  <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)
176
+ <span class="cpk-tool-call-group-line-summary">{{
177
+ usedToolsLabel
160
178
  }}</span>
179
+ <span class="cpk-tool-call-group-line-names">{{ toolNames }}</span>
161
180
  <ToolCallFailedCount :calls="calls" />
162
181
  </template>
163
182
  <ToolCallChevron :open="open" />
@@ -206,10 +225,15 @@ const layer = "cpk-tool-call-group-stack-layer";
206
225
  @click="toggle"
207
226
  >
208
227
  <template v-if="open">
209
- {{ pluralize(calls.length, "tool call") }}
228
+ {{
229
+ ɵformatCountLabel(calls.length, {
230
+ one: labels.toolCallToolCallCountOne,
231
+ other: labels.toolCallToolCallCountOther,
232
+ })
233
+ }}
210
234
  <ToolCallFailedCount :calls="calls" />
211
235
  <span class="cpk-tool-call-group-stack-collapse">
212
- Collapse
236
+ {{ labels.toolCallCollapseLabel }}
213
237
  <ToolCallChevron
214
238
  :open="true"
215
239
  class="cpk-tool-call-group-stack-collapse-icon"
@@ -236,13 +260,16 @@ const layer = "cpk-tool-call-group-stack-layer";
236
260
  >
237
261
  <!-- The status icon is decorative, so say the status. -->
238
262
  <span class="cpk-tool-call-group-stack-status">{{
239
- statusLabels[latestStatus]
263
+ latestStatusLabel
240
264
  }}</span>
241
265
  </span>
242
266
  <span class="cpk-tool-call-group-stack-meta">
243
267
  <ToolCallFailedCount :calls="calls" />
244
268
  <span class="cpk-tool-call-group-stack-count">{{
245
- pluralize(calls.length, "call")
269
+ ɵformatCountLabel(calls.length, {
270
+ one: labels.toolCallCallCountOne,
271
+ other: labels.toolCallCallCountOther,
272
+ })
246
273
  }}</span>
247
274
  <ToolCallChevron
248
275
  :open="false"
@@ -255,9 +282,7 @@ const layer = "cpk-tool-call-group-stack-layer";
255
282
  call change ("read_file: Running", then "read_file: Done"); the
256
283
  button only names it. -->
257
284
  <span aria-live="polite" class="cpk-tool-call-group-stack-live">{{
258
- open
259
- ? ""
260
- : `${latest.toolCall.function.name}: ${statusLabels[latestStatus]}`
285
+ open ? "" : `${latest.toolCall.function.name}: ${latestStatusLabel}`
261
286
  }}</span>
262
287
  </div>
263
288
  <!-- Each call gets the collapsed stack's card, easing out of the stack. -->
@@ -292,28 +317,26 @@ const layer = "cpk-tool-call-group-stack-layer";
292
317
  >
293
318
  <ToolCallStatusIcon :status="status" />
294
319
  <template v-if="current">
295
- <span class="cpk-tool-call-group-running cpk-shimmer"
296
- >Running {{ current.toolCall.function.name }}</span
297
- >
320
+ <span class="cpk-tool-call-group-running cpk-shimmer">{{
321
+ runningLabel
322
+ }}</span>
298
323
  <span v-if="preview" class="cpk-tool-call-group-preview">{{
299
324
  preview
300
325
  }}</span>
301
326
  </template>
302
327
  <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)
328
+ <span class="cpk-tool-call-group-card-summary">{{
329
+ usedToolsLabel
308
330
  }}</span>
331
+ <span class="cpk-tool-call-group-card-names">{{ toolNames }}</span>
309
332
  </template>
310
333
  <span class="cpk-tool-call-group-card-meta">
311
334
  <ToolCallFailedCount v-if="status === 'failed'" :calls="calls" />
312
335
  <span v-else class="cpk-tool-call-group-card-status">{{
313
336
  status !== "running"
314
- ? statusLabels[status]
337
+ ? toolCallStatusLabel(labels, status)
315
338
  : done > 0
316
- ? `${done} done`
339
+ ? ɵformatLabel(labels.toolCallDoneCountLabel, { count: done })
317
340
  : ""
318
341
  }}</span>
319
342
  <ToolCallChevron :open="open" />
@@ -1,11 +1,11 @@
1
1
  <script setup lang="ts">
2
2
  import type { Message, ToolCall } from "@ag-ui/core";
3
3
  import { DEFAULT_AGENT_ID } from "@copilotkit/shared";
4
+ import { ɵresolveToolCallRenderer } from "@copilotkit/core";
4
5
  import { useCopilotKit } from "../../providers/useCopilotKit";
5
6
  import { useCopilotChatConfiguration } from "../../providers/useCopilotChatConfiguration";
6
7
  import type { CopilotChatToolCallRenderSlotProps } from "./types";
7
8
  import {
8
- getCoreRenderConfig,
9
9
  getCoreRenderProps,
10
10
  getToolCallMemoDeps,
11
11
  getToolCallRenderProps,
@@ -55,9 +55,9 @@ function getCoreProps() {
55
55
 
56
56
  function getRenderConfig() {
57
57
  const agentId = config.value?.agentId ?? DEFAULT_AGENT_ID;
58
- return getCoreRenderConfig(
59
- props.toolCall,
58
+ return ɵresolveToolCallRenderer(
60
59
  copilotkit.value.renderToolCalls,
60
+ props.toolCall.function.name,
61
61
  agentId,
62
62
  );
63
63
  }
@@ -3,6 +3,14 @@ import { computed, defineComponent, h, inject, provide, useSlots } from "vue";
3
3
  import type { PropType } from "vue";
4
4
  import type { Slots, VNode } from "vue";
5
5
  import type { AssistantMessage, Message } from "@ag-ui/core";
6
+ import {
7
+ ɵgetToolCallLayouts,
8
+ ɵgetToolCallRendererNames,
9
+ } from "@copilotkit/core";
10
+ import type {
11
+ CopilotChatToolCallDisplay,
12
+ ToolCallEntry,
13
+ } from "@copilotkit/core";
6
14
  import { useCopilotKit } from "../../providers/useCopilotKit";
7
15
  import type {
8
16
  CopilotChatToolCallGroupAppearance,
@@ -17,14 +25,6 @@ import {
17
25
  ToolCallGroupContextKey,
18
26
  } from "./tool-call-display-context";
19
27
  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";
28
28
 
29
29
  const props = withDefaults(
30
30
  defineProps<{
@@ -84,13 +84,15 @@ const layout = computed(() => {
84
84
  if (display.value === "separate") return undefined;
85
85
  const viewLayout = context?.value.layouts.get(props.message.id);
86
86
  if (viewLayout) return viewLayout;
87
- const rendererNames = getToolCallRendererNames(
87
+ const rendererNames = ɵgetToolCallRendererNames(
88
88
  copilotkit.value.renderToolCalls,
89
- getToolCallSlotNames(),
90
- );
91
- return getToolCallLayouts([props.message], props.messages, rendererNames).get(
92
- props.message.id,
89
+ { slotNames: getToolCallSlotNames() },
93
90
  );
91
+ return ɵgetToolCallLayouts(
92
+ [props.message],
93
+ props.messages,
94
+ rendererNames,
95
+ ).get(props.message.id);
94
96
  });
95
97
 
96
98
  // Whether the agent may still finish a trailing group's calls. Without a