@copilotkit/vue 2.0.0-rc.7 → 2.0.0-rc.9
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/hooks/use-copilot-action.d.ts.map +1 -1
- package/dist/hooks/use-frontend-tool.d.ts +1 -1
- package/dist/hooks/use-frontend-tool.d.ts.map +1 -1
- package/dist/hooks/zod-parameters.d.ts +14 -0
- package/dist/hooks/zod-parameters.d.ts.map +1 -0
- package/dist/index.cjs +1 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +353 -16906
- package/dist/index.mjs.map +1 -1
- package/dist/use-render-activity-message-B59A4R48.js +18097 -0
- package/dist/use-render-activity-message-B59A4R48.js.map +1 -0
- package/dist/use-render-activity-message-u0OVXjd8.cjs +92 -0
- package/dist/use-render-activity-message-u0OVXjd8.cjs.map +1 -0
- package/dist/v2/components/LicenseWarningBanner.vue.d.ts.map +1 -1
- package/dist/v2/components/OpenGenerativeUIRenderer.d.ts +13 -45
- package/dist/v2/components/OpenGenerativeUIRenderer.d.ts.map +1 -1
- package/dist/v2/components/a2ui/A2UICatalogContext.d.ts +1 -1
- package/dist/v2/components/a2ui/A2UICatalogContext.d.ts.map +1 -1
- package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts +13 -5
- package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts.map +1 -1
- package/dist/v2/components/a2ui.d.ts +3 -7
- package/dist/v2/components/a2ui.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 +197 -200
- package/dist/v2/index.mjs.map +1 -1
- package/dist/v2/lib/processPartialHtml.d.ts +1 -2
- package/dist/v2/lib/processPartialHtml.d.ts.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.vue.d.ts +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 +10 -11
- package/src/__tests__/build-entries.test.ts +27 -0
- package/src/hooks/__tests__/zod-parameters.test.ts +520 -0
- package/src/hooks/use-copilot-action.ts +2 -1
- package/src/hooks/use-frontend-tool.ts +3 -6
- package/src/hooks/zod-parameters.ts +162 -0
- package/src/v2/components/A2UIMessageRenderer.ts +3 -3
- package/src/v2/components/LicenseWarningBanner.vue +31 -15
- package/src/v2/components/OpenGenerativeUIRenderer.ts +51 -373
- package/src/v2/components/__tests__/A2UICatalogContext.test.ts +1 -1
- package/src/v2/components/__tests__/LicenseWarningBanner.test.ts +20 -0
- package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.ts +55 -6
- package/src/v2/components/a2ui/A2UIBuiltInToolCallRenderer.ts +1 -1
- package/src/v2/components/a2ui/A2UICatalogContext.ts +10 -102
- package/src/v2/components/a2ui/A2UIRecoveryStates.ts +1 -1
- package/src/v2/components/a2ui.ts +1 -1
- 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__/CopilotChatActivityRendering.e2e.test.ts +26 -9
- 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 +5 -4
- 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/processPartialHtml.ts +6 -21
- package/src/v2/lib/vue-core.ts +3 -5
- package/src/v2/providers/CopilotKitProvider.vue +53 -112
- package/src/v2/providers/__tests__/CopilotKitProvider.a2ui.test.ts +1 -1
- 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 -0
- 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 +3 -4
- 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__/processPartialHtml.test.ts +0 -84
- package/src/v2/lib/__tests__/transcription-client.test.ts +0 -67
- package/src/v2/lib/transcription-client.ts +0 -151
|
@@ -1,27 +1,109 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
1
|
+
import { defineComponent, h } from "vue";
|
|
2
|
+
import type { PropType } from "vue";
|
|
3
|
+
import { ɵcopilotIcons, ɵcopilotIconSvgAttributes } from "@copilotkit/core";
|
|
4
|
+
import type { CopilotIconName } from "@copilotkit/core";
|
|
5
|
+
|
|
6
|
+
/** True when the attributes give the icon an accessible name or role. */
|
|
7
|
+
function hasAccessibleAttribute(attributes: object) {
|
|
8
|
+
return Object.keys(attributes).some(
|
|
9
|
+
(key) => key.startsWith("aria-") || key === "role" || key === "title",
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Props that change how an icon is drawn. Other attributes go on the `<svg>`. */
|
|
14
|
+
const iconDrawProps = {
|
|
15
|
+
/** Width and height of the icon. Defaults to `24`. */
|
|
16
|
+
size: { type: [Number, String], default: 24 },
|
|
17
|
+
/** Line color. Defaults to `currentColor`. */
|
|
18
|
+
color: { type: String, default: "currentColor" },
|
|
19
|
+
/** Line width. Defaults to `2`. */
|
|
20
|
+
strokeWidth: { type: [Number, String], default: 2 },
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Draws one of the chat icons as an inline `<svg>`.
|
|
25
|
+
*
|
|
26
|
+
* The `<svg>` has the classes `lucide lucide-<icon name>`, so CSS that selects
|
|
27
|
+
* them (for example `svg.lucide-arrow-up`) keeps working. The icon is hidden
|
|
28
|
+
* from screen readers unless you give it an `aria-*` attribute, a `role` or a
|
|
29
|
+
* `title`. Other attributes, such as `class` or `fill`, go on the `<svg>`.
|
|
30
|
+
*
|
|
31
|
+
* Props:
|
|
32
|
+
* - `name`: the chat icon, for example `"ArrowUp"` or `"X"`.
|
|
33
|
+
* - `size`: width and height. Defaults to `24`.
|
|
34
|
+
* - `stroke-width`: line width. Defaults to `2`.
|
|
35
|
+
* - `color`: line color. Defaults to `currentColor`.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```vue
|
|
39
|
+
* <CopilotIcon name="ArrowUp" class="cpk-chat-input-send-icon" />
|
|
40
|
+
* <CopilotIcon name="X" aria-label="Close" />
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export const CopilotIcon = defineComponent({
|
|
44
|
+
name: "CopilotIcon",
|
|
45
|
+
props: {
|
|
46
|
+
/** The chat icon to draw, for example `"ArrowUp"`. */
|
|
47
|
+
name: { type: String as PropType<CopilotIconName>, required: true },
|
|
48
|
+
...iconDrawProps,
|
|
49
|
+
},
|
|
50
|
+
setup(props, { attrs, slots }) {
|
|
51
|
+
return () => {
|
|
52
|
+
const icon = ɵcopilotIcons[props.name];
|
|
53
|
+
const content = slots.default?.() ?? [];
|
|
54
|
+
const isDecorative =
|
|
55
|
+
content.length === 0 && !hasAccessibleAttribute(attrs);
|
|
56
|
+
return h(
|
|
57
|
+
"svg",
|
|
58
|
+
{
|
|
59
|
+
...ɵcopilotIconSvgAttributes,
|
|
60
|
+
width: props.size,
|
|
61
|
+
height: props.size,
|
|
62
|
+
stroke: props.color,
|
|
63
|
+
"stroke-width": props.strokeWidth,
|
|
64
|
+
class: ["lucide", `lucide-${icon.name}`],
|
|
65
|
+
"aria-hidden": isDecorative ? "true" : undefined,
|
|
66
|
+
},
|
|
67
|
+
[...icon.nodes.map((node) => h(node.tag, node.attributes)), ...content],
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Internal. Makes a component that draws one chat icon, such as `IconArrowUp`.
|
|
75
|
+
* It takes the same `size`, `color` and `stroke-width` props as `CopilotIcon`.
|
|
76
|
+
*/
|
|
77
|
+
function defineIcon(name: CopilotIconName) {
|
|
78
|
+
return defineComponent({
|
|
79
|
+
name: `Icon${name}`,
|
|
80
|
+
props: iconDrawProps,
|
|
81
|
+
setup(props, { slots }) {
|
|
82
|
+
return () => h(CopilotIcon, { name, ...props }, slots);
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export const IconArrowUp = defineIcon("ArrowUp");
|
|
88
|
+
export const IconCheck = defineIcon("Check");
|
|
89
|
+
export const IconChevronDown = defineIcon("ChevronDown");
|
|
90
|
+
export const IconChevronLeft = defineIcon("ChevronLeft");
|
|
91
|
+
export const IconChevronRight = defineIcon("ChevronRight");
|
|
92
|
+
export const IconCircle = defineIcon("Circle");
|
|
93
|
+
export const IconCopy = defineIcon("Copy");
|
|
94
|
+
export const IconEdit = defineIcon("Edit");
|
|
95
|
+
export const IconEyeOff = defineIcon("EyeOff");
|
|
96
|
+
export const IconLoader2 = defineIcon("Loader2");
|
|
97
|
+
export const IconMessageCircle = defineIcon("MessageCircle");
|
|
98
|
+
export const IconMic = defineIcon("Mic");
|
|
99
|
+
export const IconPanelLeftOpen = defineIcon("PanelLeftOpen");
|
|
100
|
+
export const IconPlay = defineIcon("Play");
|
|
101
|
+
export const IconPlus = defineIcon("Plus");
|
|
102
|
+
export const IconRefreshCw = defineIcon("RefreshCw");
|
|
103
|
+
export const IconSquare = defineIcon("Square");
|
|
104
|
+
export const IconThumbsDown = defineIcon("ThumbsDown");
|
|
105
|
+
export const IconThumbsUp = defineIcon("ThumbsUp");
|
|
106
|
+
export const IconUpload = defineIcon("Upload");
|
|
107
|
+
export const IconVolume2 = defineIcon("Volume2");
|
|
108
|
+
export const IconWrench = defineIcon("Wrench");
|
|
109
|
+
export const IconX = defineIcon("X");
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
computed,
|
|
3
|
+
defineComponent,
|
|
4
|
+
h,
|
|
5
|
+
nextTick,
|
|
6
|
+
onMounted,
|
|
7
|
+
ref,
|
|
8
|
+
watch,
|
|
9
|
+
} from "vue";
|
|
2
10
|
import type { PropType } from "vue";
|
|
3
11
|
import { screen, fireEvent, waitFor, cleanup } from "@testing-library/vue";
|
|
4
12
|
import { afterEach, describe, expect, it } from "vitest";
|
|
@@ -27,6 +35,11 @@ import {
|
|
|
27
35
|
textChunkEvent,
|
|
28
36
|
testId,
|
|
29
37
|
} from "../../__tests__/utils/test-helpers";
|
|
38
|
+
import { mountWithProvider } from "../../__tests__/utils/mount";
|
|
39
|
+
import {
|
|
40
|
+
StateCapturingAgent,
|
|
41
|
+
toolCallMessage,
|
|
42
|
+
} from "../../__tests__/utils/agents";
|
|
30
43
|
|
|
31
44
|
afterEach(() => {
|
|
32
45
|
cleanup();
|
|
@@ -912,6 +925,54 @@ describe("useFrontendTool E2E - Dynamic Registration", () => {
|
|
|
912
925
|
});
|
|
913
926
|
});
|
|
914
927
|
|
|
928
|
+
describe("Overriding a provider tool", () => {
|
|
929
|
+
it("brings the provider tool back after the overriding component unmounts", async () => {
|
|
930
|
+
const calls: string[] = [];
|
|
931
|
+
const lookupTool = (owner: string): VueFrontendTool => ({
|
|
932
|
+
name: "lookup",
|
|
933
|
+
parameters: z.object({}),
|
|
934
|
+
followUp: false,
|
|
935
|
+
handler: async () => {
|
|
936
|
+
calls.push(owner);
|
|
937
|
+
return owner;
|
|
938
|
+
},
|
|
939
|
+
});
|
|
940
|
+
|
|
941
|
+
const OverridingTool = defineComponent({
|
|
942
|
+
setup() {
|
|
943
|
+
useFrontendTool(lookupTool("component"));
|
|
944
|
+
return () => null;
|
|
945
|
+
},
|
|
946
|
+
});
|
|
947
|
+
|
|
948
|
+
const showOverride = ref(true);
|
|
949
|
+
const agent = new StateCapturingAgent(
|
|
950
|
+
[
|
|
951
|
+
{ newMessages: [toolCallMessage("lookup")] },
|
|
952
|
+
{ newMessages: [toolCallMessage("lookup")] },
|
|
953
|
+
],
|
|
954
|
+
"test-agent",
|
|
955
|
+
);
|
|
956
|
+
const { getCore, wrapper } = mountWithProvider(
|
|
957
|
+
() => (showOverride.value ? h(OverridingTool) : h("div")),
|
|
958
|
+
{
|
|
959
|
+
frontendTools: [lookupTool("provider")],
|
|
960
|
+
agents__unsafe_dev_only: { "test-agent": agent },
|
|
961
|
+
},
|
|
962
|
+
);
|
|
963
|
+
|
|
964
|
+
await nextTick();
|
|
965
|
+
await getCore().runAgent({ agent });
|
|
966
|
+
|
|
967
|
+
showOverride.value = false;
|
|
968
|
+
await nextTick();
|
|
969
|
+
await getCore().runAgent({ agent });
|
|
970
|
+
|
|
971
|
+
expect(calls).toEqual(["component", "provider"]);
|
|
972
|
+
wrapper.unmount();
|
|
973
|
+
});
|
|
974
|
+
});
|
|
975
|
+
|
|
915
976
|
describe("Integration with Chat UI", () => {
|
|
916
977
|
it("should render tool output correctly in chat interface", async () => {
|
|
917
978
|
const agent = new MockStepwiseAgent();
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import {
|
|
2
|
+
afterEach,
|
|
3
|
+
beforeEach,
|
|
4
|
+
describe,
|
|
5
|
+
expect,
|
|
6
|
+
expectTypeOf,
|
|
7
|
+
it,
|
|
8
|
+
vi,
|
|
9
|
+
} from "vitest";
|
|
10
|
+
import { defineComponent, h, toRaw } from "vue";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import type { ActivityMessage } from "@ag-ui/core";
|
|
13
|
+
import { useRenderActivityMessage } from "../use-render-activity-message";
|
|
14
|
+
import type {
|
|
15
|
+
VueActivityMessageRenderer,
|
|
16
|
+
VueActivityMessageRendererProps,
|
|
17
|
+
} from "../../types";
|
|
18
|
+
import { renderWithCopilotKit } from "../../__tests__/utils/mount";
|
|
19
|
+
|
|
20
|
+
const ProgressRenderer = defineComponent({
|
|
21
|
+
props: { content: { type: Object, required: true } },
|
|
22
|
+
setup: () => () => null,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const progressSchema = z.object({
|
|
26
|
+
label: z.string(),
|
|
27
|
+
percent: z.number().default(0),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// A zod schema is a Standard Schema, so it fits the `content` field, and the
|
|
31
|
+
// renderer's content type is the schema's output type.
|
|
32
|
+
const progressRenderer = {
|
|
33
|
+
activityType: "progress",
|
|
34
|
+
content: progressSchema,
|
|
35
|
+
render: ProgressRenderer,
|
|
36
|
+
} satisfies VueActivityMessageRenderer<z.output<typeof progressSchema>>;
|
|
37
|
+
|
|
38
|
+
function activityMessage(content: Record<string, unknown>): ActivityMessage {
|
|
39
|
+
return {
|
|
40
|
+
id: "activity-1",
|
|
41
|
+
role: "activity",
|
|
42
|
+
activityType: "progress",
|
|
43
|
+
content,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function renderWithProgressRenderer() {
|
|
48
|
+
let helpers: ReturnType<typeof useRenderActivityMessage> | undefined;
|
|
49
|
+
const Probe = defineComponent({
|
|
50
|
+
setup() {
|
|
51
|
+
helpers = useRenderActivityMessage();
|
|
52
|
+
return () => null;
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
renderWithCopilotKit(() => h(Probe), {
|
|
57
|
+
providerProps: { renderActivityMessages: [progressRenderer] },
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (!helpers) throw new Error("useRenderActivityMessage did not run");
|
|
61
|
+
return helpers;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
describe("useRenderActivityMessage", () => {
|
|
65
|
+
let consoleWarnSpy: ReturnType<typeof vi.spyOn>;
|
|
66
|
+
|
|
67
|
+
beforeEach(() => {
|
|
68
|
+
consoleWarnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
afterEach(() => {
|
|
72
|
+
consoleWarnSpy.mockRestore();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("types a zod content schema's output as the render props content", () => {
|
|
76
|
+
type Props = VueActivityMessageRendererProps<
|
|
77
|
+
z.output<typeof progressSchema>
|
|
78
|
+
>;
|
|
79
|
+
expectTypeOf<Props["content"]>().toEqualTypeOf<{
|
|
80
|
+
label: string;
|
|
81
|
+
percent: number;
|
|
82
|
+
}>();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("passes the zod schema's parsed output to the renderer", () => {
|
|
86
|
+
const { renderActivityMessage } = renderWithProgressRenderer();
|
|
87
|
+
|
|
88
|
+
const result = renderActivityMessage(activityMessage({ label: "Upload" }));
|
|
89
|
+
|
|
90
|
+
// The provider stores renderers in reactive state, so compare the raw value.
|
|
91
|
+
expect(toRaw(result?.renderer)).toBe(ProgressRenderer);
|
|
92
|
+
expect(result?.props.content).toEqual({ label: "Upload", percent: 0 });
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("returns null and warns when the content fails the schema", () => {
|
|
96
|
+
const { renderActivityMessage } = renderWithProgressRenderer();
|
|
97
|
+
|
|
98
|
+
const result = renderActivityMessage(activityMessage({ label: 42 }));
|
|
99
|
+
|
|
100
|
+
expect(result).toBeNull();
|
|
101
|
+
expect(consoleWarnSpy).toHaveBeenCalledWith(
|
|
102
|
+
"Failed to validate content for activity message 'progress'.",
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
@@ -93,7 +93,7 @@ describe("useRenderTool", () => {
|
|
|
93
93
|
expect(typeof renderer?.render).toBe("function");
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
-
it("registers wildcard renderer and defaults parameters schema
|
|
96
|
+
it("registers wildcard renderer and defaults parameters to a schema that accepts any value", () => {
|
|
97
97
|
const core = createMockCore();
|
|
98
98
|
mockUseCopilotKit.mockReturnValue({ copilotkit: { value: core } });
|
|
99
99
|
|
|
@@ -118,11 +118,8 @@ describe("useRenderTool", () => {
|
|
|
118
118
|
const renderer = core.renderToolCalls.find((item) => item.name === "*");
|
|
119
119
|
expect(renderer).toBeDefined();
|
|
120
120
|
expect(typeof renderer?.render).toBe("function");
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
| undefined;
|
|
124
|
-
expect(wildcardArgs).toBeDefined();
|
|
125
|
-
expect(wildcardArgs!.safeParse({ arbitrary: true }).success).toBe(true);
|
|
121
|
+
const result = renderer?.args["~standard"].validate({ arbitrary: true });
|
|
122
|
+
expect(result).toEqual({ value: { arbitrary: true } });
|
|
126
123
|
});
|
|
127
124
|
|
|
128
125
|
it("accepts a Vue component renderer", () => {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Covers:
|
|
6
6
|
* 1. useRenderTool with complex Zod schemas
|
|
7
|
-
* 2. defineToolCallRenderer with Zod (named + wildcard default
|
|
7
|
+
* 2. defineToolCallRenderer with Zod (named + wildcard default schema)
|
|
8
8
|
* 3. useComponent with Zod schemas
|
|
9
9
|
* 4. The registered schema object is the original Zod instance (identity check)
|
|
10
10
|
*/
|
|
@@ -134,7 +134,7 @@ describe("useRenderTool Zod regression", () => {
|
|
|
134
134
|
const schema = z.object({
|
|
135
135
|
action: z.discriminatedUnion("type", [
|
|
136
136
|
z.object({ type: z.literal("search"), query: z.string() }),
|
|
137
|
-
z.object({ type: z.literal("navigate"), url: z.
|
|
137
|
+
z.object({ type: z.literal("navigate"), url: z.url() }),
|
|
138
138
|
]),
|
|
139
139
|
});
|
|
140
140
|
|
|
@@ -196,14 +196,15 @@ describe("useRenderTool Zod regression", () => {
|
|
|
196
196
|
});
|
|
197
197
|
|
|
198
198
|
describe("defineToolCallRenderer Zod regression", () => {
|
|
199
|
-
it("wildcard tool defaults to
|
|
199
|
+
it("wildcard tool defaults to a schema that accepts any value", () => {
|
|
200
200
|
const renderer = defineToolCallRenderer({
|
|
201
201
|
name: "*",
|
|
202
202
|
render: () => "wildcard",
|
|
203
203
|
});
|
|
204
204
|
|
|
205
205
|
expect(renderer.name).toBe("*");
|
|
206
|
-
|
|
206
|
+
const result = renderer.args["~standard"].validate({ city: "Paris" });
|
|
207
|
+
expect(result).toEqual({ value: { city: "Paris" } });
|
|
207
208
|
});
|
|
208
209
|
|
|
209
210
|
it("named tool with Zod args preserves schema identity", () => {
|
|
@@ -12,6 +12,11 @@ const EMPTY_DEPS: WatchSource<unknown>[] = [];
|
|
|
12
12
|
* The tool registration is reactive to provided dependencies and is cleaned up
|
|
13
13
|
* automatically when the current scope is disposed.
|
|
14
14
|
*
|
|
15
|
+
* A tool with the same name and `agentId` as a tool that is already
|
|
16
|
+
* registered (for example a provider `frontendTools` entry) takes its place
|
|
17
|
+
* while this scope is active. When the scope is disposed, the earlier tool is
|
|
18
|
+
* active again.
|
|
19
|
+
*
|
|
15
20
|
* @example
|
|
16
21
|
* ```ts
|
|
17
22
|
* useFrontendTool({
|
|
@@ -42,13 +47,10 @@ export function useFrontendTool<T extends Record<string, unknown>>(
|
|
|
42
47
|
const core = copilotkit.value;
|
|
43
48
|
const name = tool.name;
|
|
44
49
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
core.removeTool(name, tool.agentId);
|
|
50
|
-
}
|
|
51
|
-
core.addTool(tool);
|
|
50
|
+
// Registrations stack in core: this one shadows an earlier tool with the
|
|
51
|
+
// same name and agentId (a provider tool, or another component's), and
|
|
52
|
+
// unregistering it brings that tool back.
|
|
53
|
+
const unregister = core.addTool(tool);
|
|
52
54
|
|
|
53
55
|
// The render function is registered even when tool.parameters is
|
|
54
56
|
// undefined — tools like HITL confirm dialogs have no parameters
|
|
@@ -62,9 +64,7 @@ export function useFrontendTool<T extends Record<string, unknown>>(
|
|
|
62
64
|
} as VueToolCallRenderer<unknown>);
|
|
63
65
|
}
|
|
64
66
|
|
|
65
|
-
onCleanup(
|
|
66
|
-
core.removeTool(name, tool.agentId);
|
|
67
|
-
});
|
|
67
|
+
onCleanup(unregister);
|
|
68
68
|
},
|
|
69
69
|
{ immediate: true },
|
|
70
70
|
);
|
|
@@ -1,19 +1,11 @@
|
|
|
1
1
|
import { computed } from "vue";
|
|
2
2
|
import type { Component } from "vue";
|
|
3
3
|
import type { ActivityMessage } from "@ag-ui/core";
|
|
4
|
-
import
|
|
4
|
+
import { ɵresolveActivityRenderer } from "@copilotkit/core";
|
|
5
5
|
import { DEFAULT_AGENT_ID } from "@copilotkit/shared";
|
|
6
6
|
import { useCopilotKit } from "../providers/useCopilotKit";
|
|
7
7
|
import { useCopilotChatConfiguration } from "../providers/useCopilotChatConfiguration";
|
|
8
|
-
import type {
|
|
9
|
-
VueActivityMessageRenderer,
|
|
10
|
-
VueActivityMessageRendererProps,
|
|
11
|
-
} from "../types";
|
|
12
|
-
|
|
13
|
-
interface ActivityRendererResult {
|
|
14
|
-
renderer: Component<VueActivityMessageRendererProps<unknown>>;
|
|
15
|
-
props: VueActivityMessageRendererProps<unknown>;
|
|
16
|
-
}
|
|
8
|
+
import type { VueActivityMessageRendererProps } from "../types";
|
|
17
9
|
|
|
18
10
|
/**
|
|
19
11
|
* Returns helpers for rendering activity messages.
|
|
@@ -21,70 +13,57 @@ interface ActivityRendererResult {
|
|
|
21
13
|
* Matches the React `useRenderActivityMessage` API: `findRenderer` locates a
|
|
22
14
|
* registered renderer by activity type (preferring agent-scoped over global,
|
|
23
15
|
* with `"*"` as a wildcard fallback), and `renderActivityMessage` resolves the
|
|
24
|
-
* renderer and validates the content schema
|
|
16
|
+
* renderer and validates the content with the renderer's `content` schema
|
|
17
|
+
* (any Standard Schema, such as zod).
|
|
25
18
|
*/
|
|
26
19
|
export function useRenderActivityMessage() {
|
|
27
20
|
const { copilotkit } = useCopilotKit();
|
|
28
21
|
const config = useCopilotChatConfiguration();
|
|
29
22
|
const agentId = computed(() => config.value?.agentId ?? DEFAULT_AGENT_ID);
|
|
30
23
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
function findRenderer(
|
|
36
|
-
activityType: string,
|
|
37
|
-
): VueActivityMessageRenderer<unknown> | null {
|
|
38
|
-
const list = renderers.value;
|
|
39
|
-
if (!list.length) {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const matches = list.filter(
|
|
24
|
+
function findRenderer(activityType: string) {
|
|
25
|
+
const renderers = copilotkit.value.renderActivityMessages;
|
|
26
|
+
const matches = renderers.filter(
|
|
44
27
|
(renderer) => renderer.activityType === activityType,
|
|
45
28
|
);
|
|
46
29
|
|
|
47
30
|
return (
|
|
48
31
|
matches.find((candidate) => candidate.agentId === agentId.value) ??
|
|
49
32
|
matches.find((candidate) => candidate.agentId === undefined) ??
|
|
50
|
-
|
|
33
|
+
renderers.find((candidate) => candidate.activityType === "*") ??
|
|
51
34
|
null
|
|
52
35
|
);
|
|
53
36
|
}
|
|
54
37
|
|
|
55
|
-
function renderActivityMessage(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const parseResult = renderer.content.safeParse(message.content);
|
|
38
|
+
function renderActivityMessage(message: ActivityMessage) {
|
|
39
|
+
const match = ɵresolveActivityRenderer(
|
|
40
|
+
copilotkit.value.renderActivityMessages,
|
|
41
|
+
{
|
|
42
|
+
activityType: message.activityType,
|
|
43
|
+
agentId: agentId.value,
|
|
44
|
+
content: message.content,
|
|
45
|
+
},
|
|
46
|
+
);
|
|
65
47
|
|
|
66
|
-
if (!
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
`
|
|
70
|
-
|
|
71
|
-
|
|
48
|
+
if (!match) {
|
|
49
|
+
if (findRenderer(message.activityType)) {
|
|
50
|
+
console.warn(
|
|
51
|
+
`Failed to validate content for activity message ` +
|
|
52
|
+
`'${message.activityType}'.`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
72
55
|
return null;
|
|
73
56
|
}
|
|
74
57
|
|
|
75
|
-
const agent: AbstractAgent | undefined = copilotkit.value.getAgent(
|
|
76
|
-
agentId.value,
|
|
77
|
-
);
|
|
78
|
-
|
|
79
58
|
return {
|
|
80
|
-
renderer: renderer.render as Component<
|
|
59
|
+
renderer: match.renderer.render as Component<
|
|
81
60
|
VueActivityMessageRendererProps<unknown>
|
|
82
61
|
>,
|
|
83
62
|
props: {
|
|
84
63
|
activityType: message.activityType,
|
|
85
|
-
content:
|
|
64
|
+
content: match.content,
|
|
86
65
|
message,
|
|
87
|
-
agent,
|
|
66
|
+
agent: copilotkit.value.getAgent(agentId.value),
|
|
88
67
|
},
|
|
89
68
|
};
|
|
90
69
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Component, VNodeChild } from "vue";
|
|
2
1
|
import type { Message } from "@ag-ui/core";
|
|
2
|
+
import { ɵresolveCustomMessageRenderers } from "@copilotkit/core";
|
|
3
3
|
import { DEFAULT_AGENT_ID } from "@copilotkit/shared";
|
|
4
4
|
import { useCopilotKit } from "../providers/useCopilotKit";
|
|
5
5
|
import { useCopilotChatConfiguration } from "../providers/useCopilotChatConfiguration";
|
|
@@ -13,13 +13,6 @@ interface UseRenderCustomMessagesParams {
|
|
|
13
13
|
position: VueCustomMessageRendererPosition;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
interface CustomMessageRendererResult {
|
|
17
|
-
renderer:
|
|
18
|
-
| Component<VueCustomMessageRendererProps>
|
|
19
|
-
| ((props: VueCustomMessageRendererProps) => VNodeChild);
|
|
20
|
-
props: VueCustomMessageRendererProps;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
16
|
/**
|
|
24
17
|
* Returns a function that resolves the appropriate custom message renderer for
|
|
25
18
|
* a given message and position.
|
|
@@ -37,9 +30,7 @@ export function useRenderCustomMessages() {
|
|
|
37
30
|
const { copilotkit } = useCopilotKit();
|
|
38
31
|
const config = useCopilotChatConfiguration();
|
|
39
32
|
|
|
40
|
-
return function renderCustomMessage(
|
|
41
|
-
params: UseRenderCustomMessagesParams,
|
|
42
|
-
): CustomMessageRendererResult | null {
|
|
33
|
+
return function renderCustomMessage(params: UseRenderCustomMessagesParams) {
|
|
43
34
|
const configValue = config.value;
|
|
44
35
|
if (!configValue) return null;
|
|
45
36
|
|
|
@@ -47,17 +38,10 @@ export function useRenderCustomMessages() {
|
|
|
47
38
|
const { threadId } = configValue;
|
|
48
39
|
const core = copilotkit.value;
|
|
49
40
|
|
|
50
|
-
const customMessageRenderers =
|
|
51
|
-
.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
)
|
|
55
|
-
.sort((a, b) => {
|
|
56
|
-
const aHasAgent = a.agentId !== undefined;
|
|
57
|
-
const bHasAgent = b.agentId !== undefined;
|
|
58
|
-
if (aHasAgent === bHasAgent) return 0;
|
|
59
|
-
return aHasAgent ? -1 : 1;
|
|
60
|
-
});
|
|
41
|
+
const customMessageRenderers = ɵresolveCustomMessageRenderers(
|
|
42
|
+
core.renderCustomMessages,
|
|
43
|
+
agentId,
|
|
44
|
+
);
|
|
61
45
|
|
|
62
46
|
if (!customMessageRenderers.length) {
|
|
63
47
|
return null;
|
|
@@ -101,7 +85,7 @@ export function useRenderCustomMessages() {
|
|
|
101
85
|
? core.getStateByRun(agentId, threadId, resolvedRunId)
|
|
102
86
|
: undefined;
|
|
103
87
|
|
|
104
|
-
const props:
|
|
88
|
+
const props: VueCustomMessageRendererProps = {
|
|
105
89
|
message,
|
|
106
90
|
position,
|
|
107
91
|
runId,
|
|
@@ -112,18 +96,13 @@ export function useRenderCustomMessages() {
|
|
|
112
96
|
stateSnapshot,
|
|
113
97
|
};
|
|
114
98
|
|
|
115
|
-
//
|
|
116
|
-
//
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return {
|
|
122
|
-
renderer: candidate.render as CustomMessageRendererResult["renderer"],
|
|
123
|
-
props,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
99
|
+
// Agent-scoped renderers come first. Use the first one that has a
|
|
100
|
+
// render function.
|
|
101
|
+
const selected = customMessageRenderers.find(
|
|
102
|
+
(candidate) => candidate.render,
|
|
103
|
+
);
|
|
104
|
+
if (!selected) return null;
|
|
126
105
|
|
|
127
|
-
return
|
|
106
|
+
return { renderer: selected.render, props };
|
|
128
107
|
};
|
|
129
108
|
}
|
|
@@ -1,21 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
let result = html;
|
|
8
|
-
|
|
9
|
-
result = result.replace(/<[^>]*$/, "");
|
|
10
|
-
result = result.replace(/<(style|script|head)\b[^>]*>[\s\S]*?<\/\1>/gi, "");
|
|
11
|
-
result = result.replace(/<(style|script|head)\b[^>]*>[\s\S]*$/gi, "");
|
|
12
|
-
result = result.replace(/&[a-zA-Z0-9#]*$/, "");
|
|
13
|
-
|
|
14
|
-
const bodyMatch = result.match(/<body[^>]*>([\s\S]*)/i);
|
|
15
|
-
if (bodyMatch) {
|
|
16
|
-
result = bodyMatch[1]!;
|
|
17
|
-
result = result.replace(/<\/body>[\s\S]*/i, "");
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return result;
|
|
21
|
-
}
|
|
1
|
+
// The partial-HTML helpers live in @copilotkit/core; these names stay for
|
|
2
|
+
// existing imports.
|
|
3
|
+
export {
|
|
4
|
+
ɵextractCompleteStyles as extractCompleteStyles,
|
|
5
|
+
ɵprocessPartialHtml as processPartialHtml,
|
|
6
|
+
} from "@copilotkit/core";
|
package/src/v2/lib/vue-core.ts
CHANGED
|
@@ -44,7 +44,9 @@ export class CopilotKitCoreVue extends CopilotKitCore {
|
|
|
44
44
|
private _interruptState: InterruptRenderProps<unknown, unknown> | null = null;
|
|
45
45
|
|
|
46
46
|
constructor(config: CopilotKitCoreVueConfig) {
|
|
47
|
-
|
|
47
|
+
// Tool handlers can change reactive state. `nextTick` lets Vue flush those
|
|
48
|
+
// updates before core starts the follow-up run.
|
|
49
|
+
super({ ...config, ɵwaitForFrameworkUpdates: () => nextTick() });
|
|
48
50
|
this._renderToolCalls = config.renderToolCalls ?? [];
|
|
49
51
|
this._renderCustomMessages = config.renderCustomMessages ?? [];
|
|
50
52
|
this._renderActivityMessages = config.renderActivityMessages ?? [];
|
|
@@ -154,8 +156,4 @@ export class CopilotKitCoreVue extends CopilotKitCore {
|
|
|
154
156
|
): CopilotKitCoreSubscription {
|
|
155
157
|
return super.subscribe(subscriber);
|
|
156
158
|
}
|
|
157
|
-
|
|
158
|
-
async waitForPendingFrameworkUpdates(): Promise<void> {
|
|
159
|
-
await nextTick();
|
|
160
|
-
}
|
|
161
159
|
}
|