@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
@@ -11,8 +11,7 @@ import {
11
11
  import type { Message } from "@ag-ui/core";
12
12
  import type { Suggestion } from "@copilotkit/core";
13
13
  import type { Attachment } from "@copilotkit/shared";
14
- import { useCopilotChatConfiguration } from "../../providers/useCopilotChatConfiguration";
15
- import { CopilotChatDefaultLabels } from "../../providers/types";
14
+ import { useChatLabels } from "./use-chat-labels";
16
15
  import { useKeyboardHeight } from "../../hooks/use-keyboard-height";
17
16
  import { usePinToSend } from "../../hooks/use-pin-to-send";
18
17
  import { IconChevronDown, IconUpload } from "../icons";
@@ -127,8 +126,7 @@ const emit = defineEmits<{
127
126
  "finish-transcribe": [];
128
127
  }>();
129
128
 
130
- const config = useCopilotChatConfiguration();
131
- const labels = computed(() => config.value?.labels ?? CopilotChatDefaultLabels);
129
+ const labels = useChatLabels();
132
130
  const componentSlots = useSlots();
133
131
 
134
132
  const scrollContainerRef = ref<HTMLElement | null>(null);
@@ -457,7 +455,9 @@ onBeforeUnmount(() => {
457
455
  >
458
456
  <div class="cpk-chat-view-drop-overlay-content">
459
457
  <IconUpload class="cpk-chat-view-drop-overlay-icon" />
460
- <span class="cpk-chat-view-drop-overlay-label">Drop files here</span>
458
+ <span class="cpk-chat-view-drop-overlay-label">{{
459
+ labels.chatDropFilesLabel
460
+ }}</span>
461
461
  </div>
462
462
  </div>
463
463
  <slot
@@ -5,10 +5,15 @@
5
5
  * for 9s · 7 tools" and toggles the work it folded away.
6
6
  */
7
7
  import { computed, ref, watch } from "vue";
8
+ import {
9
+ ɵcountFailedToolCalls,
10
+ ɵformatLabel,
11
+ ɵformatWorkDuration,
12
+ ɵformatCountLabel,
13
+ } from "@copilotkit/core";
8
14
  import { IconChevronRight } from "../icons";
9
15
  import type { CopilotChatWorkSummarySlotProps } from "./types";
10
- import { pluralize } from "./tool-call-group-parts";
11
- import { formatDuration } from "./turn-work";
16
+ import { useChatLabels } from "./use-chat-labels";
12
17
 
13
18
  // `onClick` falls through to the button.
14
19
  const props = defineProps<Omit<CopilotChatWorkSummarySlotProps, "onClick">>();
@@ -28,9 +33,8 @@ watch(
28
33
  { immediate: true },
29
34
  );
30
35
 
31
- const failed = computed(
32
- () => props.calls.filter((call) => call.toolMessage?.error).length,
33
- );
36
+ const labels = useChatLabels();
37
+ const failed = computed(() => ɵcountFailedToolCalls(props.calls));
34
38
  const liveMs = computed(() =>
35
39
  props.elapsedMs !== undefined && props.workingSince !== undefined
36
40
  ? props.elapsedMs + Math.max(0, now.value - props.workingSince)
@@ -39,9 +43,33 @@ const liveMs = computed(() =>
39
43
  // A finished reply worked for at least a second.
40
44
  const duration = computed(() =>
41
45
  props.elapsedMs !== undefined
42
- ? formatDuration(Math.max(1000, props.elapsedMs))
46
+ ? ɵformatWorkDuration(Math.max(1000, props.elapsedMs))
43
47
  : undefined,
44
48
  );
49
+ const toolCount = computed(() =>
50
+ ɵformatCountLabel(props.calls.length, {
51
+ one: labels.value.toolCallToolCountOne,
52
+ other: labels.value.toolCallToolCountOther,
53
+ }),
54
+ );
55
+ const doneLabel = computed(() =>
56
+ duration.value
57
+ ? ɵformatLabel(labels.value.workSummaryWorkedForLabel, {
58
+ duration: duration.value,
59
+ })
60
+ : ɵformatCountLabel(props.calls.length, {
61
+ one: labels.value.toolCallUsedToolsOne,
62
+ other: labels.value.toolCallUsedToolsOther,
63
+ }),
64
+ );
65
+ const liveDuration = computed(() =>
66
+ liveMs.value !== undefined ? ɵformatWorkDuration(liveMs.value) : undefined,
67
+ );
68
+ const failedLabel = computed(() =>
69
+ ɵformatLabel(labels.value.toolCallFailedCountLabel, {
70
+ count: failed.value,
71
+ }),
72
+ );
45
73
  </script>
46
74
 
47
75
  <template>
@@ -54,25 +82,23 @@ const duration = computed(() =>
54
82
  class="cpk-work-summary"
55
83
  >
56
84
  <template v-if="isWorking">
57
- <span class="cpk-work-summary-label cpk-shimmer">Working</span>
85
+ <span class="cpk-work-summary-label cpk-shimmer">{{
86
+ labels.workSummaryWorkingLabel
87
+ }}</span>
58
88
  <span
59
- v-if="liveMs !== undefined"
89
+ v-if="liveDuration !== undefined"
60
90
  class="cpk-work-summary-detail cpk-work-summary-timer"
61
- >{{ formatDuration(liveMs) }}</span
91
+ >{{ liveDuration }}</span
62
92
  >
63
93
  </template>
64
94
  <template v-else>
65
- <span class="cpk-work-summary-label">{{
66
- duration
67
- ? `Worked for ${duration}`
68
- : `Used ${pluralize(calls.length, "tool")}`
69
- }}</span>
95
+ <span class="cpk-work-summary-label">{{ doneLabel }}</span>
70
96
  <span v-if="duration" class="cpk-work-summary-detail">{{
71
- pluralize(calls.length, "tool")
97
+ toolCount
98
+ }}</span>
99
+ <span v-if="failed > 0" class="cpk-work-summary-failed">{{
100
+ failedLabel
72
101
  }}</span>
73
- <span v-if="failed > 0" class="cpk-work-summary-failed"
74
- >{{ failed }} failed</span
75
- >
76
102
  </template>
77
103
  <IconChevronRight
78
104
  aria-hidden="true"
@@ -1,7 +1,7 @@
1
1
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
2
  import { defineComponent, nextTick, onMounted } from "vue";
3
3
  import { fireEvent, render, screen } from "@testing-library/vue";
4
- import type { Message, ReasoningMessage } from "@ag-ui/core";
4
+ import type { ReasoningMessage } from "@ag-ui/core";
5
5
  import type { Attachment } from "@copilotkit/shared";
6
6
  import CopilotKitProvider from "../../../providers/CopilotKitProvider.vue";
7
7
  import CopilotChatConfigurationProvider from "../../../providers/CopilotChatConfigurationProvider.vue";
@@ -16,6 +16,8 @@ import { CopilotModalHeader, CopilotSidebarView } from "../index";
16
16
  // hard-coded English.
17
17
  const germanLabels: Partial<Record<keyof CopilotChatLabels, string>> = {
18
18
  reasoningMessageThinkingLabel: "Denkt nach…",
19
+ reasoningMessageThoughtForLabel: "Gedacht für {duration}",
20
+ reasoningMessageDurationFewSeconds: "ein paar Sekunden",
19
21
  chatInputSlashMenuLabel: "Befehle",
20
22
  chatInputSlashMenuEmptyText: "Keine Befehle gefunden",
21
23
  attachmentRemoveButtonLabel: "Anhang entfernen",
@@ -26,11 +28,11 @@ const germanLabels: Partial<Record<keyof CopilotChatLabels, string>> = {
26
28
  sidebarLabel: "Chat-Seitenleiste",
27
29
  };
28
30
 
29
- const reasoning = {
31
+ const reasoning: ReasoningMessage = {
30
32
  id: "reasoning-1",
31
33
  role: "reasoning",
32
34
  content: "",
33
- } as ReasoningMessage;
35
+ };
34
36
 
35
37
  const video: Attachment = {
36
38
  id: "clip",
@@ -66,7 +68,7 @@ function renderWithLabels(template: string) {
66
68
  return {
67
69
  labels: germanLabels,
68
70
  reasoning,
69
- reasoningMessages: [reasoning] as Message[],
71
+ reasoningMessages: [reasoning],
70
72
  attachments: [video],
71
73
  toolsMenu: [{ label: "Say hi", action: vi.fn() }],
72
74
  };
@@ -112,6 +114,19 @@ describe("chat strings from labels", () => {
112
114
  expect(screen.queryByText("Thinking…")).toBeNull();
113
115
  });
114
116
 
117
+ it("uses the configured duration labels once the model is done", () => {
118
+ renderWithLabels(`
119
+ <CopilotChatReasoningMessage
120
+ :message="reasoning"
121
+ :messages="reasoningMessages"
122
+ :is-running="false"
123
+ />
124
+ `);
125
+
126
+ expect(screen.getByText("Gedacht für ein paar Sekunden")).toBeDefined();
127
+ expect(screen.queryByText(/Thought for/)).toBeNull();
128
+ });
129
+
115
130
  it("passes the elapsed reasoning time to a custom header", async () => {
116
131
  vi.useFakeTimers();
117
132
  renderWithLabels(`
@@ -7,6 +7,7 @@ import {
7
7
  } from "@testing-library/vue";
8
8
  import { defineComponent, ref, toRaw } from "vue";
9
9
  import { afterEach, describe, expect, it, vi } from "vitest";
10
+ import type * as CoreModule from "@copilotkit/core";
10
11
  import type { AbstractAgent } from "@ag-ui/client";
11
12
  import { EventType } from "@ag-ui/client";
12
13
  import type { A2UITheme as Theme } from "../../../types";
@@ -160,11 +161,25 @@ vi.mock("phoenix", () => ({
160
161
  Socket: MockPhoenixSocket,
161
162
  }));
162
163
 
163
- vi.mock("@jetbrains/websandbox", () => ({
164
- default: {
165
- create: (...args: unknown[]) => mockWebsandboxCreate(...args),
166
- },
167
- }));
164
+ // Run the real core controller against a fake websandbox
165
+ vi.mock("@copilotkit/core", async (importOriginal) => {
166
+ const actual = await importOriginal<typeof CoreModule>();
167
+ class TestOpenGenerativeUIController
168
+ extends actual.ɵOpenGenerativeUIController
169
+ {
170
+ constructor() {
171
+ super({
172
+ loadWebsandbox: async () => ({
173
+ create: (...args) => mockWebsandboxCreate(...args),
174
+ }),
175
+ });
176
+ }
177
+ }
178
+ return {
179
+ ...actual,
180
+ ɵOpenGenerativeUIController: TestOpenGenerativeUIController,
181
+ };
182
+ });
168
183
 
169
184
  function jsonResponse(body: unknown, status = 200): Response {
170
185
  return {
@@ -667,13 +682,15 @@ describe("CopilotChat activity message rendering", () => {
667
682
 
668
683
  renderOpenGenerativeUIChat();
669
684
 
685
+ // The restored chat can remount the activity while it reconnects, so wait
686
+ // until exactly one sandbox, the restored one, is alive.
670
687
  await waitFor(() => {
671
- expect(mockWebsandboxCreate).toHaveBeenCalledTimes(2);
688
+ const created = mockWebsandboxCreate.mock.calls.length;
689
+ expect(created).toBeGreaterThanOrEqual(2);
690
+ expect(mockWebsandboxDestroy).toHaveBeenCalledTimes(created - 1);
672
691
  });
673
- expect(mockWebsandboxCreate.mock.calls[1]?.[1]).toMatchObject({
692
+ expect(mockWebsandboxCreate.mock.calls.at(-1)?.[1]).toMatchObject({
674
693
  frameContent: restoredHtml,
675
694
  });
676
-
677
- expect(mockWebsandboxDestroy).toHaveBeenCalledTimes(1);
678
695
  });
679
696
  });
@@ -559,6 +559,38 @@ describe("CopilotChatInput", () => {
559
559
  expect(screen.getByRole("button", { name: "Stop" })).toBe(getSendButton());
560
560
  });
561
561
 
562
+ describe("Enter while the agent runs", () => {
563
+ async function pressEnterWhileRunning(modelValue: string) {
564
+ const onStop = vi.fn();
565
+ renderWithProvider({
566
+ props: { modelValue, isRunning: true },
567
+ listeners: { onSubmitMessage: mockOnSubmitMessage, onStop },
568
+ });
569
+ await fireEvent.keyDown(
570
+ screen.getByPlaceholderText("Type a message..."),
571
+ {
572
+ key: "Enter",
573
+ shiftKey: false,
574
+ },
575
+ );
576
+ return onStop;
577
+ }
578
+
579
+ it("sends the typed text and does not stop the run", async () => {
580
+ const onStop = await pressEnterWhileRunning(" next question ");
581
+
582
+ expect(mockOnSubmitMessage).toHaveBeenCalledWith("next question");
583
+ expect(onStop).not.toHaveBeenCalled();
584
+ });
585
+
586
+ it("stops the run when the input is empty", async () => {
587
+ const onStop = await pressEnterWhileRunning("");
588
+
589
+ expect(onStop).toHaveBeenCalledOnce();
590
+ expect(mockOnSubmitMessage).not.toHaveBeenCalled();
591
+ });
592
+ });
593
+
562
594
  it("names the send button with the configured labels", () => {
563
595
  renderWithProvider({
564
596
  template: `
@@ -799,7 +831,7 @@ describe("CopilotChatInput", () => {
799
831
 
800
832
  await fireEvent.click(addButton);
801
833
  const menuItem = await screen.findByRole("menuitem", {
802
- name: "Add photos or files",
834
+ name: "Add attachments",
803
835
  });
804
836
  await fireEvent.click(menuItem);
805
837
  expect(handleAddFile).toHaveBeenCalledTimes(1);