@copilotkit/vue 2.0.0-rc.19 → 2.0.0-rc.20
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-CsWYyd6r.cjs +91 -0
- package/dist/use-render-activity-message-CsWYyd6r.cjs.map +1 -0
- package/dist/{use-render-activity-message-g7xEf4ep.js → use-render-activity-message-DntKKNdd.js} +6354 -6747
- package/dist/use-render-activity-message-DntKKNdd.js.map +1 -0
- package/dist/v2/components/InlineFeatureWarning.vue.d.ts.map +1 -1
- package/dist/v2/components/LicenseWarningBanner.vue.d.ts +2 -2
- package/dist/v2/components/LicenseWarningBanner.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChat.vue.d.ts +1 -1
- package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts +1 -1
- package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatInspectorButton.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatReasoningMessage.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 -1
- package/dist/v2/components/chat/CopilotChatWorkSummary.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotModalHeader.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotPopup.vue.d.ts +1 -1
- package/dist/v2/components/chat/CopilotPopupView.vue.d.ts +1 -1
- package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts +1 -1
- package/dist/v2/components/chat/CopilotSidebar.vue.d.ts +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/index.d.ts +12 -12
- package/dist/v2/components/chat/inspector-shortcuts.d.ts +2 -1
- package/dist/v2/components/chat/inspector-shortcuts.d.ts.map +1 -1
- package/dist/v2/components/chat/message-feedback.d.ts +18 -49
- package/dist/v2/components/chat/message-feedback.d.ts.map +1 -1
- package/dist/v2/components/chat/normalize-auto-scroll.d.ts +2 -2
- package/dist/v2/components/chat/normalize-auto-scroll.d.ts.map +1 -1
- package/dist/v2/components/chat/use-copy-feedback.d.ts +11 -0
- package/dist/v2/components/chat/use-copy-feedback.d.ts.map +1 -0
- package/dist/v2/hooks/use-keyboard-height.d.ts +1 -1
- package/dist/v2/hooks/use-keyboard-height.d.ts.map +1 -1
- package/dist/v2/hooks/use-pin-to-send.d.ts +4 -12
- package/dist/v2/hooks/use-pin-to-send.d.ts.map +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.mjs +1 -1
- package/dist/v2/lib/is-mobile-viewport.d.ts +1 -14
- package/dist/v2/lib/is-mobile-viewport.d.ts.map +1 -1
- package/dist/v2/lib/shallow-stable.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/v2/components/InlineFeatureWarning.vue +20 -21
- package/src/v2/components/LicenseWarningBanner.vue +25 -149
- package/src/v2/components/__tests__/LicenseWarningBanner.test.ts +48 -8
- package/src/v2/components/chat/CopilotChatAssistantMessage.vue +19 -43
- package/src/v2/components/chat/CopilotChatFeedbackCommentPopover.vue +2 -2
- package/src/v2/components/chat/CopilotChatInspectorButton.vue +45 -108
- package/src/v2/components/chat/CopilotChatReasoningMessage.vue +2 -28
- package/src/v2/components/chat/CopilotChatUserMessage.vue +24 -112
- package/src/v2/components/chat/CopilotChatWorkSummary.vue +23 -59
- package/src/v2/components/chat/CopilotModalHeader.vue +11 -23
- package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.learningFeedback.test.ts +5 -5
- package/src/v2/components/chat/inspector-shortcuts.ts +10 -16
- package/src/v2/components/chat/message-feedback.ts +62 -197
- package/src/v2/components/chat/normalize-auto-scroll.ts +3 -17
- package/src/v2/components/chat/use-copy-feedback.ts +21 -0
- package/src/v2/hooks/use-keyboard-height.ts +17 -40
- package/src/v2/hooks/use-pin-to-send.ts +15 -99
- package/src/v2/lib/__tests__/shallow-stable.test.ts +54 -0
- package/src/v2/lib/is-mobile-viewport.ts +5 -23
- package/src/v2/lib/shallow-stable.ts +2 -16
- package/dist/use-render-activity-message-IH90zF01.cjs +0 -92
- package/dist/use-render-activity-message-IH90zF01.cjs.map +0 -1
- package/dist/use-render-activity-message-g7xEf4ep.js.map +0 -1
- package/dist/v2/lib/message-feedback.d.ts +0 -33
- package/dist/v2/lib/message-feedback.d.ts.map +0 -1
- package/src/v2/components/chat/__tests__/normalize-auto-scroll.test.ts +0 -39
- package/src/v2/lib/__tests__/is-mobile-viewport.test.ts +0 -48
- package/src/v2/lib/__tests__/message-feedback.test.ts +0 -152
- package/src/v2/lib/message-feedback.ts +0 -120
|
@@ -20,6 +20,11 @@ import type {
|
|
|
20
20
|
import CopilotTooltip from "../ui/CopilotTooltip.vue";
|
|
21
21
|
import { useCopilotId } from "../ui/use-id";
|
|
22
22
|
import { hideInspectorShortcuts } from "./inspector-shortcuts";
|
|
23
|
+
import {
|
|
24
|
+
ɵHoverMenuController,
|
|
25
|
+
ɵinspectorKiteFill,
|
|
26
|
+
ɵinspectorKiteIcon,
|
|
27
|
+
} from "@copilotkit/core";
|
|
23
28
|
|
|
24
29
|
defineOptions({ inheritAttrs: false });
|
|
25
30
|
|
|
@@ -37,32 +42,20 @@ const menuId = useCopilotId("cpk-inspector-menu");
|
|
|
37
42
|
const triggerId = useCopilotId("cpk-inspector-button");
|
|
38
43
|
const kiteId = useCopilotId("cpk-inspector-kite");
|
|
39
44
|
const trigger = shallowRef<HTMLButtonElement | null>(null);
|
|
40
|
-
const open = ref(false);
|
|
41
|
-
const dark = ref(false);
|
|
42
45
|
const initialFocus = ref<"first" | "none">("none");
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
open.value = next;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const scheduleClose = () => {
|
|
60
|
-
cancelClose();
|
|
61
|
-
closeTimer = setTimeout(() => {
|
|
62
|
-
// Keep the panel available while the keyboard is interacting with it.
|
|
63
|
-
if (openedByHover) open.value = false;
|
|
64
|
-
}, 180);
|
|
65
|
-
};
|
|
46
|
+
const menu = new ɵHoverMenuController();
|
|
47
|
+
const menuState = shallowRef(menu.getSnapshot());
|
|
48
|
+
const unsubscribeMenu = menu.subscribe(() => {
|
|
49
|
+
menuState.value = menu.getSnapshot();
|
|
50
|
+
});
|
|
51
|
+
onBeforeUnmount(() => {
|
|
52
|
+
unsubscribeMenu();
|
|
53
|
+
menu.dispose();
|
|
54
|
+
});
|
|
55
|
+
const open = computed(() => menuState.value.open);
|
|
56
|
+
const dark = computed(() => menuState.value.dark);
|
|
57
|
+
const { cancelClose, scheduleClose, keyboardUsed } = menu;
|
|
58
|
+
const changeOpen = (next: boolean) => menu.setOpen(next, trigger.value);
|
|
66
59
|
|
|
67
60
|
const items = computed<CopilotDropdownMenuEntry[]>(() => [
|
|
68
61
|
{
|
|
@@ -82,9 +75,8 @@ const isInspectItem = (item: CopilotDropdownMenuItem) =>
|
|
|
82
75
|
|
|
83
76
|
function onPointerEnter(event: PointerEvent) {
|
|
84
77
|
if (props.disabled || event.pointerType === "touch") return;
|
|
85
|
-
openedByHover = true;
|
|
86
78
|
initialFocus.value = "none";
|
|
87
|
-
|
|
79
|
+
menu.pointerEnter({ pointerType: event.pointerType, trigger: trigger.value });
|
|
88
80
|
}
|
|
89
81
|
|
|
90
82
|
function onClick() {
|
|
@@ -93,7 +85,7 @@ function onClick() {
|
|
|
93
85
|
}
|
|
94
86
|
|
|
95
87
|
function onKeyDown(event: KeyboardEvent) {
|
|
96
|
-
|
|
88
|
+
keyboardUsed();
|
|
97
89
|
if (event.key === "Enter" || event.key === " ") {
|
|
98
90
|
// Enter and Space inspect, as a click does, instead of opening the menu.
|
|
99
91
|
event.preventDefault();
|
|
@@ -103,7 +95,7 @@ function onKeyDown(event: KeyboardEvent) {
|
|
|
103
95
|
initialFocus.value = "first";
|
|
104
96
|
if (open.value) {
|
|
105
97
|
// Open already from hover: move into it.
|
|
106
|
-
|
|
98
|
+
changeOpen(false);
|
|
107
99
|
queueMicrotask(() => changeOpen(true));
|
|
108
100
|
} else {
|
|
109
101
|
changeOpen(true);
|
|
@@ -112,14 +104,14 @@ function onKeyDown(event: KeyboardEvent) {
|
|
|
112
104
|
}
|
|
113
105
|
|
|
114
106
|
function onSelect(item: CopilotDropdownMenuItem) {
|
|
115
|
-
const returnFocus = !openedByHover;
|
|
107
|
+
const returnFocus = !menu.openedByHover;
|
|
116
108
|
changeOpen(false);
|
|
117
109
|
item.action?.();
|
|
118
110
|
if (returnFocus && !isInspectItem(item)) trigger.value?.focus();
|
|
119
111
|
}
|
|
120
112
|
|
|
121
113
|
function onDismiss(reason: CopilotDropdownMenuDismissReason) {
|
|
122
|
-
const returnFocus = !openedByHover && reason !== "outside";
|
|
114
|
+
const returnFocus = !menu.openedByHover && reason !== "outside";
|
|
123
115
|
changeOpen(false);
|
|
124
116
|
if (returnFocus) trigger.value?.focus();
|
|
125
117
|
}
|
|
@@ -178,7 +170,7 @@ const descriptionFor = (item: CopilotDropdownMenuItem) =>
|
|
|
178
170
|
@dismiss="onDismiss"
|
|
179
171
|
@pointer-enter="cancelClose"
|
|
180
172
|
@pointer-leave="scheduleClose"
|
|
181
|
-
@keydown="
|
|
173
|
+
@keydown="keyboardUsed"
|
|
182
174
|
>
|
|
183
175
|
<template #header>
|
|
184
176
|
<div
|
|
@@ -226,90 +218,35 @@ const descriptionFor = (item: CopilotDropdownMenuItem) =>
|
|
|
226
218
|
v-if="isInspectItem(item)"
|
|
227
219
|
aria-hidden="true"
|
|
228
220
|
class="cpk-inspector-button-kite-icon cpk-inspector-button-menu-item-icon"
|
|
229
|
-
viewBox="
|
|
221
|
+
:viewBox="ɵinspectorKiteIcon.viewBox"
|
|
230
222
|
fill="none"
|
|
231
223
|
>
|
|
232
224
|
<path
|
|
233
|
-
|
|
234
|
-
:
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
:
|
|
239
|
-
|
|
240
|
-
<path
|
|
241
|
-
d="M10.762 3.705C13.4137 5.15161 16.4787 5.80132 20.545 6.14367C20.5703 6.14585 20.5787 6.18008 20.5557 6.19197C20.0359 6.45923 17.0574 7.97512 14.8455 8.78701C14.2524 9.00453 13.6564 9.20632 13.0692 9.39249C13.0562 9.39656 13.0419 9.39015 13.0369 9.37774L10.7005 3.75979C10.6849 3.72196 10.7257 3.68538 10.762 3.705Z"
|
|
242
|
-
:fill="`url(#${kiteId}-paint2_linear)`"
|
|
243
|
-
/>
|
|
244
|
-
<path
|
|
245
|
-
d="M10.7145 3.79041L17.8305 20.7659"
|
|
246
|
-
stroke="#513C9F"
|
|
247
|
-
stroke-width="0.17284"
|
|
248
|
-
stroke-linecap="round"
|
|
249
|
-
/>
|
|
250
|
-
<path
|
|
251
|
-
d="M6.44531 11.0476C6.44531 11.0476 10.375 10.3422 14.0686 9.06804C17.7623 7.7939 20.5122 6.23373 20.5122 6.23373"
|
|
252
|
-
stroke="#513C9F"
|
|
253
|
-
stroke-width="0.17284"
|
|
254
|
-
stroke-linecap="round"
|
|
255
|
-
/>
|
|
256
|
-
<path
|
|
257
|
-
d="M11.6914 5.93518L9.05534 14.7068M9.05534 14.7068H15.3203M9.05534 14.7068L0.15625 26.3646"
|
|
258
|
-
stroke="#ABABAB"
|
|
259
|
-
stroke-width="0.302474"
|
|
260
|
-
stroke-linecap="round"
|
|
261
|
-
/>
|
|
262
|
-
<path
|
|
263
|
-
d="M6.02539 23.9646L4.85806 24.1287C5.46272 25.7287 6.70381 26.4276 8.18528 26.4276C11.8147 26.4276 10.707 22.3227 12.8103 22.3227C14.3358 22.3227 13.7155 25.6498 16.9992 25.6498C19.0029 25.6498 19.2028 23.631 18.8607 22.7625C18.8589 22.7572 18.8568 22.7524 18.8538 22.7476L18.3166 21.9253C18.2817 21.8706 18.1968 21.8912 18.1907 21.9562L18.0908 22.9529C18.0838 23.0222 18.0857 23.0913 18.0936 23.1605C18.1764 23.8491 18.2291 25.5202 16.9992 25.5202C15.7015 25.5202 15.3895 22.2362 12.8103 22.2362C9.78393 22.2362 10.1726 26.298 8.31487 26.298C7.08938 26.298 6.15447 24.9153 6.02539 23.9646Z"
|
|
264
|
-
:fill="`url(#${kiteId}-paint3_linear)`"
|
|
225
|
+
v-for="path in ɵinspectorKiteIcon.paths"
|
|
226
|
+
:key="path.d"
|
|
227
|
+
:d="path.d"
|
|
228
|
+
:fill="ɵinspectorKiteFill(kiteId, path)"
|
|
229
|
+
:stroke="path.stroke"
|
|
230
|
+
:stroke-width="path.strokeWidth"
|
|
231
|
+
:stroke-linecap="path.strokeLinecap"
|
|
265
232
|
/>
|
|
266
233
|
<defs>
|
|
267
234
|
<linearGradient
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
<stop stop-color="#6430AB" />
|
|
276
|
-
<stop offset="1" stop-color="#AA89D8" />
|
|
277
|
-
</linearGradient>
|
|
278
|
-
<linearGradient
|
|
279
|
-
:id="`${kiteId}-paint1_linear`"
|
|
280
|
-
x1="12.8583"
|
|
281
|
-
y1="10.3858"
|
|
282
|
-
x2="8.40764"
|
|
283
|
-
y2="18.9846"
|
|
284
|
-
gradientUnits="userSpaceOnUse"
|
|
285
|
-
>
|
|
286
|
-
<stop stop-color="#005DBB" />
|
|
287
|
-
<stop offset="1" stop-color="#3D92E8" />
|
|
288
|
-
</linearGradient>
|
|
289
|
-
<linearGradient
|
|
290
|
-
:id="`${kiteId}-paint2_linear`"
|
|
291
|
-
x1="14.8452"
|
|
292
|
-
y1="5.02774"
|
|
293
|
-
x2="13.5047"
|
|
294
|
-
y2="9.21911"
|
|
295
|
-
gradientUnits="userSpaceOnUse"
|
|
296
|
-
>
|
|
297
|
-
<stop stop-color="#1B70C4" />
|
|
298
|
-
<stop offset="1" stop-color="#54A4F2" />
|
|
299
|
-
</linearGradient>
|
|
300
|
-
<linearGradient
|
|
301
|
-
:id="`${kiteId}-paint3_linear`"
|
|
302
|
-
x1="4.85806"
|
|
303
|
-
y1="24.2455"
|
|
304
|
-
x2="18.9963"
|
|
305
|
-
y2="24.2455"
|
|
235
|
+
v-for="gradient in ɵinspectorKiteIcon.gradients"
|
|
236
|
+
:id="`${kiteId}-${gradient.id}`"
|
|
237
|
+
:key="gradient.id"
|
|
238
|
+
:x1="gradient.x1"
|
|
239
|
+
:y1="gradient.y1"
|
|
240
|
+
:x2="gradient.x2"
|
|
241
|
+
:y2="gradient.y2"
|
|
306
242
|
gradientUnits="userSpaceOnUse"
|
|
307
243
|
>
|
|
308
|
-
<stop
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
244
|
+
<stop
|
|
245
|
+
v-for="stop in gradient.stops"
|
|
246
|
+
:key="`${stop.offset ?? '0'}-${stop.color}`"
|
|
247
|
+
:offset="stop.offset"
|
|
248
|
+
:stop-color="stop.color"
|
|
249
|
+
/>
|
|
313
250
|
</linearGradient>
|
|
314
251
|
</defs>
|
|
315
252
|
</svg>
|
|
@@ -3,8 +3,7 @@ import { computed, onBeforeUnmount, ref, watch } from "vue";
|
|
|
3
3
|
import type { Message, ReasoningMessage } from "@ag-ui/core";
|
|
4
4
|
import { IconChevronRight } from "../icons";
|
|
5
5
|
import StreamingMarkdownDefault from "./StreamingMarkdownDefault.vue";
|
|
6
|
-
import { ɵformatLabel,
|
|
7
|
-
import type { CopilotChatLabels } from "@copilotkit/core";
|
|
6
|
+
import { ɵformatLabel, ɵformatReasoningDurationLabel } from "@copilotkit/core";
|
|
8
7
|
import { useChatLabels } from "./use-chat-labels";
|
|
9
8
|
|
|
10
9
|
const props = withDefaults(
|
|
@@ -70,31 +69,6 @@ defineSlots<{
|
|
|
70
69
|
}) => unknown;
|
|
71
70
|
}>();
|
|
72
71
|
|
|
73
|
-
/** How long the model reasoned, in the chat's labels: "4 seconds", "1m 5s". */
|
|
74
|
-
function formatDuration(labels: Readonly<CopilotChatLabels>, seconds: number) {
|
|
75
|
-
const duration = ɵformatReasoningDuration(seconds);
|
|
76
|
-
switch (duration.unit) {
|
|
77
|
-
case "fewSeconds":
|
|
78
|
-
return labels.reasoningMessageDurationFewSeconds;
|
|
79
|
-
case "seconds":
|
|
80
|
-
return ɵformatLabel(labels.reasoningMessageDurationSeconds, {
|
|
81
|
-
count: duration.seconds,
|
|
82
|
-
});
|
|
83
|
-
case "minutes":
|
|
84
|
-
return ɵformatLabel(
|
|
85
|
-
duration.minutes === 1
|
|
86
|
-
? labels.reasoningMessageDurationMinutesOne
|
|
87
|
-
: labels.reasoningMessageDurationMinutesOther,
|
|
88
|
-
{ count: duration.minutes },
|
|
89
|
-
);
|
|
90
|
-
case "minutesSeconds":
|
|
91
|
-
return ɵformatLabel(labels.reasoningMessageDurationMinutesSeconds, {
|
|
92
|
-
minutes: duration.minutes,
|
|
93
|
-
seconds: duration.seconds,
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
72
|
const normalizedContent = computed(() =>
|
|
99
73
|
typeof props.message.content === "string" ? props.message.content : "",
|
|
100
74
|
);
|
|
@@ -156,7 +130,7 @@ const label = computed(() =>
|
|
|
156
130
|
isStreaming.value
|
|
157
131
|
? labels.value.reasoningMessageThinkingLabel
|
|
158
132
|
: ɵformatLabel(labels.value.reasoningMessageThoughtForLabel, {
|
|
159
|
-
duration:
|
|
133
|
+
duration: ɵformatReasoningDurationLabel(elapsed.value, labels.value),
|
|
160
134
|
}),
|
|
161
135
|
);
|
|
162
136
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed
|
|
2
|
+
import { computed } from "vue";
|
|
3
3
|
import type { UserMessage } from "@ag-ui/core";
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from "@copilotkit/
|
|
4
|
+
import {
|
|
5
|
+
ɵflattenUserMessageContent,
|
|
6
|
+
ɵgetBranchNavState,
|
|
7
|
+
ɵgetUserMessageMediaFilename,
|
|
8
|
+
ɵgetUserMessageMediaParts,
|
|
9
|
+
} from "@copilotkit/core";
|
|
10
10
|
import { useCopilotChatConfiguration } from "../../providers/useCopilotChatConfiguration";
|
|
11
11
|
import { CopilotChatDefaultLabels } from "../../providers/types";
|
|
12
12
|
import {
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
} from "../icons";
|
|
19
19
|
import CopilotTooltip from "../ui/CopilotTooltip.vue";
|
|
20
20
|
import CopilotChatAttachmentRenderer from "./CopilotChatAttachmentRenderer.vue";
|
|
21
|
+
import { useCopyFeedback } from "./use-copy-feedback";
|
|
21
22
|
import type {
|
|
22
23
|
CopilotChatUserMessageBranchNavigationSlotProps,
|
|
23
24
|
CopilotChatUserMessageCopyButtonSlotProps,
|
|
@@ -66,117 +67,34 @@ const emit = defineEmits<{
|
|
|
66
67
|
|
|
67
68
|
const config = useCopilotChatConfiguration();
|
|
68
69
|
const labels = computed(() => config.value?.labels ?? CopilotChatDefaultLabels);
|
|
69
|
-
const copied =
|
|
70
|
-
let copiedResetTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
70
|
+
const { copied, copy } = useCopyFeedback();
|
|
71
71
|
|
|
72
72
|
// Styles live in @copilotkit/core (ui/button.css, user-message.css).
|
|
73
73
|
const toolbarButtonClass =
|
|
74
74
|
"cpk-button cpk-button-assistant-message-toolbar cpk-button-size-default";
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (typeof content === "string") {
|
|
82
|
-
return content;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return content
|
|
86
|
-
.map((part) => {
|
|
87
|
-
if (
|
|
88
|
-
part &&
|
|
89
|
-
typeof part === "object" &&
|
|
90
|
-
"type" in part &&
|
|
91
|
-
(part as { type?: unknown }).type === "text" &&
|
|
92
|
-
typeof (part as { text?: unknown }).text === "string"
|
|
93
|
-
) {
|
|
94
|
-
return (part as { text: string }).text;
|
|
95
|
-
}
|
|
96
|
-
return "";
|
|
97
|
-
})
|
|
98
|
-
.filter((text) => text.length > 0)
|
|
99
|
-
.join("\n");
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
type MediaPart =
|
|
103
|
-
| ImageInputPart
|
|
104
|
-
| AudioInputPart
|
|
105
|
-
| VideoInputPart
|
|
106
|
-
| DocumentInputPart;
|
|
107
|
-
|
|
108
|
-
function getMediaParts(content: UserMessage["content"]): MediaPart[] {
|
|
109
|
-
if (!content || typeof content === "string") return [];
|
|
110
|
-
return content.filter(
|
|
111
|
-
(part): part is MediaPart =>
|
|
112
|
-
part.type === "image" ||
|
|
113
|
-
part.type === "audio" ||
|
|
114
|
-
part.type === "video" ||
|
|
115
|
-
part.type === "document",
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function getFilename(part: MediaPart): string | undefined {
|
|
120
|
-
const meta = part.metadata;
|
|
121
|
-
if (
|
|
122
|
-
meta != null &&
|
|
123
|
-
typeof meta === "object" &&
|
|
124
|
-
"filename" in meta &&
|
|
125
|
-
typeof meta.filename === "string"
|
|
126
|
-
) {
|
|
127
|
-
return meta.filename;
|
|
128
|
-
}
|
|
129
|
-
return undefined;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const mediaParts = computed(() => getMediaParts(props.message.content));
|
|
76
|
+
const mediaParts = computed(() =>
|
|
77
|
+
ɵgetUserMessageMediaParts(props.message.content),
|
|
78
|
+
);
|
|
133
79
|
|
|
134
80
|
const flattenedContent = computed(() =>
|
|
135
|
-
|
|
81
|
+
ɵflattenUserMessageContent(props.message.content),
|
|
136
82
|
);
|
|
137
83
|
const isMultiline = computed(() => flattenedContent.value.includes("\n"));
|
|
138
84
|
const hasEditAction = computed(() => typeof props.onEditMessage === "function");
|
|
139
|
-
const
|
|
140
|
-
(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
() => showBranchNavigation.value && props.branchIndex > 0,
|
|
146
|
-
);
|
|
147
|
-
const canGoNext = computed(
|
|
148
|
-
() =>
|
|
149
|
-
showBranchNavigation.value &&
|
|
150
|
-
props.branchIndex < props.numberOfBranches - 1,
|
|
85
|
+
const branchNav = computed(() =>
|
|
86
|
+
ɵgetBranchNavState({
|
|
87
|
+
branchIndex: props.branchIndex,
|
|
88
|
+
numberOfBranches: props.numberOfBranches,
|
|
89
|
+
canSwitch: typeof props.onSwitchToBranch === "function",
|
|
90
|
+
}),
|
|
151
91
|
);
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
clearTimeout(copiedResetTimeout);
|
|
156
|
-
}
|
|
157
|
-
copied.value = true;
|
|
158
|
-
copiedResetTimeout = setTimeout(() => {
|
|
159
|
-
copied.value = false;
|
|
160
|
-
copiedResetTimeout = null;
|
|
161
|
-
}, 2000);
|
|
162
|
-
}
|
|
92
|
+
const showBranchNavigation = computed(() => branchNav.value.show);
|
|
93
|
+
const canGoPrev = computed(() => branchNav.value.canGoPrev);
|
|
94
|
+
const canGoNext = computed(() => branchNav.value.canGoNext);
|
|
163
95
|
|
|
164
96
|
async function handleCopyMessage() {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if (
|
|
168
|
-
typeof navigator === "undefined" ||
|
|
169
|
-
typeof navigator.clipboard?.writeText !== "function"
|
|
170
|
-
) {
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
try {
|
|
175
|
-
await navigator.clipboard.writeText(flattenedContent.value);
|
|
176
|
-
resetCopiedStateWithDelay();
|
|
177
|
-
} catch (error) {
|
|
178
|
-
console.error("Failed to copy to clipboard:", error);
|
|
179
|
-
}
|
|
97
|
+
await copy(flattenedContent.value);
|
|
180
98
|
}
|
|
181
99
|
|
|
182
100
|
function handleEditMessage() {
|
|
@@ -212,12 +130,6 @@ function goNext() {
|
|
|
212
130
|
}
|
|
213
131
|
switchToBranch(props.branchIndex + 1);
|
|
214
132
|
}
|
|
215
|
-
|
|
216
|
-
onBeforeUnmount(() => {
|
|
217
|
-
if (copiedResetTimeout) {
|
|
218
|
-
clearTimeout(copiedResetTimeout);
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
133
|
</script>
|
|
222
134
|
|
|
223
135
|
<template>
|
|
@@ -255,7 +167,7 @@ onBeforeUnmount(() => {
|
|
|
255
167
|
:key="index"
|
|
256
168
|
:type="part.type"
|
|
257
169
|
:source="part.source"
|
|
258
|
-
:filename="
|
|
170
|
+
:filename="ɵgetUserMessageMediaFilename(part)"
|
|
259
171
|
/>
|
|
260
172
|
</div>
|
|
261
173
|
|
|
@@ -5,12 +5,7 @@
|
|
|
5
5
|
* for 9s · 7 tools" and toggles the work it folded away.
|
|
6
6
|
*/
|
|
7
7
|
import { computed, ref, watch } from "vue";
|
|
8
|
-
import {
|
|
9
|
-
ɵcountFailedToolCalls,
|
|
10
|
-
ɵformatLabel,
|
|
11
|
-
ɵformatWorkDuration,
|
|
12
|
-
ɵformatCountLabel,
|
|
13
|
-
} from "@copilotkit/core";
|
|
8
|
+
import { ɵgetWorkSummaryText } from "@copilotkit/core";
|
|
14
9
|
import { IconChevronRight } from "../icons";
|
|
15
10
|
import type { CopilotChatWorkSummarySlotProps } from "./types";
|
|
16
11
|
import { useChatLabels } from "./use-chat-labels";
|
|
@@ -34,40 +29,14 @@ watch(
|
|
|
34
29
|
);
|
|
35
30
|
|
|
36
31
|
const labels = useChatLabels();
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
:
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
props.elapsedMs !== undefined
|
|
46
|
-
? ɵformatWorkDuration(Math.max(1000, props.elapsedMs))
|
|
47
|
-
: undefined,
|
|
48
|
-
);
|
|
49
|
-
const toolCount = computed(() =>
|
|
50
|
-
ɵformatCountLabel(props.calls.length, {
|
|
51
|
-
one: labels.value.toolCallToolCountOne,
|
|
52
|
-
other: labels.value.toolCallToolCountOther,
|
|
53
|
-
}),
|
|
54
|
-
);
|
|
55
|
-
const doneLabel = computed(() =>
|
|
56
|
-
duration.value
|
|
57
|
-
? ɵformatLabel(labels.value.workSummaryWorkedForLabel, {
|
|
58
|
-
duration: duration.value,
|
|
59
|
-
})
|
|
60
|
-
: ɵformatCountLabel(props.calls.length, {
|
|
61
|
-
one: labels.value.toolCallUsedToolsOne,
|
|
62
|
-
other: labels.value.toolCallUsedToolsOther,
|
|
63
|
-
}),
|
|
64
|
-
);
|
|
65
|
-
const liveDuration = computed(() =>
|
|
66
|
-
liveMs.value !== undefined ? ɵformatWorkDuration(liveMs.value) : undefined,
|
|
67
|
-
);
|
|
68
|
-
const failedLabel = computed(() =>
|
|
69
|
-
ɵformatLabel(labels.value.toolCallFailedCountLabel, {
|
|
70
|
-
count: failed.value,
|
|
32
|
+
const text = computed(() =>
|
|
33
|
+
ɵgetWorkSummaryText({
|
|
34
|
+
isWorking: props.isWorking,
|
|
35
|
+
calls: props.calls,
|
|
36
|
+
elapsedMs: props.elapsedMs,
|
|
37
|
+
workingSince: props.workingSince,
|
|
38
|
+
now: now.value,
|
|
39
|
+
labels: labels.value,
|
|
71
40
|
}),
|
|
72
41
|
);
|
|
73
42
|
</script>
|
|
@@ -81,25 +50,20 @@ const failedLabel = computed(() =>
|
|
|
81
50
|
:aria-expanded="isOpen ? 'true' : 'false'"
|
|
82
51
|
class="cpk-work-summary"
|
|
83
52
|
>
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}}</span>
|
|
99
|
-
<span v-if="failed > 0" class="cpk-work-summary-failed">{{
|
|
100
|
-
failedLabel
|
|
101
|
-
}}</span>
|
|
102
|
-
</template>
|
|
53
|
+
<span :class="['cpk-work-summary-label', isWorking && 'cpk-shimmer']">{{
|
|
54
|
+
text.label
|
|
55
|
+
}}</span>
|
|
56
|
+
<span
|
|
57
|
+
v-if="text.detail !== null"
|
|
58
|
+
:class="[
|
|
59
|
+
'cpk-work-summary-detail',
|
|
60
|
+
isWorking && 'cpk-work-summary-timer',
|
|
61
|
+
]"
|
|
62
|
+
>{{ text.detail }}</span
|
|
63
|
+
>
|
|
64
|
+
<span v-if="text.failed !== null" class="cpk-work-summary-failed">{{
|
|
65
|
+
text.failed
|
|
66
|
+
}}</span>
|
|
103
67
|
<IconChevronRight
|
|
104
68
|
aria-hidden="true"
|
|
105
69
|
:class="[
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { computed, onBeforeUnmount, onMounted, ref, useAttrs } from "vue";
|
|
3
3
|
import { useCopilotChatConfiguration } from "../../providers/useCopilotChatConfiguration";
|
|
4
4
|
import { CopilotChatDefaultLabels } from "../../providers/types";
|
|
5
|
-
import {
|
|
5
|
+
import { ɵwatchMobileViewport } from "@copilotkit/core";
|
|
6
6
|
import CopilotModalHeaderCloseButton from "./CopilotModalHeaderCloseButton";
|
|
7
7
|
import CopilotModalHeaderTitle from "./CopilotModalHeaderTitle";
|
|
8
8
|
import { IconPanelLeftOpen } from "../icons";
|
|
@@ -45,34 +45,22 @@ function handleClose() {
|
|
|
45
45
|
config.value?.setModalOpen?.(false);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
// Tracks whether the viewport is in the mobile range
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
// on
|
|
48
|
+
// Tracks whether the viewport is in the mobile range — the same breakpoint
|
|
49
|
+
// the drawer + chat coordination use. SSR-safe: starts `false` (desktop) so
|
|
50
|
+
// the server render and first client render agree, then syncs on mount and
|
|
51
|
+
// on viewport changes.
|
|
52
52
|
const isMobile = ref(false);
|
|
53
|
-
let
|
|
54
|
-
|
|
55
|
-
function syncIsMobile() {
|
|
56
|
-
if (mobileMediaQuery) {
|
|
57
|
-
isMobile.value = mobileMediaQuery.matches;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
53
|
+
let stopWatchingMobile: (() => void) | undefined;
|
|
60
54
|
|
|
61
55
|
onMounted(() => {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
) {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
mobileMediaQuery = window.matchMedia(MOBILE_MAX_WIDTH_QUERY);
|
|
69
|
-
mobileMediaQuery.addEventListener("change", syncIsMobile);
|
|
70
|
-
syncIsMobile();
|
|
56
|
+
stopWatchingMobile = ɵwatchMobileViewport((mobile) => {
|
|
57
|
+
isMobile.value = mobile;
|
|
58
|
+
});
|
|
71
59
|
});
|
|
72
60
|
|
|
73
61
|
onBeforeUnmount(() => {
|
|
74
|
-
|
|
75
|
-
|
|
62
|
+
stopWatchingMobile?.();
|
|
63
|
+
stopWatchingMobile = undefined;
|
|
76
64
|
});
|
|
77
65
|
|
|
78
66
|
// The thread-list launcher renders ONLY when a <CopilotThreadsDrawer> wrapper
|
package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.learningFeedback.test.ts
CHANGED
|
@@ -10,12 +10,12 @@ import { useCopilotKit } from "../../../providers/useCopilotKit";
|
|
|
10
10
|
import CopilotChatMessageView from "../CopilotChatMessageView.vue";
|
|
11
11
|
import CopilotChatAssistantMessage from "../CopilotChatAssistantMessage.vue";
|
|
12
12
|
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
ɵFEEDBACK_COMMENT_CLOSE_DELAY_MS as FEEDBACK_COMMENT_CLOSE_DELAY_MS,
|
|
14
|
+
ɵMESSAGE_FEEDBACK_EVENT_NAME as MESSAGE_FEEDBACK_EVENT_NAME,
|
|
15
|
+
ɵgetMessageFeedback as getMessageFeedback,
|
|
16
|
+
ɵsetMessageFeedback as setMessageFeedback,
|
|
16
17
|
ɵresetMessageFeedbackCache,
|
|
17
|
-
} from "
|
|
18
|
-
import { FEEDBACK_COMMENT_CLOSE_DELAY_MS } from "../message-feedback";
|
|
18
|
+
} from "@copilotkit/core";
|
|
19
19
|
|
|
20
20
|
const THREAD_ID = "thread-1";
|
|
21
21
|
const AGENT_ID = "agent-1";
|