@copilotkit/vue 2.0.0-rc.20 → 2.0.0-rc.21
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/dist/index.cjs +1 -1
- package/dist/index.mjs +13 -13
- package/dist/use-render-activity-message-BAhbpSDh.js +16200 -0
- package/dist/use-render-activity-message-BAhbpSDh.js.map +1 -0
- package/dist/use-render-activity-message-DJ6q1qHV.cjs +114 -0
- package/dist/use-render-activity-message-DJ6q1qHV.cjs.map +1 -0
- package/dist/v2/components/A2UIMessageRenderer.d.ts +14 -0
- package/dist/v2/components/A2UIMessageRenderer.d.ts.map +1 -1
- package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts +10 -3
- package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts.map +1 -1
- package/dist/v2/components/CopilotKitInspector.vue.d.ts +5 -1
- package/dist/v2/components/CopilotKitInspector.vue.d.ts.map +1 -1
- package/dist/v2/components/MCPAppsActivityRenderer.d.ts.map +1 -1
- package/dist/v2/components/OpenGenerativeUIRenderer.d.ts +7 -21
- package/dist/v2/components/OpenGenerativeUIRenderer.d.ts.map +1 -1
- package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts +0 -5
- package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts.map +1 -1
- package/dist/v2/components/a2ui/A2UICatalogContext.d.ts +10 -15
- package/dist/v2/components/a2ui/A2UICatalogContext.d.ts.map +1 -1
- package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts +14 -138
- package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts.map +1 -1
- package/dist/v2/components/a2ui/catalog.d.ts.map +1 -1
- package/dist/v2/components/a2ui/utils.d.ts +3 -15
- package/dist/v2/components/a2ui/utils.d.ts.map +1 -1
- package/dist/v2/components/a2ui.d.ts +6 -1
- package/dist/v2/components/a2ui.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChat.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatAttachmentQueue.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatAudioRecorder.vue.d.ts +4 -8
- package/dist/v2/components/chat/CopilotChatAudioRecorder.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatInput.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatLightbox.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatToolCallItem.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatView.vue.d.ts +1 -1
- package/dist/v2/components/chat/CopilotChatView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts +1 -1
- package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts +1 -1
- package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotThreadsDrawer.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/StreamingMarkdownDefault.vue.d.ts +1 -0
- package/dist/v2/components/chat/StreamingMarkdownDefault.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/audioRecorder.d.ts +3 -4
- package/dist/v2/components/chat/audioRecorder.d.ts.map +1 -1
- package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts +3 -2
- package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts.map +1 -1
- package/dist/v2/components/chat/index.d.ts +6 -6
- package/dist/v2/components/chat/tool-call-display-context.d.ts +3 -1
- package/dist/v2/components/chat/tool-call-display-context.d.ts.map +1 -1
- package/dist/v2/components/chat/tool-call-group-parts.d.ts.map +1 -1
- package/dist/v2/components/chat/types.d.ts +1 -1
- package/dist/v2/components/chat/types.d.ts.map +1 -1
- package/dist/v2/components/chat/use-lightbox.d.ts.map +1 -1
- package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts +1 -1
- package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts.map +1 -1
- package/dist/v2/hooks/use-agent-context.d.ts +2 -3
- package/dist/v2/hooks/use-agent-context.d.ts.map +1 -1
- package/dist/v2/hooks/use-agent.d.ts +4 -1
- package/dist/v2/hooks/use-agent.d.ts.map +1 -1
- package/dist/v2/hooks/use-attachments.d.ts +7 -0
- package/dist/v2/hooks/use-attachments.d.ts.map +1 -1
- package/dist/v2/hooks/use-capabilities.d.ts.map +1 -1
- package/dist/v2/hooks/use-component.d.ts +1 -0
- package/dist/v2/hooks/use-component.d.ts.map +1 -1
- package/dist/v2/hooks/use-configure-suggestions.d.ts +4 -9
- package/dist/v2/hooks/use-configure-suggestions.d.ts.map +1 -1
- package/dist/v2/hooks/use-default-render-tool.d.ts.map +1 -1
- package/dist/v2/hooks/use-human-in-the-loop.d.ts +2 -1
- package/dist/v2/hooks/use-human-in-the-loop.d.ts.map +1 -1
- package/dist/v2/hooks/use-interrupt.d.ts +0 -1
- package/dist/v2/hooks/use-interrupt.d.ts.map +1 -1
- package/dist/v2/hooks/use-render-activity-message.d.ts.map +1 -1
- package/dist/v2/hooks/use-render-custom-messages.d.ts.map +1 -1
- package/dist/v2/hooks/use-suggestions.d.ts.map +1 -1
- package/dist/v2/hooks/use-threads.d.ts +0 -8
- package/dist/v2/hooks/use-threads.d.ts.map +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.mjs +1 -1
- package/dist/v2/lib/vue-core.d.ts +12 -11
- package/dist/v2/lib/vue-core.d.ts.map +1 -1
- package/dist/v2/providers/CopilotChatConfigurationProvider.vue.d.ts.map +1 -1
- package/dist/v2/providers/CopilotKitProvider.types.d.ts +9 -124
- package/dist/v2/providers/CopilotKitProvider.types.d.ts.map +1 -1
- package/dist/v2/providers/CopilotKitProvider.vue.d.ts +9 -10
- package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
- package/dist/v2/providers/chat-configuration-store-key.d.ts +8 -0
- package/dist/v2/providers/chat-configuration-store-key.d.ts.map +1 -0
- package/dist/v2/providers/markdown-renderer.d.ts +3 -1
- package/dist/v2/providers/markdown-renderer.d.ts.map +1 -1
- package/dist/v2/providers/use-inspector-thread-override.d.ts +5 -0
- package/dist/v2/providers/use-inspector-thread-override.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/v2/__tests__/exports.test.ts +10 -0
- package/src/v2/__tests__/mocks/web-inspector.ts +6 -0
- package/src/v2/__tests__/utils/test-helpers.ts +34 -4
- package/src/v2/components/A2UIMessageRenderer.ts +98 -68
- package/src/v2/components/A2UISurfaceActivityRenderer.vue +68 -103
- package/src/v2/components/CopilotKitInspector.vue +104 -51
- package/src/v2/components/MCPAppsActivityRenderer.ts +75 -201
- package/src/v2/components/OpenGenerativeUIRenderer.ts +78 -80
- package/src/v2/components/__tests__/A2UIMessageRenderer.test.ts +171 -8
- package/src/v2/components/__tests__/CopilotKitInspector.test.ts +42 -0
- package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.ts +9 -2
- package/src/v2/components/__tests__/OpenGenerativeUIToolRenderer.test.ts +38 -0
- package/src/v2/components/a2ui/A2UIBuiltInToolCallRenderer.ts +1 -6
- package/src/v2/components/a2ui/A2UICatalogContext.ts +27 -93
- package/src/v2/components/a2ui/A2UIRecoveryStates.ts +127 -327
- package/src/v2/components/a2ui/catalog.ts +2 -3
- package/src/v2/components/a2ui/utils.ts +13 -67
- package/src/v2/components/a2ui.ts +14 -21
- package/src/v2/components/chat/CopilotChat.vue +136 -324
- package/src/v2/components/chat/CopilotChatAttachmentQueue.vue +22 -45
- package/src/v2/components/chat/CopilotChatAudioRecorder.vue +19 -246
- package/src/v2/components/chat/CopilotChatInput.vue +69 -407
- package/src/v2/components/chat/CopilotChatLightbox.vue +10 -31
- package/src/v2/components/chat/CopilotChatMessageView.vue +52 -112
- package/src/v2/components/chat/CopilotChatToolCallGroup.vue +14 -45
- package/src/v2/components/chat/CopilotChatToolCallItem.vue +6 -4
- package/src/v2/components/chat/CopilotChatToolCallsView.vue +16 -19
- package/src/v2/components/chat/CopilotChatView.vue +28 -23
- package/src/v2/components/chat/CopilotPopupViewInternal.vue +21 -97
- package/src/v2/components/chat/CopilotSidebarViewInternal.vue +24 -25
- package/src/v2/components/chat/CopilotThreadsDrawer.vue +37 -102
- package/src/v2/components/chat/StreamingMarkdownDefault.vue +13 -26
- package/src/v2/components/chat/__tests__/CopilotChat.test.ts +12 -10
- package/src/v2/components/chat/__tests__/CopilotChatAttachmentQueue.test.ts +28 -0
- package/src/v2/components/chat/__tests__/CopilotChatInput.test.ts +56 -0
- package/src/v2/components/chat/__tests__/CopilotPopupView.test.ts +19 -0
- package/src/v2/components/chat/__tests__/CopilotSidebarView.position.test.ts +32 -8
- package/src/v2/components/chat/__tests__/CopilotSidebarView.test.ts +2 -1
- package/src/v2/components/chat/__tests__/StreamingMarkdownDefault.test.ts +54 -0
- package/src/v2/components/chat/audioRecorder.ts +4 -7
- package/src/v2/components/chat/copilotChatToolCallItemRender.ts +22 -71
- package/src/v2/components/chat/tool-call-display-context.ts +6 -1
- package/src/v2/components/chat/tool-call-group-parts.ts +13 -33
- package/src/v2/components/chat/types.ts +1 -1
- package/src/v2/components/chat/use-lightbox.ts +15 -33
- package/src/v2/hooks/__tests__/use-agent-error-state.test.ts +5 -3
- package/src/v2/hooks/__tests__/use-agent-stability.test.ts +25 -4
- package/src/v2/hooks/__tests__/use-agent-throttle.test.ts +5 -1
- package/src/v2/hooks/__tests__/use-agent.test.ts +6 -3
- package/src/v2/hooks/__tests__/use-component.test.ts +21 -0
- package/src/v2/hooks/__tests__/use-configure-suggestions.test.ts +30 -1
- package/src/v2/hooks/__tests__/use-default-render-tool.test.ts +10 -10
- package/src/v2/hooks/__tests__/use-frontend-tool.e2e.test.ts +4 -0
- package/src/v2/hooks/__tests__/use-human-in-the-loop.e2e.test.ts +6 -1
- package/src/v2/hooks/__tests__/use-human-in-the-loop.test.ts +187 -12
- package/src/v2/hooks/__tests__/use-interrupt.test.ts +97 -0
- package/src/v2/hooks/__tests__/use-render-activity-message.test.ts +2 -1
- package/src/v2/hooks/__tests__/use-threads.test.ts +48 -6
- package/src/v2/hooks/use-agent-context.ts +4 -10
- package/src/v2/hooks/use-agent.ts +86 -290
- package/src/v2/hooks/use-attachments.ts +42 -166
- package/src/v2/hooks/use-capabilities.ts +2 -7
- package/src/v2/hooks/use-component.ts +7 -4
- package/src/v2/hooks/use-configure-suggestions.ts +28 -218
- package/src/v2/hooks/use-default-render-tool.ts +34 -94
- package/src/v2/hooks/use-human-in-the-loop.ts +11 -80
- package/src/v2/hooks/use-interrupt.ts +29 -308
- package/src/v2/hooks/use-render-activity-message.ts +17 -20
- package/src/v2/hooks/use-render-custom-messages.ts +20 -63
- package/src/v2/hooks/use-suggestions.ts +9 -33
- package/src/v2/hooks/use-threads.ts +43 -273
- package/src/v2/lib/__tests__/vue-core-renderers.test.ts +42 -0
- package/src/v2/lib/vue-core.ts +67 -72
- package/src/v2/providers/CopilotChatConfigurationProvider.vue +48 -186
- package/src/v2/providers/CopilotKitProvider.types.ts +12 -127
- package/src/v2/providers/CopilotKitProvider.vue +188 -402
- package/src/v2/providers/__tests__/CopilotChatConfigurationProvider.test.ts +22 -2
- package/src/v2/providers/__tests__/CopilotKitProvider.a2ui.test.ts +19 -1
- package/src/v2/providers/__tests__/CopilotKitProvider.config.test.ts +124 -0
- package/src/v2/providers/__tests__/CopilotKitProvider.sandboxFunctions.test.ts +4 -1
- package/src/v2/providers/__tests__/CopilotKitProvider.test.ts +45 -2
- package/src/v2/providers/chat-configuration-store-key.ts +9 -0
- package/src/v2/providers/markdown-renderer.ts +7 -1
- package/src/v2/providers/use-inspector-thread-override.ts +22 -80
- package/vite.config.ts +5 -1
- package/vitest.config.ts +12 -7
- package/dist/use-render-activity-message-CsWYyd6r.cjs +0 -91
- package/dist/use-render-activity-message-CsWYyd6r.cjs.map +0 -1
- package/dist/use-render-activity-message-DntKKNdd.js +0 -17418
- package/dist/use-render-activity-message-DntKKNdd.js.map +0 -1
- package/dist/v2/components/chat/normalize-auto-scroll.d.ts +0 -3
- package/dist/v2/components/chat/normalize-auto-scroll.d.ts.map +0 -1
- package/dist/v2/lib/is-mobile-viewport.d.ts +0 -2
- package/dist/v2/lib/is-mobile-viewport.d.ts.map +0 -1
- package/src/v2/components/__tests__/A2UICatalogContext.test.ts +0 -63
- package/src/v2/components/a2ui/__tests__/A2UIRecoveryStates.test.ts +0 -175
- package/src/v2/components/chat/normalize-auto-scroll.ts +0 -3
- package/src/v2/lib/is-mobile-viewport.ts +0 -5
|
@@ -115,6 +115,25 @@ describe("CopilotPopupView", () => {
|
|
|
115
115
|
expect(reopened.find("[data-copilot-popup]").exists()).toBe(false);
|
|
116
116
|
});
|
|
117
117
|
|
|
118
|
+
it("stays open for a pointer down in a chat popover outside the panel", async () => {
|
|
119
|
+
const wrapper = mountPopupView({ clickOutsideToClose: true });
|
|
120
|
+
// Popovers, such as a reply rating's comment, render in a portal.
|
|
121
|
+
const popover = document.createElement("div");
|
|
122
|
+
popover.setAttribute("data-copilotkit-popover", "");
|
|
123
|
+
const field = document.createElement("textarea");
|
|
124
|
+
popover.append(field);
|
|
125
|
+
document.body.append(popover);
|
|
126
|
+
|
|
127
|
+
field.dispatchEvent(new Event("pointerdown", { bubbles: true }));
|
|
128
|
+
await nextTick();
|
|
129
|
+
vi.advanceTimersByTime(200);
|
|
130
|
+
await nextTick();
|
|
131
|
+
|
|
132
|
+
expect(wrapper.find("[data-copilot-popup]").exists()).toBe(true);
|
|
133
|
+
popover.remove();
|
|
134
|
+
wrapper.unmount();
|
|
135
|
+
});
|
|
136
|
+
|
|
118
137
|
it("ignores outside-close detection when the toggle button is clicked and supports custom slots", async () => {
|
|
119
138
|
const wrapper = mountPopupView(
|
|
120
139
|
{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
1
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
2
2
|
import { h } from "vue";
|
|
3
3
|
import { mount } from "@vue/test-utils";
|
|
4
4
|
import type { Message } from "@ag-ui/core";
|
|
@@ -22,21 +22,31 @@ function cssRule(selector: string): string {
|
|
|
22
22
|
return stylesheet.slice(body, stylesheet.indexOf("}", body));
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
/** Mounted sidebars. Only one docked sidebar may own the page margin. */
|
|
26
|
+
const mounted: { unmount: () => void }[] = [];
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
for (const wrapper of mounted.splice(0)) wrapper.unmount();
|
|
29
|
+
});
|
|
30
|
+
|
|
25
31
|
function mountSidebarView(props: Record<string, unknown> = {}) {
|
|
26
|
-
|
|
32
|
+
const wrapper = mount(CopilotKitProvider, {
|
|
27
33
|
props: { runtimeUrl: "/api/copilotkit" },
|
|
28
34
|
slots: {
|
|
29
35
|
default: () =>
|
|
30
36
|
h(CopilotSidebarView, { messages: sampleMessages, ...props }),
|
|
31
37
|
},
|
|
32
38
|
});
|
|
39
|
+
mounted.push(wrapper);
|
|
40
|
+
return wrapper;
|
|
33
41
|
}
|
|
34
42
|
|
|
35
43
|
function mountSidebar(props: Record<string, unknown> = {}) {
|
|
36
|
-
|
|
44
|
+
const wrapper = mount(CopilotKitProvider, {
|
|
37
45
|
props: { agents__unsafe_dev_only: { default: new StateCapturingAgent() } },
|
|
38
46
|
slots: { default: () => h(CopilotSidebar, props) },
|
|
39
47
|
});
|
|
48
|
+
mounted.push(wrapper);
|
|
49
|
+
return wrapper;
|
|
40
50
|
}
|
|
41
51
|
|
|
42
52
|
describe("CopilotSidebarView position prop", () => {
|
|
@@ -87,12 +97,26 @@ describe("CopilotSidebarView position prop", () => {
|
|
|
87
97
|
});
|
|
88
98
|
|
|
89
99
|
it("makes room for the sidebar on the edge it docks to", () => {
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
expect(
|
|
100
|
+
const body = document.body.style;
|
|
101
|
+
mountSidebarView({ position: "left", width: 400 });
|
|
102
|
+
expect(body.marginInlineStart).toBe("400px");
|
|
103
|
+
expect(body.marginInlineEnd).toBe("");
|
|
104
|
+
mounted.pop()?.unmount();
|
|
105
|
+
|
|
106
|
+
mountSidebarView({ width: 400 });
|
|
107
|
+
expect(body.marginInlineEnd).toBe("400px");
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("gives the page its own margins back on unmount", () => {
|
|
111
|
+
const body = document.body.style;
|
|
112
|
+
body.marginInlineEnd = "16px";
|
|
113
|
+
mountSidebarView({ width: 400 });
|
|
114
|
+
expect(body.marginInlineEnd).toBe("400px");
|
|
115
|
+
|
|
116
|
+
mounted.pop()?.unmount();
|
|
93
117
|
|
|
94
|
-
|
|
95
|
-
|
|
118
|
+
expect(body.marginInlineEnd).toBe("16px");
|
|
119
|
+
body.marginInlineEnd = "";
|
|
96
120
|
});
|
|
97
121
|
});
|
|
98
122
|
|
|
@@ -91,7 +91,8 @@ describe("CopilotSidebarView", () => {
|
|
|
91
91
|
const sidebar = wrapper.get("[data-copilot-sidebar]");
|
|
92
92
|
expect(sidebar.attributes("aria-hidden")).toBe("false");
|
|
93
93
|
expect(sidebar.attributes("style")).toContain("--sidebar-width: 612px");
|
|
94
|
-
expect(
|
|
94
|
+
expect(document.body.style.marginInlineEnd).toBe("612px");
|
|
95
|
+
wrapper.unmount();
|
|
95
96
|
});
|
|
96
97
|
|
|
97
98
|
it("applies explicit width and renders default header and toggle button", () => {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { render, fireEvent } from "@testing-library/vue";
|
|
3
|
+
import StreamingMarkdownDefault from "../StreamingMarkdownDefault.vue";
|
|
4
|
+
|
|
5
|
+
function renderDefault(props: Record<string, unknown>) {
|
|
6
|
+
return render(StreamingMarkdownDefault, { props }).container;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
describe("StreamingMarkdownDefault (vue)", () => {
|
|
10
|
+
it("renders nothing for empty content", () => {
|
|
11
|
+
expect(renderDefault({ content: "" }).innerHTML).toBe("<!--v-if-->");
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("renders fenced code with the shared code block class", () => {
|
|
15
|
+
const pre = renderDefault({ content: "```ts\nx\n```" }).querySelector(
|
|
16
|
+
"pre",
|
|
17
|
+
);
|
|
18
|
+
expect(pre?.classList.contains("cpk-markdown-code-block")).toBe(true);
|
|
19
|
+
expect(pre?.querySelector("code")?.getAttribute("data-code-info")).toBe(
|
|
20
|
+
"ts",
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("shows the caret only while streaming", () => {
|
|
25
|
+
const caret = "[data-streaming-markdown-caret]";
|
|
26
|
+
expect(
|
|
27
|
+
renderDefault({ content: "Hi", isStreaming: true }).querySelector(caret),
|
|
28
|
+
).not.toBeNull();
|
|
29
|
+
expect(renderDefault({ content: "Hi" }).querySelector(caret)).toBeNull();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("passes link and citation clicks to the callbacks", async () => {
|
|
33
|
+
const calls: string[] = [];
|
|
34
|
+
const container = renderDefault({
|
|
35
|
+
content:
|
|
36
|
+
"[link](https://example.com) cite [^ref]\n\n[^ref]: Ref https://example.org",
|
|
37
|
+
onLinkClick: (event: MouseEvent, url: string) => {
|
|
38
|
+
event.preventDefault();
|
|
39
|
+
calls.push(`link:${url}`);
|
|
40
|
+
},
|
|
41
|
+
onCitationClick: (event: MouseEvent, citation: { id: string }) => {
|
|
42
|
+
event.preventDefault();
|
|
43
|
+
calls.push(`cite:${citation.id}`);
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
await fireEvent.click(
|
|
47
|
+
container.querySelector('a[href="https://example.com"]')!,
|
|
48
|
+
);
|
|
49
|
+
await fireEvent.click(
|
|
50
|
+
container.querySelector('sup a[role="doc-noteref"]')!,
|
|
51
|
+
);
|
|
52
|
+
expect(calls).toEqual(["link:https://example.com", "cite:ref"]);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import type { ɵAudioRecorderState } from "@copilotkit/core";
|
|
2
2
|
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
this.name = "AudioRecorderError";
|
|
7
|
-
}
|
|
8
|
-
}
|
|
3
|
+
export type AudioRecorderState = ɵAudioRecorderState;
|
|
4
|
+
|
|
5
|
+
export { ɵAudioRecorderError as AudioRecorderError } from "@copilotkit/core";
|
|
9
6
|
|
|
10
7
|
export interface CopilotChatAudioRecorderRef {
|
|
11
8
|
state: AudioRecorderState;
|
|
@@ -1,95 +1,46 @@
|
|
|
1
|
-
import type { Message, ToolCall
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import type { Message, ToolCall } from "@ag-ui/core";
|
|
2
|
+
import {
|
|
3
|
+
ɵbuildToolCallRenderProps,
|
|
4
|
+
ɵfindToolMessage,
|
|
5
|
+
ɵresolveToolCallAgentId,
|
|
6
|
+
ɵresolveToolCallRenderer,
|
|
7
|
+
} from "@copilotkit/core";
|
|
6
8
|
import type { CopilotChatToolCallRenderSlotProps } from "./types";
|
|
7
9
|
import type {
|
|
8
10
|
VueToolCallRenderer,
|
|
9
11
|
VueToolCallRendererRenderProps,
|
|
10
12
|
} from "../../types";
|
|
11
13
|
|
|
12
|
-
export function findToolMessage(
|
|
13
|
-
messages: Message[],
|
|
14
|
-
toolCallId: string,
|
|
15
|
-
): ToolMessage | undefined {
|
|
16
|
-
return messages.find(
|
|
17
|
-
(message) =>
|
|
18
|
-
message.role === "tool" &&
|
|
19
|
-
(message as ToolMessage).toolCallId === toolCallId,
|
|
20
|
-
) as ToolMessage | undefined;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
14
|
export function getToolCallSlotName(toolName: string): `tool-call-${string}` {
|
|
24
15
|
return `tool-call-${toolName}`;
|
|
25
16
|
}
|
|
26
17
|
|
|
18
|
+
/** Props for a `tool-call` / `tool-call-<name>` slot. */
|
|
27
19
|
export function getToolCallRenderProps(
|
|
28
20
|
toolCall: ToolCall,
|
|
29
21
|
messages: Message[],
|
|
30
22
|
executingToolCallIds: ReadonlySet<string>,
|
|
31
23
|
): CopilotChatToolCallRenderSlotProps {
|
|
32
|
-
const toolMessage =
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
if (toolMessage) {
|
|
36
|
-
return {
|
|
37
|
-
name: toolCall.function.name,
|
|
38
|
-
args: parsedArgs,
|
|
39
|
-
status: ToolCallStatus.Complete,
|
|
40
|
-
result: contentToText(toolMessage.content),
|
|
41
|
-
toolCall,
|
|
42
|
-
toolMessage,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const isExecuting = executingToolCallIds.has(toolCall.id);
|
|
47
|
-
return {
|
|
48
|
-
name: toolCall.function.name,
|
|
49
|
-
args: parsedArgs,
|
|
50
|
-
status: isExecuting ? ToolCallStatus.Executing : ToolCallStatus.InProgress,
|
|
51
|
-
result: undefined,
|
|
24
|
+
const toolMessage = ɵfindToolMessage(messages, toolCall.id);
|
|
25
|
+
const { name, args, status, result } = ɵbuildToolCallRenderProps(
|
|
52
26
|
toolCall,
|
|
53
|
-
toolMessage
|
|
54
|
-
|
|
27
|
+
toolMessage,
|
|
28
|
+
{ isExecuting: executingToolCallIds.has(toolCall.id) },
|
|
29
|
+
);
|
|
30
|
+
return { name, args, status, result, toolCall, toolMessage };
|
|
55
31
|
}
|
|
56
32
|
|
|
33
|
+
/** Props for a registered renderer's `render`. */
|
|
57
34
|
export function getCoreRenderProps(
|
|
58
35
|
toolCall: ToolCall,
|
|
59
36
|
messages: Message[],
|
|
60
37
|
executingToolCallIds: ReadonlySet<string>,
|
|
61
38
|
): VueToolCallRendererRenderProps<unknown> {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
name: toolCall.function.name,
|
|
68
|
-
toolCallId: toolCall.id,
|
|
69
|
-
args: parsedArgs,
|
|
70
|
-
status: ToolCallStatus.Complete,
|
|
71
|
-
result: contentToText(toolMessage.content),
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const isExecuting = executingToolCallIds.has(toolCall.id);
|
|
76
|
-
if (isExecuting) {
|
|
77
|
-
return {
|
|
78
|
-
name: toolCall.function.name,
|
|
79
|
-
toolCallId: toolCall.id,
|
|
80
|
-
args: parsedArgs,
|
|
81
|
-
status: ToolCallStatus.Executing,
|
|
82
|
-
result: undefined,
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return {
|
|
87
|
-
name: toolCall.function.name,
|
|
88
|
-
toolCallId: toolCall.id,
|
|
89
|
-
args: parsedArgs && typeof parsedArgs === "object" ? parsedArgs : {},
|
|
90
|
-
status: ToolCallStatus.InProgress,
|
|
91
|
-
result: undefined,
|
|
92
|
-
};
|
|
39
|
+
return ɵbuildToolCallRenderProps(
|
|
40
|
+
toolCall,
|
|
41
|
+
ɵfindToolMessage(messages, toolCall.id),
|
|
42
|
+
{ isExecuting: executingToolCallIds.has(toolCall.id) },
|
|
43
|
+
);
|
|
93
44
|
}
|
|
94
45
|
|
|
95
46
|
export function getToolCallMemoDeps(
|
|
@@ -97,13 +48,13 @@ export function getToolCallMemoDeps(
|
|
|
97
48
|
messages: Message[],
|
|
98
49
|
executingToolCallIds: ReadonlySet<string>,
|
|
99
50
|
renderToolCalls: readonly VueToolCallRenderer<unknown>[],
|
|
100
|
-
agentId: string =
|
|
51
|
+
agentId: string = ɵresolveToolCallAgentId(undefined, undefined),
|
|
101
52
|
): unknown[] {
|
|
102
53
|
return [
|
|
103
54
|
toolCall.id,
|
|
104
55
|
toolCall.function.name,
|
|
105
56
|
toolCall.function.arguments,
|
|
106
|
-
|
|
57
|
+
ɵfindToolMessage(messages, toolCall.id)?.content,
|
|
107
58
|
executingToolCallIds.has(toolCall.id),
|
|
108
59
|
ɵresolveToolCallRenderer(renderToolCalls, toolCall.function.name, agentId)
|
|
109
60
|
?.render,
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { ComputedRef, InjectionKey } from "vue";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
ɵToolCallDisplayContextValue,
|
|
4
|
+
ɵToolCallRowStatus,
|
|
5
|
+
} from "@copilotkit/core";
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* Provided by the message view so each message's tool calls follow the view's
|
|
@@ -18,6 +21,8 @@ export const ToolCallDisplayContextKey: InjectionKey<
|
|
|
18
21
|
export interface ToolCallGroupContextValue {
|
|
19
22
|
appearance: "card" | "line" | "stack";
|
|
20
23
|
failedIds: ReadonlySet<string>;
|
|
24
|
+
/** Each call's row status, by call id. */
|
|
25
|
+
statusById: ReadonlyMap<string, ɵToolCallRowStatus>;
|
|
21
26
|
/** The agent may still finish the group's calls; see `isActive`. */
|
|
22
27
|
active: boolean;
|
|
23
28
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { defineComponent, h, onMounted, ref, watch } from "vue";
|
|
2
2
|
import type { PropType } from "vue";
|
|
3
3
|
import {
|
|
4
|
+
ɵTOOL_CALL_STATUS_ICONS,
|
|
5
|
+
ɵTOOL_CALL_STATUS_LABEL_KEYS,
|
|
4
6
|
ɵcountFailedToolCalls,
|
|
5
7
|
ɵformatLabel,
|
|
6
8
|
ɵgetArgumentPreview,
|
|
@@ -11,13 +13,7 @@ import type {
|
|
|
11
13
|
ToolCallEntry,
|
|
12
14
|
ɵToolCallRowStatus,
|
|
13
15
|
} from "@copilotkit/core";
|
|
14
|
-
import {
|
|
15
|
-
IconCheck,
|
|
16
|
-
IconChevronRight,
|
|
17
|
-
IconCircle,
|
|
18
|
-
IconLoader2,
|
|
19
|
-
IconX,
|
|
20
|
-
} from "../icons";
|
|
16
|
+
import { CopilotIcon, IconChevronRight } from "../icons";
|
|
21
17
|
import { useCopilotId } from "../ui/use-id";
|
|
22
18
|
import { useChatLabels } from "./use-chat-labels";
|
|
23
19
|
|
|
@@ -29,16 +25,7 @@ export function toolCallStatusLabel(
|
|
|
29
25
|
labels: Readonly<CopilotChatLabels>,
|
|
30
26
|
status: ɵToolCallRowStatus,
|
|
31
27
|
) {
|
|
32
|
-
|
|
33
|
-
case "running":
|
|
34
|
-
return labels.toolCallStatusRunningLabel;
|
|
35
|
-
case "done":
|
|
36
|
-
return labels.toolCallStatusDoneLabel;
|
|
37
|
-
case "failed":
|
|
38
|
-
return labels.toolCallStatusFailedLabel;
|
|
39
|
-
case "stopped":
|
|
40
|
-
return labels.toolCallStatusStoppedLabel;
|
|
41
|
-
}
|
|
28
|
+
return labels[ɵTOOL_CALL_STATUS_LABEL_KEYS[status]];
|
|
42
29
|
}
|
|
43
30
|
|
|
44
31
|
/**
|
|
@@ -83,22 +70,15 @@ export const ToolCallStatusIcon = defineComponent({
|
|
|
83
70
|
},
|
|
84
71
|
setup(props) {
|
|
85
72
|
return () =>
|
|
86
|
-
h(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
class: [
|
|
96
|
-
"cpk-tool-call-status-icon",
|
|
97
|
-
props.status === "running" && "cpk-tool-call-status-icon-running",
|
|
98
|
-
props.status === "failed" && "cpk-tool-call-status-icon-failed",
|
|
99
|
-
],
|
|
100
|
-
},
|
|
101
|
-
);
|
|
73
|
+
h(CopilotIcon, {
|
|
74
|
+
name: ɵTOOL_CALL_STATUS_ICONS[props.status],
|
|
75
|
+
"aria-hidden": "true",
|
|
76
|
+
class: [
|
|
77
|
+
"cpk-tool-call-status-icon",
|
|
78
|
+
props.status === "running" && "cpk-tool-call-status-icon-running",
|
|
79
|
+
props.status === "failed" && "cpk-tool-call-status-icon-failed",
|
|
80
|
+
],
|
|
81
|
+
});
|
|
102
82
|
},
|
|
103
83
|
});
|
|
104
84
|
|
|
@@ -21,7 +21,7 @@ import type {
|
|
|
21
21
|
ToolCallEntry,
|
|
22
22
|
} from "@copilotkit/core";
|
|
23
23
|
import type { InterruptEvent } from "../../types";
|
|
24
|
-
import type { AutoScrollMode } from "
|
|
24
|
+
import type { ɵAutoScrollMode as AutoScrollMode } from "@copilotkit/core";
|
|
25
25
|
|
|
26
26
|
export type CopilotChatInputMode = "input" | "transcribe" | "processing";
|
|
27
27
|
export type { Attachment, AttachmentsConfig, AttachmentModality };
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { nextTick, ref } from "vue";
|
|
2
|
+
import { ɵmorphViewTransition } from "@copilotkit/core";
|
|
2
3
|
import { useCopilotId } from "../ui/use-id";
|
|
3
4
|
|
|
4
|
-
type DocWithVT = Document & {
|
|
5
|
-
startViewTransition?: (cb: () => void | Promise<void>) => {
|
|
6
|
-
finished: Promise<void>;
|
|
7
|
-
};
|
|
8
|
-
};
|
|
9
|
-
|
|
10
5
|
/**
|
|
11
6
|
* Opens and closes a lightbox, using the View Transition API to morph the
|
|
12
7
|
* thumbnail into the full-screen content, as React's `useLightbox`.
|
|
@@ -24,40 +19,27 @@ export function useLightbox() {
|
|
|
24
19
|
const vtName = useCopilotId("cpk-lightbox").replace(/[^\w-]/g, "-");
|
|
25
20
|
|
|
26
21
|
const openLightbox = () => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (doc?.startViewTransition && thumb) {
|
|
32
|
-
thumb.style.viewTransitionName = vtName;
|
|
33
|
-
doc.startViewTransition(async () => {
|
|
34
|
-
thumb.style.viewTransitionName = "";
|
|
22
|
+
ɵmorphViewTransition(
|
|
23
|
+
thumbnailRef.value,
|
|
24
|
+
vtName,
|
|
25
|
+
async () => {
|
|
35
26
|
open.value = true;
|
|
36
27
|
await nextTick();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
28
|
+
},
|
|
29
|
+
"open",
|
|
30
|
+
);
|
|
41
31
|
};
|
|
42
32
|
|
|
43
33
|
const closeLightbox = () => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (doc?.startViewTransition && thumb) {
|
|
49
|
-
const transition = doc.startViewTransition(async () => {
|
|
34
|
+
ɵmorphViewTransition(
|
|
35
|
+
thumbnailRef.value,
|
|
36
|
+
vtName,
|
|
37
|
+
async () => {
|
|
50
38
|
open.value = false;
|
|
51
39
|
await nextTick();
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
thumb.style.viewTransitionName = "";
|
|
56
|
-
};
|
|
57
|
-
transition.finished.then(clear, clear);
|
|
58
|
-
} else {
|
|
59
|
-
open.value = false;
|
|
60
|
-
}
|
|
40
|
+
},
|
|
41
|
+
"close",
|
|
42
|
+
);
|
|
61
43
|
};
|
|
62
44
|
|
|
63
45
|
return { thumbnailRef, vtName, open, openLightbox, closeLightbox };
|
|
@@ -31,10 +31,10 @@ describe("useAgent error state", () => {
|
|
|
31
31
|
|
|
32
32
|
const TestComponent = defineComponent({
|
|
33
33
|
setup() {
|
|
34
|
-
const { agent } = useAgent({ agentId: "nonexistent" });
|
|
35
|
-
return { agent };
|
|
34
|
+
const { agent, isReady } = useAgent({ agentId: "nonexistent" });
|
|
35
|
+
return { agent, isReady };
|
|
36
36
|
},
|
|
37
|
-
template: `<div data-testid="agent-id">{{ agent.agentId }}</div>`,
|
|
37
|
+
template: `<div data-testid="agent-id">{{ agent.agentId }}</div><div data-testid="ready">{{ isReady }}</div>`,
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
const Host = defineComponent({
|
|
@@ -59,6 +59,8 @@ describe("useAgent error state", () => {
|
|
|
59
59
|
// Should render without crashing — agent is provisional
|
|
60
60
|
const el = await screen.findByTestId("agent-id");
|
|
61
61
|
expect(el.textContent).toBe("nonexistent");
|
|
62
|
+
// A provisional stand-in is not the real agent.
|
|
63
|
+
expect(screen.getByTestId("ready").textContent).toBe("false");
|
|
62
64
|
expect(capturedErrors).toEqual([]);
|
|
63
65
|
});
|
|
64
66
|
});
|
|
@@ -6,7 +6,23 @@ import type { AbstractAgent } from "@ag-ui/client";
|
|
|
6
6
|
import { useCopilotKit } from "../../providers/useCopilotKit";
|
|
7
7
|
import { MockStepwiseAgent } from "../../__tests__/utils/test-helpers";
|
|
8
8
|
import { useAgent } from "../use-agent";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
CopilotKitCoreRuntimeConnectionStatus,
|
|
11
|
+
ProxiedCopilotRuntimeAgent,
|
|
12
|
+
} from "@copilotkit/core";
|
|
13
|
+
|
|
14
|
+
/** Core's `ɵruntimeInfo` snapshot, built from a fake core's runtime fields. */
|
|
15
|
+
function runtimeInfoOf(core: {
|
|
16
|
+
runtimeConnectionStatus: CopilotKitCoreRuntimeConnectionStatus;
|
|
17
|
+
threadEndpoints?: unknown;
|
|
18
|
+
intelligence?: unknown;
|
|
19
|
+
}) {
|
|
20
|
+
return {
|
|
21
|
+
status: core.runtimeConnectionStatus,
|
|
22
|
+
threadEndpoints: core.threadEndpoints,
|
|
23
|
+
intelligence: core.intelligence,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
10
26
|
|
|
11
27
|
// Mock the CopilotKitProvider to control copilotkit state directly
|
|
12
28
|
vi.mock("../../providers/useCopilotKit", () => ({
|
|
@@ -26,6 +42,7 @@ describe("useAgent stability during runtime connection", () => {
|
|
|
26
42
|
type MockCopilotkit = {
|
|
27
43
|
getAgent: ReturnType<typeof vi.fn>;
|
|
28
44
|
runtimeUrl: string | undefined;
|
|
45
|
+
readonly ɵruntimeInfo: unknown;
|
|
29
46
|
runtimeConnectionStatus: CopilotKitCoreRuntimeConnectionStatus;
|
|
30
47
|
runtimeTransport: string;
|
|
31
48
|
headers: Record<string, string>;
|
|
@@ -45,6 +62,9 @@ describe("useAgent stability during runtime connection", () => {
|
|
|
45
62
|
copilotkitRef = ref({
|
|
46
63
|
getAgent: vi.fn(() => undefined),
|
|
47
64
|
runtimeUrl: "http://localhost:3000/api/copilotkit",
|
|
65
|
+
get ɵruntimeInfo() {
|
|
66
|
+
return runtimeInfoOf(this);
|
|
67
|
+
},
|
|
48
68
|
runtimeConnectionStatus:
|
|
49
69
|
CopilotKitCoreRuntimeConnectionStatus.Disconnected,
|
|
50
70
|
runtimeTransport: "rest",
|
|
@@ -198,7 +218,6 @@ describe("useAgent stability during runtime connection", () => {
|
|
|
198
218
|
// Phase 1: Disconnected — provisional created
|
|
199
219
|
const { rerender } = render(AgentTracker, { props: { tick: 0 } });
|
|
200
220
|
await nextTick();
|
|
201
|
-
const provisionalThreadId = agentInstances[0]!.threadId;
|
|
202
221
|
|
|
203
222
|
// Phase 2: Connecting
|
|
204
223
|
mockCopilotkit.runtimeConnectionStatus =
|
|
@@ -232,8 +251,10 @@ describe("useAgent stability during runtime connection", () => {
|
|
|
232
251
|
// CopilotChat's connect guard ensures connect fires only once (when Connected),
|
|
233
252
|
// so the agent reference change doesn't cause a duplicate connect.
|
|
234
253
|
expect(agentInstances.length).toBe(2);
|
|
235
|
-
// First instance was the provisional
|
|
236
|
-
|
|
254
|
+
// First instance was the provisional. The hand-off then syncs it with
|
|
255
|
+
// the registered agent, so its threadId follows the registered one.
|
|
256
|
+
expect(agentInstances[0]).toBeInstanceOf(ProxiedCopilotRuntimeAgent);
|
|
257
|
+
expect(agentInstances[0]!.threadId).toBe(registeredAgent.threadId);
|
|
237
258
|
// Second instance is the registered agent
|
|
238
259
|
expect(agentInstances[1]).toBe(registeredAgent);
|
|
239
260
|
});
|
|
@@ -541,6 +541,8 @@ describe("useAgent throttleMs", () => {
|
|
|
541
541
|
it("single notification within window does not trigger a trailing re-render", async () => {
|
|
542
542
|
const renderCount = { current: 0 };
|
|
543
543
|
mountHookComponent({ agent, throttleMs: 100, renderCount });
|
|
544
|
+
// The provider connects on mount, and the status change re-renders once.
|
|
545
|
+
await flushVue();
|
|
544
546
|
const afterMount = renderCount.current;
|
|
545
547
|
agent.setMessages([userMsg("1", "a")]);
|
|
546
548
|
agent.notifyMessagesChanged();
|
|
@@ -692,8 +694,10 @@ describe("useAgent defaultThrottleMs from provider", () => {
|
|
|
692
694
|
agent,
|
|
693
695
|
defaultThrottleMs: value,
|
|
694
696
|
});
|
|
697
|
+
// Core validates the value (the provider no longer logs its own copy).
|
|
695
698
|
expect(errorSpy).toHaveBeenCalledWith(
|
|
696
|
-
expect.stringContaining("
|
|
699
|
+
expect.stringContaining("CopilotKitCore.setDefaultThrottleMs"),
|
|
700
|
+
expect.any(Error),
|
|
697
701
|
);
|
|
698
702
|
agent.setMessages([userMsg("1", "a")]);
|
|
699
703
|
agent.notifyMessagesChanged();
|
|
@@ -21,13 +21,15 @@ describe("useAgent", () => {
|
|
|
21
21
|
|
|
22
22
|
const Child = defineComponent({
|
|
23
23
|
setup() {
|
|
24
|
-
const { agent } = useAgent({ agentId: "test-agent" });
|
|
25
|
-
return () =>
|
|
24
|
+
const { agent, isReady } = useAgent({ agentId: "test-agent" });
|
|
25
|
+
return () => [
|
|
26
26
|
h(
|
|
27
27
|
"span",
|
|
28
28
|
{ "data-testid": "agent-id" },
|
|
29
29
|
agent.value?.agentId ?? "none",
|
|
30
|
-
)
|
|
30
|
+
),
|
|
31
|
+
h("span", { "data-testid": "ready" }, String(isReady.value)),
|
|
32
|
+
];
|
|
31
33
|
},
|
|
32
34
|
});
|
|
33
35
|
|
|
@@ -38,6 +40,7 @@ describe("useAgent", () => {
|
|
|
38
40
|
});
|
|
39
41
|
|
|
40
42
|
expect(wrapper.find("[data-testid=agent-id]").text()).toBe("test-agent");
|
|
43
|
+
expect(wrapper.find("[data-testid=ready]").text()).toBe("true");
|
|
41
44
|
});
|
|
42
45
|
|
|
43
46
|
it("uses agentId from chat configuration when no agentId prop is provided", () => {
|
|
@@ -106,6 +106,27 @@ describe("useComponent", () => {
|
|
|
106
106
|
expect(forwardedDeps).toBe(deps);
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
+
it("forwards followUp, as React and Angular do", () => {
|
|
110
|
+
const Harness = defineComponent({
|
|
111
|
+
setup() {
|
|
112
|
+
useComponent({
|
|
113
|
+
name: "showWeatherCard",
|
|
114
|
+
render: defineComponent({ template: `<div />` }),
|
|
115
|
+
followUp: false,
|
|
116
|
+
});
|
|
117
|
+
return {};
|
|
118
|
+
},
|
|
119
|
+
template: `<div />`,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
render(Harness);
|
|
123
|
+
|
|
124
|
+
const [toolConfig] = mockUseFrontendTool.mock.calls[0] as [
|
|
125
|
+
{ followUp?: boolean },
|
|
126
|
+
];
|
|
127
|
+
expect(toolConfig.followUp).toBe(false);
|
|
128
|
+
});
|
|
129
|
+
|
|
109
130
|
it("creates a render function that passes args into the component", () => {
|
|
110
131
|
const DemoComponent = defineComponent({
|
|
111
132
|
props: {
|