@copilotkit/vue 1.72.1-canary.sp-longthread-perf → 1.73.0
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.
- package/PARITY.md +15 -1
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +2 -2
- package/dist/use-render-activity-message-C45MYgwB.cjs +85 -0
- package/dist/use-render-activity-message-C45MYgwB.cjs.map +1 -0
- package/dist/use-render-activity-message-DI4kGqHF.js +9758 -0
- package/dist/use-render-activity-message-DI4kGqHF.js.map +1 -0
- package/dist/v2/components/LicenseWarningBanner.vue.d.ts +3 -5
- package/dist/v2/components/LicenseWarningBanner.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChat.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts +4 -0
- package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatInput.vue.d.ts +7 -0
- package/dist/v2/components/chat/CopilotChatInput.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatUserMessage.vue.d.ts +2 -0
- package/dist/v2/components/chat/CopilotChatUserMessage.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatView.vue.d.ts +8 -2
- package/dist/v2/components/chat/CopilotChatView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotPopup.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotPopupView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotPopupWelcomeScreen.vue.d.ts +7 -4
- package/dist/v2/components/chat/CopilotPopupWelcomeScreen.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotSidebar.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotSidebarWelcomeScreen.vue.d.ts +8 -5
- package/dist/v2/components/chat/CopilotSidebarWelcomeScreen.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/index.d.ts +50 -26
- package/dist/v2/components/chat/index.d.ts.map +1 -1
- package/dist/v2/components/chat/types.d.ts +44 -17
- package/dist/v2/components/chat/types.d.ts.map +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.mjs +1 -1
- package/package.json +6 -6
- package/src/v2/components/LicenseWarningBanner.vue +5 -17
- package/src/v2/components/__tests__/LicenseWarningBanner.test.ts +23 -0
- package/src/v2/components/chat/CopilotChat.vue +21 -14
- package/src/v2/components/chat/CopilotChatAssistantMessage.vue +12 -21
- package/src/v2/components/chat/CopilotChatInput.vue +32 -26
- package/src/v2/components/chat/CopilotChatUserMessage.vue +19 -19
- package/src/v2/components/chat/CopilotChatView.vue +31 -39
- package/src/v2/components/chat/CopilotPopup.vue +8 -10
- package/src/v2/components/chat/CopilotPopupView.vue +8 -18
- package/src/v2/components/chat/CopilotPopupViewInternal.vue +5 -19
- package/src/v2/components/chat/CopilotPopupWelcomeScreen.vue +36 -6
- package/src/v2/components/chat/CopilotSidebar.vue +8 -10
- package/src/v2/components/chat/CopilotSidebarView.vue +8 -18
- package/src/v2/components/chat/CopilotSidebarViewInternal.vue +5 -19
- package/src/v2/components/chat/CopilotSidebarWelcomeScreen.vue +36 -6
- package/src/v2/components/chat/__tests__/CopilotChat.e2e.test.ts +156 -5
- package/src/v2/components/chat/__tests__/CopilotChatInput.test.ts +34 -0
- package/src/v2/components/chat/__tests__/CopilotChatUserMessage.test.ts +46 -0
- package/src/v2/components/chat/__tests__/CopilotChatView.test.ts +118 -0
- package/src/v2/components/chat/__tests__/CopilotPopupView.test.ts +79 -0
- package/src/v2/components/chat/__tests__/CopilotSidebarView.test.ts +93 -0
- package/src/v2/components/chat/types.ts +73 -18
- package/dist/use-render-activity-message-Ciee03Rx.js +0 -9702
- package/dist/use-render-activity-message-Ciee03Rx.js.map +0 -1
- package/dist/use-render-activity-message-DXJDZGkW.cjs +0 -85
- package/dist/use-render-activity-message-DXJDZGkW.cjs.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cleanup, fireEvent, screen, waitFor } from "@testing-library/vue";
|
|
2
2
|
import { computed, defineComponent, onMounted } from "vue";
|
|
3
3
|
import type { PropType } from "vue";
|
|
4
|
-
import { afterEach, describe, expect, it } from "vitest";
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
5
5
|
import { EventType } from "@ag-ui/client";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import { useConfigureSuggestions } from "../../../hooks/use-configure-suggestions";
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
toolCallResultEvent,
|
|
24
24
|
} from "../../../__tests__/utils/test-helpers";
|
|
25
25
|
import CopilotChat from "../CopilotChat.vue";
|
|
26
|
+
import CopilotPopup from "../CopilotPopup.vue";
|
|
26
27
|
|
|
27
28
|
afterEach(() => {
|
|
28
29
|
cleanup();
|
|
@@ -138,11 +139,33 @@ describe("CopilotChat E2E - Chat Basics and Streaming Patterns", () => {
|
|
|
138
139
|
components: { CopilotChat },
|
|
139
140
|
template: `
|
|
140
141
|
<CopilotChat :welcome-screen="false">
|
|
141
|
-
<template #chat-view="{
|
|
142
|
+
<template #chat-view="{
|
|
143
|
+
isRunning,
|
|
144
|
+
onStop,
|
|
145
|
+
onSubmitMessage,
|
|
146
|
+
onAddFile,
|
|
147
|
+
onStartTranscribe,
|
|
148
|
+
onCancelTranscribe,
|
|
149
|
+
onFinishTranscribe,
|
|
150
|
+
onFinishTranscribeWithAudio,
|
|
151
|
+
}">
|
|
142
152
|
<div>
|
|
143
153
|
<button data-testid="submit" @click="onSubmitMessage('trigger run')">submit</button>
|
|
144
154
|
<span data-testid="running">{{ isRunning ? "running" : "idle" }}</span>
|
|
145
|
-
<span data-testid="stop-availability">
|
|
155
|
+
<span data-testid="stop-availability">
|
|
156
|
+
{{
|
|
157
|
+
[
|
|
158
|
+
onStop,
|
|
159
|
+
onAddFile,
|
|
160
|
+
onStartTranscribe,
|
|
161
|
+
onCancelTranscribe,
|
|
162
|
+
onFinishTranscribe,
|
|
163
|
+
onFinishTranscribeWithAudio,
|
|
164
|
+
].every((command) => typeof command === "function")
|
|
165
|
+
? "available"
|
|
166
|
+
: "missing"
|
|
167
|
+
}}
|
|
168
|
+
</span>
|
|
146
169
|
</div>
|
|
147
170
|
</template>
|
|
148
171
|
</CopilotChat>
|
|
@@ -153,7 +176,7 @@ describe("CopilotChat E2E - Chat Basics and Streaming Patterns", () => {
|
|
|
153
176
|
|
|
154
177
|
expect(screen.getByTestId("running").textContent).toBe("idle");
|
|
155
178
|
expect(screen.getByTestId("stop-availability").textContent).toBe(
|
|
156
|
-
"
|
|
179
|
+
"available",
|
|
157
180
|
);
|
|
158
181
|
|
|
159
182
|
await fireEvent.click(screen.getByTestId("submit"));
|
|
@@ -172,7 +195,7 @@ describe("CopilotChat E2E - Chat Basics and Streaming Patterns", () => {
|
|
|
172
195
|
await waitFor(() => {
|
|
173
196
|
expect(screen.getByTestId("running").textContent).toBe("idle");
|
|
174
197
|
expect(screen.getByTestId("stop-availability").textContent).toBe(
|
|
175
|
-
"
|
|
198
|
+
"available",
|
|
176
199
|
);
|
|
177
200
|
});
|
|
178
201
|
});
|
|
@@ -1237,4 +1260,132 @@ describe("CopilotChat E2E - Chat Basics and Streaming Patterns", () => {
|
|
|
1237
1260
|
});
|
|
1238
1261
|
});
|
|
1239
1262
|
});
|
|
1263
|
+
|
|
1264
|
+
describe("Vue-specific semantics", () => {
|
|
1265
|
+
it("forwards a static stop listener through a custom input slot after a run starts", async () => {
|
|
1266
|
+
const agent = new MockStepwiseAgent();
|
|
1267
|
+
const onStop = vi.fn();
|
|
1268
|
+
const CustomInputChat = defineComponent({
|
|
1269
|
+
components: { CopilotChat },
|
|
1270
|
+
setup() {
|
|
1271
|
+
return { onStop };
|
|
1272
|
+
},
|
|
1273
|
+
template: `
|
|
1274
|
+
<CopilotChat :welcome-screen="false" @stop="onStop">
|
|
1275
|
+
<template #input="{ isRunning, onSubmitMessage, onStop }">
|
|
1276
|
+
<button data-testid="custom-input-submit" @click="onSubmitMessage('Hello')">
|
|
1277
|
+
submit
|
|
1278
|
+
</button>
|
|
1279
|
+
<button v-if="isRunning" data-testid="custom-input-stop" @click="onStop">
|
|
1280
|
+
stop
|
|
1281
|
+
</button>
|
|
1282
|
+
</template>
|
|
1283
|
+
</CopilotChat>
|
|
1284
|
+
`,
|
|
1285
|
+
});
|
|
1286
|
+
|
|
1287
|
+
renderWithCopilotKit({ agent, children: CustomInputChat });
|
|
1288
|
+
|
|
1289
|
+
expect(screen.queryByTestId("custom-input-stop")).toBeNull();
|
|
1290
|
+
|
|
1291
|
+
await fireEvent.click(screen.getByTestId("custom-input-submit"));
|
|
1292
|
+
await waitFor(() => expect(agent.messages.length).toBeGreaterThan(0));
|
|
1293
|
+
|
|
1294
|
+
await agent.emit(runStartedEvent());
|
|
1295
|
+
await waitFor(() => {
|
|
1296
|
+
expect(screen.getByTestId("custom-input-stop")).toBeDefined();
|
|
1297
|
+
});
|
|
1298
|
+
|
|
1299
|
+
await fireEvent.click(screen.getByTestId("custom-input-stop"));
|
|
1300
|
+
expect(onStop).toHaveBeenCalledTimes(1);
|
|
1301
|
+
|
|
1302
|
+
await agent.complete();
|
|
1303
|
+
});
|
|
1304
|
+
|
|
1305
|
+
it("does not emit unavailable transcription commands from a custom chat-view slot", async () => {
|
|
1306
|
+
const agent = new MockStepwiseAgent();
|
|
1307
|
+
const onCancelTranscribe = vi.fn();
|
|
1308
|
+
const onFinishTranscribe = vi.fn();
|
|
1309
|
+
const CustomChatView = defineComponent({
|
|
1310
|
+
components: { CopilotChat },
|
|
1311
|
+
setup() {
|
|
1312
|
+
return { onCancelTranscribe, onFinishTranscribe };
|
|
1313
|
+
},
|
|
1314
|
+
template: `
|
|
1315
|
+
<CopilotChat
|
|
1316
|
+
:welcome-screen="false"
|
|
1317
|
+
@cancel-transcribe="onCancelTranscribe"
|
|
1318
|
+
@finish-transcribe="onFinishTranscribe"
|
|
1319
|
+
>
|
|
1320
|
+
<template #chat-view="{ onCancelTranscribe, onFinishTranscribe }">
|
|
1321
|
+
<button data-testid="custom-cancel-transcribe" @click="onCancelTranscribe">
|
|
1322
|
+
cancel
|
|
1323
|
+
</button>
|
|
1324
|
+
<button data-testid="custom-finish-transcribe" @click="onFinishTranscribe">
|
|
1325
|
+
finish
|
|
1326
|
+
</button>
|
|
1327
|
+
</template>
|
|
1328
|
+
</CopilotChat>
|
|
1329
|
+
`,
|
|
1330
|
+
});
|
|
1331
|
+
|
|
1332
|
+
renderWithCopilotKit({ agent, children: CustomChatView });
|
|
1333
|
+
|
|
1334
|
+
await fireEvent.click(screen.getByTestId("custom-cancel-transcribe"));
|
|
1335
|
+
await fireEvent.click(screen.getByTestId("custom-finish-transcribe"));
|
|
1336
|
+
|
|
1337
|
+
expect(onCancelTranscribe).not.toHaveBeenCalled();
|
|
1338
|
+
expect(onFinishTranscribe).not.toHaveBeenCalled();
|
|
1339
|
+
});
|
|
1340
|
+
|
|
1341
|
+
it("preserves stop behavior through a popup close and reopen", async () => {
|
|
1342
|
+
const agent = new MockStepwiseAgent();
|
|
1343
|
+
const onStop = vi.fn();
|
|
1344
|
+
const CustomPopup = defineComponent({
|
|
1345
|
+
components: { CopilotPopup },
|
|
1346
|
+
setup() {
|
|
1347
|
+
return { onStop };
|
|
1348
|
+
},
|
|
1349
|
+
template: `
|
|
1350
|
+
<CopilotPopup :welcome-screen="false" @stop="onStop">
|
|
1351
|
+
<template #toggle-button="{ toggle }">
|
|
1352
|
+
<button data-testid="popup-toggle" @click="toggle">Toggle</button>
|
|
1353
|
+
</template>
|
|
1354
|
+
<template #input="{ isRunning, onSubmitMessage, onStop }">
|
|
1355
|
+
<button data-testid="popup-submit" @click="onSubmitMessage('Hello')">
|
|
1356
|
+
submit
|
|
1357
|
+
</button>
|
|
1358
|
+
<button v-if="isRunning" data-testid="popup-stop" @click="onStop">
|
|
1359
|
+
stop
|
|
1360
|
+
</button>
|
|
1361
|
+
</template>
|
|
1362
|
+
</CopilotPopup>
|
|
1363
|
+
`,
|
|
1364
|
+
});
|
|
1365
|
+
|
|
1366
|
+
renderWithCopilotKit({ agent, children: CustomPopup });
|
|
1367
|
+
|
|
1368
|
+
await fireEvent.click(screen.getByTestId("popup-submit"));
|
|
1369
|
+
await waitFor(() => expect(agent.messages.length).toBeGreaterThan(0));
|
|
1370
|
+
await agent.emit(runStartedEvent());
|
|
1371
|
+
await waitFor(() => {
|
|
1372
|
+
expect(screen.getByTestId("popup-stop")).toBeDefined();
|
|
1373
|
+
});
|
|
1374
|
+
|
|
1375
|
+
await fireEvent.click(screen.getByTestId("popup-toggle"));
|
|
1376
|
+
await waitFor(() => {
|
|
1377
|
+
expect(screen.queryByTestId("popup-stop")).toBeNull();
|
|
1378
|
+
});
|
|
1379
|
+
|
|
1380
|
+
await fireEvent.click(screen.getByTestId("popup-toggle"));
|
|
1381
|
+
await waitFor(() => {
|
|
1382
|
+
expect(screen.getByTestId("popup-stop")).toBeDefined();
|
|
1383
|
+
});
|
|
1384
|
+
|
|
1385
|
+
await fireEvent.click(screen.getByTestId("popup-stop"));
|
|
1386
|
+
expect(onStop).toHaveBeenCalledTimes(1);
|
|
1387
|
+
|
|
1388
|
+
await agent.complete();
|
|
1389
|
+
});
|
|
1390
|
+
});
|
|
1240
1391
|
});
|
|
@@ -562,6 +562,40 @@ describe("CopilotChatInput", () => {
|
|
|
562
562
|
expect(screen.queryByTestId("copilot-chat-input-send")).toBeNull();
|
|
563
563
|
});
|
|
564
564
|
|
|
565
|
+
it("shows finish control when only onFinishTranscribeWithAudio is provided", () => {
|
|
566
|
+
renderWithProvider({
|
|
567
|
+
props: {
|
|
568
|
+
mode: "transcribe",
|
|
569
|
+
},
|
|
570
|
+
listeners: {
|
|
571
|
+
onCancelTranscribe: () => {},
|
|
572
|
+
onFinishTranscribeWithAudio: () => {},
|
|
573
|
+
},
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
expect(
|
|
577
|
+
screen.getByTestId("copilot-chat-input-finish-transcribe"),
|
|
578
|
+
).toBeDefined();
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
it("hides finish control when neither finish handler is provided", () => {
|
|
582
|
+
renderWithProvider({
|
|
583
|
+
props: {
|
|
584
|
+
mode: "transcribe",
|
|
585
|
+
},
|
|
586
|
+
listeners: {
|
|
587
|
+
onCancelTranscribe: () => {},
|
|
588
|
+
},
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
expect(
|
|
592
|
+
screen.queryByTestId("copilot-chat-input-finish-transcribe"),
|
|
593
|
+
).toBeNull();
|
|
594
|
+
expect(
|
|
595
|
+
screen.getByTestId("copilot-chat-input-cancel-transcribe"),
|
|
596
|
+
).toBeDefined();
|
|
597
|
+
});
|
|
598
|
+
|
|
565
599
|
it("disables add menu button in transcribe mode", () => {
|
|
566
600
|
renderWithProvider({
|
|
567
601
|
props: {
|
|
@@ -254,6 +254,52 @@ describe("CopilotChatUserMessage", () => {
|
|
|
254
254
|
});
|
|
255
255
|
});
|
|
256
256
|
|
|
257
|
+
it("disables custom branch commands when no switch callback is available", async () => {
|
|
258
|
+
const message: UserMessage = {
|
|
259
|
+
id: "user-no-branch-handler",
|
|
260
|
+
role: "user",
|
|
261
|
+
timestamp: new Date(),
|
|
262
|
+
content: "Custom branch controls without a handler",
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
const wrapper = mount(CopilotChatUserMessage, {
|
|
266
|
+
props: {
|
|
267
|
+
message,
|
|
268
|
+
branchIndex: 0,
|
|
269
|
+
numberOfBranches: 2,
|
|
270
|
+
},
|
|
271
|
+
slots: {
|
|
272
|
+
"branch-navigation": ({
|
|
273
|
+
canGoPrev,
|
|
274
|
+
canGoNext,
|
|
275
|
+
goNext,
|
|
276
|
+
}: {
|
|
277
|
+
canGoPrev: boolean;
|
|
278
|
+
canGoNext: boolean;
|
|
279
|
+
goNext: () => void;
|
|
280
|
+
}) =>
|
|
281
|
+
h("div", [
|
|
282
|
+
h(
|
|
283
|
+
"span",
|
|
284
|
+
{ "data-testid": "branch-capabilities" },
|
|
285
|
+
`${canGoPrev}:${canGoNext}`,
|
|
286
|
+
),
|
|
287
|
+
h(
|
|
288
|
+
"button",
|
|
289
|
+
{ "data-testid": "branch-next", onClick: goNext },
|
|
290
|
+
"next",
|
|
291
|
+
),
|
|
292
|
+
]),
|
|
293
|
+
},
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
expect(wrapper.get("[data-testid='branch-capabilities']").text()).toBe(
|
|
297
|
+
"false:false",
|
|
298
|
+
);
|
|
299
|
+
await wrapper.get("[data-testid='branch-next']").trigger("click");
|
|
300
|
+
expect(wrapper.emitted("switch-to-branch")).toBeUndefined();
|
|
301
|
+
});
|
|
302
|
+
|
|
257
303
|
it("supports custom layout slot with all control callbacks", async () => {
|
|
258
304
|
const onEditMessage = vi.fn();
|
|
259
305
|
const onSwitchToBranch = vi.fn();
|
|
@@ -121,6 +121,124 @@ describe("CopilotChatView", () => {
|
|
|
121
121
|
]);
|
|
122
122
|
});
|
|
123
123
|
|
|
124
|
+
it("forwards a static stop listener through the input slot", async () => {
|
|
125
|
+
const onStop = vi.fn();
|
|
126
|
+
const StaticStopHost = defineComponent({
|
|
127
|
+
components: {
|
|
128
|
+
CopilotKitProvider,
|
|
129
|
+
CopilotChatConfigurationProvider,
|
|
130
|
+
CopilotChatView,
|
|
131
|
+
},
|
|
132
|
+
setup() {
|
|
133
|
+
return { chatMessages, onStop };
|
|
134
|
+
},
|
|
135
|
+
template: `
|
|
136
|
+
<CopilotKitProvider runtime-url="/api/copilotkit">
|
|
137
|
+
<CopilotChatConfigurationProvider
|
|
138
|
+
thread-id="thread-1"
|
|
139
|
+
agent-id="default"
|
|
140
|
+
>
|
|
141
|
+
<CopilotChatView :messages="chatMessages" @stop="onStop">
|
|
142
|
+
<template #input="{ onStop: slotOnStop }">
|
|
143
|
+
<button data-testid="direct-stop" @click="slotOnStop">
|
|
144
|
+
stop
|
|
145
|
+
</button>
|
|
146
|
+
</template>
|
|
147
|
+
</CopilotChatView>
|
|
148
|
+
</CopilotChatConfigurationProvider>
|
|
149
|
+
</CopilotKitProvider>
|
|
150
|
+
`,
|
|
151
|
+
});
|
|
152
|
+
const wrapper = mount(StaticStopHost);
|
|
153
|
+
|
|
154
|
+
await wrapper.get("[data-testid='direct-stop']").trigger("click");
|
|
155
|
+
|
|
156
|
+
expect(onStop).toHaveBeenCalledTimes(1);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("exposes canStop / canAddFile / canTranscribe on the input slot", () => {
|
|
160
|
+
const CapabilityHost = defineComponent({
|
|
161
|
+
components: {
|
|
162
|
+
CopilotKitProvider,
|
|
163
|
+
CopilotChatConfigurationProvider,
|
|
164
|
+
CopilotChatView,
|
|
165
|
+
},
|
|
166
|
+
setup() {
|
|
167
|
+
return { chatMessages };
|
|
168
|
+
},
|
|
169
|
+
template: `
|
|
170
|
+
<CopilotKitProvider runtime-url="/api/copilotkit">
|
|
171
|
+
<CopilotChatConfigurationProvider
|
|
172
|
+
thread-id="thread-1"
|
|
173
|
+
agent-id="default"
|
|
174
|
+
>
|
|
175
|
+
<CopilotChatView
|
|
176
|
+
:messages="chatMessages"
|
|
177
|
+
:on-stop="() => {}"
|
|
178
|
+
:on-add-file="() => {}"
|
|
179
|
+
>
|
|
180
|
+
<template
|
|
181
|
+
#input="{ canStop, canAddFile, canTranscribe }"
|
|
182
|
+
>
|
|
183
|
+
<span data-testid="can-stop">{{ canStop }}</span>
|
|
184
|
+
<span data-testid="can-add-file">{{ canAddFile }}</span>
|
|
185
|
+
<span data-testid="can-transcribe">{{ canTranscribe }}</span>
|
|
186
|
+
</template>
|
|
187
|
+
</CopilotChatView>
|
|
188
|
+
</CopilotChatConfigurationProvider>
|
|
189
|
+
</CopilotKitProvider>
|
|
190
|
+
`,
|
|
191
|
+
});
|
|
192
|
+
const wrapper = mount(CapabilityHost);
|
|
193
|
+
|
|
194
|
+
expect(wrapper.get("[data-testid='can-stop']").text()).toBe("true");
|
|
195
|
+
expect(wrapper.get("[data-testid='can-add-file']").text()).toBe("true");
|
|
196
|
+
expect(wrapper.get("[data-testid='can-transcribe']").text()).toBe("false");
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("exposes canStop / canAddFile / canTranscribe on the welcome-screen slot", () => {
|
|
200
|
+
const WelcomeCapabilityHost = defineComponent({
|
|
201
|
+
components: {
|
|
202
|
+
CopilotKitProvider,
|
|
203
|
+
CopilotChatConfigurationProvider,
|
|
204
|
+
CopilotChatView,
|
|
205
|
+
},
|
|
206
|
+
template: `
|
|
207
|
+
<CopilotKitProvider runtime-url="/api/copilotkit">
|
|
208
|
+
<CopilotChatConfigurationProvider
|
|
209
|
+
thread-id="thread-1"
|
|
210
|
+
agent-id="default"
|
|
211
|
+
>
|
|
212
|
+
<CopilotChatView
|
|
213
|
+
:messages="[]"
|
|
214
|
+
:on-stop="() => {}"
|
|
215
|
+
:on-start-transcribe="() => {}"
|
|
216
|
+
>
|
|
217
|
+
<template
|
|
218
|
+
#welcome-screen="{ canStop, canAddFile, canTranscribe }"
|
|
219
|
+
>
|
|
220
|
+
<span data-testid="welcome-can-stop">{{ canStop }}</span>
|
|
221
|
+
<span data-testid="welcome-can-add-file">{{ canAddFile }}</span>
|
|
222
|
+
<span data-testid="welcome-can-transcribe">{{
|
|
223
|
+
canTranscribe
|
|
224
|
+
}}</span>
|
|
225
|
+
</template>
|
|
226
|
+
</CopilotChatView>
|
|
227
|
+
</CopilotChatConfigurationProvider>
|
|
228
|
+
</CopilotKitProvider>
|
|
229
|
+
`,
|
|
230
|
+
});
|
|
231
|
+
const wrapper = mount(WelcomeCapabilityHost);
|
|
232
|
+
|
|
233
|
+
expect(wrapper.get("[data-testid='welcome-can-stop']").text()).toBe("true");
|
|
234
|
+
expect(wrapper.get("[data-testid='welcome-can-add-file']").text()).toBe(
|
|
235
|
+
"false",
|
|
236
|
+
);
|
|
237
|
+
expect(wrapper.get("[data-testid='welcome-can-transcribe']").text()).toBe(
|
|
238
|
+
"true",
|
|
239
|
+
);
|
|
240
|
+
});
|
|
241
|
+
|
|
124
242
|
it("renders suggestions and forwards selection callback and event", async () => {
|
|
125
243
|
const onSelectSuggestion = vi.fn();
|
|
126
244
|
const wrapper = mountChatView({
|
|
@@ -55,6 +55,43 @@ describe("CopilotPopupView", () => {
|
|
|
55
55
|
);
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
+
it("only exposes stop capability when an onStop callback is available", async () => {
|
|
59
|
+
const withoutStop = mountPopupView(
|
|
60
|
+
{},
|
|
61
|
+
{
|
|
62
|
+
"welcome-screen": ({ canStop }: { canStop: boolean }) =>
|
|
63
|
+
h("div", { "data-testid": "popup-can-stop" }, String(canStop)),
|
|
64
|
+
},
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
expect(withoutStop.get("[data-testid='popup-can-stop']").text()).toBe(
|
|
68
|
+
"false",
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const onStop = vi.fn();
|
|
72
|
+
const withStop = mountPopupView(
|
|
73
|
+
{ onStop },
|
|
74
|
+
{
|
|
75
|
+
"welcome-screen": ({
|
|
76
|
+
canStop,
|
|
77
|
+
onStop: stop,
|
|
78
|
+
}: {
|
|
79
|
+
canStop: boolean;
|
|
80
|
+
onStop: () => void;
|
|
81
|
+
}) =>
|
|
82
|
+
h(
|
|
83
|
+
"button",
|
|
84
|
+
{ "data-testid": "popup-stop", onClick: stop },
|
|
85
|
+
String(canStop),
|
|
86
|
+
),
|
|
87
|
+
},
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
expect(withStop.get("[data-testid='popup-stop']").text()).toBe("true");
|
|
91
|
+
await withStop.get("[data-testid='popup-stop']").trigger("click");
|
|
92
|
+
expect(onStop).toHaveBeenCalledTimes(1);
|
|
93
|
+
});
|
|
94
|
+
|
|
58
95
|
it("closes on escape and outside pointerdown when enabled", async () => {
|
|
59
96
|
const wrapper = mountPopupView({
|
|
60
97
|
clickOutsideToClose: true,
|
|
@@ -109,4 +146,46 @@ describe("CopilotPopupView", () => {
|
|
|
109
146
|
it("exposes the WelcomeScreen namespaced export", () => {
|
|
110
147
|
expect(NamespacedPopupView.WelcomeScreen).toBeDefined();
|
|
111
148
|
});
|
|
149
|
+
|
|
150
|
+
it("passes capability flags through the namespaced WelcomeScreen input slot", () => {
|
|
151
|
+
const wrapper = mount(NamespacedPopupView.WelcomeScreen, {
|
|
152
|
+
props: {
|
|
153
|
+
suggestions: [],
|
|
154
|
+
loadingIndexes: [],
|
|
155
|
+
modelValue: "",
|
|
156
|
+
isRunning: false,
|
|
157
|
+
inputMode: "input",
|
|
158
|
+
inputToolsMenu: [],
|
|
159
|
+
canStop: false,
|
|
160
|
+
canAddFile: false,
|
|
161
|
+
canTranscribe: false,
|
|
162
|
+
onUpdateModelValue: vi.fn(),
|
|
163
|
+
onSubmitMessage: vi.fn(),
|
|
164
|
+
onStop: vi.fn(),
|
|
165
|
+
onAddFile: vi.fn(),
|
|
166
|
+
onStartTranscribe: vi.fn(),
|
|
167
|
+
onSelectSuggestion: vi.fn(),
|
|
168
|
+
},
|
|
169
|
+
slots: {
|
|
170
|
+
input: ({
|
|
171
|
+
canStop,
|
|
172
|
+
canAddFile,
|
|
173
|
+
canTranscribe,
|
|
174
|
+
}: {
|
|
175
|
+
canStop: boolean;
|
|
176
|
+
canAddFile: boolean;
|
|
177
|
+
canTranscribe: boolean;
|
|
178
|
+
}) =>
|
|
179
|
+
h(
|
|
180
|
+
"div",
|
|
181
|
+
{ "data-testid": "popup-welcome-capabilities" },
|
|
182
|
+
`${canStop}:${canAddFile}:${canTranscribe}`,
|
|
183
|
+
),
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
expect(
|
|
188
|
+
wrapper.get("[data-testid='popup-welcome-capabilities']").text(),
|
|
189
|
+
).toBe("false:false:false");
|
|
190
|
+
});
|
|
112
191
|
});
|
|
@@ -157,6 +157,43 @@ describe("CopilotSidebarView", () => {
|
|
|
157
157
|
expect(onSelectSuggestion).toHaveBeenCalledTimes(1);
|
|
158
158
|
});
|
|
159
159
|
|
|
160
|
+
it("only exposes stop capability when an onStop callback is available", async () => {
|
|
161
|
+
const withoutStop = mountSidebarView(
|
|
162
|
+
{},
|
|
163
|
+
{
|
|
164
|
+
"welcome-screen": ({ canStop }: { canStop: boolean }) =>
|
|
165
|
+
h("div", { "data-testid": "sidebar-can-stop" }, String(canStop)),
|
|
166
|
+
},
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
expect(withoutStop.get("[data-testid='sidebar-can-stop']").text()).toBe(
|
|
170
|
+
"false",
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const onStop = vi.fn();
|
|
174
|
+
const withStop = mountSidebarView(
|
|
175
|
+
{ onStop },
|
|
176
|
+
{
|
|
177
|
+
"welcome-screen": ({
|
|
178
|
+
canStop,
|
|
179
|
+
onStop: stop,
|
|
180
|
+
}: {
|
|
181
|
+
canStop: boolean;
|
|
182
|
+
onStop: () => void;
|
|
183
|
+
}) =>
|
|
184
|
+
h(
|
|
185
|
+
"button",
|
|
186
|
+
{ "data-testid": "sidebar-stop", onClick: stop },
|
|
187
|
+
String(canStop),
|
|
188
|
+
),
|
|
189
|
+
},
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
expect(withStop.get("[data-testid='sidebar-stop']").text()).toBe("true");
|
|
193
|
+
await withStop.get("[data-testid='sidebar-stop']").trigger("click");
|
|
194
|
+
expect(onStop).toHaveBeenCalledTimes(1);
|
|
195
|
+
});
|
|
196
|
+
|
|
160
197
|
it("uses the default chat welcome screen and still forwards welcome sub-slots", () => {
|
|
161
198
|
const wrapper = mountSidebarView(
|
|
162
199
|
{
|
|
@@ -211,4 +248,60 @@ describe("CopilotSidebarView", () => {
|
|
|
211
248
|
"Hello",
|
|
212
249
|
);
|
|
213
250
|
});
|
|
251
|
+
|
|
252
|
+
it("exposes reactive capability flags from the namespaced WelcomeScreen input slot", async () => {
|
|
253
|
+
const wrapper = mount(CopilotSidebarView.WelcomeScreen, {
|
|
254
|
+
props: {
|
|
255
|
+
suggestions: [],
|
|
256
|
+
loadingIndexes: [],
|
|
257
|
+
modelValue: "",
|
|
258
|
+
isRunning: false,
|
|
259
|
+
inputMode: "input",
|
|
260
|
+
inputToolsMenu: [],
|
|
261
|
+
onUpdateModelValue: vi.fn(),
|
|
262
|
+
onSubmitMessage: vi.fn(),
|
|
263
|
+
onSelectSuggestion: vi.fn(),
|
|
264
|
+
},
|
|
265
|
+
slots: {
|
|
266
|
+
input: ({
|
|
267
|
+
canStop,
|
|
268
|
+
canAddFile,
|
|
269
|
+
canTranscribe,
|
|
270
|
+
}: {
|
|
271
|
+
canStop: boolean;
|
|
272
|
+
canAddFile: boolean;
|
|
273
|
+
canTranscribe: boolean;
|
|
274
|
+
}) =>
|
|
275
|
+
h(
|
|
276
|
+
"div",
|
|
277
|
+
{ "data-testid": "sidebar-welcome-capabilities" },
|
|
278
|
+
`${canStop}:${canAddFile}:${canTranscribe}`,
|
|
279
|
+
),
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
expect(
|
|
284
|
+
wrapper.get("[data-testid='sidebar-welcome-capabilities']").text(),
|
|
285
|
+
).toBe("false:false:false");
|
|
286
|
+
|
|
287
|
+
await wrapper.setProps({
|
|
288
|
+
onStop: vi.fn(),
|
|
289
|
+
onAddFile: vi.fn(),
|
|
290
|
+
onStartTranscribe: vi.fn(),
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
expect(
|
|
294
|
+
wrapper.get("[data-testid='sidebar-welcome-capabilities']").text(),
|
|
295
|
+
).toBe("true:true:true");
|
|
296
|
+
|
|
297
|
+
await wrapper.setProps({
|
|
298
|
+
canStop: false,
|
|
299
|
+
canAddFile: false,
|
|
300
|
+
canTranscribe: false,
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
expect(
|
|
304
|
+
wrapper.get("[data-testid='sidebar-welcome-capabilities']").text(),
|
|
305
|
+
).toBe("false:false:false");
|
|
306
|
+
});
|
|
214
307
|
});
|