@copilotkit/vue 2.0.0-rc.1 → 2.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PARITY.md +13 -12
- package/README.md +1 -2
- package/dist/components/copilot-provider/CopilotKit.vue.d.ts +3 -1
- package/dist/components/copilot-provider/CopilotKit.vue.d.ts.map +1 -1
- package/dist/index.cjs +43 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +10170 -7506
- package/dist/index.mjs.map +1 -1
- package/dist/v2/components/A2UIMessageRenderer.d.ts +7 -0
- package/dist/v2/components/A2UIMessageRenderer.d.ts.map +1 -1
- package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts.map +1 -1
- package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts +11 -2
- package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts.map +1 -1
- package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts +136 -0
- package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts.map +1 -0
- package/dist/v2/components/chat/BasicMarkdown.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChat.vue.d.ts +1 -0
- package/dist/v2/components/chat/CopilotChat.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts +3 -1
- package/dist/v2/components/chat/CopilotChatAssistantMessage.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatAssistantToolbarButton.vue.d.ts +16 -0
- package/dist/v2/components/chat/CopilotChatAssistantToolbarButton.vue.d.ts.map +1 -0
- 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/CopilotChatAudioRecorder.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts +22 -0
- package/dist/v2/components/chat/CopilotChatFeedbackCommentPopover.vue.d.ts.map +1 -0
- package/dist/v2/components/chat/CopilotChatInput.vue.d.ts +69 -16
- package/dist/v2/components/chat/CopilotChatInput.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatInspectorButton.vue.d.ts +12 -0
- package/dist/v2/components/chat/CopilotChatInspectorButton.vue.d.ts.map +1 -0
- package/dist/v2/components/chat/CopilotChatLightbox.vue.d.ts +22 -0
- package/dist/v2/components/chat/CopilotChatLightbox.vue.d.ts.map +1 -0
- package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts +20 -0
- 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/CopilotChatSuggestionPill.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatSuggestionView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatToggleButton.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts +32 -0
- package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts.map +1 -0
- package/dist/v2/components/chat/CopilotChatToolCallItem.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts +11 -1
- package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatUserMessage.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatView.vue.d.ts +1 -0
- package/dist/v2/components/chat/CopilotChatView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatWorkSummary.vue.d.ts +5 -0
- package/dist/v2/components/chat/CopilotChatWorkSummary.vue.d.ts.map +1 -0
- package/dist/v2/components/chat/CopilotModalHeader.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotModalHeaderCloseButton.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotModalHeaderTitle.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotPopup.vue.d.ts +1 -0
- package/dist/v2/components/chat/CopilotPopup.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotPopupView.vue.d.ts +1 -0
- package/dist/v2/components/chat/CopilotPopupView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts +1 -0
- package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotPopupWelcomeScreen.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotSidebar.vue.d.ts +2 -0
- package/dist/v2/components/chat/CopilotSidebar.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts +2 -0
- package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts +2 -0
- package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotSidebarWelcomeScreen.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/StreamingMarkdownDefault.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/index.d.ts +17 -0
- package/dist/v2/components/chat/index.d.ts.map +1 -1
- package/dist/v2/components/chat/inspector-shortcuts.d.ts +12 -0
- package/dist/v2/components/chat/inspector-shortcuts.d.ts.map +1 -0
- package/dist/v2/components/chat/message-feedback.d.ts +89 -0
- package/dist/v2/components/chat/message-feedback.d.ts.map +1 -0
- package/dist/v2/components/chat/tool-call-capture.d.ts +39 -0
- package/dist/v2/components/chat/tool-call-capture.d.ts.map +1 -0
- package/dist/v2/components/chat/tool-call-display-context.d.ts +39 -0
- package/dist/v2/components/chat/tool-call-display-context.d.ts.map +1 -0
- package/dist/v2/components/chat/tool-call-group-parts.d.ts +144 -0
- package/dist/v2/components/chat/tool-call-group-parts.d.ts.map +1 -0
- package/dist/v2/components/chat/tool-call-layout.d.ts +115 -0
- package/dist/v2/components/chat/tool-call-layout.d.ts.map +1 -0
- package/dist/v2/components/chat/turn-work.d.ts +35 -0
- package/dist/v2/components/chat/turn-work.d.ts.map +1 -0
- package/dist/v2/components/chat/types.d.ts +104 -4
- package/dist/v2/components/chat/types.d.ts.map +1 -1
- package/dist/v2/components/chat/use-lightbox.d.ts +18 -0
- package/dist/v2/components/chat/use-lightbox.d.ts.map +1 -0
- package/dist/v2/components/icons/index.d.ts +1 -1
- package/dist/v2/components/icons/index.d.ts.map +1 -1
- package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts +55 -0
- package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts.map +1 -0
- package/dist/v2/components/ui/CopilotPopover.vue.d.ts +40 -0
- package/dist/v2/components/ui/CopilotPopover.vue.d.ts.map +1 -0
- package/dist/v2/components/ui/CopilotTooltip.vue.d.ts +37 -0
- package/dist/v2/components/ui/CopilotTooltip.vue.d.ts.map +1 -0
- package/dist/v2/components/ui/dropdown-menu.d.ts +14 -0
- package/dist/v2/components/ui/dropdown-menu.d.ts.map +1 -0
- package/dist/v2/components/ui/floating.d.ts +84 -0
- package/dist/v2/components/ui/floating.d.ts.map +1 -0
- package/dist/v2/components/ui/presence.d.ts +9 -0
- package/dist/v2/components/ui/presence.d.ts.map +1 -0
- package/dist/v2/components/ui/use-id.d.ts +9 -0
- package/dist/v2/components/ui/use-id.d.ts.map +1 -0
- package/dist/v2/hooks/use-default-render-tool.d.ts +6 -0
- package/dist/v2/hooks/use-default-render-tool.d.ts.map +1 -1
- package/dist/v2/hooks/use-render-tool.d.ts +4 -0
- package/dist/v2/hooks/use-render-tool.d.ts.map +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.d.cts +3 -0
- package/dist/v2/index.d.mts +3 -0
- package/dist/v2/index.d.ts +3 -0
- package/dist/v2/index.d.ts.map +1 -1
- package/dist/v2/index.mjs +165 -162
- package/dist/v2/lib/message-feedback.d.ts +33 -0
- package/dist/v2/lib/message-feedback.d.ts.map +1 -0
- package/dist/v2/providers/CopilotChatConfigurationProvider.vue.d.ts.map +1 -1
- package/dist/v2/providers/CopilotKitProvider.types.d.ts +56 -1
- package/dist/v2/providers/CopilotKitProvider.types.d.ts.map +1 -1
- package/dist/v2/providers/CopilotKitProvider.vue.d.ts +5 -1
- package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
- package/dist/v2/providers/index.d.ts +1 -1
- package/dist/v2/providers/index.d.ts.map +1 -1
- package/dist/v2/providers/keys.d.ts +8 -0
- package/dist/v2/providers/keys.d.ts.map +1 -1
- package/dist/v2/providers/types.d.ts +9 -0
- package/dist/v2/providers/types.d.ts.map +1 -1
- package/dist/v2/styles/CopilotKitStyles.d.ts +18 -0
- package/dist/v2/styles/CopilotKitStyles.d.ts.map +1 -0
- package/dist/v2/types/defineToolCallRenderer.d.ts +2 -0
- package/dist/v2/types/defineToolCallRenderer.d.ts.map +1 -1
- package/dist/v2/types/vue-tool-call-renderer.d.ts +7 -0
- package/dist/v2/types/vue-tool-call-renderer.d.ts.map +1 -1
- package/package.json +11 -23
- package/src/components/copilot-provider/CopilotKit.vue +4 -1
- package/src/v2/__tests__/exports.test.ts +4 -2
- package/src/v2/components/A2UIMessageRenderer.ts +55 -67
- package/src/v2/components/A2UISurfaceActivityRenderer.vue +11 -23
- package/src/v2/components/__tests__/A2UIBasicCatalogColors.test.ts +8 -9
- package/src/v2/components/__tests__/A2UIMessageRenderer.test.ts +63 -36
- package/src/v2/components/a2ui/A2UIBuiltInToolCallRenderer.ts +14 -257
- package/src/v2/components/a2ui/A2UIRecoveryStates.ts +444 -0
- package/src/v2/components/a2ui/__tests__/A2UIRecoveryStates.test.ts +175 -0
- package/src/v2/components/chat/BasicMarkdown.vue +8 -6
- package/src/v2/components/chat/CopilotChat.vue +7 -0
- package/src/v2/components/chat/CopilotChatAssistantMessage.vue +267 -67
- package/src/v2/components/chat/CopilotChatAssistantToolbarButton.vue +46 -0
- package/src/v2/components/chat/CopilotChatAttachmentQueue.vue +141 -168
- package/src/v2/components/chat/CopilotChatAttachmentRenderer.vue +67 -18
- package/src/v2/components/chat/CopilotChatAudioRecorder.vue +2 -2
- package/src/v2/components/chat/CopilotChatFeedbackCommentPopover.vue +240 -0
- package/src/v2/components/chat/CopilotChatInput.vue +210 -161
- package/src/v2/components/chat/CopilotChatInspectorButton.vue +331 -0
- package/src/v2/components/chat/CopilotChatLightbox.vue +105 -0
- package/src/v2/components/chat/CopilotChatMessageView.vue +261 -18
- package/src/v2/components/chat/CopilotChatReasoningMessage.vue +21 -22
- package/src/v2/components/chat/CopilotChatSuggestionPill.vue +5 -14
- package/src/v2/components/chat/CopilotChatSuggestionView.vue +1 -4
- package/src/v2/components/chat/CopilotChatToggleButton.vue +3 -9
- package/src/v2/components/chat/CopilotChatToggleButtonCloseIcon.ts +1 -1
- package/src/v2/components/chat/CopilotChatToggleButtonOpenIcon.ts +1 -1
- package/src/v2/components/chat/CopilotChatToolCallGroup.vue +330 -0
- package/src/v2/components/chat/CopilotChatToolCallItem.vue +21 -11
- package/src/v2/components/chat/CopilotChatToolCallsView.vue +192 -21
- package/src/v2/components/chat/CopilotChatUserMessage.vue +105 -42
- package/src/v2/components/chat/CopilotChatView.vue +33 -38
- package/src/v2/components/chat/CopilotChatWorkSummary.vue +85 -0
- package/src/v2/components/chat/CopilotModalHeader.vue +10 -8
- package/src/v2/components/chat/CopilotModalHeaderCloseButton.ts +7 -6
- package/src/v2/components/chat/CopilotModalHeaderTitle.ts +1 -4
- package/src/v2/components/chat/CopilotPopup.vue +3 -0
- package/src/v2/components/chat/CopilotPopupView.vue +1 -0
- package/src/v2/components/chat/CopilotPopupViewInternal.vue +9 -19
- package/src/v2/components/chat/CopilotPopupWelcomeScreen.vue +5 -8
- package/src/v2/components/chat/CopilotSidebar.vue +5 -0
- package/src/v2/components/chat/CopilotSidebarView.vue +2 -0
- package/src/v2/components/chat/CopilotSidebarViewInternal.vue +24 -17
- package/src/v2/components/chat/CopilotSidebarWelcomeScreen.vue +7 -10
- package/src/v2/components/chat/StreamingMarkdownDefault.vue +3 -5
- package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.inspector.test.ts +269 -0
- package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.learningFeedback.test.ts +760 -0
- package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.slots.e2e.test.ts +3 -5
- package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.test.ts +2 -2
- package/src/v2/components/chat/__tests__/CopilotChatInput.addMenu.test.ts +328 -0
- package/src/v2/components/chat/__tests__/CopilotChatInput.slots.e2e.test.ts +6 -3
- package/src/v2/components/chat/__tests__/CopilotChatInput.test.ts +22 -13
- package/src/v2/components/chat/__tests__/CopilotChatLightbox.test.ts +160 -0
- package/src/v2/components/chat/__tests__/CopilotChatMessageView.toolCallDisplay.test.ts +735 -0
- package/src/v2/components/chat/__tests__/CopilotChatSuggestionPill.test.ts +1 -1
- package/src/v2/components/chat/__tests__/CopilotChatSuggestionView.slots.e2e.test.ts +3 -1
- package/src/v2/components/chat/__tests__/CopilotChatToolCallsView.learning.test.ts +75 -0
- package/src/v2/components/chat/__tests__/CopilotChatUserMessage.attachments.test.ts +143 -0
- package/src/v2/components/chat/__tests__/CopilotChatView.inputOverlay.test.ts +5 -4
- package/src/v2/components/chat/__tests__/CopilotChatView.rootWidth.test.ts +7 -33
- package/src/v2/components/chat/__tests__/CopilotModalHeader.slots.e2e.test.ts +1 -1
- package/src/v2/components/chat/__tests__/CopilotPopupView.slots.e2e.test.ts +3 -3
- package/src/v2/components/chat/__tests__/CopilotSidebarView.position.test.ts +126 -0
- package/src/v2/components/chat/__tests__/messageFeedbackDefaults.test.ts +33 -0
- package/src/v2/components/chat/__tests__/modalChatDisplayProps.test.ts +44 -0
- package/src/v2/components/chat/index.ts +2 -0
- package/src/v2/components/chat/inspector-shortcuts.ts +34 -0
- package/src/v2/components/chat/message-feedback.ts +291 -0
- package/src/v2/components/chat/tool-call-capture.ts +55 -0
- package/src/v2/components/chat/tool-call-display-context.ts +49 -0
- package/src/v2/components/chat/tool-call-group-parts.ts +292 -0
- package/src/v2/components/chat/tool-call-layout.ts +304 -0
- package/src/v2/components/chat/turn-work.ts +61 -0
- package/src/v2/components/chat/types.ts +113 -3
- package/src/v2/components/chat/use-lightbox.ts +64 -0
- package/src/v2/components/icons/index.ts +4 -0
- package/src/v2/components/ui/CopilotDropdownMenuContent.vue +465 -0
- package/src/v2/components/ui/CopilotPopover.vue +138 -0
- package/src/v2/components/ui/CopilotTooltip.vue +237 -0
- package/src/v2/components/ui/__tests__/CopilotTooltip.test.ts +168 -0
- package/src/v2/components/ui/dropdown-menu.ts +15 -0
- package/src/v2/components/ui/floating.ts +321 -0
- package/src/v2/components/ui/presence.ts +54 -0
- package/src/v2/components/ui/use-id.ts +16 -0
- package/src/v2/hooks/use-default-render-tool.ts +123 -62
- package/src/v2/hooks/use-render-tool.ts +8 -0
- package/src/v2/index.ts +3 -0
- package/src/v2/lib/__tests__/message-feedback.test.ts +152 -0
- package/src/v2/lib/message-feedback.ts +120 -0
- package/src/v2/providers/CopilotChatConfigurationProvider.vue +29 -2
- package/src/v2/providers/CopilotKitProvider.types.ts +57 -0
- package/src/v2/providers/CopilotKitProvider.vue +125 -3
- package/src/v2/providers/__tests__/CopilotChatConfigurationProvider.openThread.test.ts +69 -0
- package/src/v2/providers/__tests__/CopilotKitProvider.learning.test.ts +534 -0
- package/src/v2/providers/index.ts +4 -1
- package/src/v2/providers/keys.ts +12 -0
- package/src/v2/providers/types.ts +11 -0
- package/src/v2/styles/CopilotKitStyles.ts +95 -0
- package/src/v2/styles/__tests__/CopilotKitStyles.client.test.ts +149 -0
- package/src/v2/styles/__tests__/CopilotKitStyles.ssr.test.ts +71 -0
- package/src/v2/types/defineToolCallRenderer.ts +4 -0
- package/src/v2/types/vue-tool-call-renderer.ts +7 -0
- package/vite.config.ts +2 -1
- package/dist/styles.css +0 -2
- package/scripts/scope-preflight.mjs +0 -100
- package/src/styles/globals.css +0 -233
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import type { Message, ToolCall, ToolMessage } from "@ag-ui/core";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* How the chat shows tool calls.
|
|
5
|
+
*
|
|
6
|
+
* - `"grouped"` (default): calls made in a row share one card, collapsed to a
|
|
7
|
+
* summary ("Used 3 tools") that opens to a row per call.
|
|
8
|
+
* - `"line"`: the same grouping as a quiet line of text, like the reasoning
|
|
9
|
+
* message's "Thought for 4 seconds".
|
|
10
|
+
* - `"stacked"`: the latest call on top of a stack of the earlier ones; click
|
|
11
|
+
* to fan the stack out into its cards.
|
|
12
|
+
* - `"turn"`: the agent works in the open (narration, then a row per call),
|
|
13
|
+
* and when the reply is done everything before it folds into "Worked for 9s".
|
|
14
|
+
* - `"separate"`: every call gets its own card, as before grouping existed.
|
|
15
|
+
*
|
|
16
|
+
* Only calls drawn by a renderer that opts into grouping (`group: true`) are
|
|
17
|
+
* grouped; CopilotKit's built-in card from `useDefaultRenderTool()` does. Any
|
|
18
|
+
* other call always shows on its own and splits the group around it.
|
|
19
|
+
*/
|
|
20
|
+
export type CopilotChatToolCallDisplay =
|
|
21
|
+
| "grouped"
|
|
22
|
+
| "line"
|
|
23
|
+
| "stacked"
|
|
24
|
+
| "turn"
|
|
25
|
+
| "separate";
|
|
26
|
+
|
|
27
|
+
/** One tool call and, once it has finished, the message carrying its result. */
|
|
28
|
+
export interface ToolCallEntry {
|
|
29
|
+
toolCall: ToolCall;
|
|
30
|
+
toolMessage?: ToolMessage;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type ToolCallSegment =
|
|
34
|
+
/** Consecutive calls drawn by renderers that opted into grouping. */
|
|
35
|
+
| {
|
|
36
|
+
kind: "group";
|
|
37
|
+
id: string;
|
|
38
|
+
calls: ToolCallEntry[];
|
|
39
|
+
/** Nothing renders after this group yet, so a running agent may add to it. */
|
|
40
|
+
trailing: boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* A call drawn by a renderer that didn't opt into grouping, or with no
|
|
44
|
+
* renderer at all. The latter renders nothing (and warns in development)
|
|
45
|
+
* without breaking a group.
|
|
46
|
+
*/
|
|
47
|
+
| { kind: "call"; id: string; call: ToolCallEntry; rendered: boolean };
|
|
48
|
+
|
|
49
|
+
/** What one assistant message's tool-call area renders. */
|
|
50
|
+
export interface ToolCallLayout {
|
|
51
|
+
segments: ToolCallSegment[];
|
|
52
|
+
/** Changes whenever anything this layout renders changes; for memoization. */
|
|
53
|
+
signature: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Which tool-call renderers are registered. */
|
|
57
|
+
export interface ToolCallRendererNames {
|
|
58
|
+
/** Tool names with a renderer of their own. */
|
|
59
|
+
named: ReadonlySet<string>;
|
|
60
|
+
/** Of those, the ones whose renderer opted into grouping. */
|
|
61
|
+
groupedNames: ReadonlySet<string>;
|
|
62
|
+
/** A wildcard (`"*"`) renderer is registered. */
|
|
63
|
+
wildcard: boolean;
|
|
64
|
+
/** The wildcard renderer opted into grouping (the built-in card does). */
|
|
65
|
+
wildcardGroups: boolean;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function contentLength(content: ToolMessage["content"]): number {
|
|
69
|
+
return typeof content === "string"
|
|
70
|
+
? content.length
|
|
71
|
+
: JSON.stringify(content ?? "").length;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const entrySignature = ({ toolCall, toolMessage }: ToolCallEntry) =>
|
|
75
|
+
[
|
|
76
|
+
toolCall.id,
|
|
77
|
+
toolCall.function.name,
|
|
78
|
+
toolCall.function.arguments.length,
|
|
79
|
+
toolMessage
|
|
80
|
+
? `${contentLength(toolMessage.content)}${toolMessage.error ? "!" : ""}`
|
|
81
|
+
: "-",
|
|
82
|
+
].join(":");
|
|
83
|
+
|
|
84
|
+
function signatureOf(segments: ToolCallSegment[]): string {
|
|
85
|
+
return segments
|
|
86
|
+
.map((segment) =>
|
|
87
|
+
segment.kind === "call"
|
|
88
|
+
? `c(${entrySignature(segment.call)})`
|
|
89
|
+
: `g${segment.trailing ? "*" : ""}(${segment.calls.map(entrySignature).join(",")})`,
|
|
90
|
+
)
|
|
91
|
+
.join("|");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Index of tool results by the call they answer. */
|
|
95
|
+
export function getToolResults(messages: Message[]): Map<string, ToolMessage> {
|
|
96
|
+
const results = new Map<string, ToolMessage>();
|
|
97
|
+
for (const message of messages) {
|
|
98
|
+
if (message.role === "tool") results.set(message.toolCallId, message);
|
|
99
|
+
}
|
|
100
|
+
return results;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Lays out the tool calls of every assistant message in `rendered`.
|
|
105
|
+
*
|
|
106
|
+
* Calls drawn by a renderer that opted into grouping join the group that's
|
|
107
|
+
* open; anything else that shows between them closes it: assistant text, a
|
|
108
|
+
* user, reasoning or activity message, or a call drawn by any other renderer. A group belongs to
|
|
109
|
+
* the message where it starts, so later messages whose calls joined it render
|
|
110
|
+
* no tool calls themselves.
|
|
111
|
+
*
|
|
112
|
+
* @param rendered - The messages as the chat renders them, in order.
|
|
113
|
+
* @param all - Every message, for finding tool results (a transform may hide them).
|
|
114
|
+
* @param renderers - The registered renderers.
|
|
115
|
+
*/
|
|
116
|
+
export function getToolCallLayouts(
|
|
117
|
+
rendered: Message[],
|
|
118
|
+
all: Message[],
|
|
119
|
+
renderers: ToolCallRendererNames,
|
|
120
|
+
): Map<string, ToolCallLayout> {
|
|
121
|
+
const results = getToolResults(all);
|
|
122
|
+
const layouts = new Map<string, ToolCallSegment[]>();
|
|
123
|
+
let open: Extract<ToolCallSegment, { kind: "group" }> | undefined;
|
|
124
|
+
|
|
125
|
+
for (const message of rendered) {
|
|
126
|
+
if (message.role === "tool") continue;
|
|
127
|
+
if (message.role !== "assistant") {
|
|
128
|
+
open = undefined;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (typeof message.content === "string" && message.content.trim()) {
|
|
132
|
+
open = undefined;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const segments: ToolCallSegment[] = [];
|
|
136
|
+
layouts.set(message.id, segments);
|
|
137
|
+
// Streaming can repeat a call: keep its first position, last content.
|
|
138
|
+
const toolCalls = new Map<string, ToolCall>();
|
|
139
|
+
for (const toolCall of message.toolCalls ?? []) {
|
|
140
|
+
toolCalls.set(toolCall.id, toolCall);
|
|
141
|
+
}
|
|
142
|
+
for (const toolCall of toolCalls.values()) {
|
|
143
|
+
const entry = { toolCall, toolMessage: results.get(toolCall.id) };
|
|
144
|
+
|
|
145
|
+
const name = toolCall.function.name;
|
|
146
|
+
const named = renderers.named.has(name);
|
|
147
|
+
const rendered = named || renderers.wildcard;
|
|
148
|
+
const groups = named
|
|
149
|
+
? renderers.groupedNames.has(name)
|
|
150
|
+
: renderers.wildcardGroups;
|
|
151
|
+
|
|
152
|
+
if (!rendered || !groups) {
|
|
153
|
+
if (rendered) open = undefined;
|
|
154
|
+
segments.push({ kind: "call", id: toolCall.id, call: entry, rendered });
|
|
155
|
+
} else if (open) {
|
|
156
|
+
open.calls.push(entry);
|
|
157
|
+
} else {
|
|
158
|
+
open = {
|
|
159
|
+
kind: "group",
|
|
160
|
+
id: toolCall.id,
|
|
161
|
+
calls: [entry],
|
|
162
|
+
trailing: false,
|
|
163
|
+
};
|
|
164
|
+
segments.push(open);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (open) open.trailing = true;
|
|
169
|
+
|
|
170
|
+
const layout = new Map<string, ToolCallLayout>();
|
|
171
|
+
for (const [id, segments] of layouts) {
|
|
172
|
+
layout.set(id, { segments, signature: signatureOf(segments) });
|
|
173
|
+
}
|
|
174
|
+
return layout;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const TOOL_CALL_SLOT_PREFIX = "tool-call-";
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Which renderers draw tool calls, from the registered renderers and the
|
|
181
|
+
* view's tool-call slots. A slot wins over a registered renderer and never
|
|
182
|
+
* groups, since the chat can't tell what it draws: `#tool-call-<name>` takes
|
|
183
|
+
* that tool, and `#tool-call` takes every tool.
|
|
184
|
+
*
|
|
185
|
+
* @param renderers - The registered renderers (`copilotkit.renderToolCalls`).
|
|
186
|
+
* @param slotNames - The names of the slots the view was given.
|
|
187
|
+
*/
|
|
188
|
+
export function getToolCallRendererNames(
|
|
189
|
+
renderers: readonly { name: string; group?: boolean }[],
|
|
190
|
+
slotNames: readonly string[] = [],
|
|
191
|
+
): ToolCallRendererNames {
|
|
192
|
+
const wildcardSlot = slotNames.includes("tool-call");
|
|
193
|
+
const slotTools = slotNames
|
|
194
|
+
.filter((name) => name.startsWith(TOOL_CALL_SLOT_PREFIX))
|
|
195
|
+
.map((name) => name.slice(TOOL_CALL_SLOT_PREFIX.length));
|
|
196
|
+
const named = renderers.filter((renderer) => renderer.name !== "*");
|
|
197
|
+
const wildcards = renderers.filter((renderer) => renderer.name === "*");
|
|
198
|
+
return {
|
|
199
|
+
named: new Set([...named.map((renderer) => renderer.name), ...slotTools]),
|
|
200
|
+
groupedNames: new Set(
|
|
201
|
+
wildcardSlot
|
|
202
|
+
? []
|
|
203
|
+
: named
|
|
204
|
+
.filter(
|
|
205
|
+
(renderer) =>
|
|
206
|
+
renderer.group && !slotTools.includes(renderer.name),
|
|
207
|
+
)
|
|
208
|
+
.map((renderer) => renderer.name),
|
|
209
|
+
),
|
|
210
|
+
wildcard: wildcards.length > 0 || wildcardSlot,
|
|
211
|
+
wildcardGroups:
|
|
212
|
+
!wildcardSlot && wildcards.some((renderer) => renderer.group),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** A reply's working phase, for the `"turn"` display. */
|
|
217
|
+
export interface TurnWork {
|
|
218
|
+
/** Stable across the turn's life: the id of the user message it answers. */
|
|
219
|
+
key: string;
|
|
220
|
+
/** The first assistant-side message, where the "Worked for" line goes. */
|
|
221
|
+
firstMessageId: string;
|
|
222
|
+
/** Everything up to and including the last message with a tool call. */
|
|
223
|
+
workMessageIds: ReadonlySet<string>;
|
|
224
|
+
/**
|
|
225
|
+
* The reply's last assistant message, when it has text and is part of the
|
|
226
|
+
* work (it also calls a tool). Its text is the answer, so it stays out.
|
|
227
|
+
*/
|
|
228
|
+
replyTextMessageId?: string;
|
|
229
|
+
calls: ToolCallEntry[];
|
|
230
|
+
/** No user message follows, so the agent may still be working on it. */
|
|
231
|
+
isLatest: boolean;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Finds the working phase of every reply in `rendered`: its messages up to the
|
|
236
|
+
* last one that calls a tool. Text in there was narration; what follows is the
|
|
237
|
+
* reply itself. Replies that called no tools are omitted, except the latest,
|
|
238
|
+
* which may be about to.
|
|
239
|
+
*/
|
|
240
|
+
export function getTurnWork(
|
|
241
|
+
rendered: Message[],
|
|
242
|
+
layouts: ReadonlyMap<string, ToolCallLayout>,
|
|
243
|
+
): Map<string, TurnWork> {
|
|
244
|
+
const turns = new Map<string, TurnWork>();
|
|
245
|
+
let start = 0;
|
|
246
|
+
while (start < rendered.length) {
|
|
247
|
+
let end = start;
|
|
248
|
+
while (end < rendered.length && rendered[end]!.role !== "user") end++;
|
|
249
|
+
const key = start > 0 ? rendered[start - 1]!.id : "start";
|
|
250
|
+
const visible = rendered
|
|
251
|
+
.slice(start, end)
|
|
252
|
+
.filter((message) => message.role !== "tool");
|
|
253
|
+
const isLatest = end === rendered.length;
|
|
254
|
+
|
|
255
|
+
// A message's calls may sit in a group an earlier message owns, so
|
|
256
|
+
// collect every shown call first, then find the last message making one.
|
|
257
|
+
const calls: ToolCallEntry[] = [];
|
|
258
|
+
for (const message of visible) {
|
|
259
|
+
for (const segment of layouts.get(message.id)?.segments ?? []) {
|
|
260
|
+
if (segment.kind === "group") calls.push(...segment.calls);
|
|
261
|
+
else if (segment.rendered) calls.push(segment.call);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const shown = new Set(calls.map((entry) => entry.toolCall.id));
|
|
265
|
+
let lastWork = -1;
|
|
266
|
+
visible.forEach((message, index) => {
|
|
267
|
+
if (
|
|
268
|
+
message.role === "assistant" &&
|
|
269
|
+
message.toolCalls?.some((call) => shown.has(call.id))
|
|
270
|
+
) {
|
|
271
|
+
lastWork = index;
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
const first = visible[0];
|
|
276
|
+
if (first && (calls.length > 0 || isLatest)) {
|
|
277
|
+
let lastAssistant = -1;
|
|
278
|
+
visible.forEach((message, index) => {
|
|
279
|
+
if (message.role === "assistant") lastAssistant = index;
|
|
280
|
+
});
|
|
281
|
+
const replyText = visible[lastAssistant]?.content;
|
|
282
|
+
const endsWithWork =
|
|
283
|
+
lastAssistant >= 0 &&
|
|
284
|
+
lastAssistant <= lastWork &&
|
|
285
|
+
typeof replyText === "string" &&
|
|
286
|
+
replyText.trim().length > 0;
|
|
287
|
+
|
|
288
|
+
turns.set(key, {
|
|
289
|
+
key,
|
|
290
|
+
firstMessageId: first.id,
|
|
291
|
+
workMessageIds: new Set(
|
|
292
|
+
visible.slice(0, lastWork + 1).map((message) => message.id),
|
|
293
|
+
),
|
|
294
|
+
replyTextMessageId: endsWithWork
|
|
295
|
+
? visible[lastAssistant]!.id
|
|
296
|
+
: undefined,
|
|
297
|
+
calls,
|
|
298
|
+
isLatest,
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
start = end + 1;
|
|
302
|
+
}
|
|
303
|
+
return turns;
|
|
304
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { defineComponent, h, inject } from "vue";
|
|
2
|
+
import type { FunctionalComponent } from "vue";
|
|
3
|
+
import { CopilotChatCollapsible } from "./tool-call-group-parts";
|
|
4
|
+
import { ToolCallDisplayContextKey } from "./tool-call-display-context";
|
|
5
|
+
|
|
6
|
+
/** "45s", "1m 5s", "2m". Used for the live timer and the final duration. */
|
|
7
|
+
export function formatDuration(ms: number): string {
|
|
8
|
+
const seconds = Math.max(0, Math.floor(ms / 1000));
|
|
9
|
+
if (seconds < 60) return `${seconds}s`;
|
|
10
|
+
const minutes = Math.floor(seconds / 60);
|
|
11
|
+
const rest = seconds % 60;
|
|
12
|
+
return rest ? `${minutes}m ${rest}s` : `${minutes}m`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Folds its content away with a reply's work in the `"turn"` display. Without
|
|
17
|
+
* `open` (any other display) it renders the content as is.
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export const TurnWorkFold: FunctionalComponent<{ open?: boolean }> = (
|
|
21
|
+
props,
|
|
22
|
+
{ slots },
|
|
23
|
+
) =>
|
|
24
|
+
props.open === undefined
|
|
25
|
+
? slots.default?.()
|
|
26
|
+
: h(CopilotChatCollapsible, { open: props.open }, slots);
|
|
27
|
+
TurnWorkFold.props = ["open"];
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* In the `"turn"` tool-call display, text in a reply's working phase was
|
|
31
|
+
* narration: it fades to muted once a call follows it, and folds away with the
|
|
32
|
+
* rest of the work when the reply is done. The wrapper is there for every
|
|
33
|
+
* message in that display, so text that turns into narration keeps its node
|
|
34
|
+
* (and its place) rather than remounting.
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
export const CopilotChatWorkText = defineComponent({
|
|
38
|
+
name: "CopilotChatWorkText",
|
|
39
|
+
props: { messageId: { type: String, required: true } },
|
|
40
|
+
setup(props, { slots }) {
|
|
41
|
+
const context = inject(ToolCallDisplayContextKey, null);
|
|
42
|
+
return () => {
|
|
43
|
+
if (context?.value.display !== "turn") return slots.default?.();
|
|
44
|
+
const open = context.value.workTextOpen.get(props.messageId);
|
|
45
|
+
return h(
|
|
46
|
+
CopilotChatCollapsible,
|
|
47
|
+
{ open: open ?? true, class: "cpk-assistant-message-work-text" },
|
|
48
|
+
() => [
|
|
49
|
+
h(
|
|
50
|
+
"div",
|
|
51
|
+
{
|
|
52
|
+
class: "cpk-assistant-message-work-text-content",
|
|
53
|
+
"data-work-text": open === undefined ? "reply" : "narration",
|
|
54
|
+
},
|
|
55
|
+
slots.default?.(),
|
|
56
|
+
),
|
|
57
|
+
],
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
});
|
|
@@ -6,24 +6,73 @@ import type {
|
|
|
6
6
|
ToolMessage,
|
|
7
7
|
UserMessage,
|
|
8
8
|
} from "@ag-ui/core";
|
|
9
|
+
import type { VNode } from "vue";
|
|
9
10
|
import type { CopilotKitCoreErrorCode, ToolCallStatus } from "@copilotkit/core";
|
|
10
11
|
import type { Suggestion } from "@copilotkit/core";
|
|
11
12
|
import type {
|
|
12
13
|
Attachment,
|
|
13
14
|
AttachmentsConfig,
|
|
14
15
|
AttachmentModality,
|
|
16
|
+
InputContentSource,
|
|
15
17
|
} from "@copilotkit/shared";
|
|
16
18
|
import type { CopilotChatLabels } from "../../providers/types";
|
|
17
19
|
import type { InterruptEvent } from "../../types";
|
|
18
20
|
import type { AutoScrollMode } from "./normalize-auto-scroll";
|
|
21
|
+
import type {
|
|
22
|
+
CopilotChatToolCallDisplay,
|
|
23
|
+
ToolCallEntry,
|
|
24
|
+
} from "./tool-call-layout";
|
|
19
25
|
|
|
20
26
|
export type CopilotChatInputMode = "input" | "transcribe" | "processing";
|
|
21
27
|
export type { Attachment, AttachmentsConfig, AttachmentModality };
|
|
22
28
|
export type { AutoScrollMode };
|
|
29
|
+
export type { CopilotChatToolCallDisplay, ToolCallEntry };
|
|
30
|
+
|
|
31
|
+
/** How a `CopilotChatToolCallGroup` draws its calls. */
|
|
32
|
+
export type CopilotChatToolCallGroupAppearance = "card" | "line" | "stack";
|
|
33
|
+
|
|
34
|
+
/** Props of the `#tool-calls-group` slot, which replaces a group of calls. */
|
|
35
|
+
export interface CopilotChatToolCallsGroupSlotProps {
|
|
36
|
+
/** The calls in the group, in order. */
|
|
37
|
+
calls: ToolCallEntry[];
|
|
38
|
+
/** The appearance the view's `toolCallDisplay` asks for. */
|
|
39
|
+
appearance: CopilotChatToolCallGroupAppearance;
|
|
40
|
+
/** The agent is running and nothing follows the group, so more calls may join it. */
|
|
41
|
+
isActive: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Draws one call through the registered renderers and tool-call slots.
|
|
44
|
+
* Render the VNode with `<component :is="renderCall(call)" />`.
|
|
45
|
+
*/
|
|
46
|
+
renderCall: (call: ToolCallEntry) => VNode;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Props of `CopilotChatWorkSummary` and of the `#work-summary` slot, which
|
|
51
|
+
* replaces the "Working… / Worked for 9s" line of the `"turn"` display.
|
|
52
|
+
*/
|
|
53
|
+
export interface CopilotChatWorkSummarySlotProps {
|
|
54
|
+
/** The agent is still working on this reply. */
|
|
55
|
+
isWorking: boolean;
|
|
56
|
+
/** Whether the work (narration and tool calls) is showing. */
|
|
57
|
+
isOpen: boolean;
|
|
58
|
+
/** The tool calls the reply made. */
|
|
59
|
+
calls: ToolCallEntry[];
|
|
60
|
+
/**
|
|
61
|
+
* How long the agent has worked on the reply, in ms, summed over its runs
|
|
62
|
+
* so time spent waiting between them doesn't count. Only known for replies
|
|
63
|
+
* this client watched start; without it the summary shows the tool count.
|
|
64
|
+
*/
|
|
65
|
+
elapsedMs?: number;
|
|
66
|
+
/** When the current run started (epoch ms), while the agent is working. */
|
|
67
|
+
workingSince?: number;
|
|
68
|
+
/** Opens or closes the reply's work. */
|
|
69
|
+
onClick: () => void;
|
|
70
|
+
}
|
|
23
71
|
|
|
24
72
|
export interface CopilotChatAttachmentRendererProps {
|
|
25
73
|
type: AttachmentModality;
|
|
26
|
-
source
|
|
74
|
+
/** Any AG-UI content source, as in React; a `file` handle shows no preview. */
|
|
75
|
+
source: InputContentSource;
|
|
27
76
|
filename?: string;
|
|
28
77
|
className?: string;
|
|
29
78
|
}
|
|
@@ -94,6 +143,20 @@ export interface CopilotChatViewProps {
|
|
|
94
143
|
onDragLeave?: (event: DragEvent) => void;
|
|
95
144
|
onDrop?: (event: DragEvent) => void;
|
|
96
145
|
onFinishTranscribeWithAudio?: (audioBlob: Blob) => void | Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* How tool calls show. Defaults to `"grouped"`: calls made in a row share
|
|
148
|
+
* one card that opens to a row per call. `"line"` and `"stacked"` group
|
|
149
|
+
* them too; `"separate"` gives every call its own card. Calls drawn by a
|
|
150
|
+
* renderer that does not set `group: true`, or by a tool-call slot, always
|
|
151
|
+
* show on their own.
|
|
152
|
+
*/
|
|
153
|
+
toolCallDisplay?: CopilotChatToolCallDisplay;
|
|
154
|
+
/**
|
|
155
|
+
* Whether reply thumbs record ratings for Automatic Learning once a
|
|
156
|
+
* Trajectory has started. Defaults to `true`; set `false` to keep the
|
|
157
|
+
* thumbs to your own `thumbs-up` / `thumbs-down` handlers and slots.
|
|
158
|
+
*/
|
|
159
|
+
messageFeedback?: boolean;
|
|
97
160
|
}
|
|
98
161
|
|
|
99
162
|
export interface CopilotChatProps extends Omit<
|
|
@@ -319,13 +382,56 @@ export interface CopilotChatAssistantMessageCopyButtonSlotProps {
|
|
|
319
382
|
label: string;
|
|
320
383
|
}
|
|
321
384
|
|
|
385
|
+
/**
|
|
386
|
+
* Attributes and listeners that let a thumb record a Learning rating and open
|
|
387
|
+
* its comment popover. Bind them on the thumb's `<button>` with `v-bind`;
|
|
388
|
+
* they are empty while the chat records no ratings.
|
|
389
|
+
*/
|
|
390
|
+
export type CopilotChatAssistantMessageThumbProps = Record<string, unknown>;
|
|
391
|
+
|
|
322
392
|
export interface CopilotChatAssistantMessageThumbsUpButtonSlotProps {
|
|
323
|
-
|
|
393
|
+
/**
|
|
394
|
+
* Rates the reply. Pass the click event, so the comment points at the
|
|
395
|
+
* clicked thumb and a keyboard click moves focus into it.
|
|
396
|
+
*/
|
|
397
|
+
onThumbsUp: (event?: MouseEvent) => void;
|
|
324
398
|
label: string;
|
|
399
|
+
/** This rating is the chosen one (Learning only). */
|
|
400
|
+
pressed: boolean;
|
|
401
|
+
thumbProps: CopilotChatAssistantMessageThumbProps;
|
|
325
402
|
}
|
|
326
403
|
|
|
327
404
|
export interface CopilotChatAssistantMessageThumbsDownButtonSlotProps {
|
|
328
|
-
|
|
405
|
+
/** See {@link CopilotChatAssistantMessageThumbsUpButtonSlotProps.onThumbsUp}. */
|
|
406
|
+
onThumbsDown: (event?: MouseEvent) => void;
|
|
407
|
+
label: string;
|
|
408
|
+
/** This rating is the chosen one (Learning only). */
|
|
409
|
+
pressed: boolean;
|
|
410
|
+
thumbProps: CopilotChatAssistantMessageThumbProps;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/** Props of the `feedback-comment` slot: the comment field of a rating. */
|
|
414
|
+
export interface CopilotChatAssistantMessageFeedbackCommentSlotProps {
|
|
415
|
+
value: string;
|
|
416
|
+
/** The comment already saved. */
|
|
417
|
+
savedComment: string;
|
|
418
|
+
/** Bind as `:ref` on the text field, so a keyboard rating can focus it. */
|
|
419
|
+
inputRef: (element: unknown) => void;
|
|
420
|
+
onChange: (value: string) => void;
|
|
421
|
+
/** Saves the comment, closes the popover and returns focus to the thumb. */
|
|
422
|
+
onSubmit: () => void;
|
|
423
|
+
onEditingChange: (editing: boolean) => void;
|
|
424
|
+
/**
|
|
425
|
+
* Focus left the form for `next`, or for no focusable element when null.
|
|
426
|
+
* Not called when the window loses focus.
|
|
427
|
+
*/
|
|
428
|
+
onLeave: (next: Element | null) => void;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/** Props of the `inspector-button` slot. */
|
|
432
|
+
export interface CopilotChatAssistantMessageInspectorButtonSlotProps {
|
|
433
|
+
/** Opens this message in the Inspector. */
|
|
434
|
+
onInspect: () => void;
|
|
329
435
|
label: string;
|
|
330
436
|
}
|
|
331
437
|
|
|
@@ -498,6 +604,8 @@ export interface CopilotSidebarViewToggleButtonSlotProps {
|
|
|
498
604
|
export interface CopilotSidebarViewProps extends CopilotChatViewProps {
|
|
499
605
|
width?: number | string;
|
|
500
606
|
defaultOpen?: boolean;
|
|
607
|
+
/** The edge the sidebar docks to. Defaults to `"right"`. */
|
|
608
|
+
position?: "left" | "right";
|
|
501
609
|
}
|
|
502
610
|
|
|
503
611
|
export type CopilotPopupViewHeaderSlotProps = CopilotSidebarViewHeaderSlotProps;
|
|
@@ -533,4 +641,6 @@ export interface CopilotPopupProps extends CopilotChatProps {
|
|
|
533
641
|
export interface CopilotSidebarProps extends CopilotChatProps {
|
|
534
642
|
width?: number | string;
|
|
535
643
|
defaultOpen?: boolean;
|
|
644
|
+
/** The edge the sidebar docks to. Defaults to `"right"`. */
|
|
645
|
+
position?: CopilotSidebarViewProps["position"];
|
|
536
646
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { nextTick, ref } from "vue";
|
|
2
|
+
import { useCopilotId } from "../ui/use-id";
|
|
3
|
+
|
|
4
|
+
type DocWithVT = Document & {
|
|
5
|
+
startViewTransition?: (cb: () => void | Promise<void>) => {
|
|
6
|
+
finished: Promise<void>;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Opens and closes a lightbox, using the View Transition API to morph the
|
|
12
|
+
* thumbnail into the full-screen content, as React's `useLightbox`.
|
|
13
|
+
*
|
|
14
|
+
* `view-transition-name` must be on exactly one element at a time: on the
|
|
15
|
+
* thumbnail in the old state, and on the lightbox content (bind `vtName` to
|
|
16
|
+
* it) in the new one. The transition callback waits for Vue to render the
|
|
17
|
+
* change, so the API can snapshot old and new correctly.
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export function useLightbox() {
|
|
21
|
+
const thumbnailRef = ref<HTMLElement | null>(null);
|
|
22
|
+
const open = ref(false);
|
|
23
|
+
// A custom ident: Vue's ids can hold characters CSS does not allow there.
|
|
24
|
+
const vtName = useCopilotId("cpk-lightbox").replace(/[^\w-]/g, "-");
|
|
25
|
+
|
|
26
|
+
const openLightbox = () => {
|
|
27
|
+
const thumb = thumbnailRef.value;
|
|
28
|
+
const doc =
|
|
29
|
+
typeof document === "undefined" ? undefined : (document as DocWithVT);
|
|
30
|
+
|
|
31
|
+
if (doc?.startViewTransition && thumb) {
|
|
32
|
+
thumb.style.viewTransitionName = vtName;
|
|
33
|
+
doc.startViewTransition(async () => {
|
|
34
|
+
thumb.style.viewTransitionName = "";
|
|
35
|
+
open.value = true;
|
|
36
|
+
await nextTick();
|
|
37
|
+
});
|
|
38
|
+
} else {
|
|
39
|
+
open.value = true;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const closeLightbox = () => {
|
|
44
|
+
const thumb = thumbnailRef.value;
|
|
45
|
+
const doc =
|
|
46
|
+
typeof document === "undefined" ? undefined : (document as DocWithVT);
|
|
47
|
+
|
|
48
|
+
if (doc?.startViewTransition && thumb) {
|
|
49
|
+
const transition = doc.startViewTransition(async () => {
|
|
50
|
+
open.value = false;
|
|
51
|
+
await nextTick();
|
|
52
|
+
thumb.style.viewTransitionName = vtName;
|
|
53
|
+
});
|
|
54
|
+
const clear = () => {
|
|
55
|
+
thumb.style.viewTransitionName = "";
|
|
56
|
+
};
|
|
57
|
+
transition.finished.then(clear, clear);
|
|
58
|
+
} else {
|
|
59
|
+
open.value = false;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
return { thumbnailRef, vtName, open, openLightbox, closeLightbox };
|
|
64
|
+
}
|