@aleph-alpha/chat-kit 3.3.0 → 5.0.0
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/{CkInput.vue_vue_type_script_setup_true_lang-BAcBFs6I.js → CkHistory.vue_vue_type_script_setup_true_lang-Bp9hXdH6.js} +452 -348
- package/dist/adapters/responses-api.d.ts +11 -5
- package/dist/adapters/responses-api.d.ts.map +1 -1
- package/dist/adapters/responses-api.js +9 -3
- package/dist/chat-kit.css +36 -14
- package/dist/components/base/CkAgentMessage/CkAgentMessage.stories.d.ts +14 -13
- package/dist/components/base/CkAgentMessage/CkAgentMessage.stories.d.ts.map +1 -1
- package/dist/components/base/CkAgentMessage/CkAgentMessage.vue.d.ts +8 -7
- package/dist/components/base/CkAgentMessage/CkAgentMessage.vue.d.ts.map +1 -1
- package/dist/components/base/CkAgentMessage/types.d.ts +16 -5
- package/dist/components/base/CkAgentMessage/types.d.ts.map +1 -1
- package/dist/components/base/CkAgentMessageHeader/CkAgentMessageHeader.stories.d.ts +16 -0
- package/dist/components/base/CkAgentMessageHeader/CkAgentMessageHeader.stories.d.ts.map +1 -0
- package/dist/components/base/CkAgentMessageHeader/CkAgentMessageHeader.vue.d.ts +21 -0
- package/dist/components/base/CkAgentMessageHeader/CkAgentMessageHeader.vue.d.ts.map +1 -0
- package/dist/components/base/CkAgentMessageHeader/index.d.ts +3 -0
- package/dist/components/base/CkAgentMessageHeader/index.d.ts.map +1 -0
- package/dist/components/base/CkAgentMessageHeader/types.d.ts +22 -0
- package/dist/components/base/CkAgentMessageHeader/types.d.ts.map +1 -0
- package/dist/components/base/CkCitation/CkCitation.stories.d.ts +6 -0
- package/dist/components/base/CkCitation/CkCitation.stories.d.ts.map +1 -1
- package/dist/components/base/CkCitation/CkCitation.vue.d.ts.map +1 -1
- package/dist/components/base/CkCitationCard/CkCitationCard.stories.d.ts +5 -4
- package/dist/components/base/CkCitationCard/CkCitationCard.stories.d.ts.map +1 -1
- package/dist/components/base/CkCitationCard/CkCitationCard.vue.d.ts.map +1 -1
- package/dist/components/base/{CkCopyMessageActionButton/CkCopyMessageActionButton.stories.d.ts → CkCopyMessageButton/CkCopyMessageButton.stories.d.ts} +3 -3
- package/dist/components/base/CkCopyMessageButton/CkCopyMessageButton.stories.d.ts.map +1 -0
- package/dist/components/base/{CkCopyMessageActionButton/CkCopyMessageActionButton.vue.d.ts → CkCopyMessageButton/CkCopyMessageButton.vue.d.ts} +4 -4
- package/dist/components/base/CkCopyMessageButton/CkCopyMessageButton.vue.d.ts.map +1 -0
- package/dist/components/base/CkCopyMessageButton/index.d.ts +3 -0
- package/dist/components/base/CkCopyMessageButton/index.d.ts.map +1 -0
- package/dist/components/base/{CkCopyMessageActionButton → CkCopyMessageButton}/types.d.ts +3 -3
- package/dist/components/base/CkCopyMessageButton/types.d.ts.map +1 -0
- package/dist/components/base/CkFeedbackButton/types.d.ts +1 -1
- package/dist/components/base/CkFeedbackDialog/types.d.ts +1 -1
- package/dist/components/base/CkFileItemsList/CkFileItemsList.stories.d.ts +15 -4
- package/dist/components/base/CkFileItemsList/CkFileItemsList.stories.d.ts.map +1 -1
- package/dist/components/base/CkFileItemsList/CkFileItemsList.vue.d.ts +2 -1
- package/dist/components/base/CkFileItemsList/CkFileItemsList.vue.d.ts.map +1 -1
- package/dist/components/base/CkFileItemsList/types.d.ts +17 -4
- package/dist/components/base/CkFileItemsList/types.d.ts.map +1 -1
- package/dist/components/base/CkHeaderActivityButton/CkHeaderActivityButton.stories.d.ts +19 -0
- package/dist/components/base/CkHeaderActivityButton/CkHeaderActivityButton.stories.d.ts.map +1 -0
- package/dist/components/base/CkHeaderActivityButton/CkHeaderActivityButton.vue.d.ts +22 -0
- package/dist/components/base/CkHeaderActivityButton/CkHeaderActivityButton.vue.d.ts.map +1 -0
- package/dist/components/base/CkHeaderActivityButton/index.d.ts +3 -0
- package/dist/components/base/CkHeaderActivityButton/index.d.ts.map +1 -0
- package/dist/components/base/CkHeaderActivityButton/types.d.ts +36 -0
- package/dist/components/base/CkHeaderActivityButton/types.d.ts.map +1 -0
- package/dist/components/base/{CkMessageActionButton/CkMessageActionButton.stories.d.ts → CkMessageButton/CkMessageButton.stories.d.ts} +3 -3
- package/dist/components/base/CkMessageButton/CkMessageButton.stories.d.ts.map +1 -0
- package/dist/components/base/{CkMessageActionButton/CkMessageActionButton.vue.d.ts → CkMessageButton/CkMessageButton.vue.d.ts} +3 -3
- package/dist/components/base/CkMessageButton/CkMessageButton.vue.d.ts.map +1 -0
- package/dist/components/base/CkMessageButton/index.d.ts +3 -0
- package/dist/components/base/CkMessageButton/index.d.ts.map +1 -0
- package/dist/components/base/{CkMessageActionButton → CkMessageButton}/types.d.ts +2 -2
- package/dist/components/base/CkMessageButton/types.d.ts.map +1 -0
- package/dist/components/base/CkPromptInput/CkPromptInput.stories.d.ts +6 -6
- package/dist/components/base/CkPromptInput/CkPromptInput.vue.d.ts.map +1 -1
- package/dist/components/base/CkPromptInput/types.d.ts +4 -4
- package/dist/components/base/CkPromptInputDisclaimer/CkPromptInputDisclaimer.vue.d.ts.map +1 -1
- package/dist/components/base/CkPromptInputDisclaimer/types.d.ts +1 -1
- package/dist/components/base/CkPromptSendButton/CkPromptSendButton.vue.d.ts +1 -1
- package/dist/components/base/CkPromptSendButton/types.d.ts +1 -1
- package/dist/components/base/CkPromptStopButton/types.d.ts +1 -1
- package/dist/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.stories.d.ts +16 -0
- package/dist/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.stories.d.ts.map +1 -0
- package/dist/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.vue.d.ts +12 -0
- package/dist/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.vue.d.ts.map +1 -0
- package/dist/components/base/CkRegenerateMessageButton/index.d.ts +3 -0
- package/dist/components/base/{CkCopyMessageActionButton → CkRegenerateMessageButton}/index.d.ts.map +1 -1
- package/dist/components/base/CkRegenerateMessageButton/types.d.ts +27 -0
- package/dist/components/base/CkRegenerateMessageButton/types.d.ts.map +1 -0
- package/dist/components/base/index.d.ts +7 -2
- package/dist/components/base/index.d.ts.map +1 -1
- package/dist/components/composed/CkConversation/CkConversation.stories.d.ts +1 -1
- package/dist/components/composed/CkConversation/CkConversation.vue.d.ts +13 -1
- package/dist/components/composed/CkConversation/CkConversation.vue.d.ts.map +1 -1
- package/dist/components/composed/CkConversation/types.d.ts +1 -1
- package/dist/components/composed/index.d.ts +0 -1
- package/dist/components/composed/index.d.ts.map +1 -1
- package/dist/components/index.d.ts +3 -3
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +26 -24
- package/dist/composables/index.js +1 -1
- package/dist/handlers/index.js +2 -2
- package/dist/handlers/useChatKitLabels.d.ts +2 -0
- package/dist/handlers/useChatKitLabels.d.ts.map +1 -1
- package/dist/handlers/useMessageHandler.d.ts +37 -0
- package/dist/handlers/useMessageHandler.d.ts.map +1 -1
- package/dist/helpers/conversationTree.d.ts +15 -0
- package/dist/helpers/conversationTree.d.ts.map +1 -1
- package/dist/{index-C6njJ8EB.js → index-CyrVnbS9.js} +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -28
- package/dist/{useChatKitLabels-BM2I7-9o.js → useChatKitLabels-zMFV7aEz.js} +1 -0
- package/dist/{useMessageHandler-CMdy-lm0.js → useMessageHandler-N50Yj-NU.js} +45 -7
- package/package.json +3 -3
- package/src/adapters/responses-api.spec.ts +52 -5
- package/src/adapters/responses-api.ts +26 -7
- package/src/components/base/CkAgentMessage/CkAgentMessage.spec.ts +12 -17
- package/src/components/base/CkAgentMessage/CkAgentMessage.stories.ts +124 -113
- package/src/components/base/CkAgentMessage/CkAgentMessage.vue +18 -16
- package/src/components/base/CkAgentMessage/types.ts +16 -5
- package/src/components/base/CkAgentMessageHeader/CkAgentMessageHeader.spec.ts +64 -0
- package/src/components/base/CkAgentMessageHeader/CkAgentMessageHeader.stories.ts +90 -0
- package/src/components/base/CkAgentMessageHeader/CkAgentMessageHeader.vue +47 -0
- package/src/components/base/CkAgentMessageHeader/index.ts +2 -0
- package/src/components/base/CkAgentMessageHeader/types.ts +21 -0
- package/src/components/base/CkCitation/CkCitation.stories.ts +12 -0
- package/src/components/base/CkCitation/CkCitation.vue +34 -9
- package/src/components/base/CkCitationCard/CkCitationCard.stories.ts +5 -4
- package/src/components/base/CkCitationCard/CkCitationCard.vue +2 -2
- package/src/components/base/CkConversationLayout/CkConversationLayout.vue +1 -1
- package/src/components/base/{CkCopyMessageActionButton/CkCopyMessageActionButton.spec.ts → CkCopyMessageButton/CkCopyMessageButton.spec.ts} +6 -6
- package/src/components/base/{CkCopyMessageActionButton/CkCopyMessageActionButton.stories.ts → CkCopyMessageButton/CkCopyMessageButton.stories.ts} +8 -8
- package/src/components/base/{CkCopyMessageActionButton/CkCopyMessageActionButton.vue → CkCopyMessageButton/CkCopyMessageButton.vue} +6 -6
- package/src/components/base/CkCopyMessageButton/index.ts +2 -0
- package/src/components/base/{CkCopyMessageActionButton → CkCopyMessageButton}/types.ts +3 -3
- package/src/components/base/CkFeedbackButton/CkFeedbackButton.vue +5 -5
- package/src/components/base/CkFeedbackButton/types.ts +1 -1
- package/src/components/base/CkFeedbackDialog/types.ts +1 -1
- package/src/components/base/CkFileItemsList/CkFileItemsList.spec.ts +88 -13
- package/src/components/base/CkFileItemsList/CkFileItemsList.stories.ts +61 -13
- package/src/components/base/CkFileItemsList/CkFileItemsList.vue +153 -110
- package/src/components/base/CkFileItemsList/types.ts +17 -4
- package/src/components/base/CkHeaderActivityButton/CkHeaderActivityButton.spec.ts +50 -0
- package/src/components/base/CkHeaderActivityButton/CkHeaderActivityButton.stories.ts +102 -0
- package/src/components/base/CkHeaderActivityButton/CkHeaderActivityButton.vue +39 -0
- package/src/components/base/CkHeaderActivityButton/index.ts +2 -0
- package/src/components/base/CkHeaderActivityButton/types.ts +36 -0
- package/src/components/base/{CkMessageActionButton/CkMessageActionButton.spec.ts → CkMessageButton/CkMessageButton.spec.ts} +6 -6
- package/src/components/base/{CkMessageActionButton/CkMessageActionButton.stories.ts → CkMessageButton/CkMessageButton.stories.ts} +10 -10
- package/src/components/base/{CkMessageActionButton/CkMessageActionButton.vue → CkMessageButton/CkMessageButton.vue} +3 -3
- package/src/components/base/CkMessageButton/index.ts +2 -0
- package/src/components/base/{CkMessageActionButton → CkMessageButton}/types.ts +2 -2
- package/src/components/base/CkPromptInput/CkPromptInput.spec.ts +88 -0
- package/src/components/base/CkPromptInput/CkPromptInput.stories.ts +6 -6
- package/src/components/base/CkPromptInput/CkPromptInput.vue +63 -12
- package/src/components/base/CkPromptInput/types.ts +4 -4
- package/src/components/base/CkPromptInputDisclaimer/CkPromptInputDisclaimer.spec.ts +1 -1
- package/src/components/base/CkPromptInputDisclaimer/CkPromptInputDisclaimer.vue +1 -1
- package/src/components/base/CkPromptInputDisclaimer/types.ts +1 -1
- package/src/components/base/CkPromptSendButton/types.ts +1 -1
- package/src/components/base/CkPromptStopButton/types.ts +1 -1
- package/src/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.spec.ts +49 -0
- package/src/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.stories.ts +63 -0
- package/src/components/base/CkRegenerateMessageButton/CkRegenerateMessageButton.vue +43 -0
- package/src/components/base/CkRegenerateMessageButton/index.ts +2 -0
- package/src/components/base/CkRegenerateMessageButton/types.ts +27 -0
- package/src/components/base/index.ts +10 -2
- package/src/components/composed/CkConversation/CkConversation.spec.ts +81 -6
- package/src/components/composed/CkConversation/CkConversation.stories.ts +6 -6
- package/src/components/composed/CkConversation/CkConversation.vue +80 -37
- package/src/components/composed/CkConversation/types.ts +1 -1
- package/src/components/composed/index.ts +0 -1
- package/src/components/index.ts +9 -3
- package/src/handlers/useChatKitLabels.spec.ts +1 -0
- package/src/handlers/useChatKitLabels.ts +3 -0
- package/src/handlers/useMessageHandler.spec.ts +79 -0
- package/src/handlers/useMessageHandler.ts +50 -2
- package/src/helpers/conversationTree.spec.ts +120 -0
- package/src/helpers/conversationTree.ts +57 -8
- package/src/index.ts +8 -3
- package/dist/components/base/CkCopyMessageActionButton/CkCopyMessageActionButton.stories.d.ts.map +0 -1
- package/dist/components/base/CkCopyMessageActionButton/CkCopyMessageActionButton.vue.d.ts.map +0 -1
- package/dist/components/base/CkCopyMessageActionButton/index.d.ts +0 -3
- package/dist/components/base/CkCopyMessageActionButton/types.d.ts.map +0 -1
- package/dist/components/base/CkMessageActionButton/CkMessageActionButton.stories.d.ts.map +0 -1
- package/dist/components/base/CkMessageActionButton/CkMessageActionButton.vue.d.ts.map +0 -1
- package/dist/components/base/CkMessageActionButton/index.d.ts +0 -3
- package/dist/components/base/CkMessageActionButton/index.d.ts.map +0 -1
- package/dist/components/base/CkMessageActionButton/types.d.ts.map +0 -1
- package/dist/components/composed/CkInput/CkInput.stories.d.ts +0 -43
- package/dist/components/composed/CkInput/CkInput.stories.d.ts.map +0 -1
- package/dist/components/composed/CkInput/CkInput.vue.d.ts +0 -50
- package/dist/components/composed/CkInput/CkInput.vue.d.ts.map +0 -1
- package/dist/components/composed/CkInput/index.d.ts +0 -3
- package/dist/components/composed/CkInput/index.d.ts.map +0 -1
- package/dist/components/composed/CkInput/types.d.ts +0 -55
- package/dist/components/composed/CkInput/types.d.ts.map +0 -1
- package/src/components/base/CkCopyMessageActionButton/index.ts +0 -2
- package/src/components/base/CkMessageActionButton/index.ts +0 -2
- package/src/components/composed/CkInput/CkInput.spec.ts +0 -191
- package/src/components/composed/CkInput/CkInput.stories.ts +0 -434
- package/src/components/composed/CkInput/CkInput.vue +0 -106
- package/src/components/composed/CkInput/index.ts +0 -2
- package/src/components/composed/CkInput/types.ts +0 -55
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regenerate action button for chat messages. Lets the user request a new
|
|
3
|
+
* response for an assistant message. Renders an icon-only button with an
|
|
4
|
+
* accessible label and tooltip.
|
|
5
|
+
*
|
|
6
|
+
* @category Actions
|
|
7
|
+
* @useCases regenerate assistant reply, retry message, request new response, chat message action
|
|
8
|
+
* @keywords regenerate, retry, repeat, action, message, button, icon
|
|
9
|
+
* @related CkMessageButton, CkCopyMessageButton, CkAgentMessage, CkConversation
|
|
10
|
+
*/
|
|
11
|
+
export interface CkRegenerateMessageButtonProps {
|
|
12
|
+
/**
|
|
13
|
+
* Whether the button is disabled and ignores clicks.
|
|
14
|
+
* @default false
|
|
15
|
+
*/
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Accessible label and tooltip content for the button.
|
|
19
|
+
* @default 'Regenerate response'
|
|
20
|
+
*/
|
|
21
|
+
ariaLabel?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface CkRegenerateMessageButtonEmits {
|
|
25
|
+
/** Emitted when the button is pressed and not disabled. */
|
|
26
|
+
(e: 'regenerate'): void;
|
|
27
|
+
}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
export { CkSendIcon, CkStopIcon } from './icons';
|
|
2
2
|
export { CkAgentMessage } from './CkAgentMessage';
|
|
3
|
+
export { CkAgentMessageHeader } from './CkAgentMessageHeader';
|
|
4
|
+
export type { CkAgentMessageHeaderProps } from './CkAgentMessageHeader';
|
|
5
|
+
export { CkHeaderActivityButton } from './CkHeaderActivityButton';
|
|
6
|
+
export type {
|
|
7
|
+
CkHeaderActivityButtonProps,
|
|
8
|
+
CkHeaderActivityButtonEmits,
|
|
9
|
+
} from './CkHeaderActivityButton';
|
|
3
10
|
export { CkCitation } from './CkCitation';
|
|
4
11
|
export type {
|
|
5
12
|
CkCitationProps,
|
|
@@ -13,7 +20,7 @@ export type {
|
|
|
13
20
|
} from './CkCitationCard';
|
|
14
21
|
export { CkConversationLayout } from './CkConversationLayout';
|
|
15
22
|
export type { CkConversationLayoutProps } from './CkConversationLayout';
|
|
16
|
-
export {
|
|
23
|
+
export { CkCopyMessageButton } from './CkCopyMessageButton';
|
|
17
24
|
export { CkDropZoneOverlay } from './CkDropZoneOverlay';
|
|
18
25
|
export type {
|
|
19
26
|
CkDropZoneOverlayProps,
|
|
@@ -50,7 +57,7 @@ export type {
|
|
|
50
57
|
CkMarkdownRendererEmits,
|
|
51
58
|
CkMarkdownElementClasses,
|
|
52
59
|
} from './CkMarkdownRenderer';
|
|
53
|
-
export {
|
|
60
|
+
export { CkMessageButton } from './CkMessageButton';
|
|
54
61
|
export { CkModelSelector } from './CkModelSelector';
|
|
55
62
|
export type {
|
|
56
63
|
CkModelOption,
|
|
@@ -63,5 +70,6 @@ export type { CkPromptMenuButtonProps } from './CkPromptMenuButton';
|
|
|
63
70
|
export { CkPromptStopButton } from './CkPromptStopButton';
|
|
64
71
|
export { CkPromptInput } from './CkPromptInput';
|
|
65
72
|
export { CkPromptInputDisclaimer } from './CkPromptInputDisclaimer';
|
|
73
|
+
export { CkRegenerateMessageButton } from './CkRegenerateMessageButton';
|
|
66
74
|
export { CkUserMessage } from './CkUserMessage';
|
|
67
75
|
export type { CkUserMessageProps } from './CkUserMessage';
|
|
@@ -137,7 +137,7 @@ describe('CkConversation', () => {
|
|
|
137
137
|
});
|
|
138
138
|
|
|
139
139
|
expect(
|
|
140
|
-
screen.queryByTestId('ck-agent-message-icon'),
|
|
140
|
+
screen.queryByTestId('ck-agent-message-header-icon'),
|
|
141
141
|
).not.toBeInTheDocument();
|
|
142
142
|
});
|
|
143
143
|
|
|
@@ -146,7 +146,9 @@ describe('CkConversation', () => {
|
|
|
146
146
|
props: { messages: [agentMessage()], agentAvatarFallback: 'AI' },
|
|
147
147
|
});
|
|
148
148
|
|
|
149
|
-
expect(
|
|
149
|
+
expect(
|
|
150
|
+
screen.getByTestId('ck-agent-message-header-icon'),
|
|
151
|
+
).toBeInTheDocument();
|
|
150
152
|
});
|
|
151
153
|
|
|
152
154
|
it('shows the icon area when agentAvatarImage URL is provided', () => {
|
|
@@ -157,7 +159,9 @@ describe('CkConversation', () => {
|
|
|
157
159
|
},
|
|
158
160
|
});
|
|
159
161
|
|
|
160
|
-
expect(
|
|
162
|
+
expect(
|
|
163
|
+
screen.getByTestId('ck-agent-message-header-icon'),
|
|
164
|
+
).toBeInTheDocument();
|
|
161
165
|
});
|
|
162
166
|
|
|
163
167
|
it('shows the icon area when agent-message-icon slot is provided', () => {
|
|
@@ -169,7 +173,9 @@ describe('CkConversation', () => {
|
|
|
169
173
|
});
|
|
170
174
|
|
|
171
175
|
expect(screen.getByTestId('custom-icon')).toBeInTheDocument();
|
|
172
|
-
expect(
|
|
176
|
+
expect(
|
|
177
|
+
screen.getByTestId('ck-agent-message-header-icon'),
|
|
178
|
+
).toBeInTheDocument();
|
|
173
179
|
});
|
|
174
180
|
});
|
|
175
181
|
|
|
@@ -360,15 +366,44 @@ describe('CkConversation', () => {
|
|
|
360
366
|
expect(screen.getByAltText('custom-bot')).toBeInTheDocument();
|
|
361
367
|
});
|
|
362
368
|
|
|
363
|
-
it('allows
|
|
369
|
+
it('allows replacing the entire header via agent-message-header slot', () => {
|
|
370
|
+
render(CkConversation, {
|
|
371
|
+
// An avatar fallback would normally render the default header icon...
|
|
372
|
+
props: { messages: [agentMessage()], agentAvatarFallback: 'AI' },
|
|
373
|
+
slots: {
|
|
374
|
+
'agent-message-header':
|
|
375
|
+
'<div data-testid="custom-header">Custom Header</div>',
|
|
376
|
+
},
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
expect(screen.getByTestId('custom-header')).toBeInTheDocument();
|
|
380
|
+
// ...but the whole default header (and its icon) is replaced.
|
|
381
|
+
expect(
|
|
382
|
+
screen.queryByTestId('ck-agent-message-header-icon'),
|
|
383
|
+
).not.toBeInTheDocument();
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
it('allows setting the header text via agent-message-header-content slot', () => {
|
|
364
387
|
render(CkConversation, {
|
|
365
388
|
props: { messages: [agentMessage()] },
|
|
366
|
-
slots: { 'agent-message-header': 'Custom Header' },
|
|
389
|
+
slots: { 'agent-message-header-content': 'Custom Header' },
|
|
367
390
|
});
|
|
368
391
|
|
|
369
392
|
expect(screen.getByText('Custom Header')).toBeInTheDocument();
|
|
370
393
|
});
|
|
371
394
|
|
|
395
|
+
it('allows adding a header activity control via agent-message-header-activity slot', () => {
|
|
396
|
+
render(CkConversation, {
|
|
397
|
+
props: { messages: [agentMessage()] },
|
|
398
|
+
slots: {
|
|
399
|
+
'agent-message-header-activity':
|
|
400
|
+
'<button data-testid="activity">1 tool</button>',
|
|
401
|
+
},
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
expect(screen.getByTestId('activity')).toBeInTheDocument();
|
|
405
|
+
});
|
|
406
|
+
|
|
372
407
|
it('allows adding footer actions via agent-message-footer slot', () => {
|
|
373
408
|
render(CkConversation, {
|
|
374
409
|
props: { messages: [agentMessage()] },
|
|
@@ -429,6 +464,46 @@ describe('CkConversation', () => {
|
|
|
429
464
|
});
|
|
430
465
|
});
|
|
431
466
|
|
|
467
|
+
describe('bottom separator', () => {
|
|
468
|
+
function agentRowBorders(container: Element): boolean[] {
|
|
469
|
+
const rows = container.querySelectorAll<HTMLElement>(
|
|
470
|
+
'[data-message-row="assistant"]',
|
|
471
|
+
);
|
|
472
|
+
return Array.from(rows).map((row) => {
|
|
473
|
+
const message = row.querySelector<HTMLElement>('[class*="pb-6"]');
|
|
474
|
+
return Boolean(message?.className.includes('border-b'));
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
it('keeps the separator on every assistant message except the last', () => {
|
|
479
|
+
const { container } = render(CkConversation, {
|
|
480
|
+
props: {
|
|
481
|
+
messages: [
|
|
482
|
+
{ ...agentMessage(), id: 'a1' },
|
|
483
|
+
{
|
|
484
|
+
id: 'u1',
|
|
485
|
+
role: 'user',
|
|
486
|
+
content: [text('Hi')],
|
|
487
|
+
createdAt: now,
|
|
488
|
+
status: 'completed',
|
|
489
|
+
},
|
|
490
|
+
{ ...agentMessage(), id: 'a2' },
|
|
491
|
+
],
|
|
492
|
+
},
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
expect(agentRowBorders(container)).toEqual([true, false]);
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
it('hides the separator on the only assistant message', () => {
|
|
499
|
+
const { container } = render(CkConversation, {
|
|
500
|
+
props: { messages: [{ ...agentMessage(), id: 'solo' }] },
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
expect(agentRowBorders(container)).toEqual([false]);
|
|
504
|
+
});
|
|
505
|
+
});
|
|
506
|
+
|
|
432
507
|
describe('empty conversation', () => {
|
|
433
508
|
it('renders nothing when messages array is empty', () => {
|
|
434
509
|
const { container } = render(CkConversation, { props: { messages: [] } });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CkCopyMessageButton } from '../../base/CkCopyMessageButton';
|
|
2
2
|
import { CkFeedbackButton } from '../../base/CkFeedbackButton';
|
|
3
3
|
import type { CkFeedbackValue } from '../../base/CkFeedbackButton';
|
|
4
4
|
import type {
|
|
@@ -292,7 +292,7 @@ const withFooterActionsTemplateSource = `<script setup lang="ts">
|
|
|
292
292
|
import { ref } from 'vue';
|
|
293
293
|
import {
|
|
294
294
|
CkConversation,
|
|
295
|
-
|
|
295
|
+
CkCopyMessageButton,
|
|
296
296
|
CkFeedbackButton,
|
|
297
297
|
} from '@aleph-alpha/chat-kit';
|
|
298
298
|
import type { BaseMessage, CkFeedbackValue } from '@aleph-alpha/chat-kit';
|
|
@@ -315,7 +315,7 @@ function onFeedback(messageId: string, value: CkFeedbackValue) {
|
|
|
315
315
|
<template>
|
|
316
316
|
<CkConversation :messages="messages" agent-avatar-fallback="AI" style="height: 100%;">
|
|
317
317
|
<template #agent-message-footer="{ message }">
|
|
318
|
-
<
|
|
318
|
+
<CkCopyMessageButton :text="getMessageText(message)" />
|
|
319
319
|
<CkFeedbackButton
|
|
320
320
|
:value="feedback[message.id]?.value ?? null"
|
|
321
321
|
:locked="feedback[message.id]?.locked ?? false"
|
|
@@ -590,7 +590,7 @@ export const WithCustomIcon: Story = {
|
|
|
590
590
|
|
|
591
591
|
/**
|
|
592
592
|
* Overrides `#agent-message-footer` to add real action buttons next to each
|
|
593
|
-
* assistant reply: `
|
|
593
|
+
* assistant reply: `CkCopyMessageButton` for clipboard copy and
|
|
594
594
|
* `CkFeedbackButton` for binary thumbs up / thumbs down feedback. The
|
|
595
595
|
* feedback state is owned by the host and locked once submitted.
|
|
596
596
|
*/
|
|
@@ -598,7 +598,7 @@ export const WithFooterActions: Story = {
|
|
|
598
598
|
render: () => ({
|
|
599
599
|
components: {
|
|
600
600
|
CkConversation,
|
|
601
|
-
|
|
601
|
+
CkCopyMessageButton,
|
|
602
602
|
CkFeedbackButton,
|
|
603
603
|
},
|
|
604
604
|
setup() {
|
|
@@ -618,7 +618,7 @@ export const WithFooterActions: Story = {
|
|
|
618
618
|
template: `
|
|
619
619
|
<CkConversation :messages="messages" agent-avatar-fallback="AI" style="height: 100%;">
|
|
620
620
|
<template #agent-message-footer="{ message }">
|
|
621
|
-
<
|
|
621
|
+
<CkCopyMessageButton :text="getMessageText(message)" />
|
|
622
622
|
<CkFeedbackButton
|
|
623
623
|
:value="feedback[message.id]?.value ?? null"
|
|
624
624
|
:locked="feedback[message.id]?.locked ?? false"
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
import { useChatKitLabels } from '../../../handlers/useChatKitLabels';
|
|
3
3
|
import type { BaseMessage, MessageTextContent } from '../../../types';
|
|
4
4
|
import CkAgentMessage from '../../base/CkAgentMessage/CkAgentMessage.vue';
|
|
5
|
+
import CkAgentMessageHeader from '../../base/CkAgentMessageHeader/CkAgentMessageHeader.vue';
|
|
5
6
|
import CkConversationLayout from '../../base/CkConversationLayout/CkConversationLayout.vue';
|
|
6
|
-
import
|
|
7
|
+
import CkCopyMessageButton from '../../base/CkCopyMessageButton/CkCopyMessageButton.vue';
|
|
7
8
|
import CkMarkdownRenderer from '../../base/CkMarkdownRenderer/CkMarkdownRenderer.vue';
|
|
8
9
|
import CkUserMessage from '../../base/CkUserMessage/CkUserMessage.vue';
|
|
9
10
|
import type { CkConversationProps } from './types';
|
|
@@ -34,8 +35,16 @@ const slots = defineSlots<{
|
|
|
34
35
|
'agent-message-icon': (props: { message: BaseMessage }) => void;
|
|
35
36
|
/** Replace the agent loading icon shown while a message is being generated */
|
|
36
37
|
'agent-message-loading-icon': (props: { message: BaseMessage }) => void;
|
|
37
|
-
/** Replace the agent message header */
|
|
38
|
+
/** Replace the entire agent message header (the whole `CkAgentMessageHeader`) */
|
|
38
39
|
'agent-message-header': (props: { message: BaseMessage }) => void;
|
|
40
|
+
/** Replace the agent message header text (rendered inside the header row) */
|
|
41
|
+
'agent-message-header-content': (props: { message: BaseMessage }) => void;
|
|
42
|
+
/**
|
|
43
|
+
* Provide an activity control for the agent message header (rendered on the
|
|
44
|
+
* right of the header, typically a `CkHeaderActivityButton`). When provided,
|
|
45
|
+
* the header gains vertical padding and a bottom border.
|
|
46
|
+
*/
|
|
47
|
+
'agent-message-header-activity': (props: { message: BaseMessage }) => void;
|
|
39
48
|
/**
|
|
40
49
|
* Replace the agent message body. Receives the full `BaseMessage` so the
|
|
41
50
|
* consumer can inspect every content part (text, tool calls, reasoning)
|
|
@@ -64,6 +73,18 @@ const hasIcon = computed(
|
|
|
64
73
|
const isLoading = (message: BaseMessage) =>
|
|
65
74
|
message.status === 'started' || message.status === 'sending';
|
|
66
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Id of the last assistant message. Its bottom separator is hidden so the
|
|
78
|
+
* border divides user/assistant pairs without a trailing line after the final
|
|
79
|
+
* pair.
|
|
80
|
+
*/
|
|
81
|
+
const lastAgentMessageId = computed(() => {
|
|
82
|
+
for (let i = props.messages.length - 1; i >= 0; i--) {
|
|
83
|
+
if (props.messages[i].role !== 'user') return props.messages[i].id;
|
|
84
|
+
}
|
|
85
|
+
return undefined;
|
|
86
|
+
});
|
|
87
|
+
|
|
67
88
|
/** Concatenated text from every text content part in a message. */
|
|
68
89
|
function getMessageText(message: BaseMessage): string {
|
|
69
90
|
return message.content
|
|
@@ -89,42 +110,64 @@ function getMessageText(message: BaseMessage): string {
|
|
|
89
110
|
|
|
90
111
|
<template #agent-message="{ message }">
|
|
91
112
|
<slot name="agent-message" :message="message">
|
|
92
|
-
<CkAgentMessage>
|
|
93
|
-
<template
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
113
|
+
<CkAgentMessage :bottom-separator="message.id !== lastAgentMessageId">
|
|
114
|
+
<template
|
|
115
|
+
v-if="
|
|
116
|
+
hasIcon ||
|
|
117
|
+
$slots['agent-message-header'] ||
|
|
118
|
+
$slots['agent-message-header-content'] ||
|
|
119
|
+
$slots['agent-message-header-activity']
|
|
120
|
+
"
|
|
121
|
+
#header
|
|
122
|
+
>
|
|
123
|
+
<slot name="agent-message-header" :message="message">
|
|
124
|
+
<CkAgentMessageHeader>
|
|
125
|
+
<template v-if="hasIcon" #icon>
|
|
126
|
+
<template v-if="isLoading(message)">
|
|
127
|
+
<slot name="agent-message-loading-icon" :message="message">
|
|
128
|
+
<UiAvatar v-if="agentLoadingImage" class="size-8">
|
|
129
|
+
<UiAvatarImage
|
|
130
|
+
:src="agentLoadingImage"
|
|
131
|
+
:alt="labels.agentLoadingAvatarAlt"
|
|
132
|
+
/>
|
|
133
|
+
</UiAvatar>
|
|
134
|
+
<UiSpinner
|
|
135
|
+
v-else
|
|
136
|
+
class="size-8"
|
|
137
|
+
:aria-label="labels.agentLoadingAvatarAlt"
|
|
138
|
+
/>
|
|
139
|
+
</slot>
|
|
140
|
+
</template>
|
|
109
141
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
142
|
+
<template v-else>
|
|
143
|
+
<slot name="agent-message-icon" :message="message">
|
|
144
|
+
<UiAvatar class="size-8">
|
|
145
|
+
<UiAvatarImage
|
|
146
|
+
v-if="agentAvatarImage"
|
|
147
|
+
:src="agentAvatarImage"
|
|
148
|
+
:alt="labels.agentAvatarAlt"
|
|
149
|
+
/>
|
|
150
|
+
<UiAvatarFallback v-if="agentAvatarFallback">{{
|
|
151
|
+
agentAvatarFallback
|
|
152
|
+
}}</UiAvatarFallback>
|
|
153
|
+
</UiAvatar>
|
|
154
|
+
</slot>
|
|
155
|
+
</template>
|
|
156
|
+
</template>
|
|
157
|
+
|
|
158
|
+
<slot name="agent-message-header-content" :message="message" />
|
|
125
159
|
|
|
126
|
-
|
|
127
|
-
|
|
160
|
+
<template
|
|
161
|
+
v-if="$slots['agent-message-header-activity']"
|
|
162
|
+
#activity
|
|
163
|
+
>
|
|
164
|
+
<slot
|
|
165
|
+
name="agent-message-header-activity"
|
|
166
|
+
:message="message"
|
|
167
|
+
/>
|
|
168
|
+
</template>
|
|
169
|
+
</CkAgentMessageHeader>
|
|
170
|
+
</slot>
|
|
128
171
|
</template>
|
|
129
172
|
|
|
130
173
|
<slot name="agent-message-content" :message="message">
|
|
@@ -143,7 +186,7 @@ function getMessageText(message: BaseMessage): string {
|
|
|
143
186
|
|
|
144
187
|
<template #footer>
|
|
145
188
|
<slot name="agent-message-footer" :message="message">
|
|
146
|
-
<
|
|
189
|
+
<CkCopyMessageButton
|
|
147
190
|
v-if="getMessageText(message) && !isLoading(message)"
|
|
148
191
|
:text="getMessageText(message)"
|
|
149
192
|
:aria-label-copy="labels.copyMessageAction"
|
|
@@ -10,7 +10,7 @@ import type { CkMarkdownElementClasses } from '../../base/CkMarkdownRenderer';
|
|
|
10
10
|
* @category Messages
|
|
11
11
|
* @useCases complete chat conversation ui, streaming chat with markdown, assistant chat view, llm conversation component, drop-in chat surface
|
|
12
12
|
* @keywords conversation, chat, messages, assistant, agent, user, markdown, streaming, avatar
|
|
13
|
-
* @related CkConversationLayout, CkAgentMessage, CkUserMessage, CkMarkdownRenderer,
|
|
13
|
+
* @related CkConversationLayout, CkAgentMessage, CkUserMessage, CkMarkdownRenderer, CkCopyMessageButton, CkPromptInput
|
|
14
14
|
*/
|
|
15
15
|
export interface CkConversationProps {
|
|
16
16
|
/** List of messages to display, in chronological order. */
|
package/src/components/index.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
// Base (presentational) components
|
|
2
2
|
export {
|
|
3
3
|
CkAgentMessage,
|
|
4
|
+
CkAgentMessageHeader,
|
|
5
|
+
CkHeaderActivityButton,
|
|
4
6
|
CkCitation,
|
|
5
7
|
CkCitationCard,
|
|
6
8
|
CkConversationLayout,
|
|
7
|
-
|
|
9
|
+
CkCopyMessageButton,
|
|
8
10
|
CkDropZoneOverlay,
|
|
9
11
|
CkFeedbackButton,
|
|
10
12
|
CkFeedbackDialog,
|
|
@@ -12,18 +14,22 @@ export {
|
|
|
12
14
|
CkHistoryItem,
|
|
13
15
|
CkHistoryWrapper,
|
|
14
16
|
CkMarkdownRenderer,
|
|
15
|
-
|
|
17
|
+
CkMessageButton,
|
|
16
18
|
CkModelSelector,
|
|
17
19
|
CkPromptSendButton,
|
|
18
20
|
CkPromptMenuButton,
|
|
19
21
|
CkPromptStopButton,
|
|
20
22
|
CkPromptInput,
|
|
21
23
|
CkPromptInputDisclaimer,
|
|
24
|
+
CkRegenerateMessageButton,
|
|
22
25
|
CkSendIcon,
|
|
23
26
|
CkStopIcon,
|
|
24
27
|
CkUserMessage,
|
|
25
28
|
} from './base';
|
|
26
29
|
export type {
|
|
30
|
+
CkAgentMessageHeaderProps,
|
|
31
|
+
CkHeaderActivityButtonProps,
|
|
32
|
+
CkHeaderActivityButtonEmits,
|
|
27
33
|
CkCitationProps,
|
|
28
34
|
CkCitationEmits,
|
|
29
35
|
CkCitationSource,
|
|
@@ -58,7 +64,7 @@ export type {
|
|
|
58
64
|
} from './base';
|
|
59
65
|
|
|
60
66
|
// Composed (pattern) components
|
|
61
|
-
export { CkConversation, CkHistory
|
|
67
|
+
export { CkConversation, CkHistory } from './composed';
|
|
62
68
|
export type {
|
|
63
69
|
CkConversationProps,
|
|
64
70
|
CkHistoryEmits,
|
|
@@ -102,6 +102,7 @@ describe('useChatKitLabels', () => {
|
|
|
102
102
|
inputPlaceholder: 'Custom placeholder',
|
|
103
103
|
copyMessageAction: 'Custom copy',
|
|
104
104
|
copyMessageActionCopied: 'Custom copied',
|
|
105
|
+
regenerateMessageAction: 'Custom regenerate',
|
|
105
106
|
feedbackThumbsUp: 'Custom up',
|
|
106
107
|
feedbackThumbsDown: 'Custom down',
|
|
107
108
|
feedbackGroup: 'Custom group',
|
|
@@ -29,6 +29,8 @@ export type ChatKitLabels = {
|
|
|
29
29
|
copyMessageAction: string;
|
|
30
30
|
/** Accessible label / tooltip for the copy-message action button after a successful copy */
|
|
31
31
|
copyMessageActionCopied: string;
|
|
32
|
+
/** Accessible label / tooltip for the regenerate-message action button */
|
|
33
|
+
regenerateMessageAction: string;
|
|
32
34
|
/**
|
|
33
35
|
* Accessible label / tooltip for the thumbs-up button in `CkFeedbackButton`.
|
|
34
36
|
* Optional for backward compatibility; falls back to
|
|
@@ -114,6 +116,7 @@ export const defaultChatKitLabels: ChatKitLabels = {
|
|
|
114
116
|
inputPlaceholder: 'Type a message...',
|
|
115
117
|
copyMessageAction: 'Copy response',
|
|
116
118
|
copyMessageActionCopied: 'Copied!',
|
|
119
|
+
regenerateMessageAction: 'Regenerate response',
|
|
117
120
|
feedbackThumbsUp: 'Good response',
|
|
118
121
|
feedbackThumbsDown: 'Bad response',
|
|
119
122
|
feedbackGroup: 'Rate this response',
|
|
@@ -146,6 +146,36 @@ describe('useMessageHandler', () => {
|
|
|
146
146
|
expect('metadata' in msg).toBe(false);
|
|
147
147
|
expect('metadata' in handler.messages.value[0]).toBe(false);
|
|
148
148
|
});
|
|
149
|
+
|
|
150
|
+
it('branches off an explicit parentId, updating the parent and activating the new branch', () => {
|
|
151
|
+
const handler = useMessageHandler();
|
|
152
|
+
|
|
153
|
+
handler.setCurrentUserMessage('First');
|
|
154
|
+
const first = handler.commitUserMessage();
|
|
155
|
+
handler.setCurrentUserMessage('Second');
|
|
156
|
+
const second = handler.commitUserMessage();
|
|
157
|
+
|
|
158
|
+
// Branch a sibling of `second` off their shared parent `first`.
|
|
159
|
+
handler.setCurrentUserMessage('Sibling');
|
|
160
|
+
const sibling = handler.commitUserMessage({ parentId: first.id });
|
|
161
|
+
|
|
162
|
+
const parent = handler.getTree().nodes[first.id];
|
|
163
|
+
expect(parent.childrenIds).toEqual([second.id, sibling.id]);
|
|
164
|
+
// The freshly created branch becomes the active path.
|
|
165
|
+
expect(parent.activeChildIndex).toBe(1);
|
|
166
|
+
expect(handler.messages.value.map((m) => m.id)).toEqual([
|
|
167
|
+
first.id,
|
|
168
|
+
sibling.id,
|
|
169
|
+
]);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('throws when branching off an unknown parentId', () => {
|
|
173
|
+
const handler = useMessageHandler();
|
|
174
|
+
handler.setCurrentUserMessage('Hello');
|
|
175
|
+
expect(() =>
|
|
176
|
+
handler.commitUserMessage({ parentId: 'does-not-exist' }),
|
|
177
|
+
).toThrow('Unknown parent message id: does-not-exist');
|
|
178
|
+
});
|
|
149
179
|
});
|
|
150
180
|
|
|
151
181
|
describe('updateMessage', () => {
|
|
@@ -342,6 +372,55 @@ describe('useMessageHandler', () => {
|
|
|
342
372
|
expect(handler.messages.value).toHaveLength(2);
|
|
343
373
|
expect(getText(handler.messages.value[1].content)).toBe('Streaming...');
|
|
344
374
|
});
|
|
375
|
+
|
|
376
|
+
it('branches a new node off an explicit parentId on create', () => {
|
|
377
|
+
const handler = useMessageHandler();
|
|
378
|
+
handler.setTree(
|
|
379
|
+
makeTree(
|
|
380
|
+
{
|
|
381
|
+
u1: makeTreeMessage({ id: 'u1', content: [text('Hello')] }),
|
|
382
|
+
a1: makeTreeMessage({
|
|
383
|
+
id: 'a1',
|
|
384
|
+
parentId: 'u1',
|
|
385
|
+
role: 'assistant',
|
|
386
|
+
content: [text('Hi')],
|
|
387
|
+
}),
|
|
388
|
+
},
|
|
389
|
+
'u1',
|
|
390
|
+
),
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
// Regenerate: add a sibling assistant answer under the same user turn.
|
|
394
|
+
handler.updateMessage({
|
|
395
|
+
id: 'a2',
|
|
396
|
+
content: [text('Hi again')],
|
|
397
|
+
role: 'assistant',
|
|
398
|
+
status: 'completed',
|
|
399
|
+
parentId: 'u1',
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
const parent = handler.getTree().nodes.u1;
|
|
403
|
+
expect(parent.childrenIds).toEqual(['a1', 'a2']);
|
|
404
|
+
expect(parent.activeChildIndex).toBe(1);
|
|
405
|
+
expect(handler.messages.value.map((m) => m.id)).toEqual(['u1', 'a2']);
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it('ignores parentId when the node already exists', () => {
|
|
409
|
+
const handler = useMessageHandler();
|
|
410
|
+
handler.setCurrentUserMessage('Hello');
|
|
411
|
+
const msg = handler.commitUserMessage();
|
|
412
|
+
|
|
413
|
+
handler.updateMessage({
|
|
414
|
+
id: msg.id,
|
|
415
|
+
content: [text('Updated')],
|
|
416
|
+
role: 'user',
|
|
417
|
+
status: 'completed',
|
|
418
|
+
parentId: 'does-not-exist',
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
expect(getText(handler.getMessageById(msg.id)!.content)).toBe('Updated');
|
|
422
|
+
expect(handler.getTree().nodes[msg.id].parentId).toBeNull();
|
|
423
|
+
});
|
|
345
424
|
});
|
|
346
425
|
|
|
347
426
|
describe('getMessageById', () => {
|