@copilotkit/vue 1.68.3 → 1.69.1
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 +2 -1
- package/README.md +1 -1
- package/dist/components/copilot-provider/types.d.ts +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +2 -2
- package/dist/use-render-activity-message-BtaJ2iQc.cjs +97 -0
- package/dist/use-render-activity-message-BtaJ2iQc.cjs.map +1 -0
- package/dist/use-render-activity-message-CADUB--8.js +9943 -0
- package/dist/use-render-activity-message-CADUB--8.js.map +1 -0
- package/dist/v2/components/CopilotKitInspector.vue.d.ts +2 -0
- package/dist/v2/components/CopilotKitInspector.vue.d.ts.map +1 -1
- package/dist/v2/components/OpenGenerativeUIRenderer.d.ts +1 -1
- package/dist/v2/components/OpenGenerativeUIRenderer.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChat.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatInput.vue.d.ts +18 -0
- package/dist/v2/components/chat/CopilotChatInput.vue.d.ts.map +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/CopilotChatToolCallItem.vue.d.ts +21 -0
- package/dist/v2/components/chat/CopilotChatToolCallItem.vue.d.ts.map +1 -0
- package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/SaveSnippetBeside.vue.d.ts +20 -0
- package/dist/v2/components/chat/SaveSnippetBeside.vue.d.ts.map +1 -0
- package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts +10 -0
- package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts.map +1 -0
- package/dist/v2/components/chat/save-snippet-beside.d.ts +20 -0
- package/dist/v2/components/chat/save-snippet-beside.d.ts.map +1 -0
- package/dist/v2/components/icons/index.d.ts +1 -1
- package/dist/v2/components/icons/index.d.ts.map +1 -1
- package/dist/v2/hooks/use-threads.d.ts +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.mjs +1 -1
- package/dist/v2/providers/CopilotKitProvider.types.d.ts +1 -1
- package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
- package/dist/v2/providers/keys.d.ts +36 -0
- package/dist/v2/providers/keys.d.ts.map +1 -1
- package/dist/v2/providers/types.d.ts +3 -0
- package/dist/v2/providers/types.d.ts.map +1 -1
- package/dist/v2/providers/use-inspector-thread-override.d.ts +10 -0
- package/dist/v2/providers/use-inspector-thread-override.d.ts.map +1 -0
- package/package.json +5 -5
- package/src/components/copilot-provider/types.ts +1 -1
- package/src/v2/components/CopilotKitInspector.vue +19 -1
- package/src/v2/components/OpenGenerativeUIRenderer.ts +44 -10
- package/src/v2/components/chat/CopilotChat.vue +64 -4
- package/src/v2/components/chat/CopilotChatAssistantMessage.vue +52 -1
- package/src/v2/components/chat/CopilotChatMessageView.vue +57 -23
- package/src/v2/components/chat/CopilotChatReasoningMessage.vue +68 -32
- package/src/v2/components/chat/CopilotChatToolCallItem.vue +86 -0
- package/src/v2/components/chat/CopilotChatToolCallsView.vue +72 -130
- package/src/v2/components/chat/SaveSnippetBeside.vue +82 -0
- package/src/v2/components/chat/__tests__/CopilotChatToolCallsView.test.ts +302 -1
- package/src/v2/components/chat/__tests__/CopilotThreadsDrawer.ssr.test.ts +1 -1
- package/src/v2/components/chat/copilotChatToolCallItemRender.ts +126 -0
- package/src/v2/components/chat/save-snippet-beside.ts +84 -0
- package/src/v2/components/icons/__tests__/icons.test.ts +2 -0
- package/src/v2/components/icons/index.ts +1 -0
- package/src/v2/hooks/use-threads.ts +1 -1
- package/src/v2/providers/CopilotKitProvider.types.ts +1 -1
- package/src/v2/providers/CopilotKitProvider.vue +66 -6
- package/src/v2/providers/__tests__/inspector-thread-override.test.ts +214 -0
- package/src/v2/providers/keys.ts +47 -0
- package/src/v2/providers/types.ts +3 -0
- package/src/v2/providers/use-inspector-thread-override.ts +99 -0
- package/dist/use-render-activity-message-DljRBrXN.js +0 -9513
- package/dist/use-render-activity-message-DljRBrXN.js.map +0 -1
- package/dist/use-render-activity-message-bkrPa-92.cjs +0 -85
- package/dist/use-render-activity-message-bkrPa-92.cjs.map +0 -1
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
useSlots,
|
|
21
21
|
watch,
|
|
22
22
|
} from "vue";
|
|
23
|
+
import { CopilotKitCoreErrorCode } from "@copilotkit/core";
|
|
23
24
|
import type { Suggestion } from "@copilotkit/core";
|
|
24
25
|
import CopilotChatConfigurationProvider from "../../providers/CopilotChatConfigurationProvider.vue";
|
|
25
26
|
import { useCopilotChatConfiguration } from "../../providers/useCopilotChatConfiguration";
|
|
@@ -39,6 +40,7 @@ import { LastUserMessageKey } from "./last-user-message-context";
|
|
|
39
40
|
import type { LastUserMessageState } from "./last-user-message-context";
|
|
40
41
|
import type { Message } from "@ag-ui/core";
|
|
41
42
|
import type { InputContent } from "@copilotkit/shared";
|
|
43
|
+
import { useInspectorThreadOverride } from "../../providers/use-inspector-thread-override";
|
|
42
44
|
import type {
|
|
43
45
|
CopilotChatInputSlotProps,
|
|
44
46
|
CopilotChatProps,
|
|
@@ -105,6 +107,7 @@ type ActiveConnectCycle = {
|
|
|
105
107
|
core: object;
|
|
106
108
|
agent: AbstractAgent;
|
|
107
109
|
threadId: string;
|
|
110
|
+
inspectorRequestId: string | null;
|
|
108
111
|
abortController: AbortController;
|
|
109
112
|
detached: boolean;
|
|
110
113
|
};
|
|
@@ -122,16 +125,27 @@ const resolvedAgentId = computed(
|
|
|
122
125
|
const providedThreadId = computed(
|
|
123
126
|
() => props.threadId ?? existingConfig.value?.threadId,
|
|
124
127
|
);
|
|
125
|
-
const
|
|
128
|
+
const baseThreadId = computed(
|
|
126
129
|
() => providedThreadId.value ?? generatedThreadId.value,
|
|
127
130
|
);
|
|
128
131
|
// "Explicit" means the caller actually picked this thread — via the
|
|
129
132
|
// `threadId` prop on CopilotChat or a wrapping provider that flagged its
|
|
130
133
|
// threadId as caller-chosen. An auto-minted UUID leaking down through a
|
|
131
134
|
// CopilotChatConfigurationProvider does NOT count.
|
|
132
|
-
const
|
|
135
|
+
const baseHasExplicitThreadId = computed(
|
|
133
136
|
() => !!props.threadId || !!existingConfig.value?.hasExplicitThreadId,
|
|
134
137
|
);
|
|
138
|
+
const { inspectorThreadId, inspectorRequestId, failInspectorOverride } =
|
|
139
|
+
useInspectorThreadOverride({
|
|
140
|
+
agentId: resolvedAgentId,
|
|
141
|
+
baseThreadId,
|
|
142
|
+
});
|
|
143
|
+
const resolvedThreadId = computed(
|
|
144
|
+
() => inspectorThreadId.value ?? baseThreadId.value,
|
|
145
|
+
);
|
|
146
|
+
const hasExplicitThreadId = computed(
|
|
147
|
+
() => inspectorThreadId.value !== null || baseHasExplicitThreadId.value,
|
|
148
|
+
);
|
|
135
149
|
const lastConnectedThreadId = ref<string | null>(null);
|
|
136
150
|
const isConnecting = computed(
|
|
137
151
|
() =>
|
|
@@ -297,6 +311,28 @@ watch(
|
|
|
297
311
|
{ immediate: true },
|
|
298
312
|
);
|
|
299
313
|
|
|
314
|
+
watch(
|
|
315
|
+
[
|
|
316
|
+
() => copilotkit.value,
|
|
317
|
+
resolvedAgentId,
|
|
318
|
+
resolvedThreadId,
|
|
319
|
+
inspectorRequestId,
|
|
320
|
+
],
|
|
321
|
+
([core, agentId, threadId, requestId], _old, onCleanup) => {
|
|
322
|
+
if (!requestId) return;
|
|
323
|
+
const subscription = core.subscribe({
|
|
324
|
+
onError: (event) => {
|
|
325
|
+
if (event.code !== CopilotKitCoreErrorCode.AGENT_CONNECT_FAILED) return;
|
|
326
|
+
if (event.context?.agentId !== agentId) return;
|
|
327
|
+
if (event.context?.threadId !== threadId) return;
|
|
328
|
+
failInspectorOverride(requestId);
|
|
329
|
+
},
|
|
330
|
+
});
|
|
331
|
+
onCleanup(() => subscription.unsubscribe());
|
|
332
|
+
},
|
|
333
|
+
{ immediate: true },
|
|
334
|
+
);
|
|
335
|
+
|
|
300
336
|
watch(
|
|
301
337
|
[
|
|
302
338
|
isMounted,
|
|
@@ -304,8 +340,13 @@ watch(
|
|
|
304
340
|
() => agent.value,
|
|
305
341
|
resolvedThreadId,
|
|
306
342
|
hasExplicitThreadId,
|
|
343
|
+
inspectorRequestId,
|
|
307
344
|
],
|
|
308
|
-
(
|
|
345
|
+
(
|
|
346
|
+
[mounted, core, currentAgent, threadId, isExplicit, requestId],
|
|
347
|
+
_old,
|
|
348
|
+
onCleanup,
|
|
349
|
+
) => {
|
|
309
350
|
if (!mounted) {
|
|
310
351
|
return;
|
|
311
352
|
}
|
|
@@ -316,6 +357,20 @@ watch(
|
|
|
316
357
|
return;
|
|
317
358
|
}
|
|
318
359
|
|
|
360
|
+
const previousCycle = activeConnectCycle.value;
|
|
361
|
+
const inspectorTransition =
|
|
362
|
+
previousCycle !== null &&
|
|
363
|
+
previousCycle.threadId !== threadId &&
|
|
364
|
+
previousCycle.inspectorRequestId !== requestId &&
|
|
365
|
+
(previousCycle.inspectorRequestId !== null || requestId !== null);
|
|
366
|
+
if (inspectorTransition) {
|
|
367
|
+
try {
|
|
368
|
+
core.stopAgent({ agent: currentAgent });
|
|
369
|
+
} catch {
|
|
370
|
+
// No live run to stop.
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
319
374
|
// Pin the thread this chat renders onto its agent, before anything issues a
|
|
320
375
|
// request. `CopilotKitCore.connectAgent` reads `agent.threadId` synchronously
|
|
321
376
|
// to decide whether this is a fresh restore, so a later assignment would let
|
|
@@ -357,7 +412,8 @@ watch(
|
|
|
357
412
|
existingCycle &&
|
|
358
413
|
existingCycle.core === (core as object) &&
|
|
359
414
|
existingCycle.agent === currentAgent &&
|
|
360
|
-
existingCycle.threadId === threadId
|
|
415
|
+
existingCycle.threadId === threadId &&
|
|
416
|
+
existingCycle.inspectorRequestId === requestId;
|
|
361
417
|
|
|
362
418
|
let cycle: ActiveConnectCycle;
|
|
363
419
|
if (hasSameDeps && existingCycle) {
|
|
@@ -372,6 +428,7 @@ watch(
|
|
|
372
428
|
core: core as object,
|
|
373
429
|
agent: currentAgent,
|
|
374
430
|
threadId,
|
|
431
|
+
inspectorRequestId: requestId,
|
|
375
432
|
abortController: connectAbortController,
|
|
376
433
|
detached: false,
|
|
377
434
|
};
|
|
@@ -387,6 +444,9 @@ watch(
|
|
|
387
444
|
return;
|
|
388
445
|
}
|
|
389
446
|
console.error("CopilotChat: connectAgent failed", error);
|
|
447
|
+
if (requestId) {
|
|
448
|
+
failInspectorOverride(requestId);
|
|
449
|
+
}
|
|
390
450
|
})
|
|
391
451
|
.finally(() => {
|
|
392
452
|
// Whether the connect succeeded or failed, we're no longer in
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
defineComponent,
|
|
5
5
|
getCurrentInstance,
|
|
6
6
|
h,
|
|
7
|
+
inject,
|
|
7
8
|
onBeforeUnmount,
|
|
8
9
|
onMounted,
|
|
9
10
|
ref,
|
|
@@ -13,6 +14,7 @@ import { StreamMarkdown } from "streamdown-vue";
|
|
|
13
14
|
import { useCopilotChatConfiguration } from "../../providers/useCopilotChatConfiguration";
|
|
14
15
|
import { CopilotChatDefaultLabels } from "../../providers/types";
|
|
15
16
|
import {
|
|
17
|
+
IconBookmark,
|
|
16
18
|
IconCheck,
|
|
17
19
|
IconCopy,
|
|
18
20
|
IconDownload,
|
|
@@ -34,6 +36,7 @@ import type {
|
|
|
34
36
|
CopilotChatAssistantMessageToolbarSlotProps,
|
|
35
37
|
} from "./types";
|
|
36
38
|
import { useKatexStyles } from "../../hooks/use-katex-styles";
|
|
39
|
+
import { InspectorKey } from "../../providers/keys";
|
|
37
40
|
|
|
38
41
|
useKatexStyles();
|
|
39
42
|
|
|
@@ -88,6 +91,10 @@ const emit = defineEmits<{
|
|
|
88
91
|
|
|
89
92
|
const config = useCopilotChatConfiguration();
|
|
90
93
|
const labels = computed(() => config.value?.labels ?? CopilotChatDefaultLabels);
|
|
94
|
+
const inspector = inject(InspectorKey, null);
|
|
95
|
+
const isLocalInspectorEnabled = computed(
|
|
96
|
+
() => inspector?.isLocalInspectorEnabled.value === true,
|
|
97
|
+
);
|
|
91
98
|
const instance = getCurrentInstance();
|
|
92
99
|
const copied = ref(false);
|
|
93
100
|
let copiedResetTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
@@ -661,10 +668,31 @@ const isLatestAssistantMessage = computed(
|
|
|
661
668
|
const shouldShowToolbar = computed(
|
|
662
669
|
() =>
|
|
663
670
|
props.toolbarVisible &&
|
|
664
|
-
hasContent.value &&
|
|
671
|
+
(hasContent.value || isLocalInspectorEnabled.value) &&
|
|
665
672
|
!(props.isRunning && isLatestAssistantMessage.value),
|
|
666
673
|
);
|
|
667
674
|
|
|
675
|
+
function handleViewInspector() {
|
|
676
|
+
inspector?.openInspector({
|
|
677
|
+
messageId: props.message.id,
|
|
678
|
+
threadId: config.value?.threadId,
|
|
679
|
+
agentId: config.value?.agentId,
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
function handleSaveSnippet() {
|
|
684
|
+
if (!hasContent.value) {
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
void inspector?.saveEventSnippet({
|
|
688
|
+
kind: "text",
|
|
689
|
+
messageId: props.message.id,
|
|
690
|
+
content: props.message.content ?? "",
|
|
691
|
+
threadId: config.value?.threadId,
|
|
692
|
+
agentId: config.value?.agentId,
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
|
|
668
696
|
function resetCopiedStateWithDelay() {
|
|
669
697
|
if (copiedResetTimeout) {
|
|
670
698
|
clearTimeout(copiedResetTimeout);
|
|
@@ -814,6 +842,29 @@ onBeforeUnmount(() => {
|
|
|
814
842
|
</button>
|
|
815
843
|
</slot>
|
|
816
844
|
|
|
845
|
+
<button
|
|
846
|
+
v-if="isLocalInspectorEnabled"
|
|
847
|
+
data-testid="copilot-inspector-button"
|
|
848
|
+
type="button"
|
|
849
|
+
:class="toolbarButtonClass"
|
|
850
|
+
:aria-label="`${labels.assistantMessageToolbarInspectorLabel} (${labels.assistantMessageToolbarInspectorLocalOnlyLabel})`"
|
|
851
|
+
:title="`${labels.assistantMessageToolbarInspectorLabel} (${labels.assistantMessageToolbarInspectorLocalOnlyLabel})`"
|
|
852
|
+
@click="handleViewInspector"
|
|
853
|
+
>
|
|
854
|
+
I
|
|
855
|
+
</button>
|
|
856
|
+
<button
|
|
857
|
+
v-if="isLocalInspectorEnabled && hasContent"
|
|
858
|
+
data-testid="copilot-save-snippet-button"
|
|
859
|
+
type="button"
|
|
860
|
+
:class="toolbarButtonClass"
|
|
861
|
+
:aria-label="`${labels.assistantMessageToolbarSaveSnippetLabel} (${labels.assistantMessageToolbarInspectorLocalOnlyLabel})`"
|
|
862
|
+
:title="`${labels.assistantMessageToolbarSaveSnippetLabel} (${labels.assistantMessageToolbarInspectorLocalOnlyLabel})`"
|
|
863
|
+
@click="handleSaveSnippet"
|
|
864
|
+
>
|
|
865
|
+
<IconBookmark class="cpk:size-[18px]" />
|
|
866
|
+
</button>
|
|
867
|
+
|
|
817
868
|
<slot
|
|
818
869
|
v-if="hasThumbsUp"
|
|
819
870
|
name="thumbs-up-button"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, ref, useSlots, watch } from "vue";
|
|
2
|
+
import { computed, inject, ref, useSlots, watch } from "vue";
|
|
3
3
|
import type { Component } from "vue";
|
|
4
4
|
import type {
|
|
5
5
|
ActivityMessage,
|
|
@@ -19,6 +19,9 @@ import { useCopilotChatConfiguration } from "../../providers/useCopilotChatConfi
|
|
|
19
19
|
import CopilotChatAssistantMessage from "./CopilotChatAssistantMessage.vue";
|
|
20
20
|
import CopilotChatReasoningMessage from "./CopilotChatReasoningMessage.vue";
|
|
21
21
|
import CopilotChatUserMessage from "./CopilotChatUserMessage.vue";
|
|
22
|
+
import { InspectorKey } from "../../providers/keys";
|
|
23
|
+
import { IconBookmark } from "../icons";
|
|
24
|
+
import SaveSnippetBeside from "./SaveSnippetBeside.vue";
|
|
22
25
|
|
|
23
26
|
interface MessageMetaProps {
|
|
24
27
|
message: Message;
|
|
@@ -38,6 +41,23 @@ interface ActivitySlotProps {
|
|
|
38
41
|
agent: unknown;
|
|
39
42
|
}
|
|
40
43
|
|
|
44
|
+
const inspector = inject(InspectorKey, null);
|
|
45
|
+
const canSaveActivity = (message: ActivityMessage) =>
|
|
46
|
+
inspector?.isLocalInspectorEnabled.value === true &&
|
|
47
|
+
(message.activityType === "a2ui-surface" ||
|
|
48
|
+
message.activityType === "open-generative-ui");
|
|
49
|
+
|
|
50
|
+
function saveActivitySnippet(message: ActivityMessage) {
|
|
51
|
+
void inspector?.saveEventSnippet({
|
|
52
|
+
kind: "activity",
|
|
53
|
+
messageId: message.id,
|
|
54
|
+
activityType: message.activityType,
|
|
55
|
+
content: message.content,
|
|
56
|
+
threadId: config.value?.threadId,
|
|
57
|
+
agentId: config.value?.agentId,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
41
61
|
type InterruptSlotProps = InterruptRenderProps<unknown, unknown>;
|
|
42
62
|
type CustomMessagePosition = VueCustomMessageRendererProps["position"];
|
|
43
63
|
type ResolvedCustomMessageRenderer = {
|
|
@@ -414,28 +434,42 @@ function resolveToolMessage(
|
|
|
414
434
|
/>
|
|
415
435
|
</slot>
|
|
416
436
|
|
|
417
|
-
<
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
437
|
+
<div v-else-if="message.role === 'activity'">
|
|
438
|
+
<SaveSnippetBeside :enabled="canSaveActivity(message)">
|
|
439
|
+
<slot
|
|
440
|
+
:name="getActivitySlotName(message.activityType)"
|
|
441
|
+
:activity-type="message.activityType"
|
|
442
|
+
:content="message.content"
|
|
443
|
+
:message="message"
|
|
444
|
+
:agent="resolvedThreadAgent"
|
|
445
|
+
>
|
|
446
|
+
<slot
|
|
447
|
+
name="activity-message"
|
|
448
|
+
:activity-type="message.activityType"
|
|
449
|
+
:content="message.content"
|
|
450
|
+
:message="message"
|
|
451
|
+
:agent="resolvedThreadAgent"
|
|
452
|
+
>
|
|
453
|
+
<component
|
|
454
|
+
v-if="resolveActivityRenderer(message)"
|
|
455
|
+
:is="resolveActivityRenderer(message)!.renderer"
|
|
456
|
+
v-bind="resolveActivityRenderer(message)!.props"
|
|
457
|
+
/>
|
|
458
|
+
</slot>
|
|
459
|
+
</slot>
|
|
460
|
+
<template #save>
|
|
461
|
+
<button
|
|
462
|
+
type="button"
|
|
463
|
+
class="cpk:inline-flex cpk:h-8 cpk:w-8 cpk:items-center cpk:justify-center cpk:rounded-md cpk:p-0 cpk:text-[rgb(93,93,93)] cpk:hover:bg-[#E8E8E8] cpk:dark:text-[rgb(243,243,243)] cpk:dark:hover:bg-[#303030]"
|
|
464
|
+
data-testid="copilot-activity-save-snippet-button"
|
|
465
|
+
:aria-label="`${config?.labels.assistantMessageToolbarSaveSnippetLabel ?? 'Save as snippet'} (Local Only)`"
|
|
466
|
+
@click="saveActivitySnippet(message)"
|
|
467
|
+
>
|
|
468
|
+
<IconBookmark class="cpk:size-[18px]" />
|
|
469
|
+
</button>
|
|
470
|
+
</template>
|
|
471
|
+
</SaveSnippetBeside>
|
|
472
|
+
</div>
|
|
439
473
|
|
|
440
474
|
<slot
|
|
441
475
|
v-if="componentSlots['message-after']"
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, onBeforeUnmount, ref, watch } from "vue";
|
|
2
|
+
import { computed, inject, onBeforeUnmount, ref, watch } from "vue";
|
|
3
3
|
import type { Message, ReasoningMessage } from "@ag-ui/core";
|
|
4
4
|
import { StreamMarkdown } from "streamdown-vue";
|
|
5
|
-
import { IconChevronRight } from "../icons";
|
|
5
|
+
import { IconBookmark, IconChevronRight } from "../icons";
|
|
6
|
+
import { InspectorKey } from "../../providers/keys";
|
|
7
|
+
import { useCopilotChatConfiguration } from "../../providers/useCopilotChatConfiguration";
|
|
8
|
+
import { CopilotChatDefaultLabels } from "../../providers/types";
|
|
6
9
|
|
|
7
10
|
const props = withDefaults(
|
|
8
11
|
defineProps<{
|
|
@@ -139,6 +142,27 @@ function toggleOpen() {
|
|
|
139
142
|
userToggledDuringStreaming.value = true;
|
|
140
143
|
isOpen.value = !isOpen.value;
|
|
141
144
|
}
|
|
145
|
+
|
|
146
|
+
const inspector = inject(InspectorKey, null);
|
|
147
|
+
const chatConfiguration = useCopilotChatConfiguration();
|
|
148
|
+
const canSaveReasoning = computed(
|
|
149
|
+
() => inspector?.isLocalInspectorEnabled.value === true && hasContent.value,
|
|
150
|
+
);
|
|
151
|
+
const saveLabel = computed(
|
|
152
|
+
() =>
|
|
153
|
+
chatConfiguration.value?.labels.assistantMessageToolbarSaveSnippetLabel ??
|
|
154
|
+
CopilotChatDefaultLabels.assistantMessageToolbarSaveSnippetLabel,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
function saveReasoningSnippet() {
|
|
158
|
+
void inspector?.saveEventSnippet({
|
|
159
|
+
kind: "reasoning",
|
|
160
|
+
messageId: props.message.id,
|
|
161
|
+
content: normalizedContent.value,
|
|
162
|
+
threadId: chatConfiguration.value?.threadId,
|
|
163
|
+
agentId: chatConfiguration.value?.agentId,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
142
166
|
</script>
|
|
143
167
|
|
|
144
168
|
<template>
|
|
@@ -169,41 +193,53 @@ function toggleOpen() {
|
|
|
169
193
|
},
|
|
170
194
|
}"
|
|
171
195
|
>
|
|
172
|
-
<
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
<button
|
|
181
|
-
type="button"
|
|
182
|
-
class="cpk:inline-flex cpk:items-center cpk:gap-1 cpk:py-1 cpk:text-sm cpk:text-muted-foreground cpk:transition-colors cpk:select-none"
|
|
183
|
-
:class="
|
|
184
|
-
hasContent
|
|
185
|
-
? 'cpk:hover:text-foreground cpk:cursor-pointer'
|
|
186
|
-
: 'cpk:cursor-default'
|
|
187
|
-
"
|
|
188
|
-
:aria-expanded="hasContent ? isOpen : undefined"
|
|
189
|
-
@click="hasContent ? toggleOpen() : undefined"
|
|
196
|
+
<div class="cpk:flex cpk:items-center cpk:gap-1">
|
|
197
|
+
<slot
|
|
198
|
+
name="header"
|
|
199
|
+
:is-open="isOpen"
|
|
200
|
+
:label="label"
|
|
201
|
+
:has-content="hasContent"
|
|
202
|
+
:is-streaming="isStreaming"
|
|
203
|
+
:on-click="hasContent ? toggleOpen : undefined"
|
|
190
204
|
>
|
|
191
|
-
<
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
class="
|
|
205
|
+
<button
|
|
206
|
+
type="button"
|
|
207
|
+
class="cpk:inline-flex cpk:items-center cpk:gap-1 cpk:py-1 cpk:text-sm cpk:text-muted-foreground cpk:transition-colors cpk:select-none"
|
|
208
|
+
:class="
|
|
209
|
+
hasContent
|
|
210
|
+
? 'cpk:hover:text-foreground cpk:cursor-pointer'
|
|
211
|
+
: 'cpk:cursor-default'
|
|
212
|
+
"
|
|
213
|
+
:aria-expanded="hasContent ? isOpen : undefined"
|
|
214
|
+
@click="hasContent ? toggleOpen() : undefined"
|
|
195
215
|
>
|
|
216
|
+
<span class="cpk:font-medium">{{ label }}</span>
|
|
196
217
|
<span
|
|
197
|
-
|
|
218
|
+
v-if="isStreaming && !hasContent"
|
|
219
|
+
class="cpk:inline-flex cpk:items-center cpk:ml-1"
|
|
220
|
+
>
|
|
221
|
+
<span
|
|
222
|
+
class="cpk:w-1.5 cpk:h-1.5 cpk:rounded-full cpk:bg-muted-foreground cpk:animate-pulse"
|
|
223
|
+
/>
|
|
224
|
+
</span>
|
|
225
|
+
<IconChevronRight
|
|
226
|
+
v-if="hasContent"
|
|
227
|
+
class="cpk:size-3.5 cpk:shrink-0 cpk:transition-transform cpk:duration-200"
|
|
228
|
+
:class="{ 'cpk:rotate-90': isOpen }"
|
|
198
229
|
/>
|
|
199
|
-
</
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
230
|
+
</button>
|
|
231
|
+
</slot>
|
|
232
|
+
<button
|
|
233
|
+
v-if="canSaveReasoning"
|
|
234
|
+
type="button"
|
|
235
|
+
class="cpk:inline-flex cpk:h-8 cpk:w-8 cpk:items-center cpk:justify-center cpk:rounded-md cpk:p-0 cpk:text-[rgb(93,93,93)] cpk:hover:bg-[#E8E8E8] cpk:dark:text-[rgb(243,243,243)] cpk:dark:hover:bg-[#303030]"
|
|
236
|
+
data-testid="copilot-save-snippet-button"
|
|
237
|
+
:aria-label="`${saveLabel} (Local Only)`"
|
|
238
|
+
@click="saveReasoningSnippet"
|
|
239
|
+
>
|
|
240
|
+
<IconBookmark class="cpk:size-[18px]" />
|
|
205
241
|
</button>
|
|
206
|
-
</
|
|
242
|
+
</div>
|
|
207
243
|
|
|
208
244
|
<slot
|
|
209
245
|
name="toggle"
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { Message, ToolCall } from "@ag-ui/core";
|
|
3
|
+
import { DEFAULT_AGENT_ID } from "@copilotkit/shared";
|
|
4
|
+
import { useCopilotKit } from "../../providers/useCopilotKit";
|
|
5
|
+
import { useCopilotChatConfiguration } from "../../providers/useCopilotChatConfiguration";
|
|
6
|
+
import type { CopilotChatToolCallRenderSlotProps } from "./types";
|
|
7
|
+
import {
|
|
8
|
+
getCoreRenderConfig,
|
|
9
|
+
getCoreRenderProps,
|
|
10
|
+
getToolCallMemoDeps,
|
|
11
|
+
getToolCallRenderProps,
|
|
12
|
+
getToolCallSlotName,
|
|
13
|
+
} from "./copilotChatToolCallItemRender";
|
|
14
|
+
|
|
15
|
+
const props = withDefaults(
|
|
16
|
+
defineProps<{
|
|
17
|
+
toolCall: ToolCall;
|
|
18
|
+
messages?: Message[];
|
|
19
|
+
}>(),
|
|
20
|
+
{
|
|
21
|
+
messages: () => [],
|
|
22
|
+
},
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
defineSlots<{
|
|
26
|
+
"tool-call"?: (props: CopilotChatToolCallRenderSlotProps) => unknown;
|
|
27
|
+
[key: `tool-call-${string}`]: (
|
|
28
|
+
props: CopilotChatToolCallRenderSlotProps,
|
|
29
|
+
) => unknown;
|
|
30
|
+
}>();
|
|
31
|
+
|
|
32
|
+
const { copilotkit, executingToolCallIds } = useCopilotKit();
|
|
33
|
+
const config = useCopilotChatConfiguration();
|
|
34
|
+
|
|
35
|
+
function getRenderProps(): CopilotChatToolCallRenderSlotProps {
|
|
36
|
+
return getToolCallRenderProps(
|
|
37
|
+
props.toolCall,
|
|
38
|
+
props.messages,
|
|
39
|
+
executingToolCallIds.value,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getCoreProps() {
|
|
44
|
+
return getCoreRenderProps(
|
|
45
|
+
props.toolCall,
|
|
46
|
+
props.messages,
|
|
47
|
+
executingToolCallIds.value,
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getRenderConfig() {
|
|
52
|
+
const agentId = config.value?.agentId ?? DEFAULT_AGENT_ID;
|
|
53
|
+
return getCoreRenderConfig(
|
|
54
|
+
props.toolCall,
|
|
55
|
+
copilotkit.value.renderToolCalls,
|
|
56
|
+
agentId,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function getMemoDeps() {
|
|
61
|
+
const agentId = config.value?.agentId ?? DEFAULT_AGENT_ID;
|
|
62
|
+
return getToolCallMemoDeps(
|
|
63
|
+
props.toolCall,
|
|
64
|
+
props.messages,
|
|
65
|
+
executingToolCallIds.value,
|
|
66
|
+
copilotkit.value.renderToolCalls,
|
|
67
|
+
agentId,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
</script>
|
|
71
|
+
|
|
72
|
+
<template>
|
|
73
|
+
<slot
|
|
74
|
+
:name="getToolCallSlotName(toolCall.function.name)"
|
|
75
|
+
v-bind="getRenderProps()"
|
|
76
|
+
>
|
|
77
|
+
<slot name="tool-call" v-bind="getRenderProps()">
|
|
78
|
+
<component
|
|
79
|
+
:is="getRenderConfig()?.render"
|
|
80
|
+
v-if="getRenderConfig()"
|
|
81
|
+
v-memo="getMemoDeps()"
|
|
82
|
+
v-bind="getCoreProps()"
|
|
83
|
+
/>
|
|
84
|
+
</slot>
|
|
85
|
+
</slot>
|
|
86
|
+
</template>
|