@copilotkit/vue 2.0.0-rc.26 → 2.0.0-rc.28
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/CONTRIBUTOR_GUIDE.md +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{use-render-activity-message-BVZr0Z-G.js → use-render-activity-message-BLHkxK7Q.js} +5686 -5983
- package/dist/use-render-activity-message-BLHkxK7Q.js.map +1 -0
- package/dist/use-render-activity-message-d1Uz5YiB.cjs +113 -0
- package/dist/use-render-activity-message-d1Uz5YiB.cjs.map +1 -0
- package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts +3 -6
- package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.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/CopilotChatFeedbackCommentPopover.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatInput.vue.d.ts +1 -16
- 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/CopilotChatView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotThreadsDrawer.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/message-feedback.d.ts +20 -0
- package/dist/v2/components/chat/message-feedback.d.ts.map +1 -1
- package/dist/v2/hooks/use-configure-suggestions.d.ts.map +1 -1
- package/dist/v2/hooks/use-default-render-tool.d.ts +2 -7
- package/dist/v2/hooks/use-default-render-tool.d.ts.map +1 -1
- package/dist/v2/hooks/use-frontend-tool.d.ts +2 -2
- package/dist/v2/hooks/use-frontend-tool.d.ts.map +1 -1
- package/dist/v2/hooks/use-render-activity-message.d.ts.map +1 -1
- package/dist/v2/hooks/use-suggestions.d.ts.map +1 -1
- package/dist/v2/hooks/use-threads.d.ts +6 -15
- package/dist/v2/hooks/use-threads.d.ts.map +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.mjs +1 -1
- package/dist/v2/lib/vue-core.d.ts +16 -2
- package/dist/v2/lib/vue-core.d.ts.map +1 -1
- package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/__tests__/build-entries.test.ts +3 -1
- package/src/v2/components/a2ui/A2UIBuiltInToolCallRenderer.ts +4 -19
- package/src/v2/components/chat/CopilotChat.vue +50 -218
- package/src/v2/components/chat/CopilotChatAssistantMessage.vue +28 -141
- package/src/v2/components/chat/CopilotChatFeedbackCommentPopover.vue +11 -76
- package/src/v2/components/chat/CopilotChatInput.vue +82 -269
- package/src/v2/components/chat/CopilotChatMessageView.vue +14 -64
- package/src/v2/components/chat/CopilotChatReasoningMessage.vue +25 -52
- package/src/v2/components/chat/CopilotChatView.vue +92 -135
- package/src/v2/components/chat/CopilotPopupViewInternal.vue +18 -58
- package/src/v2/components/chat/CopilotSidebarViewInternal.vue +22 -45
- package/src/v2/components/chat/CopilotThreadsDrawer.vue +6 -3
- package/src/v2/components/chat/__tests__/CopilotChatInput.test.ts +43 -0
- package/src/v2/components/chat/__tests__/CopilotChatView.pinToSend.test.ts +43 -1
- package/src/v2/components/chat/message-feedback.ts +33 -1
- package/src/v2/hooks/use-configure-suggestions.ts +3 -4
- package/src/v2/hooks/use-default-render-tool.ts +7 -68
- package/src/v2/hooks/use-frontend-tool.ts +10 -20
- package/src/v2/hooks/use-render-activity-message.ts +4 -2
- package/src/v2/hooks/use-suggestions.ts +9 -4
- package/src/v2/hooks/use-threads.ts +6 -15
- package/src/v2/lib/vue-core.ts +19 -2
- package/src/v2/providers/CopilotKitProvider.vue +107 -184
- package/src/v2/providers/__tests__/CopilotKitProvider.a2ui.test.ts +18 -0
- package/src/v2/providers/__tests__/CopilotKitProvider.test.ts +35 -2
- package/dist/use-render-activity-message-8p2HwK2y.cjs +0 -114
- package/dist/use-render-activity-message-8p2HwK2y.cjs.map +0 -1
- package/dist/use-render-activity-message-BVZr0Z-G.js.map +0 -1
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import {
|
|
3
3
|
computed,
|
|
4
|
-
nextTick,
|
|
5
4
|
onBeforeUnmount,
|
|
6
5
|
onMounted,
|
|
7
6
|
ref,
|
|
8
7
|
useAttrs,
|
|
9
8
|
watch,
|
|
10
9
|
} from "vue";
|
|
11
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
ɵSIDEBAR_DEFAULT_WIDTH,
|
|
12
|
+
ɵSIDEBAR_TRANSITION_MS,
|
|
13
|
+
ɵcreateDockedSidebar,
|
|
14
|
+
ɵdimensionToCss,
|
|
15
|
+
ɵwatchElementWidth,
|
|
16
|
+
} from "@copilotkit/core";
|
|
12
17
|
import type { ɵDockedSidebar } from "@copilotkit/core";
|
|
13
18
|
import { CopilotChatDefaultLabels } from "../../providers/types";
|
|
14
19
|
import { useCopilotChatConfiguration } from "../../providers/useCopilotChatConfiguration";
|
|
@@ -32,9 +37,6 @@ import type {
|
|
|
32
37
|
|
|
33
38
|
defineOptions({ inheritAttrs: false });
|
|
34
39
|
|
|
35
|
-
const DEFAULT_SIDEBAR_WIDTH = 480;
|
|
36
|
-
const SIDEBAR_TRANSITION_MS = 260;
|
|
37
|
-
|
|
38
40
|
const props = withDefaults(
|
|
39
41
|
defineProps<Omit<CopilotSidebarViewProps, "defaultOpen">>(),
|
|
40
42
|
{
|
|
@@ -98,9 +100,8 @@ const config = useCopilotChatConfiguration();
|
|
|
98
100
|
|
|
99
101
|
const sidebarRef = ref<HTMLElement | null>(null);
|
|
100
102
|
const measuredSidebarWidth = ref<number | string>(
|
|
101
|
-
props.width ??
|
|
103
|
+
props.width ?? ɵSIDEBAR_DEFAULT_WIDTH,
|
|
102
104
|
);
|
|
103
|
-
let resizeObserver: ResizeObserver | null = null;
|
|
104
105
|
|
|
105
106
|
const isSidebarOpen = computed(() => config.value?.isModalOpen ?? false);
|
|
106
107
|
const resolvedSidebarWidth = computed(
|
|
@@ -130,7 +131,7 @@ const asideStyle = computed(
|
|
|
130
131
|
}) as Record<string, string>,
|
|
131
132
|
);
|
|
132
133
|
const widthCss = computed(() =>
|
|
133
|
-
ɵdimensionToCss(resolvedSidebarWidth.value,
|
|
134
|
+
ɵdimensionToCss(resolvedSidebarWidth.value, ɵSIDEBAR_DEFAULT_WIDTH),
|
|
134
135
|
);
|
|
135
136
|
|
|
136
137
|
// The page makes room on the docked edge (desktop only).
|
|
@@ -142,17 +143,6 @@ watch(
|
|
|
142
143
|
},
|
|
143
144
|
);
|
|
144
145
|
|
|
145
|
-
function updateMeasuredWidth() {
|
|
146
|
-
if (props.width !== undefined || !sidebarRef.value) {
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const nextWidth = sidebarRef.value.getBoundingClientRect().width;
|
|
151
|
-
if (nextWidth > 0) {
|
|
152
|
-
measuredSidebarWidth.value = nextWidth;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
146
|
function closeSidebar() {
|
|
157
147
|
config.value?.setModalOpen?.(false);
|
|
158
148
|
}
|
|
@@ -226,48 +216,35 @@ const chatViewEventProps = computed(() => {
|
|
|
226
216
|
return listeners;
|
|
227
217
|
});
|
|
228
218
|
|
|
219
|
+
// Without a `width` prop, the page margin follows the width the CSS gives
|
|
220
|
+
// the sidebar.
|
|
229
221
|
watch(
|
|
230
|
-
() => props.width,
|
|
231
|
-
(
|
|
232
|
-
if (
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
222
|
+
[sidebarRef, () => props.width],
|
|
223
|
+
([element, width], _old, onCleanup) => {
|
|
224
|
+
if (width !== undefined || !element) return;
|
|
225
|
+
onCleanup(
|
|
226
|
+
ɵwatchElementWidth(element, (next) => {
|
|
227
|
+
measuredSidebarWidth.value = next;
|
|
228
|
+
}),
|
|
229
|
+
);
|
|
237
230
|
},
|
|
231
|
+
{ flush: "post" },
|
|
238
232
|
);
|
|
239
233
|
|
|
240
|
-
onMounted(
|
|
234
|
+
onMounted(() => {
|
|
241
235
|
dock = ɵcreateDockedSidebar(document, {
|
|
242
|
-
transitionMs: SIDEBAR_TRANSITION_MS,
|
|
236
|
+
transitionMs: ɵSIDEBAR_TRANSITION_MS,
|
|
243
237
|
});
|
|
244
238
|
dock.set({
|
|
245
239
|
open: isSidebarOpen.value,
|
|
246
240
|
position: props.position,
|
|
247
241
|
width: widthCss.value,
|
|
248
242
|
});
|
|
249
|
-
await nextTick();
|
|
250
|
-
updateMeasuredWidth();
|
|
251
|
-
|
|
252
|
-
if (
|
|
253
|
-
props.width !== undefined ||
|
|
254
|
-
!sidebarRef.value ||
|
|
255
|
-
typeof ResizeObserver === "undefined"
|
|
256
|
-
) {
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
resizeObserver = new ResizeObserver(() => {
|
|
261
|
-
updateMeasuredWidth();
|
|
262
|
-
});
|
|
263
|
-
resizeObserver.observe(sidebarRef.value);
|
|
264
243
|
});
|
|
265
244
|
|
|
266
245
|
onBeforeUnmount(() => {
|
|
267
246
|
dock?.dispose();
|
|
268
247
|
dock = undefined;
|
|
269
|
-
resizeObserver?.disconnect();
|
|
270
|
-
resizeObserver = null;
|
|
271
248
|
});
|
|
272
249
|
</script>
|
|
273
250
|
|
|
@@ -21,10 +21,10 @@ import type {
|
|
|
21
21
|
// lands and is published; declared locally here because the built element types
|
|
22
22
|
// in this worktree predate it.
|
|
23
23
|
type CollapseChangeDetail = { collapsed: boolean };
|
|
24
|
-
import { DEFAULT_AGENT_ID } from "@copilotkit/shared";
|
|
25
24
|
import {
|
|
26
25
|
ɵcreateThreadsDrawerActions,
|
|
27
26
|
ɵgetThreadsDrawerElementProps,
|
|
27
|
+
ɵresolveAgentId,
|
|
28
28
|
ɵresolveThreadsLicense,
|
|
29
29
|
ɵtoDrawerThread,
|
|
30
30
|
} from "@copilotkit/core";
|
|
@@ -82,8 +82,11 @@ const threadsLicense = computed(() => ɵresolveThreadsLicense(license.value));
|
|
|
82
82
|
const licensed = computed(() => threadsLicense.value.licensed);
|
|
83
83
|
const licensePending = computed(() => threadsLicense.value.licensePending);
|
|
84
84
|
|
|
85
|
-
const resolvedAgentId = computed(
|
|
86
|
-
(
|
|
85
|
+
const resolvedAgentId = computed(() =>
|
|
86
|
+
ɵresolveAgentId({
|
|
87
|
+
agentId: props.agentId,
|
|
88
|
+
chatAgentId: config.value?.agentId,
|
|
89
|
+
}),
|
|
87
90
|
);
|
|
88
91
|
const activeThreadId = computed(() => config.value?.threadId ?? null);
|
|
89
92
|
|
|
@@ -1218,4 +1218,47 @@ describe("CopilotChatInput", () => {
|
|
|
1218
1218
|
expect(input.value).toBe("部分");
|
|
1219
1219
|
});
|
|
1220
1220
|
});
|
|
1221
|
+
|
|
1222
|
+
// `onSubmitMessage` is both a declared prop (to detect a listener) and the
|
|
1223
|
+
// `submit-message` emit. A template `@submit-message` listener must enable
|
|
1224
|
+
// sending and fire once per send.
|
|
1225
|
+
describe("@submit-message listener", () => {
|
|
1226
|
+
function renderWithTemplateListener(onSubmit?: (value: string) => void) {
|
|
1227
|
+
const Host = defineComponent({
|
|
1228
|
+
components: { CopilotChatConfigurationProvider, CopilotChatInput },
|
|
1229
|
+
setup() {
|
|
1230
|
+
return { TEST_THREAD_ID, onSubmit };
|
|
1231
|
+
},
|
|
1232
|
+
template: onSubmit
|
|
1233
|
+
? `
|
|
1234
|
+
<CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
|
|
1235
|
+
<CopilotChatInput model-value="hello" @submit-message="onSubmit" />
|
|
1236
|
+
</CopilotChatConfigurationProvider>
|
|
1237
|
+
`
|
|
1238
|
+
: `
|
|
1239
|
+
<CopilotChatConfigurationProvider :thread-id="TEST_THREAD_ID">
|
|
1240
|
+
<CopilotChatInput model-value="hello" />
|
|
1241
|
+
</CopilotChatConfigurationProvider>
|
|
1242
|
+
`,
|
|
1243
|
+
});
|
|
1244
|
+
return render(Host);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
it("enables the send button and fires the listener once per send", async () => {
|
|
1248
|
+
const onSubmit = vi.fn();
|
|
1249
|
+
renderWithTemplateListener(onSubmit);
|
|
1250
|
+
|
|
1251
|
+
expect(getSendButton().disabled).toBe(false);
|
|
1252
|
+
await fireEvent.click(getSendButton());
|
|
1253
|
+
|
|
1254
|
+
expect(onSubmit).toHaveBeenCalledTimes(1);
|
|
1255
|
+
expect(onSubmit).toHaveBeenCalledWith("hello");
|
|
1256
|
+
});
|
|
1257
|
+
|
|
1258
|
+
it("keeps the send button disabled without a listener", () => {
|
|
1259
|
+
renderWithTemplateListener();
|
|
1260
|
+
|
|
1261
|
+
expect(getSendButton().disabled).toBe(true);
|
|
1262
|
+
});
|
|
1263
|
+
});
|
|
1221
1264
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
2
|
import { defineComponent, h, provide, ref } from "vue";
|
|
3
|
-
import { render, waitFor } from "@testing-library/vue";
|
|
3
|
+
import { fireEvent, render, waitFor } from "@testing-library/vue";
|
|
4
4
|
import type { Message } from "@ag-ui/core";
|
|
5
5
|
import CopilotKitProvider from "../../../providers/CopilotKitProvider.vue";
|
|
6
6
|
import CopilotChatConfigurationProvider from "../../../providers/CopilotChatConfigurationProvider.vue";
|
|
@@ -75,6 +75,10 @@ async function waitForMount(screen: ReturnType<typeof render>) {
|
|
|
75
75
|
await screen.findByTestId("copilot-chat-view");
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
function rect(top: number, bottom: number) {
|
|
79
|
+
return { top, bottom, left: 0, right: 0, width: 0, height: bottom - top };
|
|
80
|
+
}
|
|
81
|
+
|
|
78
82
|
describe("CopilotChatView pin-to-send mode", () => {
|
|
79
83
|
it("renders the pin-to-send spacer element when autoScroll='pin-to-send'", async () => {
|
|
80
84
|
const screen = renderView("pin-to-send");
|
|
@@ -163,4 +167,42 @@ describe("CopilotChatView pin-to-send mode", () => {
|
|
|
163
167
|
expect(spacer.getAttribute("data-pin-to-send-spacer")).not.toBeNull(),
|
|
164
168
|
);
|
|
165
169
|
});
|
|
170
|
+
// The spacer under the messages is not content: the scroll-to-bottom
|
|
171
|
+
// button follows the end of the messages, as in React.
|
|
172
|
+
describe("scroll-to-bottom button", () => {
|
|
173
|
+
async function setup(contentBottom: number) {
|
|
174
|
+
const screen = renderView("pin-to-send");
|
|
175
|
+
await waitForMount(screen);
|
|
176
|
+
const scrollElement = screen.getByTestId("copilot-chat-view-scroll");
|
|
177
|
+
const contentElement = screen.getByTestId("copilot-scroll-content");
|
|
178
|
+
// The spacer makes the scroll height far larger than the view.
|
|
179
|
+
Object.defineProperty(scrollElement, "scrollHeight", {
|
|
180
|
+
configurable: true,
|
|
181
|
+
get: () => 2000,
|
|
182
|
+
});
|
|
183
|
+
Object.defineProperty(scrollElement, "clientHeight", {
|
|
184
|
+
configurable: true,
|
|
185
|
+
get: () => 400,
|
|
186
|
+
});
|
|
187
|
+
scrollElement.getBoundingClientRect = () => rect(0, 400) as DOMRect;
|
|
188
|
+
contentElement.getBoundingClientRect = () =>
|
|
189
|
+
rect(-200, contentBottom) as DOMRect;
|
|
190
|
+
await fireEvent.scroll(scrollElement);
|
|
191
|
+
return screen;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
it("stays hidden when only the spacer is below the view", async () => {
|
|
195
|
+
const screen = await setup(390);
|
|
196
|
+
expect(
|
|
197
|
+
screen.queryByTestId("copilot-chat-view-scroll-to-bottom"),
|
|
198
|
+
).toBeNull();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("shows when messages sit below the view", async () => {
|
|
202
|
+
const screen = await setup(700);
|
|
203
|
+
expect(
|
|
204
|
+
await screen.findByTestId("copilot-chat-view-scroll-to-bottom"),
|
|
205
|
+
).toBeDefined();
|
|
206
|
+
});
|
|
207
|
+
});
|
|
166
208
|
});
|
|
@@ -114,6 +114,26 @@ export interface FeedbackComment {
|
|
|
114
114
|
readonly close: ɵFeedbackCommentController["close"];
|
|
115
115
|
/** Moves focus back to the thumb without opening the comment again. */
|
|
116
116
|
readonly returnFocus: (target: HTMLElement | null) => void;
|
|
117
|
+
/** The chosen thumb the popover points at. */
|
|
118
|
+
readonly anchor: ComputedRef<HTMLElement | null>;
|
|
119
|
+
/** A thumb click; returns whether the app's handler should run. */
|
|
120
|
+
readonly rate: ɵFeedbackCommentController["rate"];
|
|
121
|
+
/** The attributes and handlers of one thumb. */
|
|
122
|
+
readonly thumb: ɵFeedbackCommentController["thumb"];
|
|
123
|
+
/** Points at the chosen thumb when the click gave no element. */
|
|
124
|
+
readonly findAnchor: ɵFeedbackCommentController["findAnchor"];
|
|
125
|
+
/** Closes a comment whose rating changed or whose toolbar hid. */
|
|
126
|
+
readonly sync: ɵFeedbackCommentController["sync"];
|
|
127
|
+
/** Moves focus into the field when a keyboard rating asked for it. */
|
|
128
|
+
readonly focusField: ɵFeedbackCommentController["focusField"];
|
|
129
|
+
/** Saves, closes, and returns focus to the thumb. */
|
|
130
|
+
readonly submit: ɵFeedbackCommentController["submit"];
|
|
131
|
+
/** Escape in the popover; returns whether to stop the event. */
|
|
132
|
+
readonly popoverEscape: ɵFeedbackCommentController["popoverEscape"];
|
|
133
|
+
/** Tab out of the popover, back into the page's order. */
|
|
134
|
+
readonly popoverKeyDown: ɵFeedbackCommentController["popoverKeyDown"];
|
|
135
|
+
/** Focus left the comment form. */
|
|
136
|
+
readonly popoverFocusLeave: ɵFeedbackCommentController["popoverFocusLeave"];
|
|
117
137
|
}
|
|
118
138
|
|
|
119
139
|
/**
|
|
@@ -124,8 +144,10 @@ export interface FeedbackComment {
|
|
|
124
144
|
export function useFeedbackComment(
|
|
125
145
|
controls: Ref<MessageFeedbackControls | null>,
|
|
126
146
|
): FeedbackComment {
|
|
147
|
+
const input = shallowRef<HTMLInputElement | null>(null);
|
|
127
148
|
const controller = new ɵFeedbackCommentController({
|
|
128
149
|
getControls: () => controls.value,
|
|
150
|
+
getInput: () => input.value,
|
|
129
151
|
});
|
|
130
152
|
const state = shallowRef(controller.getSnapshot());
|
|
131
153
|
const unsubscribe = controller.subscribe(() => {
|
|
@@ -145,12 +167,22 @@ export function useFeedbackComment(
|
|
|
145
167
|
}),
|
|
146
168
|
focusRequest: computed(() => state.value.focusRequest),
|
|
147
169
|
takeFocusRequest: controller.takeFocusRequest,
|
|
148
|
-
input
|
|
170
|
+
input,
|
|
149
171
|
show: controller.show,
|
|
150
172
|
enter: controller.enter,
|
|
151
173
|
leave: controller.leave,
|
|
152
174
|
setEditing: controller.setEditing,
|
|
153
175
|
close: controller.close,
|
|
154
176
|
returnFocus: controller.returnFocus,
|
|
177
|
+
anchor: computed(() => state.value.anchor),
|
|
178
|
+
rate: controller.rate,
|
|
179
|
+
thumb: controller.thumb,
|
|
180
|
+
findAnchor: controller.findAnchor,
|
|
181
|
+
sync: controller.sync,
|
|
182
|
+
focusField: controller.focusField,
|
|
183
|
+
submit: controller.submit,
|
|
184
|
+
popoverEscape: controller.popoverEscape,
|
|
185
|
+
popoverKeyDown: controller.popoverKeyDown,
|
|
186
|
+
popoverFocusLeave: controller.popoverFocusLeave,
|
|
155
187
|
};
|
|
156
188
|
}
|
|
@@ -2,8 +2,7 @@ import { computed, watch } from "vue";
|
|
|
2
2
|
import type { WatchSource } from "vue";
|
|
3
3
|
import { useCopilotKit } from "../providers/useCopilotKit";
|
|
4
4
|
import { useCopilotChatConfiguration } from "../providers/useCopilotChatConfiguration";
|
|
5
|
-
import {
|
|
6
|
-
import { ɵbindSuggestionsConfig } from "@copilotkit/core";
|
|
5
|
+
import { ɵbindSuggestionsConfig, ɵresolveAgentId } from "@copilotkit/core";
|
|
7
6
|
import type { ɵSuggestionsConfigInput } from "@copilotkit/core";
|
|
8
7
|
|
|
9
8
|
/**
|
|
@@ -27,8 +26,8 @@ export function useConfigureSuggestions(
|
|
|
27
26
|
): void {
|
|
28
27
|
const { copilotkit } = useCopilotKit();
|
|
29
28
|
const chatConfig = useCopilotChatConfiguration();
|
|
30
|
-
const chatAgentId = computed(
|
|
31
|
-
(
|
|
29
|
+
const chatAgentId = computed(() =>
|
|
30
|
+
ɵresolveAgentId({ chatAgentId: chatConfig.value?.agentId }),
|
|
32
31
|
);
|
|
33
32
|
const extraDeps = deps ?? [];
|
|
34
33
|
|
|
@@ -2,84 +2,23 @@ import { defineComponent, h, inject, ref } from "vue";
|
|
|
2
2
|
import type { WatchSource } from "vue";
|
|
3
3
|
import type { Component, VNodeChild } from "vue";
|
|
4
4
|
import {
|
|
5
|
+
ɵadaptDefaultToolCallRenderProps as adaptRendererProps,
|
|
5
6
|
ɵgetToolCallBadge,
|
|
6
7
|
ɵnormalizeToolCallStatus,
|
|
7
8
|
ɵstringifyToolCallAttr,
|
|
8
9
|
ɵstringifyToolCallPayload,
|
|
9
10
|
} from "@copilotkit/core";
|
|
10
|
-
import type {
|
|
11
|
+
import type {
|
|
12
|
+
ɵDefaultToolCallRenderProps,
|
|
13
|
+
ɵRawToolCallRenderProps,
|
|
14
|
+
} from "@copilotkit/core";
|
|
11
15
|
import { useRenderTool } from "./use-render-tool";
|
|
12
16
|
import { ToolCallGroupContextKey } from "../components/chat/tool-call-display-context";
|
|
13
17
|
import { ToolCallRow } from "../components/chat/tool-call-group-parts";
|
|
14
18
|
import { useChatLabels } from "../components/chat/use-chat-labels";
|
|
15
19
|
|
|
16
|
-
type DefaultRenderProps =
|
|
17
|
-
|
|
18
|
-
toolCallId: string;
|
|
19
|
-
parameters: unknown;
|
|
20
|
-
status: "inProgress" | "executing" | "complete";
|
|
21
|
-
result: string | undefined;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Module-level dedup set so an unknown status value only emits a console
|
|
26
|
-
* warning the FIRST time we encounter it. Otherwise a stuck/unmapped status
|
|
27
|
-
* would log on every re-render (potentially many per second).
|
|
28
|
-
*/
|
|
29
|
-
const warnedUnknownStatuses = new Set<string>();
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Map a {@link ToolCallStatus} enum value to the documented string-union
|
|
33
|
-
* status the {@link DefaultRenderProps} contract exposes. Unknown / future
|
|
34
|
-
* enum members log a warning (once per distinct value) and fall back to
|
|
35
|
-
* `"inProgress"`.
|
|
36
|
-
*/
|
|
37
|
-
function mapToolCallStatus(
|
|
38
|
-
status: ToolCallStatus,
|
|
39
|
-
): DefaultRenderProps["status"] {
|
|
40
|
-
const normalized = ɵnormalizeToolCallStatus(status);
|
|
41
|
-
if (normalized !== "unknown") return normalized;
|
|
42
|
-
const key = String(status);
|
|
43
|
-
if (!warnedUnknownStatuses.has(key)) {
|
|
44
|
-
warnedUnknownStatuses.add(key);
|
|
45
|
-
console.warn(
|
|
46
|
-
`[CopilotKit] Unknown ToolCallStatus "${key}" in default tool-call renderer; falling back to "inProgress".`,
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
return "inProgress";
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Convert framework-internal raw renderer props (`args`, enum status) to the
|
|
54
|
-
* documented DefaultRenderProps shape. Idempotent on already-documented input
|
|
55
|
-
* — if the caller passes `parameters` and a string-union `status`, those win.
|
|
56
|
-
*/
|
|
57
|
-
type AdaptInput = {
|
|
58
|
-
name?: unknown;
|
|
59
|
-
toolCallId?: unknown;
|
|
60
|
-
args?: unknown;
|
|
61
|
-
parameters?: unknown;
|
|
62
|
-
status?: unknown;
|
|
63
|
-
result?: unknown;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
function adaptRendererProps(raw: AdaptInput): DefaultRenderProps {
|
|
67
|
-
const parameters = raw.parameters !== undefined ? raw.parameters : raw.args;
|
|
68
|
-
const rawStatus = raw.status;
|
|
69
|
-
const status: DefaultRenderProps["status"] =
|
|
70
|
-
rawStatus === "inProgress" ||
|
|
71
|
-
rawStatus === "executing" ||
|
|
72
|
-
rawStatus === "complete"
|
|
73
|
-
? rawStatus
|
|
74
|
-
: mapToolCallStatus(rawStatus as ToolCallStatus);
|
|
75
|
-
return {
|
|
76
|
-
name: raw.name as string,
|
|
77
|
-
toolCallId: raw.toolCallId as string,
|
|
78
|
-
parameters,
|
|
79
|
-
status,
|
|
80
|
-
result: raw.result as string | undefined,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
20
|
+
type DefaultRenderProps = ɵDefaultToolCallRenderProps;
|
|
21
|
+
type AdaptInput = ɵRawToolCallRenderProps;
|
|
83
22
|
|
|
84
23
|
const DefaultToolCallRenderer = defineComponent({
|
|
85
24
|
props: {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { watch } from "vue";
|
|
2
|
+
import { ɵregisterFrontendTools } from "@copilotkit/core";
|
|
2
3
|
import type { WatchSource } from "vue";
|
|
3
4
|
import { useCopilotKit } from "../providers/useCopilotKit";
|
|
4
5
|
import type { VueFrontendTool } from "../types";
|
|
@@ -14,8 +15,8 @@ const EMPTY_DEPS: WatchSource<unknown>[] = [];
|
|
|
14
15
|
*
|
|
15
16
|
* A tool with the same name and `agentId` as a tool that is already
|
|
16
17
|
* registered (for example a provider `frontendTools` entry) takes its place
|
|
17
|
-
* while this scope is active
|
|
18
|
-
* active again.
|
|
18
|
+
* while this scope is active, with a console warning. When the scope is
|
|
19
|
+
* disposed, the earlier tool is active again.
|
|
19
20
|
*
|
|
20
21
|
* @example
|
|
21
22
|
* ```ts
|
|
@@ -45,26 +46,15 @@ export function useFrontendTool<T extends Record<string, unknown>>(
|
|
|
45
46
|
],
|
|
46
47
|
(_newValues, _old, onCleanup) => {
|
|
47
48
|
const core = copilotkit.value;
|
|
48
|
-
const name = tool.name;
|
|
49
|
-
|
|
50
49
|
// Registrations stack in core: this one shadows an earlier tool with the
|
|
51
50
|
// same name and agentId (a provider tool, or another component's), and
|
|
52
|
-
// unregistering it brings that tool back.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
core.addHookRenderToolCall({
|
|
60
|
-
name,
|
|
61
|
-
args: tool.parameters,
|
|
62
|
-
agentId: tool.agentId,
|
|
63
|
-
render: tool.render,
|
|
64
|
-
} as VueToolCallRenderer);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
onCleanup(unregister);
|
|
51
|
+
// unregistering it brings that tool back. The renderer stays registered
|
|
52
|
+
// so past calls still render in the chat history.
|
|
53
|
+
onCleanup(
|
|
54
|
+
ɵregisterFrontendTools(core, [tool], (renderer) =>
|
|
55
|
+
core.addHookRenderToolCall(renderer as VueToolCallRenderer),
|
|
56
|
+
),
|
|
57
|
+
);
|
|
68
58
|
},
|
|
69
59
|
{ immediate: true },
|
|
70
60
|
);
|
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
ɵdescribeActivityRendererFailure,
|
|
6
6
|
ɵfindActivityRenderer,
|
|
7
7
|
ɵmatchActivityRenderer,
|
|
8
|
+
ɵresolveAgentId,
|
|
8
9
|
} from "@copilotkit/core";
|
|
9
|
-
import { DEFAULT_AGENT_ID } from "@copilotkit/shared";
|
|
10
10
|
import { useCopilotKit } from "../providers/useCopilotKit";
|
|
11
11
|
import { useCopilotChatConfiguration } from "../providers/useCopilotChatConfiguration";
|
|
12
12
|
import type { VueActivityMessageRendererProps } from "../types";
|
|
@@ -23,7 +23,9 @@ import type { VueActivityMessageRendererProps } from "../types";
|
|
|
23
23
|
export function useRenderActivityMessage() {
|
|
24
24
|
const { copilotkit } = useCopilotKit();
|
|
25
25
|
const config = useCopilotChatConfiguration();
|
|
26
|
-
const agentId = computed(() =>
|
|
26
|
+
const agentId = computed(() =>
|
|
27
|
+
ɵresolveAgentId({ chatAgentId: config.value?.agentId }),
|
|
28
|
+
);
|
|
27
29
|
|
|
28
30
|
function findRenderer(activityType: string) {
|
|
29
31
|
return ɵfindActivityRenderer(copilotkit.value.renderActivityMessages, {
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { computed, ref, toValue, watch } from "vue";
|
|
2
2
|
import type { MaybeRefOrGetter, Ref } from "vue";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
ɵresolveAgentId,
|
|
5
|
+
ɵsubscribeToAgentSuggestions,
|
|
6
|
+
} from "@copilotkit/core";
|
|
4
7
|
import type {
|
|
5
8
|
CopilotKitCoreGetSuggestionsResult,
|
|
6
9
|
Suggestion,
|
|
7
10
|
} from "@copilotkit/core";
|
|
8
11
|
import { useCopilotKit } from "../providers/useCopilotKit";
|
|
9
12
|
import { useCopilotChatConfiguration } from "../providers/useCopilotChatConfiguration";
|
|
10
|
-
import { DEFAULT_AGENT_ID } from "@copilotkit/shared";
|
|
11
13
|
|
|
12
14
|
export interface UseSuggestionsOptions {
|
|
13
15
|
agentId?: MaybeRefOrGetter<string | undefined>;
|
|
@@ -38,8 +40,11 @@ export function useSuggestions(
|
|
|
38
40
|
): UseSuggestionsResult {
|
|
39
41
|
const { copilotkit } = useCopilotKit();
|
|
40
42
|
const config = useCopilotChatConfiguration();
|
|
41
|
-
const resolvedAgentId = computed(
|
|
42
|
-
(
|
|
43
|
+
const resolvedAgentId = computed(() =>
|
|
44
|
+
ɵresolveAgentId({
|
|
45
|
+
agentId: toValue(options.agentId),
|
|
46
|
+
chatAgentId: config.value?.agentId,
|
|
47
|
+
}),
|
|
43
48
|
);
|
|
44
49
|
|
|
45
50
|
const suggestions = ref<Suggestion[]>([]);
|
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
import { computed, onScopeDispose, shallowRef, toValue, watch } from "vue";
|
|
2
2
|
import type { MaybeRefOrGetter, Ref } from "vue";
|
|
3
3
|
import { ɵThreadsController, ɵcreateThreadStore } from "@copilotkit/core";
|
|
4
|
+
import type { ɵThreadSummary } from "@copilotkit/core";
|
|
4
5
|
import { useCopilotKit } from "../providers/useCopilotKit";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
createdAt: string;
|
|
12
|
-
updatedAt: string;
|
|
13
|
-
/**
|
|
14
|
-
* ISO-8601 timestamp of the most recent agent run on this thread. Absent
|
|
15
|
-
* when the thread has never been run. Prefer this over `updatedAt` for
|
|
16
|
-
* user-facing "last activity" displays — it is not bumped by metadata-only
|
|
17
|
-
* actions like rename or archive.
|
|
18
|
-
*/
|
|
19
|
-
lastRunAt?: string;
|
|
20
|
-
}
|
|
7
|
+
/**
|
|
8
|
+
* One thread as the hook returns it. This is core's thread summary, the same
|
|
9
|
+
* type React and Angular expose, so the adapters cannot drift apart.
|
|
10
|
+
*/
|
|
11
|
+
export type Thread = ɵThreadSummary;
|
|
21
12
|
|
|
22
13
|
export interface UseThreadsInput {
|
|
23
14
|
agentId: MaybeRefOrGetter<string>;
|
package/src/v2/lib/vue-core.ts
CHANGED
|
@@ -86,12 +86,18 @@ export class CopilotKitCoreVue extends CopilotKitCore {
|
|
|
86
86
|
this._renderers.setCustom(renderers);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
/**
|
|
89
|
+
/**
|
|
90
|
+
* The renderers the provider was given, without hook or built-in
|
|
91
|
+
* renderers. Nothing in CopilotKit reads it now; it stays for app code.
|
|
92
|
+
*/
|
|
90
93
|
get propRenderToolCalls() {
|
|
91
94
|
return this._renderers.propToolCalls;
|
|
92
95
|
}
|
|
93
96
|
|
|
94
|
-
/**
|
|
97
|
+
/**
|
|
98
|
+
* Prop, hook and built-in renderers merged. For one name and agentId, a
|
|
99
|
+
* hook renderer wins over a prop one, and both win over a built-in one.
|
|
100
|
+
*/
|
|
95
101
|
get renderToolCalls() {
|
|
96
102
|
return this._renderers.toolCalls;
|
|
97
103
|
}
|
|
@@ -112,6 +118,17 @@ export class CopilotKitCoreVue extends CopilotKitCore {
|
|
|
112
118
|
this._renderers.removeHookToolCall(name, agentId);
|
|
113
119
|
}
|
|
114
120
|
|
|
121
|
+
/**
|
|
122
|
+
* @internal Add a renderer for a tool a built-in feature owns (A2UI,
|
|
123
|
+
* generative UI). Prop and hook renderers with the same name and agent win
|
|
124
|
+
* over it, and `setRenderToolCalls` never removes it.
|
|
125
|
+
*
|
|
126
|
+
* @returns A function that removes the renderer.
|
|
127
|
+
*/
|
|
128
|
+
ɵaddBuiltInRenderToolCall(entry: VueToolCallRenderer): () => void {
|
|
129
|
+
return this._renderers.addBuiltInToolCall(entry);
|
|
130
|
+
}
|
|
131
|
+
|
|
115
132
|
private notifyRenderersChanged(kind: ɵRendererKind): void {
|
|
116
133
|
void this.notifySubscribers((subscriber) => {
|
|
117
134
|
const vueSubscriber = subscriber as CopilotKitCoreVueSubscriber;
|