@copilotkit/vue 2.0.0-rc.6 → 2.0.0-rc.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PARITY.md +1 -1
- package/dist/index.cjs +1 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +292 -16949
- package/dist/index.mjs.map +1 -1
- package/dist/use-render-activity-message-C5LCG9a9.js +16451 -0
- package/dist/use-render-activity-message-C5LCG9a9.js.map +1 -0
- package/dist/use-render-activity-message-CPzguixR.cjs +74 -0
- package/dist/use-render-activity-message-CPzguixR.cjs.map +1 -0
- package/dist/v2/components/LicenseWarningBanner.vue.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 +196 -199
- package/dist/v2/index.mjs.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.types.d.ts +0 -5
- package/dist/v2/providers/CopilotKitProvider.types.d.ts.map +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 +7 -8
- package/src/__tests__/build-entries.test.ts +27 -0
- package/src/v2/components/LicenseWarningBanner.vue +31 -15
- package/src/v2/components/__tests__/LicenseWarningBanner.test.ts +20 -0
- 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__/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 +4 -3
- 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/vue-core.ts +3 -5
- package/src/v2/providers/CopilotKitProvider.types.ts +0 -5
- package/src/v2/providers/CopilotKitProvider.vue +29 -80
- 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 -33
- 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 +1 -2
- 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__/transcription-client.test.ts +0 -67
- package/src/v2/lib/transcription-client.ts +0 -151
|
@@ -9,8 +9,7 @@ import type { Attachment } from "@copilotkit/shared";
|
|
|
9
9
|
import type { CopilotChatAttachmentQueueProps } from "./types";
|
|
10
10
|
import { IconPlay } from "../icons";
|
|
11
11
|
import CopilotChatLightbox from "./CopilotChatLightbox.vue";
|
|
12
|
-
import {
|
|
13
|
-
import { CopilotChatDefaultLabels } from "../../providers/types";
|
|
12
|
+
import { useChatLabels } from "./use-chat-labels";
|
|
14
13
|
|
|
15
14
|
const props = withDefaults(defineProps<CopilotChatAttachmentQueueProps>(), {
|
|
16
15
|
attachments: () => [],
|
|
@@ -21,8 +20,7 @@ const emit = defineEmits<{
|
|
|
21
20
|
"remove-attachment": [id: string];
|
|
22
21
|
}>();
|
|
23
22
|
|
|
24
|
-
const
|
|
25
|
-
const labels = computed(() => config.value?.labels ?? CopilotChatDefaultLabels);
|
|
23
|
+
const labels = useChatLabels();
|
|
26
24
|
|
|
27
25
|
const activeLightboxAttachment = ref<Attachment | null>(null);
|
|
28
26
|
const documentBlobUrl = ref<string | null>(null);
|
|
@@ -32,10 +30,10 @@ const lightboxLabel = computed(() => {
|
|
|
32
30
|
if (!attachment) return undefined;
|
|
33
31
|
if (attachment.filename) return attachment.filename;
|
|
34
32
|
return attachment.type === "image"
|
|
35
|
-
?
|
|
33
|
+
? labels.value.attachmentImageAltText
|
|
36
34
|
: attachment.type === "video"
|
|
37
35
|
? "Video attachment"
|
|
38
|
-
:
|
|
36
|
+
: labels.value.attachmentDocumentLabel;
|
|
39
37
|
});
|
|
40
38
|
const isPreviewableDocument = computed(() => {
|
|
41
39
|
const attachment = activeLightboxAttachment.value;
|
|
@@ -267,7 +265,7 @@ function createBlobUrl(
|
|
|
267
265
|
class="cpk-attachment-queue-document-name"
|
|
268
266
|
data-testid="copilot-chat-attachment-document-filename"
|
|
269
267
|
>
|
|
270
|
-
{{ attachment.filename ||
|
|
268
|
+
{{ attachment.filename || labels.attachmentDocumentLabel }}
|
|
271
269
|
</span>
|
|
272
270
|
<span
|
|
273
271
|
v-if="attachment.size != null"
|
|
@@ -369,10 +367,16 @@ function createBlobUrl(
|
|
|
369
367
|
</div>
|
|
370
368
|
<div class="cpk-attachment-queue-document-card-details">
|
|
371
369
|
<div class="cpk-attachment-queue-document-card-name">
|
|
372
|
-
{{
|
|
370
|
+
{{
|
|
371
|
+
activeLightboxAttachment.filename ||
|
|
372
|
+
labels.attachmentDocumentLabel
|
|
373
|
+
}}
|
|
373
374
|
</div>
|
|
374
375
|
<div class="cpk-attachment-queue-document-card-meta">
|
|
375
|
-
{{
|
|
376
|
+
{{
|
|
377
|
+
activeLightboxAttachment.source.mimeType ||
|
|
378
|
+
labels.attachmentUnknownTypeText
|
|
379
|
+
}}
|
|
376
380
|
{{
|
|
377
381
|
activeLightboxAttachment.size != null
|
|
378
382
|
? ` · ${formatFileSize(activeLightboxAttachment.size)}`
|
|
@@ -381,7 +385,7 @@ function createBlobUrl(
|
|
|
381
385
|
</div>
|
|
382
386
|
</div>
|
|
383
387
|
<div class="cpk-attachment-queue-document-card-note">
|
|
384
|
-
|
|
388
|
+
{{ labels.attachmentNoPreviewText }}
|
|
385
389
|
</div>
|
|
386
390
|
</div>
|
|
387
391
|
</template>
|
|
@@ -4,19 +4,27 @@ import { getDocumentIcon, getSourceUrl } from "@copilotkit/shared";
|
|
|
4
4
|
import type { CopilotChatAttachmentRendererProps } from "./types";
|
|
5
5
|
import CopilotChatLightbox from "./CopilotChatLightbox.vue";
|
|
6
6
|
import { useLightbox } from "./use-lightbox";
|
|
7
|
+
import { useChatLabels } from "./use-chat-labels";
|
|
7
8
|
|
|
8
9
|
const props = withDefaults(defineProps<CopilotChatAttachmentRendererProps>(), {
|
|
9
10
|
filename: undefined,
|
|
10
11
|
className: "",
|
|
11
12
|
});
|
|
12
13
|
|
|
14
|
+
const labels = useChatLabels();
|
|
13
15
|
const imageLoadFailed = ref(false);
|
|
14
16
|
const sourceUrl = computed(() => getSourceUrl(props.source));
|
|
15
17
|
const documentLabel = computed(
|
|
16
|
-
() =>
|
|
18
|
+
() =>
|
|
19
|
+
props.filename ||
|
|
20
|
+
props.source.mimeType ||
|
|
21
|
+
labels.value.attachmentUnknownTypeText,
|
|
17
22
|
);
|
|
18
23
|
const documentAriaLabel = computed(
|
|
19
|
-
() =>
|
|
24
|
+
() =>
|
|
25
|
+
props.filename ||
|
|
26
|
+
props.source.mimeType ||
|
|
27
|
+
labels.value.attachmentDocumentAltText,
|
|
20
28
|
);
|
|
21
29
|
|
|
22
30
|
const imageButton = ref<HTMLButtonElement | null>(null);
|
|
@@ -43,7 +51,7 @@ const {
|
|
|
43
51
|
<img
|
|
44
52
|
ref="thumbnailRef"
|
|
45
53
|
:src="sourceUrl"
|
|
46
|
-
alt="
|
|
54
|
+
:alt="labels.attachmentImageAltText"
|
|
47
55
|
class="cpk-attachment-renderer cpk-attachment-renderer-image"
|
|
48
56
|
:class="props.className"
|
|
49
57
|
data-testid="copilot-chat-attachment-renderer-image"
|
|
@@ -52,14 +60,14 @@ const {
|
|
|
52
60
|
<!-- Teleported to the body; inside the button only to keep one root. -->
|
|
53
61
|
<CopilotChatLightbox
|
|
54
62
|
v-if="lightboxOpen"
|
|
55
|
-
label="
|
|
63
|
+
:label="labels.attachmentImageAltText"
|
|
56
64
|
:return-focus-to="imageButton"
|
|
57
65
|
@close="closeLightbox"
|
|
58
66
|
>
|
|
59
67
|
<img
|
|
60
68
|
:style="{ viewTransitionName: vtName }"
|
|
61
69
|
:src="sourceUrl"
|
|
62
|
-
alt="
|
|
70
|
+
:alt="labels.attachmentImageAltText"
|
|
63
71
|
class="cpk-attachment-renderer-lightbox-image"
|
|
64
72
|
data-testid="copilot-chat-attachment-renderer-lightbox-image"
|
|
65
73
|
/>
|
|
@@ -71,7 +79,7 @@ const {
|
|
|
71
79
|
:class="props.className"
|
|
72
80
|
data-testid="copilot-chat-attachment-renderer-image-fallback"
|
|
73
81
|
>
|
|
74
|
-
<span>
|
|
82
|
+
<span>{{ labels.attachmentImageLoadErrorText }}</span>
|
|
75
83
|
</div>
|
|
76
84
|
|
|
77
85
|
<div
|
|
@@ -8,8 +8,7 @@ import {
|
|
|
8
8
|
useAttrs,
|
|
9
9
|
watch,
|
|
10
10
|
} from "vue";
|
|
11
|
-
import {
|
|
12
|
-
import { CopilotChatDefaultLabels } from "../../providers/types";
|
|
11
|
+
import { ɵcomposerButtonState, ɵresolveComposerKey } from "@copilotkit/core";
|
|
13
12
|
import {
|
|
14
13
|
IconArrowUp,
|
|
15
14
|
IconCheck,
|
|
@@ -29,6 +28,7 @@ import type {
|
|
|
29
28
|
import { useCopilotId } from "../ui/use-id";
|
|
30
29
|
import type { CopilotChatAudioRecorderRef } from "./audioRecorder";
|
|
31
30
|
import type { CopilotChatInputMode, ToolsMenuItem } from "./types";
|
|
31
|
+
import { useChatLabels } from "./use-chat-labels";
|
|
32
32
|
|
|
33
33
|
defineOptions({ inheritAttrs: false });
|
|
34
34
|
|
|
@@ -107,7 +107,6 @@ const emit = defineEmits<{
|
|
|
107
107
|
}>();
|
|
108
108
|
|
|
109
109
|
const attrs = useAttrs();
|
|
110
|
-
const config = useCopilotChatConfiguration();
|
|
111
110
|
const shellRef = ref<HTMLElement | null>(null);
|
|
112
111
|
const textareaRef = ref<HTMLTextAreaElement | null>(null);
|
|
113
112
|
const gridRef = ref<HTMLElement | null>(null);
|
|
@@ -148,16 +147,13 @@ const isControlled = computed(() => props.modelValue !== undefined);
|
|
|
148
147
|
const inputValue = computed(() =>
|
|
149
148
|
isControlled.value ? (props.modelValue ?? "") : localValue.value,
|
|
150
149
|
);
|
|
151
|
-
const labels =
|
|
150
|
+
const labels = useChatLabels();
|
|
152
151
|
const resolvedPlaceholder = computed(
|
|
153
152
|
() => props.placeholder ?? labels.value.chatInputPlaceholder,
|
|
154
153
|
);
|
|
155
154
|
const isExpanded = computed(
|
|
156
155
|
() => props.mode === "input" && layout.value === "expanded",
|
|
157
156
|
);
|
|
158
|
-
const isProcessing = computed(
|
|
159
|
-
() => props.mode !== "transcribe" && props.isRunning,
|
|
160
|
-
);
|
|
161
157
|
const shouldShowDisclaimer = computed(
|
|
162
158
|
() => props.showDisclaimer ?? props.positioning === "absolute",
|
|
163
159
|
);
|
|
@@ -177,16 +173,20 @@ const hasFinishTranscribeAction = computed(
|
|
|
177
173
|
typeof props.onFinishTranscribe === "function" ||
|
|
178
174
|
typeof props.onFinishTranscribeWithAudio === "function",
|
|
179
175
|
);
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
176
|
+
const composerInput = computed(() => ({
|
|
177
|
+
mode: props.mode,
|
|
178
|
+
isRunning: props.isRunning,
|
|
179
|
+
value: inputValue.value,
|
|
180
|
+
canSubmit: hasSubmitAction.value,
|
|
181
|
+
canStop: hasStopAction.value,
|
|
182
|
+
disabled: props.disabled,
|
|
183
|
+
}));
|
|
184
|
+
const composerButton = computed(() =>
|
|
185
|
+
ɵcomposerButtonState(composerInput.value),
|
|
189
186
|
);
|
|
187
|
+
const isProcessing = computed(() => composerButton.value.isProcessing);
|
|
188
|
+
const sendDisabled = computed(() => composerButton.value.disabled);
|
|
189
|
+
const showsStop = computed(() => composerButton.value.action === "stop");
|
|
190
190
|
|
|
191
191
|
const containerClass = computed(() => [
|
|
192
192
|
"cpk-chat-input",
|
|
@@ -408,14 +408,16 @@ function handleInput(event: Event) {
|
|
|
408
408
|
updateSlashState(nextValue);
|
|
409
409
|
}
|
|
410
410
|
|
|
411
|
+
// The button stops a run whatever the input holds. Enter differs: see
|
|
412
|
+
// handleKeydown.
|
|
411
413
|
function handleSendButtonClick() {
|
|
412
|
-
if (
|
|
413
|
-
|
|
414
|
-
emit("stop");
|
|
415
|
-
}
|
|
414
|
+
if (showsStop.value) {
|
|
415
|
+
emit("stop");
|
|
416
416
|
return;
|
|
417
417
|
}
|
|
418
|
-
|
|
418
|
+
if (!isProcessing.value) {
|
|
419
|
+
submit();
|
|
420
|
+
}
|
|
419
421
|
}
|
|
420
422
|
|
|
421
423
|
function handleKeydown(event: KeyboardEvent) {
|
|
@@ -473,15 +475,23 @@ function handleKeydown(event: KeyboardEvent) {
|
|
|
473
475
|
}
|
|
474
476
|
}
|
|
475
477
|
|
|
476
|
-
if (
|
|
478
|
+
if (props.mode !== "input") {
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Enter with text sends, also while a run is going. Enter in an empty input
|
|
483
|
+
// stops the run. Read the textarea: a controlled modelValue can lag a tick.
|
|
484
|
+
const action = ɵresolveComposerKey(event, {
|
|
485
|
+
...composerInput.value,
|
|
486
|
+
value: textareaRef.value?.value ?? inputValue.value,
|
|
487
|
+
});
|
|
488
|
+
if (event.key === "Enter" && !event.shiftKey) {
|
|
477
489
|
event.preventDefault();
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
emit("stop");
|
|
481
|
-
}
|
|
482
|
-
return;
|
|
483
|
-
}
|
|
490
|
+
}
|
|
491
|
+
if (action === "send") {
|
|
484
492
|
submit();
|
|
493
|
+
} else if (action === "stop") {
|
|
494
|
+
emit("stop");
|
|
485
495
|
}
|
|
486
496
|
}
|
|
487
497
|
|
|
@@ -1295,7 +1305,7 @@ onBeforeUnmount(() => {
|
|
|
1295
1305
|
type="button"
|
|
1296
1306
|
data-testid="copilot-chat-input-send"
|
|
1297
1307
|
:aria-label="
|
|
1298
|
-
|
|
1308
|
+
showsStop
|
|
1299
1309
|
? labels.chatInputToolbarStopButtonLabel
|
|
1300
1310
|
: labels.chatInputToolbarSendButtonLabel
|
|
1301
1311
|
"
|
|
@@ -1304,7 +1314,7 @@ onBeforeUnmount(() => {
|
|
|
1304
1314
|
@click="handleSendButtonClick"
|
|
1305
1315
|
>
|
|
1306
1316
|
<IconSquare
|
|
1307
|
-
v-if="
|
|
1317
|
+
v-if="showsStop"
|
|
1308
1318
|
class="cpk-chat-input-stop-icon"
|
|
1309
1319
|
/>
|
|
1310
1320
|
<IconArrowUp v-else class="cpk-chat-input-send-icon" />
|
|
@@ -15,6 +15,27 @@ import {
|
|
|
15
15
|
createRowKeyStore,
|
|
16
16
|
resolveRowRenderKeysById,
|
|
17
17
|
} from "@copilotkit/shared";
|
|
18
|
+
import {
|
|
19
|
+
ɵdeduplicateMessages,
|
|
20
|
+
ɵgetToolCallLayouts,
|
|
21
|
+
ɵgetToolCallRendererNames,
|
|
22
|
+
ɵgetTurnWork,
|
|
23
|
+
ɵgetWorkOpenState,
|
|
24
|
+
ɵisTurnWorkOpen,
|
|
25
|
+
ɵisTurnWorking,
|
|
26
|
+
ɵrecordWorkTime,
|
|
27
|
+
ɵresolveActivityRenderer,
|
|
28
|
+
ɵresolveCustomMessageRenderers,
|
|
29
|
+
ɵgetLatestTurnKey,
|
|
30
|
+
} from "@copilotkit/core";
|
|
31
|
+
import type {
|
|
32
|
+
CopilotChatToolCallDisplay,
|
|
33
|
+
ToolCallEntry,
|
|
34
|
+
ɵToolCallDisplayContextValue,
|
|
35
|
+
ɵToolCallLayout,
|
|
36
|
+
ɵTurnWork,
|
|
37
|
+
ɵWorkTime,
|
|
38
|
+
} from "@copilotkit/core";
|
|
18
39
|
import type {
|
|
19
40
|
InterruptRenderProps,
|
|
20
41
|
VueCustomMessageRendererProps,
|
|
@@ -33,18 +54,6 @@ import {
|
|
|
33
54
|
} from "./message-feedback";
|
|
34
55
|
import type { MessageFeedbackScope } from "./message-feedback";
|
|
35
56
|
import { ToolCallDisplayContextKey } from "./tool-call-display-context";
|
|
36
|
-
import type { ToolCallDisplayContextValue } from "./tool-call-display-context";
|
|
37
|
-
import {
|
|
38
|
-
getToolCallLayouts,
|
|
39
|
-
getToolCallRendererNames,
|
|
40
|
-
getTurnWork,
|
|
41
|
-
} from "./tool-call-layout";
|
|
42
|
-
import type {
|
|
43
|
-
CopilotChatToolCallDisplay,
|
|
44
|
-
ToolCallEntry,
|
|
45
|
-
ToolCallLayout,
|
|
46
|
-
TurnWork,
|
|
47
|
-
} from "./tool-call-layout";
|
|
48
57
|
import type { CopilotChatWorkSummarySlotProps } from "./types";
|
|
49
58
|
|
|
50
59
|
interface MessageMetaProps {
|
|
@@ -203,47 +212,22 @@ watch(
|
|
|
203
212
|
{ immediate: true },
|
|
204
213
|
);
|
|
205
214
|
|
|
206
|
-
function deduplicateMessages(messages: Message[]): Message[] {
|
|
207
|
-
const byId = new Map<string, Message>();
|
|
208
|
-
for (const message of messages) {
|
|
209
|
-
const existing = byId.get(message.id);
|
|
210
|
-
if (
|
|
211
|
-
existing &&
|
|
212
|
-
message.role === "assistant" &&
|
|
213
|
-
existing.role === "assistant"
|
|
214
|
-
) {
|
|
215
|
-
const content = message.content || existing.content;
|
|
216
|
-
const toolCalls = message.toolCalls ?? existing.toolCalls;
|
|
217
|
-
byId.set(message.id, {
|
|
218
|
-
...existing,
|
|
219
|
-
...message,
|
|
220
|
-
content,
|
|
221
|
-
toolCalls,
|
|
222
|
-
} as AssistantMessage);
|
|
223
|
-
} else {
|
|
224
|
-
byId.set(message.id, message);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
return [...byId.values()];
|
|
228
|
-
}
|
|
229
|
-
|
|
230
215
|
const deduplicatedMessages = computed(() =>
|
|
231
|
-
|
|
216
|
+
ɵdeduplicateMessages(props.messages),
|
|
232
217
|
);
|
|
233
218
|
|
|
234
219
|
// Groups of calls can span messages (an agent often sends each call as its
|
|
235
220
|
// own message), so they're laid out here for the whole list and handed to
|
|
236
221
|
// each message's tool calls view through provide/inject.
|
|
237
|
-
const toolCallLayouts = computed<ReadonlyMap<string,
|
|
222
|
+
const toolCallLayouts = computed<ReadonlyMap<string, ɵToolCallLayout>>(() =>
|
|
238
223
|
props.toolCallDisplay === "separate"
|
|
239
224
|
? new Map()
|
|
240
|
-
:
|
|
225
|
+
: ɵgetToolCallLayouts(
|
|
241
226
|
deduplicatedMessages.value,
|
|
242
227
|
props.messages,
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
),
|
|
228
|
+
ɵgetToolCallRendererNames(copilotkit.value.renderToolCalls, {
|
|
229
|
+
slotNames: forwardedSlotNames.value,
|
|
230
|
+
}),
|
|
247
231
|
),
|
|
248
232
|
);
|
|
249
233
|
const learningFeedbackEnabled = useLearningFeedbackEnabled(copilotkit);
|
|
@@ -265,11 +249,11 @@ provide(
|
|
|
265
249
|
|
|
266
250
|
const turnWork = computed(() =>
|
|
267
251
|
props.toolCallDisplay === "turn"
|
|
268
|
-
?
|
|
252
|
+
? ɵgetTurnWork(deduplicatedMessages.value, toolCallLayouts.value)
|
|
269
253
|
: undefined,
|
|
270
254
|
);
|
|
271
255
|
const turnByFirstMessage = computed(() => {
|
|
272
|
-
const byFirst = new Map<string,
|
|
256
|
+
const byFirst = new Map<string, ɵTurnWork>();
|
|
273
257
|
for (const turn of turnWork.value?.values() ?? []) {
|
|
274
258
|
byFirst.set(turn.firstMessageId, turn);
|
|
275
259
|
}
|
|
@@ -280,30 +264,23 @@ const lastRenderedMessage = computed(
|
|
|
280
264
|
() => deduplicatedMessages.value[deduplicatedMessages.value.length - 1],
|
|
281
265
|
);
|
|
282
266
|
// The latest reply is keyed by the user message it answers (see getTurnWork).
|
|
283
|
-
const latestTurnKey = computed(() =>
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
if (rendered[i]!.role === "user") return rendered[i]!.id;
|
|
287
|
-
}
|
|
288
|
-
return "start";
|
|
289
|
-
});
|
|
290
|
-
const isWorkingOn = (turnKey: string) =>
|
|
291
|
-
props.isRunning && turnKey === latestTurnKey.value;
|
|
267
|
+
const latestTurnKey = computed(() =>
|
|
268
|
+
ɵgetLatestTurnKey(deduplicatedMessages.value),
|
|
269
|
+
);
|
|
292
270
|
|
|
293
271
|
// Work shows while the agent is on it and folds once the reply is done,
|
|
294
272
|
// unless the user has opened or closed it themselves.
|
|
295
273
|
const toggledTurns = ref<ReadonlyMap<string, boolean>>(new Map());
|
|
296
|
-
const
|
|
297
|
-
toggledTurns.value
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
//
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
>();
|
|
274
|
+
const turnOpenState = computed(() => ({
|
|
275
|
+
toggledTurns: toggledTurns.value,
|
|
276
|
+
isRunning: props.isRunning,
|
|
277
|
+
latestTurnKey: latestTurnKey.value,
|
|
278
|
+
}));
|
|
279
|
+
|
|
280
|
+
// How long the agent worked, for "Worked for 9s". Only known for replies this
|
|
281
|
+
// client watched start from the user's message; a restored thread shows the
|
|
282
|
+
// tool count instead.
|
|
283
|
+
const workTimes = new Map<string, ɵWorkTime>();
|
|
307
284
|
const workTimesVersion = ref(0);
|
|
308
285
|
watch(
|
|
309
286
|
[
|
|
@@ -314,42 +291,25 @@ watch(
|
|
|
314
291
|
],
|
|
315
292
|
([display, isRunning, turnKey, lastRole]) => {
|
|
316
293
|
if (display !== "turn") return;
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
} else {
|
|
324
|
-
for (const times of workTimes.values()) {
|
|
325
|
-
if (times.workingSince === undefined) continue;
|
|
326
|
-
times.elapsedMs += now - times.workingSince;
|
|
327
|
-
times.workingSince = undefined;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
294
|
+
ɵrecordWorkTime(workTimes, {
|
|
295
|
+
isRunning,
|
|
296
|
+
latestTurnKey: turnKey,
|
|
297
|
+
lastMessageRole: lastRole,
|
|
298
|
+
now: Date.now(),
|
|
299
|
+
});
|
|
330
300
|
workTimesVersion.value++;
|
|
331
301
|
},
|
|
332
302
|
{ immediate: true },
|
|
333
303
|
);
|
|
334
304
|
|
|
335
|
-
// Whether each working-phase message's work
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const textOpen = new Map<string, boolean>();
|
|
340
|
-
for (const turn of turnWork.value?.values() ?? []) {
|
|
341
|
-
const turnOpen = isWorkOpen(turn.key);
|
|
342
|
-
for (const id of turn.workMessageIds) {
|
|
343
|
-
open.set(id, turnOpen);
|
|
344
|
-
if (id !== turn.replyTextMessageId) textOpen.set(id, turnOpen);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
return { workOpen: open, workTextOpen: textOpen };
|
|
348
|
-
});
|
|
305
|
+
// Whether each working-phase message's work, and its text, shows.
|
|
306
|
+
const workOpenState = computed(() =>
|
|
307
|
+
ɵgetWorkOpenState(turnWork.value?.values() ?? [], turnOpenState.value),
|
|
308
|
+
);
|
|
349
309
|
|
|
350
310
|
provide(
|
|
351
311
|
ToolCallDisplayContextKey,
|
|
352
|
-
computed
|
|
312
|
+
computed<ɵToolCallDisplayContextValue>(() => ({
|
|
353
313
|
display: props.toolCallDisplay,
|
|
354
314
|
isRunning: props.isRunning,
|
|
355
315
|
layouts: toolCallLayouts.value,
|
|
@@ -364,8 +324,8 @@ const WorkSummaryRow: FunctionalComponent<{
|
|
|
364
324
|
calls: ToolCallEntry[];
|
|
365
325
|
}> = ({ turnKey, calls }) => {
|
|
366
326
|
void workTimesVersion.value;
|
|
367
|
-
const isWorking =
|
|
368
|
-
const isOpen =
|
|
327
|
+
const isWorking = ɵisTurnWorking(turnKey, turnOpenState.value);
|
|
328
|
+
const isOpen = ɵisTurnWorkOpen(turnKey, turnOpenState.value);
|
|
369
329
|
const times = workTimes.get(turnKey);
|
|
370
330
|
const summaryProps: CopilotChatWorkSummarySlotProps = {
|
|
371
331
|
isWorking,
|
|
@@ -534,21 +494,12 @@ function resolveCustomMessageRenderer(
|
|
|
534
494
|
return null;
|
|
535
495
|
}
|
|
536
496
|
|
|
537
|
-
|
|
538
|
-
const
|
|
539
|
-
.
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
.sort((a, b) => {
|
|
544
|
-
const aHasAgent = a.agentId !== undefined;
|
|
545
|
-
const bHasAgent = b.agentId !== undefined;
|
|
546
|
-
if (aHasAgent === bHasAgent) return 0;
|
|
547
|
-
return aHasAgent ? -1 : 1;
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
const selected = renderers[0];
|
|
551
|
-
if (!selected?.render) {
|
|
497
|
+
// Try each renderer in order and use the first that has something to draw.
|
|
498
|
+
const selected = ɵresolveCustomMessageRenderers(
|
|
499
|
+
copilotkit.value.renderCustomMessages,
|
|
500
|
+
resolvedAgentId.value,
|
|
501
|
+
).find((renderer) => renderer.render);
|
|
502
|
+
if (!selected) {
|
|
552
503
|
return null;
|
|
553
504
|
}
|
|
554
505
|
|
|
@@ -563,45 +514,26 @@ function resolveActivityRenderer(
|
|
|
563
514
|
): { renderer: Component; props: ActivitySlotProps } | null {
|
|
564
515
|
stateTick.value += 0;
|
|
565
516
|
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
const bScoped = b.agentId !== undefined;
|
|
576
|
-
if (aScoped === bScoped) return 0;
|
|
577
|
-
return aScoped ? -1 : 1;
|
|
578
|
-
})[0];
|
|
579
|
-
|
|
580
|
-
if (!renderer) return null;
|
|
581
|
-
const parsed = renderer.content.safeParse(message.content);
|
|
582
|
-
if (!parsed.success) return null;
|
|
517
|
+
const match = ɵresolveActivityRenderer(
|
|
518
|
+
copilotkit.value.renderActivityMessages,
|
|
519
|
+
{
|
|
520
|
+
activityType: message.activityType,
|
|
521
|
+
agentId: resolvedAgentId.value,
|
|
522
|
+
content: message.content,
|
|
523
|
+
},
|
|
524
|
+
);
|
|
525
|
+
if (!match) return null;
|
|
583
526
|
|
|
584
527
|
return {
|
|
585
|
-
renderer: renderer.render as Component,
|
|
528
|
+
renderer: match.renderer.render as Component,
|
|
586
529
|
props: {
|
|
587
530
|
activityType: message.activityType,
|
|
588
|
-
content:
|
|
531
|
+
content: match.content,
|
|
589
532
|
message,
|
|
590
533
|
agent: resolvedThreadAgent.value,
|
|
591
534
|
},
|
|
592
535
|
};
|
|
593
536
|
}
|
|
594
|
-
|
|
595
|
-
function resolveToolMessage(
|
|
596
|
-
message: Message,
|
|
597
|
-
toolCallId: string,
|
|
598
|
-
): ToolMessage | undefined {
|
|
599
|
-
return props.messages.find(
|
|
600
|
-
(candidate) =>
|
|
601
|
-
candidate.role === "tool" &&
|
|
602
|
-
(candidate as ToolMessage).toolCallId === toolCallId,
|
|
603
|
-
) as ToolMessage | undefined;
|
|
604
|
-
}
|
|
605
537
|
</script>
|
|
606
538
|
|
|
607
539
|
<template>
|
|
@@ -3,8 +3,9 @@ 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 {
|
|
7
|
-
import {
|
|
6
|
+
import { ɵformatLabel, ɵformatReasoningDuration } from "@copilotkit/core";
|
|
7
|
+
import type { CopilotChatLabels } from "@copilotkit/core";
|
|
8
|
+
import { useChatLabels } from "./use-chat-labels";
|
|
8
9
|
|
|
9
10
|
const props = withDefaults(
|
|
10
11
|
defineProps<{
|
|
@@ -69,13 +70,29 @@ defineSlots<{
|
|
|
69
70
|
}) => unknown;
|
|
70
71
|
}>();
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
+
}
|
|
79
96
|
}
|
|
80
97
|
|
|
81
98
|
const normalizedContent = computed(() =>
|
|
@@ -133,13 +150,14 @@ onBeforeUnmount(() => {
|
|
|
133
150
|
clearElapsedInterval();
|
|
134
151
|
});
|
|
135
152
|
|
|
136
|
-
const
|
|
153
|
+
const labels = useChatLabels();
|
|
137
154
|
/** `labels.reasoningMessageThinkingLabel` while streaming, then "Thought for …". */
|
|
138
155
|
const label = computed(() =>
|
|
139
156
|
isStreaming.value
|
|
140
|
-
?
|
|
141
|
-
|
|
142
|
-
|
|
157
|
+
? labels.value.reasoningMessageThinkingLabel
|
|
158
|
+
: ɵformatLabel(labels.value.reasoningMessageThoughtForLabel, {
|
|
159
|
+
duration: formatDuration(labels.value, elapsed.value),
|
|
160
|
+
}),
|
|
143
161
|
);
|
|
144
162
|
|
|
145
163
|
function toggleOpen() {
|