@copilotkit/vue 2.0.0-rc.1 → 2.0.0-rc.3
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 +13 -12
- package/README.md +1 -2
- package/dist/components/copilot-provider/CopilotKit.vue.d.ts +3 -1
- package/dist/components/copilot-provider/CopilotKit.vue.d.ts.map +1 -1
- package/dist/index.cjs +43 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +10170 -7506
- package/dist/index.mjs.map +1 -1
- package/dist/v2/components/A2UIMessageRenderer.d.ts +7 -0
- package/dist/v2/components/A2UIMessageRenderer.d.ts.map +1 -1
- package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts.map +1 -1
- package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts +11 -2
- package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts.map +1 -1
- package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts +136 -0
- package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts.map +1 -0
- package/dist/v2/components/chat/BasicMarkdown.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChat.vue.d.ts +1 -0
- package/dist/v2/components/chat/CopilotChat.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts +3 -1
- package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatAssistantToolbarButton.vue.d.ts +16 -0
- package/dist/v2/components/chat/CopilotChatAssistantToolbarButton.vue.d.ts.map +1 -0
- package/dist/v2/components/chat/CopilotChatAttachmentQueue.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatAttachmentRenderer.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatAudioRecorder.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts +22 -0
- package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts.map +1 -0
- package/dist/v2/components/chat/CopilotChatInput.vue.d.ts +69 -16
- package/dist/v2/components/chat/CopilotChatInput.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatInspectorButton.vue.d.ts +12 -0
- package/dist/v2/components/chat/CopilotChatInspectorButton.vue.d.ts.map +1 -0
- package/dist/v2/components/chat/CopilotChatLightbox.vue.d.ts +22 -0
- package/dist/v2/components/chat/CopilotChatLightbox.vue.d.ts.map +1 -0
- package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts +20 -0
- package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatReasoningMessage.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatSuggestionPill.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatSuggestionView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatToggleButton.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts +32 -0
- package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts.map +1 -0
- package/dist/v2/components/chat/CopilotChatToolCallItem.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts +11 -1
- package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatUserMessage.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatView.vue.d.ts +1 -0
- package/dist/v2/components/chat/CopilotChatView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatWorkSummary.vue.d.ts +5 -0
- package/dist/v2/components/chat/CopilotChatWorkSummary.vue.d.ts.map +1 -0
- package/dist/v2/components/chat/CopilotModalHeader.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotModalHeaderCloseButton.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotModalHeaderTitle.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotPopup.vue.d.ts +1 -0
- package/dist/v2/components/chat/CopilotPopup.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotPopupView.vue.d.ts +1 -0
- package/dist/v2/components/chat/CopilotPopupView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts +1 -0
- package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotPopupWelcomeScreen.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotSidebar.vue.d.ts +2 -0
- package/dist/v2/components/chat/CopilotSidebar.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts +2 -0
- package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts +2 -0
- package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotSidebarWelcomeScreen.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/StreamingMarkdownDefault.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/index.d.ts +17 -0
- package/dist/v2/components/chat/index.d.ts.map +1 -1
- package/dist/v2/components/chat/inspector-shortcuts.d.ts +12 -0
- package/dist/v2/components/chat/inspector-shortcuts.d.ts.map +1 -0
- package/dist/v2/components/chat/message-feedback.d.ts +89 -0
- package/dist/v2/components/chat/message-feedback.d.ts.map +1 -0
- package/dist/v2/components/chat/tool-call-capture.d.ts +39 -0
- package/dist/v2/components/chat/tool-call-capture.d.ts.map +1 -0
- package/dist/v2/components/chat/tool-call-display-context.d.ts +39 -0
- package/dist/v2/components/chat/tool-call-display-context.d.ts.map +1 -0
- package/dist/v2/components/chat/tool-call-group-parts.d.ts +144 -0
- package/dist/v2/components/chat/tool-call-group-parts.d.ts.map +1 -0
- package/dist/v2/components/chat/tool-call-layout.d.ts +115 -0
- package/dist/v2/components/chat/tool-call-layout.d.ts.map +1 -0
- package/dist/v2/components/chat/turn-work.d.ts +35 -0
- package/dist/v2/components/chat/turn-work.d.ts.map +1 -0
- package/dist/v2/components/chat/types.d.ts +104 -4
- package/dist/v2/components/chat/types.d.ts.map +1 -1
- package/dist/v2/components/chat/use-lightbox.d.ts +18 -0
- package/dist/v2/components/chat/use-lightbox.d.ts.map +1 -0
- package/dist/v2/components/icons/index.d.ts +1 -1
- package/dist/v2/components/icons/index.d.ts.map +1 -1
- package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts +55 -0
- package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts.map +1 -0
- package/dist/v2/components/ui/CopilotPopover.vue.d.ts +40 -0
- package/dist/v2/components/ui/CopilotPopover.vue.d.ts.map +1 -0
- package/dist/v2/components/ui/CopilotTooltip.vue.d.ts +37 -0
- package/dist/v2/components/ui/CopilotTooltip.vue.d.ts.map +1 -0
- package/dist/v2/components/ui/dropdown-menu.d.ts +14 -0
- package/dist/v2/components/ui/dropdown-menu.d.ts.map +1 -0
- package/dist/v2/components/ui/floating.d.ts +84 -0
- package/dist/v2/components/ui/floating.d.ts.map +1 -0
- package/dist/v2/components/ui/presence.d.ts +9 -0
- package/dist/v2/components/ui/presence.d.ts.map +1 -0
- package/dist/v2/components/ui/use-id.d.ts +9 -0
- package/dist/v2/components/ui/use-id.d.ts.map +1 -0
- package/dist/v2/hooks/use-default-render-tool.d.ts +6 -0
- package/dist/v2/hooks/use-default-render-tool.d.ts.map +1 -1
- package/dist/v2/hooks/use-render-tool.d.ts +4 -0
- package/dist/v2/hooks/use-render-tool.d.ts.map +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.d.cts +3 -0
- package/dist/v2/index.d.mts +3 -0
- package/dist/v2/index.d.ts +3 -0
- package/dist/v2/index.d.ts.map +1 -1
- package/dist/v2/index.mjs +165 -162
- package/dist/v2/lib/message-feedback.d.ts +33 -0
- package/dist/v2/lib/message-feedback.d.ts.map +1 -0
- package/dist/v2/providers/CopilotChatConfigurationProvider.vue.d.ts.map +1 -1
- package/dist/v2/providers/CopilotKitProvider.types.d.ts +56 -1
- package/dist/v2/providers/CopilotKitProvider.types.d.ts.map +1 -1
- package/dist/v2/providers/CopilotKitProvider.vue.d.ts +5 -1
- package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
- package/dist/v2/providers/index.d.ts +1 -1
- package/dist/v2/providers/index.d.ts.map +1 -1
- package/dist/v2/providers/keys.d.ts +8 -0
- package/dist/v2/providers/keys.d.ts.map +1 -1
- package/dist/v2/providers/types.d.ts +9 -0
- package/dist/v2/providers/types.d.ts.map +1 -1
- package/dist/v2/styles/CopilotKitStyles.d.ts +18 -0
- package/dist/v2/styles/CopilotKitStyles.d.ts.map +1 -0
- package/dist/v2/types/defineToolCallRenderer.d.ts +2 -0
- package/dist/v2/types/defineToolCallRenderer.d.ts.map +1 -1
- package/dist/v2/types/vue-tool-call-renderer.d.ts +7 -0
- package/dist/v2/types/vue-tool-call-renderer.d.ts.map +1 -1
- package/package.json +11 -23
- package/src/components/copilot-provider/CopilotKit.vue +4 -1
- package/src/v2/__tests__/exports.test.ts +4 -2
- package/src/v2/components/A2UIMessageRenderer.ts +55 -67
- package/src/v2/components/A2UISurfaceActivityRenderer.vue +11 -23
- package/src/v2/components/__tests__/A2UIBasicCatalogColors.test.ts +8 -9
- package/src/v2/components/__tests__/A2UIMessageRenderer.test.ts +63 -36
- package/src/v2/components/a2ui/A2UIBuiltInToolCallRenderer.ts +14 -257
- package/src/v2/components/a2ui/A2UIRecoveryStates.ts +444 -0
- package/src/v2/components/a2ui/__tests__/A2UIRecoveryStates.test.ts +175 -0
- package/src/v2/components/chat/BasicMarkdown.vue +8 -6
- package/src/v2/components/chat/CopilotChat.vue +7 -0
- package/src/v2/components/chat/CopilotChatAssistantMessage.vue +267 -67
- package/src/v2/components/chat/CopilotChatAssistantToolbarButton.vue +46 -0
- package/src/v2/components/chat/CopilotChatAttachmentQueue.vue +141 -168
- package/src/v2/components/chat/CopilotChatAttachmentRenderer.vue +67 -18
- package/src/v2/components/chat/CopilotChatAudioRecorder.vue +2 -2
- package/src/v2/components/chat/CopilotChatFeedbackCommentPopover.vue +240 -0
- package/src/v2/components/chat/CopilotChatInput.vue +210 -161
- package/src/v2/components/chat/CopilotChatInspectorButton.vue +331 -0
- package/src/v2/components/chat/CopilotChatLightbox.vue +105 -0
- package/src/v2/components/chat/CopilotChatMessageView.vue +261 -18
- package/src/v2/components/chat/CopilotChatReasoningMessage.vue +21 -22
- package/src/v2/components/chat/CopilotChatSuggestionPill.vue +5 -14
- package/src/v2/components/chat/CopilotChatSuggestionView.vue +1 -4
- package/src/v2/components/chat/CopilotChatToggleButton.vue +3 -9
- package/src/v2/components/chat/CopilotChatToggleButtonCloseIcon.ts +1 -1
- package/src/v2/components/chat/CopilotChatToggleButtonOpenIcon.ts +1 -1
- package/src/v2/components/chat/CopilotChatToolCallGroup.vue +330 -0
- package/src/v2/components/chat/CopilotChatToolCallItem.vue +21 -11
- package/src/v2/components/chat/CopilotChatToolCallsView.vue +192 -21
- package/src/v2/components/chat/CopilotChatUserMessage.vue +105 -42
- package/src/v2/components/chat/CopilotChatView.vue +33 -38
- package/src/v2/components/chat/CopilotChatWorkSummary.vue +85 -0
- package/src/v2/components/chat/CopilotModalHeader.vue +10 -8
- package/src/v2/components/chat/CopilotModalHeaderCloseButton.ts +7 -6
- package/src/v2/components/chat/CopilotModalHeaderTitle.ts +1 -4
- package/src/v2/components/chat/CopilotPopup.vue +3 -0
- package/src/v2/components/chat/CopilotPopupView.vue +1 -0
- package/src/v2/components/chat/CopilotPopupViewInternal.vue +9 -19
- package/src/v2/components/chat/CopilotPopupWelcomeScreen.vue +5 -8
- package/src/v2/components/chat/CopilotSidebar.vue +5 -0
- package/src/v2/components/chat/CopilotSidebarView.vue +2 -0
- package/src/v2/components/chat/CopilotSidebarViewInternal.vue +24 -17
- package/src/v2/components/chat/CopilotSidebarWelcomeScreen.vue +7 -10
- package/src/v2/components/chat/StreamingMarkdownDefault.vue +3 -5
- package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.inspector.test.ts +269 -0
- package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.learningFeedback.test.ts +760 -0
- package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.slots.e2e.test.ts +3 -5
- package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.test.ts +2 -2
- package/src/v2/components/chat/__tests__/CopilotChatInput.addMenu.test.ts +328 -0
- package/src/v2/components/chat/__tests__/CopilotChatInput.slots.e2e.test.ts +6 -3
- package/src/v2/components/chat/__tests__/CopilotChatInput.test.ts +22 -13
- package/src/v2/components/chat/__tests__/CopilotChatLightbox.test.ts +160 -0
- package/src/v2/components/chat/__tests__/CopilotChatMessageView.toolCallDisplay.test.ts +735 -0
- package/src/v2/components/chat/__tests__/CopilotChatSuggestionPill.test.ts +1 -1
- package/src/v2/components/chat/__tests__/CopilotChatSuggestionView.slots.e2e.test.ts +3 -1
- package/src/v2/components/chat/__tests__/CopilotChatToolCallsView.learning.test.ts +75 -0
- package/src/v2/components/chat/__tests__/CopilotChatUserMessage.attachments.test.ts +143 -0
- package/src/v2/components/chat/__tests__/CopilotChatView.inputOverlay.test.ts +5 -4
- package/src/v2/components/chat/__tests__/CopilotChatView.rootWidth.test.ts +7 -33
- package/src/v2/components/chat/__tests__/CopilotModalHeader.slots.e2e.test.ts +1 -1
- package/src/v2/components/chat/__tests__/CopilotPopupView.slots.e2e.test.ts +3 -3
- package/src/v2/components/chat/__tests__/CopilotSidebarView.position.test.ts +126 -0
- package/src/v2/components/chat/__tests__/messageFeedbackDefaults.test.ts +33 -0
- package/src/v2/components/chat/__tests__/modalChatDisplayProps.test.ts +44 -0
- package/src/v2/components/chat/index.ts +2 -0
- package/src/v2/components/chat/inspector-shortcuts.ts +34 -0
- package/src/v2/components/chat/message-feedback.ts +291 -0
- package/src/v2/components/chat/tool-call-capture.ts +55 -0
- package/src/v2/components/chat/tool-call-display-context.ts +49 -0
- package/src/v2/components/chat/tool-call-group-parts.ts +292 -0
- package/src/v2/components/chat/tool-call-layout.ts +304 -0
- package/src/v2/components/chat/turn-work.ts +61 -0
- package/src/v2/components/chat/types.ts +113 -3
- package/src/v2/components/chat/use-lightbox.ts +64 -0
- package/src/v2/components/icons/index.ts +4 -0
- package/src/v2/components/ui/CopilotDropdownMenuContent.vue +465 -0
- package/src/v2/components/ui/CopilotPopover.vue +138 -0
- package/src/v2/components/ui/CopilotTooltip.vue +237 -0
- package/src/v2/components/ui/__tests__/CopilotTooltip.test.ts +168 -0
- package/src/v2/components/ui/dropdown-menu.ts +15 -0
- package/src/v2/components/ui/floating.ts +321 -0
- package/src/v2/components/ui/presence.ts +54 -0
- package/src/v2/components/ui/use-id.ts +16 -0
- package/src/v2/hooks/use-default-render-tool.ts +123 -62
- package/src/v2/hooks/use-render-tool.ts +8 -0
- package/src/v2/index.ts +3 -0
- package/src/v2/lib/__tests__/message-feedback.test.ts +152 -0
- package/src/v2/lib/message-feedback.ts +120 -0
- package/src/v2/providers/CopilotChatConfigurationProvider.vue +29 -2
- package/src/v2/providers/CopilotKitProvider.types.ts +57 -0
- package/src/v2/providers/CopilotKitProvider.vue +125 -3
- package/src/v2/providers/__tests__/CopilotChatConfigurationProvider.openThread.test.ts +69 -0
- package/src/v2/providers/__tests__/CopilotKitProvider.learning.test.ts +534 -0
- package/src/v2/providers/index.ts +4 -1
- package/src/v2/providers/keys.ts +12 -0
- package/src/v2/providers/types.ts +11 -0
- package/src/v2/styles/CopilotKitStyles.ts +95 -0
- package/src/v2/styles/__tests__/CopilotKitStyles.client.test.ts +149 -0
- package/src/v2/styles/__tests__/CopilotKitStyles.ssr.test.ts +71 -0
- package/src/v2/types/defineToolCallRenderer.ts +4 -0
- package/src/v2/types/vue-tool-call-renderer.ts +7 -0
- package/vite.config.ts +2 -1
- package/dist/styles.css +0 -2
- package/scripts/scope-preflight.mjs +0 -100
- package/src/styles/globals.css +0 -233
|
@@ -34,7 +34,7 @@ describe("CopilotChatSuggestionPill", () => {
|
|
|
34
34
|
);
|
|
35
35
|
expect(button.attributes("aria-busy")).toBe("true");
|
|
36
36
|
expect(button.attributes("disabled")).toBeDefined();
|
|
37
|
-
expect(wrapper.find(".cpk
|
|
37
|
+
expect(wrapper.find(".cpk-suggestion-pill-spinner").exists()).toBe(true);
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
it("renders icon component when provided", () => {
|
|
@@ -88,7 +88,9 @@ describe("CopilotChatSuggestionView Slot System E2E Tests", () => {
|
|
|
88
88
|
renderInWrapper(Host);
|
|
89
89
|
const containerEl = document.querySelector(".custom-container-class");
|
|
90
90
|
expect(containerEl).toBeTruthy();
|
|
91
|
-
expect(containerEl?.classList.contains("cpk
|
|
91
|
+
expect(containerEl?.classList.contains("cpk-suggestion-view")).toBe(
|
|
92
|
+
true,
|
|
93
|
+
);
|
|
92
94
|
});
|
|
93
95
|
});
|
|
94
96
|
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { h } from "vue";
|
|
3
|
+
import { mount } from "@vue/test-utils";
|
|
4
|
+
import type { AssistantMessage } from "@ag-ui/core";
|
|
5
|
+
import CopilotKitProvider from "../../../providers/CopilotKitProvider.vue";
|
|
6
|
+
import CopilotChatConfigurationProvider from "../../../providers/CopilotChatConfigurationProvider.vue";
|
|
7
|
+
import type { CopilotKitLearningOptions } from "../../../providers/CopilotKitProvider.types";
|
|
8
|
+
import CopilotChatToolCallsView from "../CopilotChatToolCallsView.vue";
|
|
9
|
+
|
|
10
|
+
// Ported from React's CopilotChatToolCallsView.learning test.
|
|
11
|
+
|
|
12
|
+
const message: AssistantMessage = {
|
|
13
|
+
id: "message-1",
|
|
14
|
+
role: "assistant",
|
|
15
|
+
content: "",
|
|
16
|
+
toolCalls: [
|
|
17
|
+
{
|
|
18
|
+
id: "tool-1",
|
|
19
|
+
type: "function",
|
|
20
|
+
function: { name: "approve", arguments: "{}" },
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
};
|
|
24
|
+
const learning: CopilotKitLearningOptions = {
|
|
25
|
+
sink: () => {},
|
|
26
|
+
capture: { clicks: false, navigation: false, network: false },
|
|
27
|
+
autoStart: false,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function mountView(learningProp?: CopilotKitLearningOptions) {
|
|
31
|
+
return mount(CopilotKitProvider, {
|
|
32
|
+
props: {
|
|
33
|
+
runtimeUrl: "/api/copilotkit",
|
|
34
|
+
...(learningProp ? { learning: learningProp } : {}),
|
|
35
|
+
},
|
|
36
|
+
slots: {
|
|
37
|
+
default: () =>
|
|
38
|
+
h(
|
|
39
|
+
CopilotChatConfigurationProvider,
|
|
40
|
+
{ threadId: "thread-1", agentId: "default" },
|
|
41
|
+
{
|
|
42
|
+
default: () =>
|
|
43
|
+
h("div", { "data-testid": "message" }, [
|
|
44
|
+
h(
|
|
45
|
+
CopilotChatToolCallsView,
|
|
46
|
+
{ message, messages: [message] },
|
|
47
|
+
{ "tool-call-approve": () => h("button", "Approve") },
|
|
48
|
+
),
|
|
49
|
+
]),
|
|
50
|
+
},
|
|
51
|
+
),
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
describe("tool call capture attributes", () => {
|
|
57
|
+
it("keeps tool UI as a direct child when learning is disabled", () => {
|
|
58
|
+
const wrapper = mountView();
|
|
59
|
+
|
|
60
|
+
const button = wrapper.get("button").element;
|
|
61
|
+
expect(button.parentElement?.getAttribute("data-testid")).toBe("message");
|
|
62
|
+
expect(wrapper.find("[data-tool-call-id]").exists()).toBe(false);
|
|
63
|
+
wrapper.unmount();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("wraps tool UI in data-tool-call-id while learning is configured", () => {
|
|
67
|
+
const wrapper = mountView(learning);
|
|
68
|
+
|
|
69
|
+
const scope = wrapper.get("button").element.parentElement;
|
|
70
|
+
expect(scope?.getAttribute("data-tool-call-id")).toBe("tool-1");
|
|
71
|
+
expect((scope as HTMLElement).style.display).toBe("contents");
|
|
72
|
+
expect(scope?.parentElement?.getAttribute("data-testid")).toBe("message");
|
|
73
|
+
wrapper.unmount();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { nextTick } from "vue";
|
|
3
|
+
import { fireEvent, render, screen, within } from "@testing-library/vue";
|
|
4
|
+
import type { UserMessage } from "@ag-ui/core";
|
|
5
|
+
import CopilotChatUserMessage from "../CopilotChatUserMessage.vue";
|
|
6
|
+
|
|
7
|
+
const message = {
|
|
8
|
+
id: "user-media",
|
|
9
|
+
role: "user",
|
|
10
|
+
content: [
|
|
11
|
+
{ type: "text", text: "Look at these" },
|
|
12
|
+
{
|
|
13
|
+
type: "image",
|
|
14
|
+
source: { type: "url", value: "https://example.com/cat.png" },
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
type: "document",
|
|
18
|
+
source: {
|
|
19
|
+
type: "data",
|
|
20
|
+
value: "JVBERi0=",
|
|
21
|
+
mimeType: "application/pdf",
|
|
22
|
+
},
|
|
23
|
+
metadata: { filename: "report.pdf" },
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
} as unknown as UserMessage;
|
|
27
|
+
|
|
28
|
+
describe("CopilotChatUserMessage attachments", () => {
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
document.body.innerHTML = "";
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("renders media parts in the attachments row before the bubble", () => {
|
|
34
|
+
const { container } = render(CopilotChatUserMessage, {
|
|
35
|
+
props: { message },
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const attachments = container.querySelector(
|
|
39
|
+
".cpk-user-message-attachments",
|
|
40
|
+
);
|
|
41
|
+
expect(attachments).not.toBeNull();
|
|
42
|
+
const bubble = container.querySelector(".cpk-user-message-bubble");
|
|
43
|
+
expect(
|
|
44
|
+
attachments!.compareDocumentPosition(bubble!) &
|
|
45
|
+
Node.DOCUMENT_POSITION_FOLLOWING,
|
|
46
|
+
).toBeTruthy();
|
|
47
|
+
expect(bubble!.textContent?.trim()).toBe("Look at these");
|
|
48
|
+
|
|
49
|
+
const image = within(attachments as HTMLElement).getByRole("img", {
|
|
50
|
+
name: "Image attachment",
|
|
51
|
+
});
|
|
52
|
+
expect(image.getAttribute("src")).toBe("https://example.com/cat.png");
|
|
53
|
+
|
|
54
|
+
// The filename comes from the part's metadata.
|
|
55
|
+
const link = within(attachments as HTMLElement).getByRole("link", {
|
|
56
|
+
name: "report.pdf",
|
|
57
|
+
});
|
|
58
|
+
expect(link.getAttribute("href")).toBe(
|
|
59
|
+
"data:application/pdf;base64,JVBERi0=",
|
|
60
|
+
);
|
|
61
|
+
expect(link.getAttribute("download")).toBe("report.pdf");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("renders no attachments row for a text-only message", () => {
|
|
65
|
+
const { container } = render(CopilotChatUserMessage, {
|
|
66
|
+
props: {
|
|
67
|
+
message: { id: "u", role: "user", content: "Hi" } as UserMessage,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
expect(container.querySelector(".cpk-user-message-attachments")).toBeNull();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("opens an attached image in the lightbox", async () => {
|
|
74
|
+
render(CopilotChatUserMessage, { props: { message } });
|
|
75
|
+
|
|
76
|
+
await fireEvent.click(
|
|
77
|
+
screen.getByRole("button", { name: "Image attachment" }),
|
|
78
|
+
);
|
|
79
|
+
const dialog = screen.getByRole("dialog", { name: "Image attachment" });
|
|
80
|
+
expect(
|
|
81
|
+
dialog.querySelector(".cpk-attachment-renderer-lightbox-image"),
|
|
82
|
+
).not.toBeNull();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("does not mark a multiline bubble with data-multiline, as React", () => {
|
|
86
|
+
const { container } = render(CopilotChatUserMessage, {
|
|
87
|
+
props: {
|
|
88
|
+
message: {
|
|
89
|
+
id: "u",
|
|
90
|
+
role: "user",
|
|
91
|
+
content: "one\ntwo",
|
|
92
|
+
} as UserMessage,
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
const bubble = container.querySelector(".cpk-user-message-bubble");
|
|
96
|
+
expect(bubble!.hasAttribute("data-multiline")).toBe(false);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe("CopilotChatUserMessage toolbar tooltips", () => {
|
|
101
|
+
afterEach(() => {
|
|
102
|
+
document.body.innerHTML = "";
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("shows the copy and edit labels as tooltips, not as title", async () => {
|
|
106
|
+
render(CopilotChatUserMessage, {
|
|
107
|
+
props: {
|
|
108
|
+
message: { id: "u", role: "user", content: "Hi" } as UserMessage,
|
|
109
|
+
onEditMessage: () => {},
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const copy = screen.getByRole("button", { name: "Copy" });
|
|
114
|
+
const edit = screen.getByTestId("copilot-edit-button");
|
|
115
|
+
expect(copy.hasAttribute("title")).toBe(false);
|
|
116
|
+
expect(edit.hasAttribute("title")).toBe(false);
|
|
117
|
+
|
|
118
|
+
await fireEvent.focus(copy);
|
|
119
|
+
const tooltip = screen.getByRole("tooltip");
|
|
120
|
+
expect(tooltip.textContent).toContain("Copy");
|
|
121
|
+
expect(tooltip.getAttribute("data-side")).toBe("bottom");
|
|
122
|
+
expect(copy.getAttribute("aria-describedby")).toBe(tooltip.id);
|
|
123
|
+
await fireEvent.blur(copy);
|
|
124
|
+
await nextTick();
|
|
125
|
+
|
|
126
|
+
await fireEvent.focus(edit);
|
|
127
|
+
expect(screen.getByRole("tooltip").textContent).toContain("Edit");
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("gives the branch buttons no tooltip or title, as React", async () => {
|
|
131
|
+
render(CopilotChatUserMessage, {
|
|
132
|
+
props: {
|
|
133
|
+
message: { id: "u", role: "user", content: "Hi" } as UserMessage,
|
|
134
|
+
numberOfBranches: 2,
|
|
135
|
+
onSwitchToBranch: () => {},
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
const next = screen.getByRole("button", { name: "Next branch" });
|
|
139
|
+
expect(next.hasAttribute("title")).toBe(false);
|
|
140
|
+
await fireEvent.focus(next);
|
|
141
|
+
expect(screen.queryByRole("tooltip")).toBeNull();
|
|
142
|
+
});
|
|
143
|
+
});
|
|
@@ -80,10 +80,11 @@ describe("CopilotChatView input overlay layout", () => {
|
|
|
80
80
|
await waitForMount(screen);
|
|
81
81
|
|
|
82
82
|
const overlay = screen.getByTestId("copilot-input-overlay");
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
expect(overlay.
|
|
86
|
-
|
|
83
|
+
// The shared stylesheet pins this class to the bottom of the chat
|
|
84
|
+
// (position: absolute; bottom: 0). jsdom loads no CSS, so assert the class.
|
|
85
|
+
expect(overlay.classList.contains("cpk-chat-view-input-overlay")).toBe(
|
|
86
|
+
true,
|
|
87
|
+
);
|
|
87
88
|
|
|
88
89
|
// Input (send button) lives inside the overlay, not outside it.
|
|
89
90
|
const sendButton = screen.getByTestId("copilot-chat-input-send");
|
|
@@ -1,39 +1,13 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { dirname, resolve } from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
1
|
import { describe, expect, it } from "vitest";
|
|
5
2
|
import { h } from "vue";
|
|
6
3
|
import { mount } from "@vue/test-utils";
|
|
4
|
+
import { stylesheet } from "@copilotkit/core/styles";
|
|
7
5
|
import CopilotKitProvider from "../../../providers/CopilotKitProvider.vue";
|
|
8
6
|
import CopilotChatConfigurationProvider from "../../../providers/CopilotChatConfigurationProvider.vue";
|
|
9
7
|
import CopilotChatView from "../CopilotChatView.vue";
|
|
10
8
|
|
|
11
9
|
const CHAT_ROOT_SELECTOR = ".copilotKitChat[data-copilotkit]";
|
|
12
10
|
|
|
13
|
-
// Resolve from this file, so the read does not depend on the working directory.
|
|
14
|
-
// (A `new URL(...)` object fails here: under jsdom it is not Node's URL.)
|
|
15
|
-
const globalsCss = readFileSync(
|
|
16
|
-
resolve(
|
|
17
|
-
dirname(fileURLToPath(import.meta.url)),
|
|
18
|
-
"../../../../styles/globals.css",
|
|
19
|
-
),
|
|
20
|
-
{ encoding: "utf8" },
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
/** Returns the body of the first `@layer <name> { ... }` block. */
|
|
24
|
-
function layerBody(css: string, name: string): string {
|
|
25
|
-
const start = css.indexOf(`@layer ${name} {`);
|
|
26
|
-
if (start === -1) return "";
|
|
27
|
-
let depth = 0;
|
|
28
|
-
for (let i = css.indexOf("{", start); i < css.length; i++) {
|
|
29
|
-
if (css[i] === "{") depth++;
|
|
30
|
-
if (css[i] === "}" && --depth === 0) {
|
|
31
|
-
return css.slice(css.indexOf("{", start) + 1, i);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return "";
|
|
35
|
-
}
|
|
36
|
-
|
|
37
11
|
function mountChatView(props: Record<string, unknown>) {
|
|
38
12
|
return mount(CopilotKitProvider, {
|
|
39
13
|
props: { runtimeUrl: "/api/copilotkit" },
|
|
@@ -49,14 +23,14 @@ function mountChatView(props: Record<string, unknown>) {
|
|
|
49
23
|
}
|
|
50
24
|
|
|
51
25
|
// PE-1053, the Vue side of PE-788: the chat root is an inline-size container
|
|
52
|
-
// (
|
|
26
|
+
// (`.cpk-chat-view`), so its content gives it no intrinsic width. As a flex
|
|
53
27
|
// item in a row its auto width collapsed to a narrow column. jsdom does no
|
|
54
|
-
// layout, so these tests pin the two halves of the fix: the
|
|
55
|
-
// rule, and a chat root that the rule's
|
|
28
|
+
// layout, so these tests pin the two halves of the fix: the zero-specificity
|
|
29
|
+
// width rule in the shared stylesheet, and a chat root that the rule's
|
|
30
|
+
// selector matches.
|
|
56
31
|
describe("CopilotChatView root width (PE-1053)", () => {
|
|
57
|
-
it("fills its container
|
|
58
|
-
|
|
59
|
-
expect(base).toContain(`${CHAT_ROOT_SELECTOR} { width: 100%; }`);
|
|
32
|
+
it("fills its container with a :where() rule, so app widths still win", () => {
|
|
33
|
+
expect(stylesheet).toContain(`:where(${CHAT_ROOT_SELECTOR}){width:100%}`);
|
|
60
34
|
});
|
|
61
35
|
|
|
62
36
|
// The welcome screen and the message view share this one root element.
|
|
@@ -95,7 +95,7 @@ describe("CopilotModalHeader Slot System E2E Tests", () => {
|
|
|
95
95
|
|
|
96
96
|
const title = screen.getByTestId("custom-title");
|
|
97
97
|
expect(title.classList.contains("custom-title-class")).toBe(true);
|
|
98
|
-
expect(title.classList.contains("cpk
|
|
98
|
+
expect(title.classList.contains("cpk-modal-header-title")).toBe(true);
|
|
99
99
|
});
|
|
100
100
|
});
|
|
101
101
|
|
|
@@ -540,7 +540,7 @@ describe("CopilotPopupView Slot System E2E Tests", () => {
|
|
|
540
540
|
});
|
|
541
541
|
|
|
542
542
|
describe("8. Integration Tests", () => {
|
|
543
|
-
it("keeps the
|
|
543
|
+
it("keeps the positioning wrapper class on the popup's parent", () => {
|
|
544
544
|
const Host = defineComponent({
|
|
545
545
|
components: { CopilotPopupView },
|
|
546
546
|
setup() {
|
|
@@ -554,8 +554,8 @@ describe("CopilotPopupView Slot System E2E Tests", () => {
|
|
|
554
554
|
const positioningWrapper = popup?.parentElement;
|
|
555
555
|
|
|
556
556
|
expect(positioningWrapper?.hasAttribute("data-copilotkit")).toBe(true);
|
|
557
|
-
// jsdom does not load the
|
|
558
|
-
expect(positioningWrapper?.classList.contains("cpk
|
|
557
|
+
// jsdom does not load the stylesheet; this guards the class contract only.
|
|
558
|
+
expect(positioningWrapper?.classList.contains("cpk-popup-view")).toBe(
|
|
559
559
|
true,
|
|
560
560
|
);
|
|
561
561
|
});
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { h } from "vue";
|
|
3
|
+
import { mount } from "@vue/test-utils";
|
|
4
|
+
import type { Message } from "@ag-ui/core";
|
|
5
|
+
import { stylesheet } from "@copilotkit/core/styles";
|
|
6
|
+
import CopilotKitProvider from "../../../providers/CopilotKitProvider.vue";
|
|
7
|
+
import { StateCapturingAgent } from "../../../__tests__/utils/agents";
|
|
8
|
+
import CopilotSidebar from "../CopilotSidebar.vue";
|
|
9
|
+
import { CopilotSidebarView } from "../index";
|
|
10
|
+
|
|
11
|
+
// Ported from react-core's CopilotSidebarView.position.test.tsx.
|
|
12
|
+
|
|
13
|
+
const sampleMessages: Message[] = [
|
|
14
|
+
{ id: "1", role: "user", content: "Hello", timestamp: new Date() } as Message,
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
/** Declarations of the stylesheet's `:where(<selector>)` rule, outside media queries. */
|
|
18
|
+
function cssRule(selector: string): string {
|
|
19
|
+
const start = stylesheet.indexOf(`}:where(${selector}){`);
|
|
20
|
+
if (start === -1) throw new Error(`no rule for ${selector}`);
|
|
21
|
+
const body = stylesheet.indexOf("{", start + 1) + 1;
|
|
22
|
+
return stylesheet.slice(body, stylesheet.indexOf("}", body));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function mountSidebarView(props: Record<string, unknown> = {}) {
|
|
26
|
+
return mount(CopilotKitProvider, {
|
|
27
|
+
props: { runtimeUrl: "/api/copilotkit" },
|
|
28
|
+
slots: {
|
|
29
|
+
default: () =>
|
|
30
|
+
h(CopilotSidebarView, { messages: sampleMessages, ...props }),
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function mountSidebar(props: Record<string, unknown> = {}) {
|
|
36
|
+
return mount(CopilotKitProvider, {
|
|
37
|
+
props: { agents__unsafe_dev_only: { default: new StateCapturingAgent() } },
|
|
38
|
+
slots: { default: () => h(CopilotSidebar, props) },
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
describe("CopilotSidebarView position prop", () => {
|
|
43
|
+
describe("CopilotSidebarView", () => {
|
|
44
|
+
it("defaults to right-anchored when position is omitted", () => {
|
|
45
|
+
const aside = mountSidebarView().get("[data-copilot-sidebar]");
|
|
46
|
+
expect(aside.classes()).toContain("cpk-sidebar-view");
|
|
47
|
+
expect(aside.attributes("data-position")).toBe("right");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('renders right-anchored when position="right" explicitly', () => {
|
|
51
|
+
const aside = mountSidebarView({ position: "right" }).get(
|
|
52
|
+
"[data-copilot-sidebar]",
|
|
53
|
+
);
|
|
54
|
+
expect(aside.attributes("data-position")).toBe("right");
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('renders left-anchored when position="left"', () => {
|
|
58
|
+
const aside = mountSidebarView({ position: "left" }).get(
|
|
59
|
+
"[data-copilot-sidebar]",
|
|
60
|
+
);
|
|
61
|
+
expect(aside.classes()).toContain("cpk-sidebar-view");
|
|
62
|
+
expect(aside.attributes("data-position")).toBe("left");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('slides off to the left when closed and position="left"', () => {
|
|
66
|
+
const aside = mountSidebarView({
|
|
67
|
+
position: "left",
|
|
68
|
+
defaultOpen: false,
|
|
69
|
+
}).get("[data-copilot-sidebar]");
|
|
70
|
+
expect(aside.classes()).toContain("cpk-sidebar-view-closed");
|
|
71
|
+
expect(aside.attributes("data-position")).toBe("left");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('anchors the toggle button to the left when position="left"', () => {
|
|
75
|
+
const toggle = mountSidebarView({ position: "left" }).get(
|
|
76
|
+
'[data-slot="chat-toggle-button"]',
|
|
77
|
+
);
|
|
78
|
+
expect(toggle.classes()).toContain("cpk-sidebar-view-toggle-button-left");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("keeps the toggle button right-anchored by default", () => {
|
|
82
|
+
const toggle = mountSidebarView().get('[data-slot="chat-toggle-button"]');
|
|
83
|
+
expect(toggle.classes()).toContain("cpk-chat-toggle-button");
|
|
84
|
+
expect(toggle.classes()).not.toContain(
|
|
85
|
+
"cpk-sidebar-view-toggle-button-left",
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("makes room for the sidebar on the edge it docks to", () => {
|
|
90
|
+
const left = mountSidebarView({ position: "left", width: 400 });
|
|
91
|
+
expect(left.html()).toContain("margin-inline-start: 400px");
|
|
92
|
+
expect(left.html()).not.toContain("margin-inline-end");
|
|
93
|
+
|
|
94
|
+
const right = mountSidebarView({ width: 400 });
|
|
95
|
+
expect(right.html()).toContain("margin-inline-end: 400px");
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// jsdom does no layout, so these pin the rules the attributes above rely on.
|
|
100
|
+
describe("stylesheet", () => {
|
|
101
|
+
it("docks left for data-position=left", () => {
|
|
102
|
+
const left = cssRule(".cpk-sidebar-view[data-position=left]");
|
|
103
|
+
expect(left).toContain("right:auto;left:0");
|
|
104
|
+
expect(cssRule(".cpk-sidebar-view-closed[data-position=left]")).toBe(
|
|
105
|
+
"translate:-100% 0",
|
|
106
|
+
);
|
|
107
|
+
expect(cssRule(".cpk-sidebar-view-toggle-button-left")).toBe(
|
|
108
|
+
"right:auto;left:1.5rem",
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe("CopilotSidebar wrapper", () => {
|
|
114
|
+
it('forwards position="left" through to CopilotSidebarView', () => {
|
|
115
|
+
const aside = mountSidebar({ position: "left" }).get(
|
|
116
|
+
"[data-copilot-sidebar]",
|
|
117
|
+
);
|
|
118
|
+
expect(aside.attributes("data-position")).toBe("left");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("defaults to right-anchored when position is omitted", () => {
|
|
122
|
+
const aside = mountSidebar().get("[data-copilot-sidebar]");
|
|
123
|
+
expect(aside.attributes("data-position")).toBe("right");
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import type { Component } from "vue";
|
|
3
|
+
import CopilotChat from "../CopilotChat.vue";
|
|
4
|
+
import CopilotChatView from "../CopilotChatView.vue";
|
|
5
|
+
import CopilotChatMessageView from "../CopilotChatMessageView.vue";
|
|
6
|
+
import CopilotPopup from "../CopilotPopup.vue";
|
|
7
|
+
import CopilotPopupView from "../CopilotPopupView.vue";
|
|
8
|
+
import CopilotSidebar from "../CopilotSidebar.vue";
|
|
9
|
+
import CopilotSidebarView from "../CopilotSidebarView.vue";
|
|
10
|
+
|
|
11
|
+
type WithProps = { props?: Record<string, { default?: unknown }> };
|
|
12
|
+
|
|
13
|
+
// Vue turns a missing boolean prop into `false`, so each component that
|
|
14
|
+
// declares `messageFeedback` must default it to `true`, or it would turn
|
|
15
|
+
// reply ratings off for every chat built on it.
|
|
16
|
+
describe("messageFeedback defaults", () => {
|
|
17
|
+
it.each([
|
|
18
|
+
["CopilotChat", CopilotChat],
|
|
19
|
+
["CopilotChatView", CopilotChatView],
|
|
20
|
+
["CopilotChatMessageView", CopilotChatMessageView],
|
|
21
|
+
["CopilotPopup", CopilotPopup],
|
|
22
|
+
["CopilotPopupView", CopilotPopupView],
|
|
23
|
+
["CopilotSidebar", CopilotSidebar],
|
|
24
|
+
["CopilotSidebarView", CopilotSidebarView],
|
|
25
|
+
] as [string, Component][])(
|
|
26
|
+
"%s defaults messageFeedback to true",
|
|
27
|
+
(_, component) => {
|
|
28
|
+
const props = (component as WithProps).props;
|
|
29
|
+
expect(props?.messageFeedback).toBeDefined();
|
|
30
|
+
expect(props?.messageFeedback?.default).toBe(true);
|
|
31
|
+
},
|
|
32
|
+
);
|
|
33
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { h } from "vue";
|
|
3
|
+
import type { Component } from "vue";
|
|
4
|
+
import { mount } from "@vue/test-utils";
|
|
5
|
+
import CopilotKitProvider from "../../../providers/CopilotKitProvider.vue";
|
|
6
|
+
import { StateCapturingAgent } from "../../../__tests__/utils/agents";
|
|
7
|
+
import CopilotChatMessageView from "../CopilotChatMessageView.vue";
|
|
8
|
+
import CopilotPopup from "../CopilotPopup.vue";
|
|
9
|
+
import CopilotSidebar from "../CopilotSidebar.vue";
|
|
10
|
+
|
|
11
|
+
function mountChat(component: Component, props: Record<string, unknown>) {
|
|
12
|
+
return mount(CopilotKitProvider, {
|
|
13
|
+
props: { agents__unsafe_dev_only: { default: new StateCapturingAgent() } },
|
|
14
|
+
slots: {
|
|
15
|
+
default: () => h(component, { welcomeScreen: false, ...props }),
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// The sidebar and popup draw their chat through their own views, which must
|
|
21
|
+
// pass the message view's display settings on.
|
|
22
|
+
describe.each([
|
|
23
|
+
["CopilotSidebar", CopilotSidebar],
|
|
24
|
+
["CopilotPopup", CopilotPopup],
|
|
25
|
+
] as [string, Component][])("%s message view settings", (_, component) => {
|
|
26
|
+
it("passes toolCallDisplay and messageFeedback to the message view", () => {
|
|
27
|
+
const wrapper = mountChat(component, {
|
|
28
|
+
toolCallDisplay: "line",
|
|
29
|
+
messageFeedback: false,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const view = wrapper.findComponent(CopilotChatMessageView);
|
|
33
|
+
expect(view.props("toolCallDisplay")).toBe("line");
|
|
34
|
+
expect(view.props("messageFeedback")).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("keeps reply ratings on by default", () => {
|
|
38
|
+
const wrapper = mountChat(component, {});
|
|
39
|
+
|
|
40
|
+
const view = wrapper.findComponent(CopilotChatMessageView);
|
|
41
|
+
expect(view.props("toolCallDisplay")).toBe("grouped");
|
|
42
|
+
expect(view.props("messageFeedback")).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -13,7 +13,9 @@ export { default as CopilotChatReasoningMessage } from "./CopilotChatReasoningMe
|
|
|
13
13
|
export { default as CopilotChatSuggestionPill } from "./CopilotChatSuggestionPill.vue";
|
|
14
14
|
export { default as CopilotChatSuggestionView } from "./CopilotChatSuggestionView.vue";
|
|
15
15
|
export { default as CopilotChatToolCallsView } from "./CopilotChatToolCallsView.vue";
|
|
16
|
+
export { default as CopilotChatToolCallGroup } from "./CopilotChatToolCallGroup.vue";
|
|
16
17
|
export { default as CopilotChatUserMessage } from "./CopilotChatUserMessage.vue";
|
|
18
|
+
export { default as CopilotChatWorkSummary } from "./CopilotChatWorkSummary.vue";
|
|
17
19
|
export { default as CopilotChatView } from "./CopilotChatView.vue";
|
|
18
20
|
export { default as CopilotThreadsDrawer } from "./CopilotThreadsDrawer.vue";
|
|
19
21
|
import _CopilotChatToggleButton from "./CopilotChatToggleButton.vue";
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { onBeforeUnmount, readonly, ref } from "vue";
|
|
2
|
+
import type { Ref } from "vue";
|
|
3
|
+
|
|
4
|
+
// Page-lifetime preference, shared by every message and chat. Deliberately
|
|
5
|
+
// avoid sessionStorage: it survives reloads, while this preference must not.
|
|
6
|
+
let shortcutsHidden = false;
|
|
7
|
+
const listeners = new Set<() => void>();
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Whether the user hid the Inspector buttons in the message toolbars ("Hide
|
|
11
|
+
* this icon"), until the page reloads.
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export function useInspectorShortcutsHidden(): Readonly<Ref<boolean>> {
|
|
15
|
+
const hidden = ref(shortcutsHidden);
|
|
16
|
+
const listener = () => {
|
|
17
|
+
hidden.value = shortcutsHidden;
|
|
18
|
+
};
|
|
19
|
+
listeners.add(listener);
|
|
20
|
+
onBeforeUnmount(() => listeners.delete(listener));
|
|
21
|
+
return readonly(hidden);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Hides the Inspector buttons of every message until the page reloads. */
|
|
25
|
+
export function hideInspectorShortcuts(): void {
|
|
26
|
+
shortcutsHidden = true;
|
|
27
|
+
listeners.forEach((listener) => listener());
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** @internal Shows the buttons again, so each test starts fresh. */
|
|
31
|
+
export function ɵresetInspectorShortcuts(): void {
|
|
32
|
+
shortcutsHidden = false;
|
|
33
|
+
listeners.forEach((listener) => listener());
|
|
34
|
+
}
|