@copilotkit/vue 1.75.1 → 1.75.2
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 +2 -2
- package/dist/use-render-activity-message-CGdS03Xj.cjs +85 -0
- package/dist/use-render-activity-message-CGdS03Xj.cjs.map +1 -0
- package/dist/{use-render-activity-message-xvpuaGyf.js → use-render-activity-message-XmuT9fKy.js} +2382 -2390
- package/dist/use-render-activity-message-XmuT9fKy.js.map +1 -0
- package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts.map +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.mjs +1 -1
- package/package.json +5 -5
- package/src/v2/components/chat/CopilotChatMessageView.vue +41 -30
- package/src/v2/components/chat/__tests__/CopilotChatMessageView.slotMetaCost.test.ts +187 -0
- package/dist/use-render-activity-message-BOPauH9X.cjs +0 -85
- package/dist/use-render-activity-message-BOPauH9X.cjs.map +0 -1
- package/dist/use-render-activity-message-xvpuaGyf.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CopilotChatMessageView.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/chat/CopilotChatMessageView.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CopilotChatMessageView.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/chat/CopilotChatMessageView.vue"],"names":[],"mappings":"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"}
|
package/dist/v2/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("@copilotkit/core"),i=require("@ag-ui/client"),e=require("../use-render-activity-message-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("@copilotkit/core"),i=require("@ag-ui/client"),e=require("../use-render-activity-message-CGdS03Xj.cjs"),n=require("@copilotkit/shared");exports.A2UIActivityContentSchema=e.A2UIActivityContentSchema;exports.A2UISurfaceActivityRenderer=e._sfc_main;exports.A2UISurfaceActivityType=e.A2UISurfaceActivityType;exports.CopilotChat=e.CopilotChat;exports.CopilotChatAssistantMessage=e._sfc_main$1;exports.CopilotChatAttachmentQueue=e._sfc_main$2;exports.CopilotChatAttachmentRenderer=e._sfc_main$3;exports.CopilotChatAudioRecorder=e._sfc_main$4;exports.CopilotChatConfigurationProvider=e._sfc_main$5;exports.CopilotChatDefaultLabels=e.CopilotChatDefaultLabels;exports.CopilotChatInput=e._sfc_main$6;exports.CopilotChatMessageView=e._sfc_main$7;exports.CopilotChatReasoningMessage=e._sfc_main$8;exports.CopilotChatSuggestionPill=e._sfc_main$9;exports.CopilotChatSuggestionView=e._sfc_main$10;exports.CopilotChatToggleButton=e.CopilotChatToggleButton;exports.CopilotChatToggleButtonCloseIcon=e.CopilotChatToggleButtonCloseIcon;exports.CopilotChatToggleButtonOpenIcon=e.CopilotChatToggleButtonOpenIcon;exports.CopilotChatToolCallsView=e._sfc_main$11;exports.CopilotChatUserMessage=e._sfc_main$12;exports.CopilotChatView=e._sfc_main$13;exports.CopilotKitCoreVue=e.CopilotKitCoreVue;exports.CopilotKitInspector=e._sfc_main$14;exports.CopilotKitProvider=e._sfc_main$15;exports.CopilotModalHeader=e.CopilotModalHeader;exports.CopilotPopup=e._sfc_main$16;exports.CopilotPopupView=e.CopilotPopupView;exports.CopilotSidebar=e._sfc_main$17;exports.CopilotSidebarView=e.CopilotSidebarView;exports.CopilotThreadsDrawer=e._sfc_main$18;exports.GenerateSandboxedUiArgsSchema=e.GenerateSandboxedUiArgsSchema;exports.LicenseContextKey=e.LicenseContextKey;exports.MCPAppsActivityContentSchema=e.MCPAppsActivityContentSchema;exports.MCPAppsActivityRenderer=e.MCPAppsActivityRenderer;exports.MCPAppsActivityType=e.MCPAppsActivityType;exports.OpenGenerativeUIActivityRenderer=e.OpenGenerativeUIActivityRenderer;exports.OpenGenerativeUIActivityType=e.OpenGenerativeUIActivityType;exports.OpenGenerativeUIContentSchema=e.OpenGenerativeUIContentSchema;exports.OpenGenerativeUIRenderer=e.OpenGenerativeUIRenderer;exports.OpenGenerativeUIToolRenderer=e.OpenGenerativeUIToolRenderer;exports.UseAgentUpdate=e.UseAgentUpdate;exports.createA2UIMessageRenderer=e.createA2UIMessageRenderer;exports.createDefaultLicenseRef=e.createDefaultLicenseRef;exports.defineToolCallRenderer=e.defineToolCallRenderer;exports.extractCompleteStyles=e.extractCompleteStyles;exports.getOperationSurfaceId=e.getOperationSurfaceId;exports.processPartialHtml=e.processPartialHtml;exports.useAgent=e.useAgent;exports.useAgentContext=e.useAgentContext;exports.useAttachments=e.useAttachments;exports.useCapabilities=e.useCapabilities;exports.useComponent=e.useComponent;exports.useConfigureSuggestions=e.useConfigureSuggestions;exports.useCopilotChatConfiguration=e.useCopilotChatConfiguration;exports.useCopilotKit=e.useCopilotKit;exports.useDefaultRenderTool=e.useDefaultRenderTool;exports.useFrontendTool=e.useFrontendTool;exports.useHumanInTheLoop=e.useHumanInTheLoop;exports.useInterrupt=e.useInterrupt;exports.useKatexStyles=e.useKatexStyles;exports.useKeyboardHeight=e.useKeyboardHeight;exports.useLicenseContext=e.useLicenseContext;exports.useRenderActivityMessage=e.useRenderActivityMessage;exports.useRenderCustomMessages=e.useRenderCustomMessages;exports.useRenderTool=e.useRenderTool;exports.useSandboxFunctions=e.useSandboxFunctions;exports.useSuggestions=e.useSuggestions;exports.useThreads=e.useThreads;exports.vueBasicCatalog=e.vueBasicCatalog;Object.defineProperty(exports,"createLicenseContextValue",{enumerable:!0,get:()=>n.createLicenseContextValue});Object.keys(o).forEach(t=>{t!=="default"&&!Object.prototype.hasOwnProperty.call(exports,t)&&Object.defineProperty(exports,t,{enumerable:!0,get:()=>o[t]})});Object.keys(i).forEach(t=>{t!=="default"&&!Object.prototype.hasOwnProperty.call(exports,t)&&Object.defineProperty(exports,t,{enumerable:!0,get:()=>i[t]})});
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/v2/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from "@copilotkit/core";
|
|
2
2
|
export * from "@ag-ui/client";
|
|
3
|
-
import { A as o, _ as i, a as n, C, b as r, c as p, d as l, e as u, f as c, g, h as d, i as h, j as A, k as v, l as S, m, n as y, o as I, p as f, q as R, r as T, s as U, t as x, u as M, v as P, w as b, x as V, y as w, z as K, B as O, G, L, M as B, D, E as H, O as F, F as Q, H as j, I as k, J as q, U as z, K as E, N as J, P as N, Q as W, R as X, S as Y, T as Z, V as _, W as $, X as ee, Y as ae, Z as te, $ as se, a0 as oe, a1 as ie, a2 as ne, a3 as Ce, a4 as re, a5 as pe, a6 as le, a7 as ue, a8 as ce, a9 as ge, aa as de, ab as he, ac as Ae, ad as ve, ae as Se } from "../use-render-activity-message-
|
|
3
|
+
import { A as o, _ as i, a as n, C, b as r, c as p, d as l, e as u, f as c, g, h as d, i as h, j as A, k as v, l as S, m, n as y, o as I, p as f, q as R, r as T, s as U, t as x, u as M, v as P, w as b, x as V, y as w, z as K, B as O, G, L, M as B, D, E as H, O as F, F as Q, H as j, I as k, J as q, U as z, K as E, N as J, P as N, Q as W, R as X, S as Y, T as Z, V as _, W as $, X as ee, Y as ae, Z as te, $ as se, a0 as oe, a1 as ie, a2 as ne, a3 as Ce, a4 as re, a5 as pe, a6 as le, a7 as ue, a8 as ce, a9 as ge, aa as de, ab as he, ac as Ae, ad as ve, ae as Se } from "../use-render-activity-message-XmuT9fKy.js";
|
|
4
4
|
import { createLicenseContextValue as ye } from "@copilotkit/shared";
|
|
5
5
|
export {
|
|
6
6
|
o as A2UIActivityContentSchema,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@copilotkit/vue",
|
|
3
|
-
"version": "1.75.
|
|
3
|
+
"version": "1.75.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Vue 3 components and composables for CopilotKit",
|
|
6
6
|
"keywords": [
|
|
@@ -70,10 +70,10 @@
|
|
|
70
70
|
"streamdown-vue": "^1.0.29",
|
|
71
71
|
"zod": "^3.25.75",
|
|
72
72
|
"zod-to-json-schema": "^3.24.5",
|
|
73
|
-
"@copilotkit/core": "1.75.
|
|
74
|
-
"@copilotkit/shared": "1.75.
|
|
75
|
-
"@copilotkit/web-
|
|
76
|
-
"@copilotkit/web-
|
|
73
|
+
"@copilotkit/core": "1.75.2",
|
|
74
|
+
"@copilotkit/shared": "1.75.2",
|
|
75
|
+
"@copilotkit/web-components": "1.75.2",
|
|
76
|
+
"@copilotkit/web-inspector": "1.75.2"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
79
|
"@eslint/js": "^9.39.2",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, onMounted, ref, useSlots, watch } from "vue";
|
|
3
|
-
import type { Component } from "vue";
|
|
3
|
+
import type { Component, FunctionalComponent, VNodeChild } from "vue";
|
|
4
4
|
import type {
|
|
5
5
|
ActivityMessage,
|
|
6
6
|
AssistantMessage,
|
|
@@ -262,9 +262,11 @@ function getMeta(
|
|
|
262
262
|
? Math.max(messageIdsInRun.indexOf(message.id), 0)
|
|
263
263
|
: 0;
|
|
264
264
|
const numberOfMessagesInRun = resolvedRunId ? messageIdsInRun.length : 1;
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
265
|
+
|
|
266
|
+
// `getStateByRun` deep-clones the whole run state, so resolve it only when
|
|
267
|
+
// a consumer reads `stateSnapshot`, and at most once per meta object.
|
|
268
|
+
let stateSnapshot: unknown;
|
|
269
|
+
let stateSnapshotResolved = false;
|
|
268
270
|
|
|
269
271
|
return {
|
|
270
272
|
runId,
|
|
@@ -272,10 +274,37 @@ function getMeta(
|
|
|
272
274
|
messageIndexInRun,
|
|
273
275
|
numberOfMessagesInRun,
|
|
274
276
|
agentId,
|
|
275
|
-
stateSnapshot
|
|
277
|
+
get stateSnapshot() {
|
|
278
|
+
if (!stateSnapshotResolved) {
|
|
279
|
+
stateSnapshotResolved = true;
|
|
280
|
+
stateSnapshot = resolvedRunId
|
|
281
|
+
? core.getStateByRun(agentId, threadId, resolvedRunId)
|
|
282
|
+
: undefined;
|
|
283
|
+
}
|
|
284
|
+
return stateSnapshot;
|
|
285
|
+
},
|
|
276
286
|
};
|
|
277
287
|
}
|
|
278
288
|
|
|
289
|
+
// `Object.assign` onto the meta object keeps the lazy `stateSnapshot` getter.
|
|
290
|
+
// A spread would call it.
|
|
291
|
+
function getMessageSlotProps(
|
|
292
|
+
message: Message,
|
|
293
|
+
position: MessageMetaProps["position"],
|
|
294
|
+
): MessageMetaProps {
|
|
295
|
+
return Object.assign(getMeta(message), { message, position });
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Calls a `#message-before` / `#message-after` slot with the meta object
|
|
299
|
+
// itself. A template `<slot v-bind>` inside `v-for` goes through
|
|
300
|
+
// `mergeProps`, which reads every key and so would clone the run state for
|
|
301
|
+
// slots that never read `stateSnapshot`.
|
|
302
|
+
const MessageMetaSlot: FunctionalComponent<{
|
|
303
|
+
render: (props: MessageMetaProps) => unknown;
|
|
304
|
+
slotProps: MessageMetaProps;
|
|
305
|
+
}> = ({ render, slotProps }) => render(slotProps) as VNodeChild;
|
|
306
|
+
MessageMetaSlot.props = ["render", "slotProps"];
|
|
307
|
+
|
|
279
308
|
function getActivitySlotName(activityType: string): `activity-${string}` {
|
|
280
309
|
return `activity-${activityType}`;
|
|
281
310
|
}
|
|
@@ -310,11 +339,7 @@ function resolveCustomMessageRenderer(
|
|
|
310
339
|
|
|
311
340
|
return {
|
|
312
341
|
renderer: selected.render as ResolvedCustomMessageRenderer["renderer"],
|
|
313
|
-
props:
|
|
314
|
-
...getMeta(message),
|
|
315
|
-
message,
|
|
316
|
-
position,
|
|
317
|
-
},
|
|
342
|
+
props: getMessageSlotProps(message, position),
|
|
318
343
|
};
|
|
319
344
|
}
|
|
320
345
|
|
|
@@ -370,17 +395,10 @@ function resolveToolMessage(
|
|
|
370
395
|
v-for="message in deduplicatedMessages"
|
|
371
396
|
:key="rowRenderKeys.get(message.id) ?? message.id"
|
|
372
397
|
>
|
|
373
|
-
<
|
|
398
|
+
<MessageMetaSlot
|
|
374
399
|
v-if="componentSlots['message-before']"
|
|
375
|
-
|
|
376
|
-
:
|
|
377
|
-
position="before"
|
|
378
|
-
:run-id="getMeta(message).runId"
|
|
379
|
-
:message-index="getMeta(message).messageIndex"
|
|
380
|
-
:message-index-in-run="getMeta(message).messageIndexInRun"
|
|
381
|
-
:number-of-messages-in-run="getMeta(message).numberOfMessagesInRun"
|
|
382
|
-
:agent-id="getMeta(message).agentId"
|
|
383
|
-
:state-snapshot="getMeta(message).stateSnapshot"
|
|
400
|
+
:render="componentSlots['message-before']"
|
|
401
|
+
:slot-props="getMessageSlotProps(message, 'before')"
|
|
384
402
|
/>
|
|
385
403
|
<component
|
|
386
404
|
v-else-if="resolveCustomMessageRenderer(message, 'before')"
|
|
@@ -463,17 +481,10 @@ function resolveToolMessage(
|
|
|
463
481
|
</slot>
|
|
464
482
|
</slot>
|
|
465
483
|
|
|
466
|
-
<
|
|
484
|
+
<MessageMetaSlot
|
|
467
485
|
v-if="componentSlots['message-after']"
|
|
468
|
-
|
|
469
|
-
:
|
|
470
|
-
position="after"
|
|
471
|
-
:run-id="getMeta(message).runId"
|
|
472
|
-
:message-index="getMeta(message).messageIndex"
|
|
473
|
-
:message-index-in-run="getMeta(message).messageIndexInRun"
|
|
474
|
-
:number-of-messages-in-run="getMeta(message).numberOfMessagesInRun"
|
|
475
|
-
:agent-id="getMeta(message).agentId"
|
|
476
|
-
:state-snapshot="getMeta(message).stateSnapshot"
|
|
486
|
+
:render="componentSlots['message-after']"
|
|
487
|
+
:slot-props="getMessageSlotProps(message, 'after')"
|
|
477
488
|
/>
|
|
478
489
|
<component
|
|
479
490
|
v-else-if="resolveCustomMessageRenderer(message, 'after')"
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { defineComponent, h, nextTick, ref } from "vue";
|
|
3
|
+
import { mount } from "@vue/test-utils";
|
|
4
|
+
import type { Message } from "@ag-ui/core";
|
|
5
|
+
import { CopilotKitCore } from "@copilotkit/core";
|
|
6
|
+
import CopilotKitProvider from "../../../providers/CopilotKitProvider.vue";
|
|
7
|
+
import CopilotChatConfigurationProvider from "../../../providers/CopilotChatConfigurationProvider.vue";
|
|
8
|
+
import CopilotChatMessageView from "../CopilotChatMessageView.vue";
|
|
9
|
+
import CopilotChat from "../CopilotChat.vue";
|
|
10
|
+
import { renderWithCopilotKit } from "../../../__tests__/utils/mount";
|
|
11
|
+
import { StateCapturingAgent } from "../../../__tests__/utils/agents";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* `getStateByRun` deep-clones the whole run state. The `#message-before` and
|
|
15
|
+
* `#message-after` slots used to resolve their meta props with six separate
|
|
16
|
+
* `getMeta()` calls per row, each of which cloned the state, whether or not
|
|
17
|
+
* the slot read `stateSnapshot` (#7507).
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const messages: Message[] = [
|
|
21
|
+
{ id: "user-1", role: "user", content: "Hello" },
|
|
22
|
+
{ id: "assistant-1", role: "assistant", content: "Hi there" },
|
|
23
|
+
{ id: "user-2", role: "user", content: "Again" },
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
function installRunSpies() {
|
|
27
|
+
vi.spyOn(CopilotKitCore.prototype, "getRunIdForMessage").mockReturnValue(
|
|
28
|
+
"run-1",
|
|
29
|
+
);
|
|
30
|
+
return vi
|
|
31
|
+
.spyOn(CopilotKitCore.prototype, "getStateByRun")
|
|
32
|
+
.mockImplementation(() => ({ plan: "cloned" }));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function mountMessageView(
|
|
36
|
+
slots: Parameters<typeof h>[2],
|
|
37
|
+
providerProps: Record<string, unknown> = {},
|
|
38
|
+
) {
|
|
39
|
+
return mount(CopilotKitProvider, {
|
|
40
|
+
props: { runtimeUrl: "/api/copilotkit", ...providerProps },
|
|
41
|
+
slots: {
|
|
42
|
+
default: () =>
|
|
43
|
+
h(
|
|
44
|
+
CopilotChatConfigurationProvider,
|
|
45
|
+
{ threadId: "thread-1", agentId: "default" },
|
|
46
|
+
{
|
|
47
|
+
default: () => h(CopilotChatMessageView, { messages }, slots),
|
|
48
|
+
},
|
|
49
|
+
),
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
describe("CopilotChatMessageView message slot meta cost", () => {
|
|
55
|
+
afterEach(() => {
|
|
56
|
+
vi.restoreAllMocks();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("does not clone run state for a slot that never reads stateSnapshot", () => {
|
|
60
|
+
const getStateByRun = installRunSpies();
|
|
61
|
+
|
|
62
|
+
const wrapper = mountMessageView({
|
|
63
|
+
"message-before": ({ message }: { message: Message }) =>
|
|
64
|
+
h("span", { "data-testid": "before" }, message.id),
|
|
65
|
+
"message-after": ({ message }: { message: Message }) =>
|
|
66
|
+
h("span", { "data-testid": "after" }, message.id),
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
expect(wrapper.findAll("[data-testid='after']")).toHaveLength(3);
|
|
70
|
+
expect(wrapper.findAll("[data-testid='before']")).toHaveLength(3);
|
|
71
|
+
expect(getStateByRun).not.toHaveBeenCalled();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("clones run state at most once per slot render when stateSnapshot is read", () => {
|
|
75
|
+
const getStateByRun = installRunSpies();
|
|
76
|
+
const received: unknown[] = [];
|
|
77
|
+
|
|
78
|
+
mountMessageView({
|
|
79
|
+
"message-after": (props: { stateSnapshot: unknown }) => {
|
|
80
|
+
received.push(props.stateSnapshot);
|
|
81
|
+
received.push(props.stateSnapshot);
|
|
82
|
+
return h("span");
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
expect(received).toHaveLength(6);
|
|
87
|
+
expect(
|
|
88
|
+
received.every((s) => (s as { plan: string }).plan === "cloned"),
|
|
89
|
+
).toBe(true);
|
|
90
|
+
expect(getStateByRun).toHaveBeenCalledTimes(3);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("still passes every meta prop to the slot", () => {
|
|
94
|
+
installRunSpies();
|
|
95
|
+
const received: Record<string, unknown>[] = [];
|
|
96
|
+
|
|
97
|
+
mountMessageView({
|
|
98
|
+
"message-after": (props: Record<string, unknown>) => {
|
|
99
|
+
received.push({ ...props });
|
|
100
|
+
return h("span");
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
expect(received).toHaveLength(3);
|
|
105
|
+
expect(received[1]).toMatchObject({
|
|
106
|
+
message: messages[1],
|
|
107
|
+
position: "after",
|
|
108
|
+
runId: "run-1",
|
|
109
|
+
agentId: "default",
|
|
110
|
+
stateSnapshot: { plan: "cloned" },
|
|
111
|
+
});
|
|
112
|
+
for (const props of received) {
|
|
113
|
+
expect(props).toHaveProperty("messageIndex");
|
|
114
|
+
expect(props).toHaveProperty("messageIndexInRun");
|
|
115
|
+
expect(props).toHaveProperty("numberOfMessagesInRun");
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("clones run state once per row for a provider custom message renderer", () => {
|
|
120
|
+
const getStateByRun = installRunSpies();
|
|
121
|
+
const received: unknown[] = [];
|
|
122
|
+
const renderer = defineComponent({
|
|
123
|
+
props: ["message", "position", "stateSnapshot"],
|
|
124
|
+
setup(props) {
|
|
125
|
+
return () => {
|
|
126
|
+
received.push(props.stateSnapshot);
|
|
127
|
+
return h("span", { "data-testid": "custom" });
|
|
128
|
+
};
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const wrapper = mountMessageView(
|
|
133
|
+
{},
|
|
134
|
+
{ renderCustomMessages: [{ render: renderer }] },
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
// One `before` and one `after` renderer per row.
|
|
138
|
+
expect(wrapper.findAll("[data-testid='custom']")).toHaveLength(6);
|
|
139
|
+
expect(
|
|
140
|
+
received.every((s) => (s as { plan: string }).plan === "cloned"),
|
|
141
|
+
).toBe(true);
|
|
142
|
+
expect(getStateByRun).toHaveBeenCalledTimes(6);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("re-renders slot content when state the slot reads changes", async () => {
|
|
146
|
+
installRunSpies();
|
|
147
|
+
const label = ref("first");
|
|
148
|
+
|
|
149
|
+
const wrapper = mountMessageView({
|
|
150
|
+
"message-after": ({ message }: { message: Message }) =>
|
|
151
|
+
h("span", { "data-testid": "after" }, `${message.id}:${label.value}`),
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
expect(wrapper.findAll("[data-testid='after']")[0]!.text()).toBe(
|
|
155
|
+
"user-1:first",
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
label.value = "second";
|
|
159
|
+
await nextTick();
|
|
160
|
+
|
|
161
|
+
expect(wrapper.findAll("[data-testid='after']")[0]!.text()).toBe(
|
|
162
|
+
"user-1:second",
|
|
163
|
+
);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("keeps the snapshot lazy through CopilotChat slot forwarding", () => {
|
|
167
|
+
const getStateByRun = installRunSpies();
|
|
168
|
+
const agent = new StateCapturingAgent([], "default");
|
|
169
|
+
agent.setMessages(messages);
|
|
170
|
+
|
|
171
|
+
const { wrapper } = renderWithCopilotKit(
|
|
172
|
+
() =>
|
|
173
|
+
h(
|
|
174
|
+
CopilotChat,
|
|
175
|
+
{ welcomeScreen: false },
|
|
176
|
+
{
|
|
177
|
+
"message-after": ({ message }: { message: Message }) =>
|
|
178
|
+
h("span", { "data-testid": "after" }, message.id),
|
|
179
|
+
},
|
|
180
|
+
),
|
|
181
|
+
{ agents: { default: agent } },
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
expect(wrapper.findAll("[data-testid='after']")).toHaveLength(3);
|
|
185
|
+
expect(getStateByRun).not.toHaveBeenCalled();
|
|
186
|
+
});
|
|
187
|
+
});
|