@copilotkit/vue 2.0.0-rc.20 → 2.0.0-rc.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +13 -13
- package/dist/use-render-activity-message-CyrhHFhA.js +16200 -0
- package/dist/use-render-activity-message-CyrhHFhA.js.map +1 -0
- package/dist/use-render-activity-message-EwHHrwQB.cjs +114 -0
- package/dist/use-render-activity-message-EwHHrwQB.cjs.map +1 -0
- package/dist/v2/components/A2UIMessageRenderer.d.ts +14 -0
- package/dist/v2/components/A2UIMessageRenderer.d.ts.map +1 -1
- package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts +10 -3
- package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts.map +1 -1
- package/dist/v2/components/CopilotKitInspector.vue.d.ts +5 -1
- package/dist/v2/components/CopilotKitInspector.vue.d.ts.map +1 -1
- package/dist/v2/components/MCPAppsActivityRenderer.d.ts.map +1 -1
- package/dist/v2/components/OpenGenerativeUIRenderer.d.ts +7 -21
- package/dist/v2/components/OpenGenerativeUIRenderer.d.ts.map +1 -1
- package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts +0 -5
- package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts.map +1 -1
- package/dist/v2/components/a2ui/A2UICatalogContext.d.ts +10 -15
- package/dist/v2/components/a2ui/A2UICatalogContext.d.ts.map +1 -1
- package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts +14 -138
- package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts.map +1 -1
- package/dist/v2/components/a2ui/catalog.d.ts.map +1 -1
- package/dist/v2/components/a2ui/utils.d.ts +3 -15
- package/dist/v2/components/a2ui/utils.d.ts.map +1 -1
- package/dist/v2/components/a2ui.d.ts +6 -1
- 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/CopilotChatAudioRecorder.vue.d.ts +4 -8
- package/dist/v2/components/chat/CopilotChatAudioRecorder.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatInput.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatLightbox.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts.map +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.map +1 -1
- package/dist/v2/components/chat/CopilotChatView.vue.d.ts +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/CopilotSidebarView.vue.d.ts +1 -1
- package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts +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/StreamingMarkdownDefault.vue.d.ts +1 -0
- package/dist/v2/components/chat/StreamingMarkdownDefault.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/audioRecorder.d.ts +3 -4
- package/dist/v2/components/chat/audioRecorder.d.ts.map +1 -1
- package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts +3 -2
- package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts.map +1 -1
- package/dist/v2/components/chat/index.d.ts +6 -6
- package/dist/v2/components/chat/tool-call-display-context.d.ts +3 -1
- 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.map +1 -1
- package/dist/v2/components/chat/types.d.ts +1 -1
- package/dist/v2/components/chat/types.d.ts.map +1 -1
- package/dist/v2/components/chat/use-lightbox.d.ts.map +1 -1
- package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts +1 -1
- package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts.map +1 -1
- package/dist/v2/hooks/use-agent-context.d.ts +2 -3
- package/dist/v2/hooks/use-agent-context.d.ts.map +1 -1
- package/dist/v2/hooks/use-agent.d.ts +4 -1
- package/dist/v2/hooks/use-agent.d.ts.map +1 -1
- package/dist/v2/hooks/use-attachments.d.ts +7 -0
- package/dist/v2/hooks/use-attachments.d.ts.map +1 -1
- package/dist/v2/hooks/use-capabilities.d.ts.map +1 -1
- package/dist/v2/hooks/use-component.d.ts +1 -0
- package/dist/v2/hooks/use-component.d.ts.map +1 -1
- package/dist/v2/hooks/use-configure-suggestions.d.ts +4 -9
- package/dist/v2/hooks/use-configure-suggestions.d.ts.map +1 -1
- package/dist/v2/hooks/use-default-render-tool.d.ts.map +1 -1
- package/dist/v2/hooks/use-human-in-the-loop.d.ts +2 -1
- package/dist/v2/hooks/use-human-in-the-loop.d.ts.map +1 -1
- package/dist/v2/hooks/use-interrupt.d.ts +0 -1
- package/dist/v2/hooks/use-interrupt.d.ts.map +1 -1
- package/dist/v2/hooks/use-render-activity-message.d.ts.map +1 -1
- package/dist/v2/hooks/use-render-custom-messages.d.ts.map +1 -1
- package/dist/v2/hooks/use-suggestions.d.ts.map +1 -1
- package/dist/v2/hooks/use-threads.d.ts +0 -8
- 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 +12 -11
- package/dist/v2/lib/vue-core.d.ts.map +1 -1
- package/dist/v2/providers/CopilotChatConfigurationProvider.vue.d.ts.map +1 -1
- package/dist/v2/providers/CopilotKitProvider.types.d.ts +9 -124
- package/dist/v2/providers/CopilotKitProvider.types.d.ts.map +1 -1
- package/dist/v2/providers/CopilotKitProvider.vue.d.ts +9 -10
- package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
- package/dist/v2/providers/chat-configuration-store-key.d.ts +8 -0
- package/dist/v2/providers/chat-configuration-store-key.d.ts.map +1 -0
- package/dist/v2/providers/markdown-renderer.d.ts +3 -1
- package/dist/v2/providers/markdown-renderer.d.ts.map +1 -1
- package/dist/v2/providers/use-inspector-thread-override.d.ts +5 -0
- package/dist/v2/providers/use-inspector-thread-override.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/v2/__tests__/exports.test.ts +10 -0
- package/src/v2/__tests__/mocks/web-inspector.ts +6 -0
- package/src/v2/__tests__/utils/test-helpers.ts +34 -4
- package/src/v2/components/A2UIMessageRenderer.ts +98 -68
- package/src/v2/components/A2UISurfaceActivityRenderer.vue +68 -103
- package/src/v2/components/CopilotKitInspector.vue +104 -51
- package/src/v2/components/MCPAppsActivityRenderer.ts +75 -201
- package/src/v2/components/OpenGenerativeUIRenderer.ts +78 -80
- package/src/v2/components/__tests__/A2UIMessageRenderer.test.ts +171 -8
- package/src/v2/components/__tests__/CopilotKitInspector.test.ts +42 -0
- package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.ts +9 -2
- package/src/v2/components/__tests__/OpenGenerativeUIToolRenderer.test.ts +38 -0
- package/src/v2/components/a2ui/A2UIBuiltInToolCallRenderer.ts +1 -6
- package/src/v2/components/a2ui/A2UICatalogContext.ts +27 -93
- package/src/v2/components/a2ui/A2UIRecoveryStates.ts +127 -327
- package/src/v2/components/a2ui/catalog.ts +2 -3
- package/src/v2/components/a2ui/utils.ts +13 -67
- package/src/v2/components/a2ui.ts +14 -21
- package/src/v2/components/chat/CopilotChat.vue +136 -324
- package/src/v2/components/chat/CopilotChatAttachmentQueue.vue +22 -45
- package/src/v2/components/chat/CopilotChatAudioRecorder.vue +19 -246
- package/src/v2/components/chat/CopilotChatInput.vue +69 -407
- package/src/v2/components/chat/CopilotChatLightbox.vue +10 -31
- package/src/v2/components/chat/CopilotChatMessageView.vue +52 -112
- package/src/v2/components/chat/CopilotChatToolCallGroup.vue +14 -45
- package/src/v2/components/chat/CopilotChatToolCallItem.vue +6 -4
- package/src/v2/components/chat/CopilotChatToolCallsView.vue +16 -19
- package/src/v2/components/chat/CopilotChatView.vue +28 -23
- package/src/v2/components/chat/CopilotPopupViewInternal.vue +21 -97
- package/src/v2/components/chat/CopilotSidebarViewInternal.vue +24 -25
- package/src/v2/components/chat/CopilotThreadsDrawer.vue +37 -102
- package/src/v2/components/chat/StreamingMarkdownDefault.vue +13 -26
- package/src/v2/components/chat/__tests__/CopilotChat.test.ts +12 -10
- package/src/v2/components/chat/__tests__/CopilotChatAttachmentQueue.test.ts +28 -0
- package/src/v2/components/chat/__tests__/CopilotChatInput.test.ts +56 -0
- package/src/v2/components/chat/__tests__/CopilotPopupView.test.ts +19 -0
- package/src/v2/components/chat/__tests__/CopilotSidebarView.position.test.ts +32 -8
- package/src/v2/components/chat/__tests__/CopilotSidebarView.test.ts +2 -1
- package/src/v2/components/chat/__tests__/StreamingMarkdownDefault.test.ts +54 -0
- package/src/v2/components/chat/audioRecorder.ts +4 -7
- package/src/v2/components/chat/copilotChatToolCallItemRender.ts +22 -71
- package/src/v2/components/chat/tool-call-display-context.ts +6 -1
- package/src/v2/components/chat/tool-call-group-parts.ts +13 -33
- package/src/v2/components/chat/types.ts +1 -1
- package/src/v2/components/chat/use-lightbox.ts +15 -33
- package/src/v2/hooks/__tests__/use-agent-error-state.test.ts +5 -3
- package/src/v2/hooks/__tests__/use-agent-stability.test.ts +25 -4
- package/src/v2/hooks/__tests__/use-agent-throttle.test.ts +5 -1
- package/src/v2/hooks/__tests__/use-agent.test.ts +6 -3
- package/src/v2/hooks/__tests__/use-component.test.ts +21 -0
- package/src/v2/hooks/__tests__/use-configure-suggestions.test.ts +30 -1
- package/src/v2/hooks/__tests__/use-default-render-tool.test.ts +10 -10
- package/src/v2/hooks/__tests__/use-frontend-tool.e2e.test.ts +4 -0
- package/src/v2/hooks/__tests__/use-human-in-the-loop.e2e.test.ts +6 -1
- package/src/v2/hooks/__tests__/use-human-in-the-loop.test.ts +187 -12
- package/src/v2/hooks/__tests__/use-interrupt.test.ts +97 -0
- package/src/v2/hooks/__tests__/use-render-activity-message.test.ts +2 -1
- package/src/v2/hooks/__tests__/use-threads.test.ts +48 -6
- package/src/v2/hooks/use-agent-context.ts +4 -10
- package/src/v2/hooks/use-agent.ts +86 -290
- package/src/v2/hooks/use-attachments.ts +42 -166
- package/src/v2/hooks/use-capabilities.ts +2 -7
- package/src/v2/hooks/use-component.ts +7 -4
- package/src/v2/hooks/use-configure-suggestions.ts +28 -218
- package/src/v2/hooks/use-default-render-tool.ts +34 -94
- package/src/v2/hooks/use-human-in-the-loop.ts +11 -80
- package/src/v2/hooks/use-interrupt.ts +29 -308
- package/src/v2/hooks/use-render-activity-message.ts +17 -20
- package/src/v2/hooks/use-render-custom-messages.ts +20 -63
- package/src/v2/hooks/use-suggestions.ts +9 -33
- package/src/v2/hooks/use-threads.ts +43 -273
- package/src/v2/lib/__tests__/vue-core-renderers.test.ts +42 -0
- package/src/v2/lib/vue-core.ts +67 -72
- package/src/v2/providers/CopilotChatConfigurationProvider.vue +48 -186
- package/src/v2/providers/CopilotKitProvider.types.ts +12 -127
- package/src/v2/providers/CopilotKitProvider.vue +188 -402
- package/src/v2/providers/__tests__/CopilotChatConfigurationProvider.test.ts +22 -2
- package/src/v2/providers/__tests__/CopilotKitProvider.a2ui.test.ts +19 -1
- package/src/v2/providers/__tests__/CopilotKitProvider.config.test.ts +124 -0
- package/src/v2/providers/__tests__/CopilotKitProvider.sandboxFunctions.test.ts +4 -1
- package/src/v2/providers/__tests__/CopilotKitProvider.test.ts +45 -2
- package/src/v2/providers/chat-configuration-store-key.ts +9 -0
- package/src/v2/providers/markdown-renderer.ts +7 -1
- package/src/v2/providers/use-inspector-thread-override.ts +22 -80
- package/vite.config.ts +5 -1
- package/vitest.config.ts +12 -7
- package/dist/use-render-activity-message-CsWYyd6r.cjs +0 -91
- package/dist/use-render-activity-message-CsWYyd6r.cjs.map +0 -1
- package/dist/use-render-activity-message-DntKKNdd.js +0 -17418
- package/dist/use-render-activity-message-DntKKNdd.js.map +0 -1
- package/dist/v2/components/chat/normalize-auto-scroll.d.ts +0 -3
- package/dist/v2/components/chat/normalize-auto-scroll.d.ts.map +0 -1
- package/dist/v2/lib/is-mobile-viewport.d.ts +0 -2
- package/dist/v2/lib/is-mobile-viewport.d.ts.map +0 -1
- package/src/v2/components/__tests__/A2UICatalogContext.test.ts +0 -63
- package/src/v2/components/a2ui/__tests__/A2UIRecoveryStates.test.ts +0 -175
- package/src/v2/components/chat/normalize-auto-scroll.ts +0 -3
- package/src/v2/lib/is-mobile-viewport.ts +0 -5
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { PropType } from "vue";
|
|
3
|
-
import
|
|
1
|
+
import { defineComponent, h, onBeforeUnmount, shallowRef, watch } from "vue";
|
|
2
|
+
import type { Component, PropType } from "vue";
|
|
3
|
+
import {
|
|
4
|
+
ɵA2UIActivityController,
|
|
5
|
+
ɵA2UI_SURFACE_ACTIVITY_TYPE,
|
|
6
|
+
ɵA2UI_SURFACE_CONTENT_SCHEMA,
|
|
7
|
+
} from "@copilotkit/core";
|
|
8
|
+
import type {
|
|
9
|
+
ɵA2UIActionAgent,
|
|
10
|
+
ɵA2UIActionInterceptor,
|
|
11
|
+
ɵA2UISurfaceContent,
|
|
12
|
+
} from "@copilotkit/core";
|
|
13
|
+
import type { ActivityMessage } from "@ag-ui/core";
|
|
4
14
|
import type { VueActivityMessageRenderer } from "../types";
|
|
5
15
|
import type { A2UITheme } from "../types";
|
|
6
16
|
import A2UISurfaceActivityRenderer from "./A2UISurfaceActivityRenderer.vue";
|
|
7
|
-
import {
|
|
8
|
-
A2UIBuildingState,
|
|
9
|
-
A2UILifecycleFields,
|
|
10
|
-
A2UIRecoveryFailure,
|
|
11
|
-
A2UIRetryingState,
|
|
12
|
-
resolveDebugExposure,
|
|
13
|
-
} from "./a2ui/A2UIRecoveryStates";
|
|
17
|
+
import { renderA2UILifecycleState } from "./a2ui/A2UIRecoveryStates";
|
|
14
18
|
import type { A2UIRecoveryRendererOptions } from "./a2ui/A2UIRecoveryStates";
|
|
15
19
|
|
|
16
|
-
const A2UI_OPERATIONS_KEY = "a2ui_operations";
|
|
17
|
-
|
|
18
20
|
export type A2UIMessageRendererOptions = {
|
|
19
21
|
theme: A2UITheme;
|
|
20
22
|
catalog?: any;
|
|
@@ -25,88 +27,116 @@ export type A2UIMessageRendererOptions = {
|
|
|
25
27
|
* sub-label appears, and how much retry/debug detail to surface.
|
|
26
28
|
*/
|
|
27
29
|
recovery?: A2UIRecoveryRendererOptions;
|
|
30
|
+
/**
|
|
31
|
+
* Intercept actions before they reach the agent: return `null` to handle an
|
|
32
|
+
* action client-side, return an action to forward that one instead, or
|
|
33
|
+
* return nothing to forward it unchanged.
|
|
34
|
+
*/
|
|
35
|
+
onAction?: ɵA2UIActionInterceptor;
|
|
28
36
|
};
|
|
29
37
|
|
|
38
|
+
function isComponent(value: unknown): value is Component {
|
|
39
|
+
return (
|
|
40
|
+
typeof value === "function" || (typeof value === "object" && value !== null)
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
30
44
|
/**
|
|
31
45
|
* The `a2ui-surface` activity carries the WHOLE generative-UI lifecycle on one
|
|
32
46
|
* stable messageId: pre-paint `status` ("building" | "retrying" | "failed")
|
|
33
|
-
* with recovery detail, then `a2ui_operations` on paint.
|
|
34
|
-
*
|
|
35
|
-
* the
|
|
47
|
+
* with recovery detail, then `a2ui_operations` on paint. Core's
|
|
48
|
+
* `ɵA2UIActivityController` decides what shows; this renderer draws it and
|
|
49
|
+
* keeps the surface mounted, hidden under the loader, until it has painted.
|
|
36
50
|
*/
|
|
37
|
-
const A2UISurfaceContentSchema = z
|
|
38
|
-
.object({
|
|
39
|
-
a2ui_operations: z.array(z.any()).optional(),
|
|
40
|
-
...A2UILifecycleFields,
|
|
41
|
-
})
|
|
42
|
-
.loose();
|
|
43
|
-
|
|
44
51
|
export function createA2UIMessageRenderer(
|
|
45
52
|
options: A2UIMessageRendererOptions,
|
|
46
53
|
): VueActivityMessageRenderer<any> {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// Renders the pre-paint lifecycle state for a content snapshot.
|
|
52
|
-
const renderLifecycle = (content: any) => {
|
|
53
|
-
const debugExposure = resolveDebugExposure(content, optionDebugExposure);
|
|
54
|
-
if (content?.status === "failed") {
|
|
55
|
-
return h(A2UIRecoveryFailure, { content, debugExposure });
|
|
56
|
-
}
|
|
57
|
-
if (content?.status === "retrying") {
|
|
58
|
-
return h(A2UIRetryingState, {
|
|
59
|
-
content,
|
|
60
|
-
showAfterMs,
|
|
61
|
-
showAfterAttempts,
|
|
62
|
-
debugExposure,
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
// "building" / default: a host-supplied loader wins; else the skeleton.
|
|
66
|
-
if (options.loadingComponent) {
|
|
67
|
-
return h(options.loadingComponent as any);
|
|
68
|
-
}
|
|
69
|
-
return h(A2UIBuildingState, { content });
|
|
70
|
-
};
|
|
54
|
+
const loadingComponent = isComponent(options.loadingComponent)
|
|
55
|
+
? options.loadingComponent
|
|
56
|
+
: undefined;
|
|
71
57
|
|
|
72
58
|
return {
|
|
73
|
-
activityType:
|
|
74
|
-
content:
|
|
59
|
+
activityType: ɵA2UI_SURFACE_ACTIVITY_TYPE,
|
|
60
|
+
content: ɵA2UI_SURFACE_CONTENT_SCHEMA,
|
|
75
61
|
render: defineComponent({
|
|
76
62
|
name: "A2UIMessageRendererHost",
|
|
77
63
|
props: {
|
|
78
64
|
activityType: { type: String, required: true },
|
|
79
|
-
content: {
|
|
80
|
-
|
|
65
|
+
content: {
|
|
66
|
+
type: Object as PropType<ɵA2UISurfaceContent>,
|
|
67
|
+
required: true,
|
|
68
|
+
},
|
|
69
|
+
message: { type: Object as PropType<ActivityMessage>, required: true },
|
|
81
70
|
agent: {
|
|
82
|
-
type: Object as PropType
|
|
71
|
+
type: Object as PropType<ɵA2UIActionAgent>,
|
|
83
72
|
required: false,
|
|
84
73
|
default: undefined,
|
|
85
74
|
},
|
|
86
75
|
},
|
|
87
76
|
setup(props) {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
77
|
+
const controller = new ɵA2UIActivityController({
|
|
78
|
+
recovery: options.recovery,
|
|
79
|
+
warn:
|
|
80
|
+
process.env.NODE_ENV !== "production"
|
|
81
|
+
? (message) => console.warn(message)
|
|
82
|
+
: undefined,
|
|
83
|
+
});
|
|
84
|
+
const snapshot = shallowRef(controller.getSnapshot());
|
|
85
|
+
const unsubscribe = controller.subscribe(() => {
|
|
86
|
+
snapshot.value = controller.getSnapshot();
|
|
87
|
+
});
|
|
88
|
+
watch(
|
|
89
|
+
() => props.content,
|
|
90
|
+
(content) => controller.setContent(content),
|
|
91
|
+
{ immediate: true },
|
|
92
92
|
);
|
|
93
|
+
onBeforeUnmount(() => {
|
|
94
|
+
unsubscribe();
|
|
95
|
+
controller.dispose();
|
|
96
|
+
});
|
|
97
|
+
const markRendered = () => controller.markRendered();
|
|
93
98
|
|
|
94
99
|
return () => {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (operations.value.length === 0) {
|
|
99
|
-
return renderLifecycle(props.content);
|
|
100
|
+
const current = snapshot.value;
|
|
101
|
+
if (current.view === "lifecycle") {
|
|
102
|
+
return renderA2UILifecycleState(current, loadingComponent);
|
|
100
103
|
}
|
|
101
104
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
const handingOff = current.view === "handoff";
|
|
106
|
+
return h("div", { style: { position: "relative" } }, [
|
|
107
|
+
// The surface stays mounted in the same place across the
|
|
108
|
+
// hand-off; only its wrapper styling changes, so what painted
|
|
109
|
+
// while hidden is kept.
|
|
110
|
+
h(
|
|
111
|
+
"div",
|
|
112
|
+
{
|
|
113
|
+
"aria-hidden": handingOff ? "true" : undefined,
|
|
114
|
+
style: handingOff
|
|
115
|
+
? {
|
|
116
|
+
position: "absolute",
|
|
117
|
+
inset: "0",
|
|
118
|
+
opacity: 0,
|
|
119
|
+
pointerEvents: "none",
|
|
120
|
+
}
|
|
121
|
+
: undefined,
|
|
122
|
+
},
|
|
123
|
+
[
|
|
124
|
+
h(A2UISurfaceActivityRenderer, {
|
|
125
|
+
activityType: ɵA2UI_SURFACE_ACTIVITY_TYPE,
|
|
126
|
+
content: { operations: current.operations },
|
|
127
|
+
message: props.message,
|
|
128
|
+
agent: props.agent,
|
|
129
|
+
theme: options.theme,
|
|
130
|
+
catalog: options.catalog,
|
|
131
|
+
onAction: options.onAction,
|
|
132
|
+
onRendered: markRendered,
|
|
133
|
+
}),
|
|
134
|
+
],
|
|
135
|
+
),
|
|
136
|
+
handingOff
|
|
137
|
+
? renderA2UILifecycleState(current, loadingComponent)
|
|
138
|
+
: null,
|
|
139
|
+
]);
|
|
110
140
|
};
|
|
111
141
|
},
|
|
112
142
|
}),
|
|
@@ -1,147 +1,112 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed,
|
|
3
|
-
import type { VNode } from "vue";
|
|
2
|
+
import { computed, onBeforeUnmount, shallowRef, watch } from "vue";
|
|
4
3
|
import type { ActivityMessage } from "@ag-ui/core";
|
|
5
4
|
import type { A2UITheme } from "../types";
|
|
6
5
|
import type { A2UIOperation } from "./a2ui";
|
|
7
|
-
import { getOperationSurfaceId } from "./a2ui";
|
|
8
6
|
import { useCopilotKit } from "../providers";
|
|
9
7
|
import { MessageProcessor } from "@a2ui/web_core/v0_9";
|
|
10
8
|
import type { SurfaceModel } from "@a2ui/web_core/v0_9";
|
|
9
|
+
import { A2UIOperationApplier } from "@copilotkit/a2ui-renderer/engine";
|
|
10
|
+
import { A2UISurfaceDiagnostics } from "@copilotkit/a2ui-renderer/engine-core";
|
|
11
|
+
import { ɵrunA2UIAction, ɵtoA2UIClientEvent } from "@copilotkit/core";
|
|
12
|
+
import type {
|
|
13
|
+
ɵA2UIActionAgent,
|
|
14
|
+
ɵA2UIActionInterceptor,
|
|
15
|
+
} from "@copilotkit/core";
|
|
11
16
|
import { vueBasicCatalog, A2uiSurface } from "./a2ui/index";
|
|
12
17
|
import type { VueComponentImplementation } from "./a2ui/index";
|
|
13
18
|
|
|
14
|
-
const DEFAULT_SURFACE_ID = "default";
|
|
15
|
-
|
|
16
19
|
const props = defineProps<{
|
|
17
20
|
activityType: string;
|
|
18
|
-
content: { operations: A2UIOperation[] };
|
|
21
|
+
content: { operations: readonly A2UIOperation[] };
|
|
19
22
|
message: ActivityMessage;
|
|
20
|
-
agent?:
|
|
23
|
+
agent?: ɵA2UIActionAgent;
|
|
21
24
|
theme?: A2UITheme;
|
|
22
25
|
catalog?: any;
|
|
26
|
+
/** Intercepts a user action before it reaches the agent. */
|
|
27
|
+
onAction?: ɵA2UIActionInterceptor;
|
|
23
28
|
}>();
|
|
24
29
|
|
|
25
|
-
const
|
|
30
|
+
const emit = defineEmits<{
|
|
31
|
+
/** After each batch of operations was applied. */
|
|
32
|
+
rendered: [];
|
|
33
|
+
}>();
|
|
26
34
|
|
|
27
|
-
|
|
28
|
-
// Use shallowRef to avoid Vue's deep UnwrapRef which strips private class members
|
|
29
|
-
const processorRef =
|
|
30
|
-
shallowRef<MessageProcessor<VueComponentImplementation> | null>(null);
|
|
31
|
-
// Version counter to trigger Vue reactivity on processor state changes
|
|
32
|
-
const version = ref(0);
|
|
33
|
-
// Error state
|
|
34
|
-
const error = ref<string | null>(null);
|
|
35
|
-
// Track last processed operations hash to avoid re-processing
|
|
36
|
-
let lastOpsHash = "";
|
|
35
|
+
const { copilotkit } = useCopilotKit();
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
type Surface = SurfaceModel<VueComponentImplementation>;
|
|
38
|
+
|
|
39
|
+
// One processor for all surfaces of the activity; the core-shared applier
|
|
40
|
+
// validates the operations and applies only what is new in each snapshot.
|
|
41
|
+
// shallowRef avoids Vue's deep UnwrapRef, which strips private class members.
|
|
42
|
+
let processor: MessageProcessor<VueComponentImplementation> | null = null;
|
|
43
|
+
let applier: A2UIOperationApplier<VueComponentImplementation> | null = null;
|
|
44
|
+
const surfaces = shallowRef<readonly Surface[]>([]);
|
|
45
|
+
const error = shallowRef<string | null>(null);
|
|
46
|
+
const diagnostics =
|
|
47
|
+
process.env.NODE_ENV !== "production"
|
|
48
|
+
? new A2UISurfaceDiagnostics({ warn: (message) => console.warn(message) })
|
|
49
|
+
: null;
|
|
50
|
+
|
|
51
|
+
function getApplier() {
|
|
52
|
+
if (!processor || !applier) {
|
|
40
53
|
const catalog = props.catalog ?? vueBasicCatalog;
|
|
41
|
-
|
|
54
|
+
const created = new MessageProcessor<VueComponentImplementation>(
|
|
42
55
|
[catalog],
|
|
43
|
-
(action
|
|
44
|
-
|
|
45
|
-
|
|
56
|
+
(action) =>
|
|
57
|
+
ɵrunA2UIAction({
|
|
58
|
+
message: ɵtoA2UIClientEvent(action),
|
|
59
|
+
agent: props.agent,
|
|
60
|
+
core: copilotkit.value,
|
|
61
|
+
onAction: props.onAction,
|
|
62
|
+
}),
|
|
46
63
|
);
|
|
64
|
+
processor = created;
|
|
65
|
+
applier = new A2UIOperationApplier(created, catalog.id);
|
|
47
66
|
}
|
|
48
|
-
return
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async function handleAction(message: unknown) {
|
|
52
|
-
if (!props.agent) return;
|
|
53
|
-
try {
|
|
54
|
-
copilotkit.value.setProperties({
|
|
55
|
-
...copilotkit.value.properties,
|
|
56
|
-
a2uiAction: message,
|
|
57
|
-
});
|
|
58
|
-
await copilotkit.value.runAgent({ agent: props.agent as any });
|
|
59
|
-
} finally {
|
|
60
|
-
const { a2uiAction, ...rest } = copilotkit.value.properties ?? {};
|
|
61
|
-
copilotkit.value.setProperties(rest);
|
|
62
|
-
}
|
|
67
|
+
return applier;
|
|
63
68
|
}
|
|
64
69
|
|
|
65
|
-
function processOperations(operations: A2UIOperation[]) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const hash = JSON.stringify(operations);
|
|
69
|
-
if (hash === lastOpsHash) return;
|
|
70
|
-
lastOpsHash = hash;
|
|
71
|
-
|
|
72
|
-
const processor = getOrCreateProcessor();
|
|
70
|
+
function processOperations(operations: readonly A2UIOperation[]) {
|
|
71
|
+
const current = getApplier();
|
|
73
72
|
try {
|
|
74
|
-
|
|
75
|
-
const grouped = new Map<string, A2UIOperation[]>();
|
|
76
|
-
for (const op of operations) {
|
|
77
|
-
const surfaceId = getOperationSurfaceId(op) ?? DEFAULT_SURFACE_ID;
|
|
78
|
-
if (!grouped.has(surfaceId)) grouped.set(surfaceId, []);
|
|
79
|
-
grouped.get(surfaceId)!.push(op);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// For each surface, skip createSurface if the surface already exists
|
|
83
|
-
for (const [surfaceId, ops] of grouped) {
|
|
84
|
-
const existing = processor.model.getSurface(surfaceId);
|
|
85
|
-
const filtered = existing
|
|
86
|
-
? ops.filter((op) => !(op as any)?.createSurface)
|
|
87
|
-
: ops;
|
|
88
|
-
processor.processMessages(filtered as any);
|
|
89
|
-
}
|
|
73
|
+
surfaces.value = current.apply(operations);
|
|
90
74
|
error.value = null;
|
|
91
75
|
} catch (err) {
|
|
92
76
|
console.warn("[A2UI Vue] processMessages error:", err);
|
|
93
77
|
error.value = err instanceof Error ? err.message : String(err);
|
|
78
|
+
surfaces.value = [];
|
|
79
|
+
return;
|
|
94
80
|
}
|
|
95
|
-
|
|
81
|
+
if (processor) diagnostics?.check(operations, processor.model);
|
|
82
|
+
emit("rendered");
|
|
96
83
|
}
|
|
97
84
|
|
|
98
|
-
//
|
|
85
|
+
// A new catalog needs a new processor, rebuilt from the current operations.
|
|
99
86
|
watch(
|
|
100
|
-
() =>
|
|
87
|
+
() => props.catalog,
|
|
101
88
|
() => {
|
|
102
|
-
|
|
89
|
+
processor = null;
|
|
90
|
+
applier = null;
|
|
91
|
+
processOperations(props.content.operations ?? []);
|
|
103
92
|
},
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
watch(
|
|
96
|
+
() => props.content.operations,
|
|
97
|
+
(operations) => processOperations(operations ?? []),
|
|
104
98
|
{ deep: true, immediate: true },
|
|
105
99
|
);
|
|
106
100
|
|
|
107
101
|
onBeforeUnmount(() => {
|
|
108
|
-
|
|
109
|
-
|
|
102
|
+
diagnostics?.dispose();
|
|
103
|
+
processor = null;
|
|
104
|
+
applier = null;
|
|
110
105
|
});
|
|
111
106
|
|
|
112
107
|
const hasOperations = computed(
|
|
113
108
|
() => (props.content.operations ?? []).length > 0,
|
|
114
109
|
);
|
|
115
|
-
|
|
116
|
-
// Compute the list of surfaces to render
|
|
117
|
-
const surfaceEntries = computed(() => {
|
|
118
|
-
// Touch version to ensure reactivity
|
|
119
|
-
void version.value;
|
|
120
|
-
|
|
121
|
-
if (!processorRef.value) return [];
|
|
122
|
-
|
|
123
|
-
const entries: Array<{
|
|
124
|
-
surfaceId: string;
|
|
125
|
-
surface: SurfaceModel<VueComponentImplementation>;
|
|
126
|
-
}> = [];
|
|
127
|
-
|
|
128
|
-
// Group operations by surface to know which surfaces we expect
|
|
129
|
-
const grouped = new Map<string, A2UIOperation[]>();
|
|
130
|
-
for (const op of props.content.operations ?? []) {
|
|
131
|
-
const surfaceId = getOperationSurfaceId(op) ?? DEFAULT_SURFACE_ID;
|
|
132
|
-
if (!grouped.has(surfaceId)) grouped.set(surfaceId, []);
|
|
133
|
-
grouped.get(surfaceId)!.push(op);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
for (const [surfaceId] of grouped) {
|
|
137
|
-
const surface = processorRef.value.model.getSurface(surfaceId);
|
|
138
|
-
if (surface) {
|
|
139
|
-
entries.push({ surfaceId, surface });
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return entries;
|
|
144
|
-
});
|
|
145
110
|
</script>
|
|
146
111
|
|
|
147
112
|
<template>
|
|
@@ -160,13 +125,13 @@ const surfaceEntries = computed(() => {
|
|
|
160
125
|
data-testid="a2ui-activity-renderer"
|
|
161
126
|
>
|
|
162
127
|
<div
|
|
163
|
-
v-for="
|
|
164
|
-
:key="
|
|
128
|
+
v-for="surface in surfaces"
|
|
129
|
+
:key="surface.id"
|
|
165
130
|
class="cpk-a2ui-message-surface-host"
|
|
166
|
-
:data-surface-id="
|
|
131
|
+
:data-surface-id="surface.id"
|
|
167
132
|
>
|
|
168
133
|
<div class="a2ui-surface cpk-a2ui-message-surface">
|
|
169
|
-
<A2uiSurface :surface="
|
|
134
|
+
<A2uiSurface :surface="surface" />
|
|
170
135
|
</div>
|
|
171
136
|
</div>
|
|
172
137
|
</div>
|
|
@@ -4,9 +4,9 @@ defineOptions({
|
|
|
4
4
|
inheritAttrs: false,
|
|
5
5
|
});
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import type {
|
|
7
|
+
import { onBeforeUnmount, onMounted, ref, useAttrs, watch } from "vue";
|
|
8
|
+
import { ɵmountInspector } from "@copilotkit/web-inspector/mount";
|
|
9
|
+
import type { ɵInspectorMount } from "@copilotkit/web-inspector/mount";
|
|
10
10
|
import type { CopilotKitCoreVue } from "../lib/vue-core";
|
|
11
11
|
import type { VueInspectorOpenRequest } from "../providers/keys";
|
|
12
12
|
|
|
@@ -15,72 +15,125 @@ const props = defineProps<{
|
|
|
15
15
|
openRequest?: VueInspectorOpenRequest | null;
|
|
16
16
|
}>();
|
|
17
17
|
|
|
18
|
+
const emit = defineEmits<{
|
|
19
|
+
"visibility-change": [visible: boolean];
|
|
20
|
+
}>();
|
|
21
|
+
|
|
18
22
|
const attrs = useAttrs();
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
23
|
+
const host = ref<HTMLSpanElement | null>(null);
|
|
24
|
+
let mount: ɵInspectorMount | null = null;
|
|
25
|
+
let appliedAttributes: Record<string, string> = {};
|
|
26
|
+
const boundListeners = new Map<
|
|
27
|
+
string,
|
|
28
|
+
{ eventName: string; listener: (event: Event) => void }
|
|
29
|
+
>();
|
|
30
|
+
|
|
31
|
+
function isListener(name: string, value: unknown) {
|
|
32
|
+
const isHandler = typeof value === "function" || Array.isArray(value);
|
|
33
|
+
return /^on[A-Z]/.test(name) && isHandler;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** `onCpkInspectorVisibilityChange` listens to `cpk-inspector-visibility-change`, as in Vue. */
|
|
37
|
+
function toEventName(name: string) {
|
|
38
|
+
return name
|
|
39
|
+
.slice(2)
|
|
40
|
+
.replace(/\B([A-Z])/g, "-$1")
|
|
41
|
+
.toLowerCase();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Text attributes and listeners go to the Inspector element (the host is only
|
|
45
|
+
// a mount point), so `data-testid` or `@cpk-inspector-visibility-change`
|
|
46
|
+
// land where callers expect them.
|
|
47
|
+
function toAttributes(source: Record<string, unknown>) {
|
|
48
|
+
const attributes: Record<string, string> = {};
|
|
49
|
+
for (const [name, value] of Object.entries(source)) {
|
|
50
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
51
|
+
attributes[name] = String(value);
|
|
52
|
+
} else if (value === true) {
|
|
53
|
+
attributes[name] = "";
|
|
36
54
|
}
|
|
37
|
-
}
|
|
38
|
-
|
|
55
|
+
}
|
|
56
|
+
return attributes;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function callListener(name: string, event: Event) {
|
|
60
|
+
const handler = attrs[name];
|
|
61
|
+
const handlers = Array.isArray(handler) ? handler : [handler];
|
|
62
|
+
for (const candidate of handlers) {
|
|
63
|
+
if (typeof candidate === "function") candidate(event);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function syncListeners(element: Element) {
|
|
68
|
+
const names = Object.keys(attrs).filter((name) =>
|
|
69
|
+
isListener(name, attrs[name]),
|
|
70
|
+
);
|
|
71
|
+
for (const [name, bound] of boundListeners) {
|
|
72
|
+
if (names.includes(name)) continue;
|
|
73
|
+
element.removeEventListener(bound.eventName, bound.listener);
|
|
74
|
+
boundListeners.delete(name);
|
|
75
|
+
}
|
|
76
|
+
for (const name of names) {
|
|
77
|
+
if (boundListeners.has(name)) continue;
|
|
78
|
+
const bound = {
|
|
79
|
+
eventName: toEventName(name),
|
|
80
|
+
listener: (event: Event) => callListener(name, event),
|
|
81
|
+
};
|
|
82
|
+
element.addEventListener(bound.eventName, bound.listener);
|
|
83
|
+
boundListeners.set(name, bound);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function syncAttributes() {
|
|
88
|
+
const element = mount?.element;
|
|
89
|
+
if (!element) return;
|
|
90
|
+
const next = toAttributes(attrs);
|
|
91
|
+
for (const name of Object.keys(appliedAttributes)) {
|
|
92
|
+
if (!(name in next)) element.removeAttribute(name);
|
|
93
|
+
}
|
|
94
|
+
for (const [name, value] of Object.entries(next)) {
|
|
95
|
+
element.setAttribute(name, value);
|
|
96
|
+
}
|
|
97
|
+
appliedAttributes = next;
|
|
98
|
+
syncListeners(element);
|
|
99
|
+
}
|
|
39
100
|
|
|
40
101
|
onMounted(() => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
})
|
|
54
|
-
.catch((error: unknown) => {
|
|
55
|
-
console.error("Failed to load CopilotKit inspector:", error);
|
|
56
|
-
});
|
|
102
|
+
if (!host.value) return;
|
|
103
|
+
mount = ɵmountInspector(host.value, props.core ?? null, {
|
|
104
|
+
load: () => import("@copilotkit/web-inspector"),
|
|
105
|
+
notificationContext: {
|
|
106
|
+
development: process.env.NODE_ENV === "development",
|
|
107
|
+
framework: "vue",
|
|
108
|
+
sdkVersion,
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
mount.onVisibility((visible) => emit("visibility-change", visible));
|
|
112
|
+
mount.onElement(syncAttributes);
|
|
113
|
+
if (props.openRequest) mount.open(props.openRequest);
|
|
57
114
|
});
|
|
58
115
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
116
|
+
onBeforeUnmount(() => {
|
|
117
|
+
boundListeners.clear();
|
|
118
|
+
mount?.dispose();
|
|
119
|
+
mount = null;
|
|
62
120
|
});
|
|
63
121
|
|
|
64
122
|
watch(
|
|
65
123
|
() => props.core,
|
|
66
|
-
(core) =>
|
|
67
|
-
if (inspector.value) inspector.value.core = core ?? null;
|
|
68
|
-
},
|
|
124
|
+
(core) => mount?.setCore(core ?? null),
|
|
69
125
|
);
|
|
70
126
|
|
|
71
127
|
watch(
|
|
72
128
|
() => props.openRequest,
|
|
73
129
|
(request) => {
|
|
74
|
-
if (request)
|
|
130
|
+
if (request) mount?.open(request);
|
|
75
131
|
},
|
|
76
132
|
);
|
|
133
|
+
|
|
134
|
+
watch(() => ({ ...attrs }), syncAttributes);
|
|
77
135
|
</script>
|
|
78
136
|
|
|
79
137
|
<template>
|
|
80
|
-
<
|
|
81
|
-
:is="inspectorTag"
|
|
82
|
-
v-if="inspectorTag"
|
|
83
|
-
v-bind="attrs"
|
|
84
|
-
v-configure-inspector
|
|
85
|
-
/>
|
|
138
|
+
<span ref="host" style="display: contents" />
|
|
86
139
|
</template>
|