@copilotkit/vue 2.0.0-rc.7 → 2.0.0-rc.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/use-copilot-action.d.ts.map +1 -1
- package/dist/hooks/use-frontend-tool.d.ts +1 -1
- package/dist/hooks/use-frontend-tool.d.ts.map +1 -1
- package/dist/hooks/zod-parameters.d.ts +14 -0
- package/dist/hooks/zod-parameters.d.ts.map +1 -0
- package/dist/index.cjs +1 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +353 -16906
- package/dist/index.mjs.map +1 -1
- package/dist/use-render-activity-message-B59A4R48.js +18097 -0
- package/dist/use-render-activity-message-B59A4R48.js.map +1 -0
- package/dist/use-render-activity-message-u0OVXjd8.cjs +92 -0
- package/dist/use-render-activity-message-u0OVXjd8.cjs.map +1 -0
- package/dist/v2/components/LicenseWarningBanner.vue.d.ts.map +1 -1
- package/dist/v2/components/OpenGenerativeUIRenderer.d.ts +13 -45
- package/dist/v2/components/OpenGenerativeUIRenderer.d.ts.map +1 -1
- package/dist/v2/components/a2ui/A2UICatalogContext.d.ts +1 -1
- package/dist/v2/components/a2ui/A2UICatalogContext.d.ts.map +1 -1
- package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts +13 -5
- package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts.map +1 -1
- package/dist/v2/components/a2ui.d.ts +3 -7
- 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/CopilotChatAttachmentRenderer.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatInput.vue.d.ts +6 -270
- package/dist/v2/components/chat/CopilotChatInput.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts +1 -1
- 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/CopilotChatToolCallGroup.vue.d.ts +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 +1 -1
- package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatWorkSummary.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts +0 -1
- package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts.map +1 -1
- package/dist/v2/components/chat/index.d.ts +0 -1
- package/dist/v2/components/chat/index.d.ts.map +1 -1
- package/dist/v2/components/chat/tool-call-display-context.d.ts +2 -19
- 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 +7 -20
- package/dist/v2/components/chat/tool-call-group-parts.d.ts.map +1 -1
- package/dist/v2/components/chat/turn-work.d.ts +0 -2
- package/dist/v2/components/chat/turn-work.d.ts.map +1 -1
- package/dist/v2/components/chat/types.d.ts +1 -2
- package/dist/v2/components/chat/types.d.ts.map +1 -1
- package/dist/v2/components/chat/use-chat-labels.d.ts +8 -0
- package/dist/v2/components/chat/use-chat-labels.d.ts.map +1 -0
- package/dist/v2/components/icons/index.d.ts +968 -1
- package/dist/v2/components/icons/index.d.ts.map +1 -1
- package/dist/v2/hooks/use-frontend-tool.d.ts +5 -0
- package/dist/v2/hooks/use-frontend-tool.d.ts.map +1 -1
- package/dist/v2/hooks/use-render-activity-message.d.ts +13 -9
- package/dist/v2/hooks/use-render-activity-message.d.ts.map +1 -1
- package/dist/v2/hooks/use-render-custom-messages.d.ts +5 -7
- package/dist/v2/hooks/use-render-custom-messages.d.ts.map +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.mjs +197 -200
- package/dist/v2/index.mjs.map +1 -1
- package/dist/v2/lib/processPartialHtml.d.ts +1 -2
- package/dist/v2/lib/processPartialHtml.d.ts.map +1 -1
- package/dist/v2/lib/vue-core.d.ts +0 -1
- package/dist/v2/lib/vue-core.d.ts.map +1 -1
- package/dist/v2/providers/CopilotKitProvider.vue.d.ts +1 -1
- package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
- package/dist/v2/providers/types.d.ts +3 -46
- package/dist/v2/providers/types.d.ts.map +1 -1
- package/dist/v2/types/human-in-the-loop.d.ts +8 -29
- package/dist/v2/types/human-in-the-loop.d.ts.map +1 -1
- package/dist/v2/types/interrupt.d.ts +1 -22
- package/dist/v2/types/interrupt.d.ts.map +1 -1
- package/dist/v2/types/vue-activity-message-renderer.d.ts +16 -15
- package/dist/v2/types/vue-activity-message-renderer.d.ts.map +1 -1
- package/dist/v2/types/vue-custom-message-renderer.d.ts +7 -16
- package/dist/v2/types/vue-custom-message-renderer.d.ts.map +1 -1
- package/dist/v2/types/vue-tool-call-renderer.d.ts +16 -35
- package/dist/v2/types/vue-tool-call-renderer.d.ts.map +1 -1
- package/package.json +10 -11
- package/src/__tests__/build-entries.test.ts +27 -0
- package/src/hooks/__tests__/zod-parameters.test.ts +520 -0
- package/src/hooks/use-copilot-action.ts +2 -1
- package/src/hooks/use-frontend-tool.ts +3 -6
- package/src/hooks/zod-parameters.ts +162 -0
- package/src/v2/components/A2UIMessageRenderer.ts +3 -3
- package/src/v2/components/LicenseWarningBanner.vue +31 -15
- package/src/v2/components/OpenGenerativeUIRenderer.ts +51 -373
- package/src/v2/components/__tests__/A2UICatalogContext.test.ts +1 -1
- package/src/v2/components/__tests__/LicenseWarningBanner.test.ts +20 -0
- package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.ts +55 -6
- package/src/v2/components/a2ui/A2UIBuiltInToolCallRenderer.ts +1 -1
- package/src/v2/components/a2ui/A2UICatalogContext.ts +10 -102
- package/src/v2/components/a2ui/A2UIRecoveryStates.ts +1 -1
- package/src/v2/components/a2ui.ts +1 -1
- package/src/v2/components/chat/CopilotChat.vue +19 -40
- package/src/v2/components/chat/CopilotChatAttachmentQueue.vue +14 -10
- package/src/v2/components/chat/CopilotChatAttachmentRenderer.vue +14 -6
- package/src/v2/components/chat/CopilotChatInput.vue +40 -30
- package/src/v2/components/chat/CopilotChatMessageView.vue +72 -140
- package/src/v2/components/chat/CopilotChatReasoningMessage.vue +31 -13
- package/src/v2/components/chat/CopilotChatToolCallGroup.vue +60 -37
- package/src/v2/components/chat/CopilotChatToolCallItem.vue +3 -3
- package/src/v2/components/chat/CopilotChatToolCallsView.vue +15 -13
- package/src/v2/components/chat/CopilotChatView.vue +5 -5
- package/src/v2/components/chat/CopilotChatWorkSummary.vue +44 -18
- package/src/v2/components/chat/__tests__/CopilotChat.labels.test.ts +19 -4
- package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.ts +26 -9
- package/src/v2/components/chat/__tests__/CopilotChatInput.test.ts +33 -1
- package/src/v2/components/chat/__tests__/CopilotChatMessageView.test.ts +247 -403
- package/src/v2/components/chat/__tests__/CopilotChatMessageView.toolCallDisplay.test.ts +1 -99
- package/src/v2/components/chat/copilotChatToolCallItemRender.ts +3 -19
- package/src/v2/components/chat/index.ts +0 -1
- package/src/v2/components/chat/tool-call-display-context.ts +2 -23
- package/src/v2/components/chat/tool-call-group-parts.ts +44 -85
- package/src/v2/components/chat/turn-work.ts +0 -9
- package/src/v2/components/chat/types.ts +4 -4
- package/src/v2/components/chat/use-chat-labels.ts +16 -0
- package/src/v2/components/icons/__tests__/icons.test.ts +72 -68
- package/src/v2/components/icons/index.ts +109 -27
- package/src/v2/hooks/__tests__/use-frontend-tool.e2e.test.ts +62 -1
- package/src/v2/hooks/__tests__/use-render-activity-message.test.ts +105 -0
- package/src/v2/hooks/__tests__/use-render-tool.test.ts +3 -6
- package/src/v2/hooks/__tests__/zod-regression.test.ts +5 -4
- package/src/v2/hooks/use-frontend-tool.ts +10 -10
- package/src/v2/hooks/use-render-activity-message.ts +27 -48
- package/src/v2/hooks/use-render-custom-messages.ts +14 -35
- package/src/v2/lib/processPartialHtml.ts +6 -21
- package/src/v2/lib/vue-core.ts +3 -5
- package/src/v2/providers/CopilotKitProvider.vue +53 -112
- package/src/v2/providers/__tests__/CopilotKitProvider.a2ui.test.ts +1 -1
- package/src/v2/providers/__tests__/CopilotKitProvider.headersAtSendTime.test.ts +3 -3
- package/src/v2/providers/__tests__/CopilotKitProvider.learning.test.ts +3 -1
- package/src/v2/providers/__tests__/CopilotKitProvider.test.ts +17 -0
- package/src/v2/providers/types.ts +3 -49
- package/src/v2/types/__tests__/defineToolCallRenderer.test.ts +28 -33
- package/src/v2/types/defineToolCallRenderer.ts +5 -4
- package/src/v2/types/human-in-the-loop.ts +8 -32
- package/src/v2/types/interrupt.ts +7 -31
- package/src/v2/types/vue-activity-message-renderer.ts +24 -15
- package/src/v2/types/vue-custom-message-renderer.ts +12 -16
- package/src/v2/types/vue-tool-call-renderer.ts +23 -38
- package/vite.config.ts +3 -4
- package/dist/v2/components/chat/BasicMarkdown.vue.d.ts +0 -9
- package/dist/v2/components/chat/BasicMarkdown.vue.d.ts.map +0 -1
- package/dist/v2/components/chat/tool-call-layout.d.ts +0 -115
- package/dist/v2/components/chat/tool-call-layout.d.ts.map +0 -1
- package/dist/v2/lib/transcription-client.d.ts +0 -19
- package/dist/v2/lib/transcription-client.d.ts.map +0 -1
- package/src/v2/components/chat/BasicMarkdown.vue +0 -160
- package/src/v2/components/chat/__tests__/BasicMarkdown.test.ts +0 -69
- package/src/v2/components/chat/tool-call-layout.ts +0 -304
- package/src/v2/lib/__tests__/processPartialHtml.test.ts +0 -84
- package/src/v2/lib/__tests__/transcription-client.test.ts +0 -67
- package/src/v2/lib/transcription-client.ts +0 -151
|
@@ -1,188 +1,172 @@
|
|
|
1
|
-
import { defineComponent } from "vue";
|
|
1
|
+
import { defineComponent, h } from "vue";
|
|
2
2
|
import { render, screen } from "@testing-library/vue";
|
|
3
3
|
import { describe, expect, it } from "vitest";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
-
import type {
|
|
6
|
-
ActivityMessage,
|
|
7
|
-
AssistantMessage,
|
|
8
|
-
Message,
|
|
9
|
-
UserMessage,
|
|
10
|
-
} from "@ag-ui/core";
|
|
5
|
+
import type { Message, ToolCall } from "@ag-ui/core";
|
|
11
6
|
import CopilotKitProvider from "../../../providers/CopilotKitProvider.vue";
|
|
12
7
|
import CopilotChatConfigurationProvider from "../../../providers/CopilotChatConfigurationProvider.vue";
|
|
13
8
|
import CopilotChatMessageView from "../CopilotChatMessageView.vue";
|
|
9
|
+
import type { VueActivityMessageRenderer } from "../../../types";
|
|
10
|
+
|
|
11
|
+
const agentId = "default";
|
|
12
|
+
const threadId = "thread-test";
|
|
13
|
+
|
|
14
|
+
/** Slot templates that print what the view hands each message slot. */
|
|
15
|
+
const assistantContentSlot = `
|
|
16
|
+
<template #assistant-message="{ message }">
|
|
17
|
+
<div data-testid="assistant-content">{{ message.content }}</div>
|
|
18
|
+
</template>`;
|
|
19
|
+
const assistantToolCallsSlot = `
|
|
20
|
+
<template #assistant-message="{ message }">
|
|
21
|
+
<div data-testid="assistant-tool-calls-count">{{ message.toolCalls?.length ?? 0 }}</div>
|
|
22
|
+
<div data-testid="assistant-tool-call-args">{{ (message.toolCalls ?? []).map((call) => call.function.arguments).join("|") }}</div>
|
|
23
|
+
<div data-testid="assistant-content">{{ message.content }}</div>
|
|
24
|
+
</template>`;
|
|
25
|
+
const userContentSlot = `
|
|
26
|
+
<template #user-message="{ message }">
|
|
27
|
+
<div data-testid="user-content">{{ message.content }}</div>
|
|
28
|
+
</template>`;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Renders a message view inside the providers.
|
|
32
|
+
*
|
|
33
|
+
* @param options.slots - Slot templates placed inside the message view.
|
|
34
|
+
* @param options.renderActivityMessages - Activity renderers to register.
|
|
35
|
+
*/
|
|
36
|
+
function renderMessageView(options: {
|
|
37
|
+
messages: Message[];
|
|
38
|
+
slots?: string;
|
|
39
|
+
renderActivityMessages?: VueActivityMessageRenderer<unknown>[];
|
|
40
|
+
}) {
|
|
41
|
+
const { messages, slots = "", renderActivityMessages = [] } = options;
|
|
42
|
+
const Host = defineComponent({
|
|
43
|
+
components: {
|
|
44
|
+
CopilotKitProvider,
|
|
45
|
+
CopilotChatConfigurationProvider,
|
|
46
|
+
CopilotChatMessageView,
|
|
47
|
+
},
|
|
48
|
+
setup() {
|
|
49
|
+
return { messages, agentId, threadId, renderActivityMessages };
|
|
50
|
+
},
|
|
51
|
+
template: `
|
|
52
|
+
<CopilotKitProvider
|
|
53
|
+
runtime-url="/api/copilotkit"
|
|
54
|
+
:render-activity-messages="renderActivityMessages"
|
|
55
|
+
>
|
|
56
|
+
<CopilotChatConfigurationProvider :agent-id="agentId" :thread-id="threadId">
|
|
57
|
+
<CopilotChatMessageView :messages="messages">${slots}</CopilotChatMessageView>
|
|
58
|
+
</CopilotChatConfigurationProvider>
|
|
59
|
+
</CopilotKitProvider>
|
|
60
|
+
`,
|
|
61
|
+
});
|
|
14
62
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const threadId = "thread-test";
|
|
18
|
-
|
|
19
|
-
function renderMessageView({
|
|
20
|
-
messages,
|
|
21
|
-
hostTemplate = `<CopilotChatMessageView :messages="messages" />`,
|
|
22
|
-
}: {
|
|
23
|
-
messages: Message[];
|
|
24
|
-
hostTemplate?: string;
|
|
25
|
-
}) {
|
|
26
|
-
const ActivityRenderer = defineComponent({
|
|
27
|
-
name: "ActivityRenderer",
|
|
28
|
-
props: {
|
|
29
|
-
content: { type: Object, required: true },
|
|
30
|
-
},
|
|
31
|
-
setup(props) {
|
|
32
|
-
return {
|
|
33
|
-
percent: (props.content as { percent: number }).percent,
|
|
34
|
-
};
|
|
35
|
-
},
|
|
36
|
-
template: `
|
|
37
|
-
<div data-testid="activity-renderer">
|
|
38
|
-
Progress: {{ percent }}%
|
|
39
|
-
</div>
|
|
40
|
-
`,
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
const Host = defineComponent({
|
|
44
|
-
components: {
|
|
45
|
-
CopilotKitProvider,
|
|
46
|
-
CopilotChatConfigurationProvider,
|
|
47
|
-
CopilotChatMessageView,
|
|
48
|
-
ActivityRenderer,
|
|
49
|
-
},
|
|
50
|
-
setup() {
|
|
51
|
-
return { messages, agentId, threadId };
|
|
52
|
-
},
|
|
53
|
-
template: `
|
|
54
|
-
<CopilotKitProvider runtime-url="/api/copilotkit">
|
|
55
|
-
<CopilotChatConfigurationProvider :agent-id="agentId" :thread-id="threadId">
|
|
56
|
-
${hostTemplate}
|
|
57
|
-
</CopilotChatConfigurationProvider>
|
|
58
|
-
</CopilotKitProvider>
|
|
59
|
-
`,
|
|
60
|
-
});
|
|
63
|
+
return render(Host);
|
|
64
|
+
}
|
|
61
65
|
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
it("renders activity messages via matching custom renderer", () => {
|
|
66
|
-
const messages: Message[] = [
|
|
67
|
-
{
|
|
68
|
-
id: "act-1",
|
|
69
|
-
role: "activity",
|
|
70
|
-
activityType: "search-progress",
|
|
71
|
-
content: { percent: 42 },
|
|
72
|
-
} as ActivityMessage,
|
|
73
|
-
];
|
|
74
|
-
|
|
75
|
-
const renderers = [
|
|
76
|
-
{
|
|
77
|
-
activityType: "search-progress",
|
|
78
|
-
content: z.object({ percent: z.number() }),
|
|
79
|
-
},
|
|
80
|
-
];
|
|
81
|
-
expect(renderers).toHaveLength(1);
|
|
66
|
+
function toolCall(id: string, name: string, args = "{}"): ToolCall {
|
|
67
|
+
return { id, type: "function", function: { name, arguments: args } };
|
|
68
|
+
}
|
|
82
69
|
|
|
70
|
+
describe("CopilotChatMessageView activity rendering", () => {
|
|
71
|
+
const progress: Message = {
|
|
72
|
+
id: "act-1",
|
|
73
|
+
role: "activity",
|
|
74
|
+
activityType: "search-progress",
|
|
75
|
+
content: { percent: 42 },
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/** A `"*"` renderer that prints the content it was given. */
|
|
79
|
+
const wildcardRenderer: VueActivityMessageRenderer<unknown> = {
|
|
80
|
+
activityType: "*",
|
|
81
|
+
content: z.object({ percent: z.number() }),
|
|
82
|
+
render: (props) =>
|
|
83
|
+
h(
|
|
84
|
+
"div",
|
|
85
|
+
{ "data-testid": "wildcard-activity" },
|
|
86
|
+
JSON.stringify(props.content),
|
|
87
|
+
),
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
it("renders activity messages through their activity-<type> slot", () => {
|
|
83
91
|
renderMessageView({
|
|
84
|
-
messages,
|
|
85
|
-
|
|
86
|
-
<
|
|
87
|
-
<
|
|
88
|
-
|
|
89
|
-
</template>
|
|
90
|
-
</CopilotChatMessageView>
|
|
91
|
-
`,
|
|
92
|
+
messages: [progress],
|
|
93
|
+
slots: `
|
|
94
|
+
<template #activity-search-progress="{ content }">
|
|
95
|
+
<div data-testid="activity-renderer">Progress: {{ content.percent }}%</div>
|
|
96
|
+
</template>`,
|
|
92
97
|
});
|
|
93
98
|
|
|
94
99
|
expect(screen.getByTestId("activity-renderer").textContent).toContain("42");
|
|
95
100
|
});
|
|
96
101
|
|
|
97
102
|
it("skips rendering when no activity renderer matches", () => {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
renderMessageView({
|
|
104
|
+
messages: [
|
|
105
|
+
{
|
|
106
|
+
id: "act-2",
|
|
107
|
+
role: "activity",
|
|
108
|
+
activityType: "unknown-type",
|
|
109
|
+
content: { message: "should not render" },
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
expect(screen.queryByText("should not render")).toBeNull();
|
|
115
|
+
});
|
|
106
116
|
|
|
117
|
+
it("falls back to the * renderer for a type with no renderer of its own", () => {
|
|
107
118
|
renderMessageView({
|
|
108
|
-
messages,
|
|
109
|
-
|
|
119
|
+
messages: [progress],
|
|
120
|
+
renderActivityMessages: [wildcardRenderer],
|
|
110
121
|
});
|
|
111
122
|
|
|
112
|
-
expect(screen.
|
|
123
|
+
expect(screen.getByTestId("wildcard-activity").textContent).toBe(
|
|
124
|
+
'{"percent":42}',
|
|
125
|
+
);
|
|
113
126
|
});
|
|
114
|
-
});
|
|
115
127
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
CopilotChatConfigurationProvider,
|
|
125
|
-
CopilotChatMessageView,
|
|
126
|
-
},
|
|
127
|
-
setup() {
|
|
128
|
-
return { messages, agentId, threadId };
|
|
129
|
-
},
|
|
130
|
-
template: `
|
|
131
|
-
<CopilotKitProvider runtime-url="/api/copilotkit">
|
|
132
|
-
<CopilotChatConfigurationProvider :agent-id="agentId" :thread-id="threadId">
|
|
133
|
-
<CopilotChatMessageView :messages="messages" />
|
|
134
|
-
</CopilotChatConfigurationProvider>
|
|
135
|
-
</CopilotKitProvider>
|
|
136
|
-
`,
|
|
128
|
+
it("uses an activity-<type> slot before the * renderer", () => {
|
|
129
|
+
renderMessageView({
|
|
130
|
+
messages: [progress],
|
|
131
|
+
renderActivityMessages: [wildcardRenderer],
|
|
132
|
+
slots: `
|
|
133
|
+
<template #activity-search-progress>
|
|
134
|
+
<div data-testid="activity-slot">slot</div>
|
|
135
|
+
</template>`,
|
|
137
136
|
});
|
|
138
137
|
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
expect(screen.getByTestId("activity-slot")).toBeTruthy();
|
|
139
|
+
expect(screen.queryByTestId("wildcard-activity")).toBeNull();
|
|
140
|
+
});
|
|
141
|
+
});
|
|
141
142
|
|
|
143
|
+
describe("CopilotChatMessageView duplicate message deduplication", () => {
|
|
142
144
|
it("preserves assistant text content when later duplicate has empty content (multi-tool-call scenario)", () => {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
id: "user-1",
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
role: "assistant",
|
|
169
|
-
content: "",
|
|
170
|
-
toolCalls: [
|
|
171
|
-
{
|
|
172
|
-
id: "tc-1",
|
|
173
|
-
type: "function",
|
|
174
|
-
function: { name: "captureData", arguments: "{}" },
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
id: "tc-2",
|
|
178
|
-
type: "function",
|
|
179
|
-
function: { name: "updateMemory", arguments: "{}" },
|
|
180
|
-
},
|
|
181
|
-
],
|
|
182
|
-
} as AssistantMessage,
|
|
183
|
-
];
|
|
184
|
-
|
|
185
|
-
renderMessageView({ messages });
|
|
145
|
+
renderMessageView({
|
|
146
|
+
messages: [
|
|
147
|
+
{ id: "user-1", role: "user", content: "Record a headache" },
|
|
148
|
+
{
|
|
149
|
+
id: "assistant-1",
|
|
150
|
+
role: "assistant",
|
|
151
|
+
content: "Let me record that...",
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
id: "assistant-1",
|
|
155
|
+
role: "assistant",
|
|
156
|
+
content: "",
|
|
157
|
+
toolCalls: [toolCall("tc-1", "captureData")],
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
id: "assistant-1",
|
|
161
|
+
role: "assistant",
|
|
162
|
+
content: "",
|
|
163
|
+
toolCalls: [
|
|
164
|
+
toolCall("tc-1", "captureData"),
|
|
165
|
+
toolCall("tc-2", "updateMemory"),
|
|
166
|
+
],
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
});
|
|
186
170
|
|
|
187
171
|
const assistantMessages = screen.getAllByTestId(
|
|
188
172
|
"copilot-assistant-message",
|
|
@@ -194,25 +178,21 @@ describe("CopilotChatMessageView duplicate message deduplication", () => {
|
|
|
194
178
|
});
|
|
195
179
|
|
|
196
180
|
it("uses latest content when all assistant duplicates have non-empty content", () => {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
id: "user-1",
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
} as AssistantMessage,
|
|
213
|
-
];
|
|
214
|
-
|
|
215
|
-
renderMessageView({ messages });
|
|
181
|
+
renderMessageView({
|
|
182
|
+
messages: [
|
|
183
|
+
{ id: "user-1", role: "user", content: "Hello" },
|
|
184
|
+
{
|
|
185
|
+
id: "assistant-1",
|
|
186
|
+
role: "assistant",
|
|
187
|
+
content: "Partial response...",
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
id: "assistant-1",
|
|
191
|
+
role: "assistant",
|
|
192
|
+
content: "Full response from the assistant.",
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
});
|
|
216
196
|
|
|
217
197
|
const assistantMessages = screen.getAllByTestId(
|
|
218
198
|
"copilot-assistant-message",
|
|
@@ -221,100 +201,45 @@ describe("CopilotChatMessageView duplicate message deduplication", () => {
|
|
|
221
201
|
expect(assistantMessages[0]?.textContent).toContain(
|
|
222
202
|
"Full response from the assistant.",
|
|
223
203
|
);
|
|
224
|
-
|
|
225
|
-
const userMessages = screen.getAllByTestId("copilot-user-message");
|
|
226
|
-
expect(userMessages).toHaveLength(1);
|
|
204
|
+
expect(screen.getAllByTestId("copilot-user-message")).toHaveLength(1);
|
|
227
205
|
});
|
|
228
206
|
|
|
229
207
|
it("uses later content when earlier content is empty", () => {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
id: "assistant-1",
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
} as AssistantMessage,
|
|
241
|
-
];
|
|
242
|
-
|
|
243
|
-
const Host = defineComponent({
|
|
244
|
-
components: {
|
|
245
|
-
CopilotKitProvider,
|
|
246
|
-
CopilotChatConfigurationProvider,
|
|
247
|
-
CopilotChatMessageView,
|
|
248
|
-
},
|
|
249
|
-
setup() {
|
|
250
|
-
return { messages, agentId, threadId };
|
|
251
|
-
},
|
|
252
|
-
template: `
|
|
253
|
-
<CopilotKitProvider runtime-url="/api/copilotkit">
|
|
254
|
-
<CopilotChatConfigurationProvider :agent-id="agentId" :thread-id="threadId">
|
|
255
|
-
<CopilotChatMessageView :messages="messages">
|
|
256
|
-
<template #assistant-message="{ message }">
|
|
257
|
-
<div data-testid="assistant-content">{{ message.content }}</div>
|
|
258
|
-
</template>
|
|
259
|
-
</CopilotChatMessageView>
|
|
260
|
-
</CopilotChatConfigurationProvider>
|
|
261
|
-
</CopilotKitProvider>
|
|
262
|
-
`,
|
|
208
|
+
renderMessageView({
|
|
209
|
+
messages: [
|
|
210
|
+
{ id: "assistant-1", role: "assistant", content: "" },
|
|
211
|
+
{
|
|
212
|
+
id: "assistant-1",
|
|
213
|
+
role: "assistant",
|
|
214
|
+
content: "Here is the result.",
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
slots: assistantContentSlot,
|
|
263
218
|
});
|
|
264
219
|
|
|
265
|
-
render(Host);
|
|
266
|
-
|
|
267
220
|
expect(screen.getByTestId("assistant-content").textContent).toContain(
|
|
268
221
|
"Here is the result.",
|
|
269
222
|
);
|
|
270
223
|
});
|
|
271
224
|
|
|
272
225
|
it("recovers toolCalls when later duplicate has content but undefined toolCalls", () => {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
role: "assistant",
|
|
289
|
-
content: "Here is the result.",
|
|
290
|
-
} as AssistantMessage,
|
|
291
|
-
];
|
|
292
|
-
|
|
293
|
-
const Host = defineComponent({
|
|
294
|
-
components: {
|
|
295
|
-
CopilotKitProvider,
|
|
296
|
-
CopilotChatConfigurationProvider,
|
|
297
|
-
CopilotChatMessageView,
|
|
298
|
-
},
|
|
299
|
-
setup() {
|
|
300
|
-
return { messages, agentId, threadId };
|
|
301
|
-
},
|
|
302
|
-
template: `
|
|
303
|
-
<CopilotKitProvider runtime-url="/api/copilotkit">
|
|
304
|
-
<CopilotChatConfigurationProvider :agent-id="agentId" :thread-id="threadId">
|
|
305
|
-
<CopilotChatMessageView :messages="messages">
|
|
306
|
-
<template #assistant-message="{ message }">
|
|
307
|
-
<div data-testid="assistant-tool-calls-count">{{ message.toolCalls?.length ?? 0 }}</div>
|
|
308
|
-
<div data-testid="assistant-content">{{ message.content }}</div>
|
|
309
|
-
</template>
|
|
310
|
-
</CopilotChatMessageView>
|
|
311
|
-
</CopilotChatConfigurationProvider>
|
|
312
|
-
</CopilotKitProvider>
|
|
313
|
-
`,
|
|
226
|
+
renderMessageView({
|
|
227
|
+
messages: [
|
|
228
|
+
{
|
|
229
|
+
id: "assistant-1",
|
|
230
|
+
role: "assistant",
|
|
231
|
+
content: "",
|
|
232
|
+
toolCalls: [toolCall("tc-1", "captureData")],
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
id: "assistant-1",
|
|
236
|
+
role: "assistant",
|
|
237
|
+
content: "Here is the result.",
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
slots: assistantToolCallsSlot,
|
|
314
241
|
});
|
|
315
242
|
|
|
316
|
-
render(Host);
|
|
317
|
-
|
|
318
243
|
expect(screen.getByTestId("assistant-content").textContent).toContain(
|
|
319
244
|
"Here is the result.",
|
|
320
245
|
);
|
|
@@ -324,171 +249,90 @@ describe("CopilotChatMessageView duplicate message deduplication", () => {
|
|
|
324
249
|
});
|
|
325
250
|
|
|
326
251
|
it("keeps empty toolCalls array from later chunk", () => {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
content: "Done.",
|
|
344
|
-
toolCalls: [],
|
|
345
|
-
} as AssistantMessage,
|
|
346
|
-
];
|
|
347
|
-
|
|
348
|
-
const Host = defineComponent({
|
|
349
|
-
components: {
|
|
350
|
-
CopilotKitProvider,
|
|
351
|
-
CopilotChatConfigurationProvider,
|
|
352
|
-
CopilotChatMessageView,
|
|
353
|
-
},
|
|
354
|
-
setup() {
|
|
355
|
-
return { messages, agentId, threadId };
|
|
356
|
-
},
|
|
357
|
-
template: `
|
|
358
|
-
<CopilotKitProvider runtime-url="/api/copilotkit">
|
|
359
|
-
<CopilotChatConfigurationProvider :agent-id="agentId" :thread-id="threadId">
|
|
360
|
-
<CopilotChatMessageView :messages="messages">
|
|
361
|
-
<template #assistant-message="{ message }">
|
|
362
|
-
<div data-testid="assistant-tool-calls-count">{{ message.toolCalls?.length ?? 0 }}</div>
|
|
363
|
-
</template>
|
|
364
|
-
</CopilotChatMessageView>
|
|
365
|
-
</CopilotChatConfigurationProvider>
|
|
366
|
-
</CopilotKitProvider>
|
|
367
|
-
`,
|
|
252
|
+
renderMessageView({
|
|
253
|
+
messages: [
|
|
254
|
+
{
|
|
255
|
+
id: "assistant-1",
|
|
256
|
+
role: "assistant",
|
|
257
|
+
content: "",
|
|
258
|
+
toolCalls: [toolCall("tc-1", "captureData")],
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
id: "assistant-1",
|
|
262
|
+
role: "assistant",
|
|
263
|
+
content: "Done.",
|
|
264
|
+
toolCalls: [],
|
|
265
|
+
},
|
|
266
|
+
],
|
|
267
|
+
slots: assistantToolCallsSlot,
|
|
368
268
|
});
|
|
369
269
|
|
|
370
|
-
render(Host);
|
|
371
|
-
|
|
372
270
|
expect(screen.getByTestId("assistant-tool-calls-count").textContent).toBe(
|
|
373
271
|
"0",
|
|
374
272
|
);
|
|
375
273
|
});
|
|
376
274
|
|
|
377
|
-
it("
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
const Host = defineComponent({
|
|
392
|
-
components: {
|
|
393
|
-
CopilotKitProvider,
|
|
394
|
-
CopilotChatConfigurationProvider,
|
|
395
|
-
CopilotChatMessageView,
|
|
396
|
-
},
|
|
397
|
-
setup() {
|
|
398
|
-
return { messages, agentId, threadId };
|
|
399
|
-
},
|
|
400
|
-
template: `
|
|
401
|
-
<CopilotKitProvider runtime-url="/api/copilotkit">
|
|
402
|
-
<CopilotChatConfigurationProvider :agent-id="agentId" :thread-id="threadId">
|
|
403
|
-
<CopilotChatMessageView :messages="messages">
|
|
404
|
-
<template #assistant-message="{ message }">
|
|
405
|
-
<div data-testid="assistant-content">{{ message.content }}</div>
|
|
406
|
-
</template>
|
|
407
|
-
</CopilotChatMessageView>
|
|
408
|
-
</CopilotChatConfigurationProvider>
|
|
409
|
-
</CopilotKitProvider>
|
|
410
|
-
`,
|
|
275
|
+
it("collapses a tool call that repeats in one message, keeping the copy with arguments", () => {
|
|
276
|
+
renderMessageView({
|
|
277
|
+
messages: [
|
|
278
|
+
{
|
|
279
|
+
id: "assistant-1",
|
|
280
|
+
role: "assistant",
|
|
281
|
+
content: "",
|
|
282
|
+
toolCalls: [
|
|
283
|
+
toolCall("tc-1", "getWeather", '{"city":"Paris"}'),
|
|
284
|
+
toolCall("tc-1", "getWeather", ""),
|
|
285
|
+
],
|
|
286
|
+
},
|
|
287
|
+
],
|
|
288
|
+
slots: assistantToolCallsSlot,
|
|
411
289
|
});
|
|
412
290
|
|
|
413
|
-
|
|
291
|
+
expect(screen.getByTestId("assistant-tool-calls-count").textContent).toBe(
|
|
292
|
+
"1",
|
|
293
|
+
);
|
|
294
|
+
expect(screen.getByTestId("assistant-tool-call-args").textContent).toBe(
|
|
295
|
+
'{"city":"Paris"}',
|
|
296
|
+
);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it("handles undefined content on both occurrences", () => {
|
|
300
|
+
renderMessageView({
|
|
301
|
+
messages: [
|
|
302
|
+
{ id: "assistant-1", role: "assistant", content: undefined },
|
|
303
|
+
{ id: "assistant-1", role: "assistant", content: undefined },
|
|
304
|
+
],
|
|
305
|
+
slots: assistantContentSlot,
|
|
306
|
+
});
|
|
414
307
|
|
|
415
308
|
expect(screen.getByTestId("assistant-content").textContent).toBe("");
|
|
416
309
|
});
|
|
417
310
|
|
|
418
311
|
it("keeps last entry for non-assistant roles", () => {
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
id: "user-1",
|
|
422
|
-
role: "user",
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
{
|
|
426
|
-
id: "user-1",
|
|
427
|
-
role: "user",
|
|
428
|
-
content: "Hello (updated)",
|
|
429
|
-
} as UserMessage,
|
|
430
|
-
];
|
|
431
|
-
|
|
432
|
-
const Host = defineComponent({
|
|
433
|
-
components: {
|
|
434
|
-
CopilotKitProvider,
|
|
435
|
-
CopilotChatConfigurationProvider,
|
|
436
|
-
CopilotChatMessageView,
|
|
437
|
-
},
|
|
438
|
-
setup() {
|
|
439
|
-
return { messages, agentId, threadId };
|
|
440
|
-
},
|
|
441
|
-
template: `
|
|
442
|
-
<CopilotKitProvider runtime-url="/api/copilotkit">
|
|
443
|
-
<CopilotChatConfigurationProvider :agent-id="agentId" :thread-id="threadId">
|
|
444
|
-
<CopilotChatMessageView :messages="messages">
|
|
445
|
-
<template #user-message="{ message }">
|
|
446
|
-
<div data-testid="user-content">{{ message.content }}</div>
|
|
447
|
-
</template>
|
|
448
|
-
</CopilotChatMessageView>
|
|
449
|
-
</CopilotChatConfigurationProvider>
|
|
450
|
-
</CopilotKitProvider>
|
|
451
|
-
`,
|
|
312
|
+
renderMessageView({
|
|
313
|
+
messages: [
|
|
314
|
+
{ id: "user-1", role: "user", content: "Hello" },
|
|
315
|
+
{ id: "user-1", role: "user", content: "Hello (updated)" },
|
|
316
|
+
],
|
|
317
|
+
slots: userContentSlot,
|
|
452
318
|
});
|
|
453
319
|
|
|
454
|
-
render(Host);
|
|
455
|
-
|
|
456
320
|
expect(screen.getByTestId("user-content").textContent).toBe(
|
|
457
321
|
"Hello (updated)",
|
|
458
322
|
);
|
|
459
323
|
});
|
|
460
324
|
|
|
461
325
|
it("preserves order of unique messages", () => {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
id: "user-1",
|
|
465
|
-
role: "
|
|
466
|
-
content: "
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
{
|
|
474
|
-
id: "user-2",
|
|
475
|
-
role: "user",
|
|
476
|
-
content: "Second question",
|
|
477
|
-
} as UserMessage,
|
|
478
|
-
{
|
|
479
|
-
id: "assistant-2",
|
|
480
|
-
role: "assistant",
|
|
481
|
-
content: "Second answer",
|
|
482
|
-
} as AssistantMessage,
|
|
483
|
-
];
|
|
484
|
-
|
|
485
|
-
renderMessageView({ messages });
|
|
486
|
-
|
|
487
|
-
const userMessages = screen.getAllByTestId("copilot-user-message");
|
|
488
|
-
const assistantMessages = screen.getAllByTestId(
|
|
489
|
-
"copilot-assistant-message",
|
|
490
|
-
);
|
|
491
|
-
expect(userMessages).toHaveLength(2);
|
|
492
|
-
expect(assistantMessages).toHaveLength(2);
|
|
326
|
+
renderMessageView({
|
|
327
|
+
messages: [
|
|
328
|
+
{ id: "user-1", role: "user", content: "First question" },
|
|
329
|
+
{ id: "assistant-1", role: "assistant", content: "First answer" },
|
|
330
|
+
{ id: "user-2", role: "user", content: "Second question" },
|
|
331
|
+
{ id: "assistant-2", role: "assistant", content: "Second answer" },
|
|
332
|
+
],
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
expect(screen.getAllByTestId("copilot-user-message")).toHaveLength(2);
|
|
336
|
+
expect(screen.getAllByTestId("copilot-assistant-message")).toHaveLength(2);
|
|
493
337
|
});
|
|
494
338
|
});
|