@aleph-alpha/chat-kit 5.11.0 → 5.13.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/{CkHistory.vue_vue_type_script_setup_true_lang-SL1vOAd9.js → CkHistory.vue_vue_type_script_setup_true_lang-BNcJURkq.js} +216 -87
- package/dist/chat-kit.css +13 -13
- package/dist/components/base/CkCitation/CkCitation.stories.d.ts +1 -4
- 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/CkCitation/types.d.ts +6 -1
- package/dist/components/base/CkCitation/types.d.ts.map +1 -1
- package/dist/components/base/CkCitationCard/CkCitationCard.stories.d.ts +13 -2
- package/dist/components/base/CkCitationCard/CkCitationCard.stories.d.ts.map +1 -1
- package/dist/components/base/CkCitationCard/CkCitationCard.vue.d.ts +1 -0
- package/dist/components/base/CkCitationCard/CkCitationCard.vue.d.ts.map +1 -1
- package/dist/components/base/CkCitationCard/types.d.ts +6 -1
- package/dist/components/base/CkCitationCard/types.d.ts.map +1 -1
- package/dist/components/base/CkCitationLabel/CkCitationLabel.stories.d.ts +39 -0
- package/dist/components/base/CkCitationLabel/CkCitationLabel.stories.d.ts.map +1 -0
- package/dist/components/base/CkCitationLabel/CkCitationLabel.vue.d.ts +9 -0
- package/dist/components/base/CkCitationLabel/CkCitationLabel.vue.d.ts.map +1 -0
- package/dist/components/base/CkCitationLabel/index.d.ts +3 -0
- package/dist/components/base/CkCitationLabel/index.d.ts.map +1 -0
- package/dist/components/base/CkCitationLabel/types.d.ts +44 -0
- package/dist/components/base/CkCitationLabel/types.d.ts.map +1 -0
- package/dist/components/base/CkFeedbackDialog/CkFeedbackDialog.stories.d.ts +7 -0
- package/dist/components/base/CkFeedbackDialog/CkFeedbackDialog.stories.d.ts.map +1 -1
- package/dist/components/base/CkFeedbackDialog/CkFeedbackDialog.vue.d.ts +2 -2
- package/dist/components/base/CkFeedbackDialog/CkFeedbackDialog.vue.d.ts.map +1 -1
- package/dist/components/base/CkFeedbackDialog/types.d.ts +19 -0
- package/dist/components/base/CkFeedbackDialog/types.d.ts.map +1 -1
- package/dist/components/base/CkFileItemsList/CkFileItemsList.vue.d.ts +1 -1
- package/dist/components/base/CkUserMessage/CkUserMessage.vue.d.ts.map +1 -1
- package/dist/components/base/index.d.ts +2 -0
- package/dist/components/base/index.d.ts.map +1 -1
- package/dist/components/composed/CkConversation/CkConversation.stories.d.ts +12 -0
- package/dist/components/composed/CkConversation/CkConversation.stories.d.ts.map +1 -1
- package/dist/components/index.d.ts +2 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +28 -27
- package/dist/composables/useIsTruncated.d.ts +22 -0
- package/dist/composables/useIsTruncated.d.ts.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -28
- package/dist/types.d.ts +33 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/components/base/CkCitation/CkCitation.spec.ts +14 -3
- package/src/components/base/CkCitation/CkCitation.stories.ts +85 -3
- package/src/components/base/CkCitation/CkCitation.vue +13 -36
- package/src/components/base/CkCitation/types.ts +6 -1
- package/src/components/base/CkCitationCard/CkCitationCard.spec.ts +37 -0
- package/src/components/base/CkCitationCard/CkCitationCard.stories.ts +30 -3
- package/src/components/base/CkCitationCard/CkCitationCard.vue +53 -11
- package/src/components/base/CkCitationCard/types.ts +6 -1
- package/src/components/base/CkCitationLabel/CkCitationLabel.spec.ts +73 -0
- package/src/components/base/CkCitationLabel/CkCitationLabel.stories.ts +86 -0
- package/src/components/base/CkCitationLabel/CkCitationLabel.vue +70 -0
- package/src/components/base/CkCitationLabel/index.ts +2 -0
- package/src/components/base/CkCitationLabel/types.ts +43 -0
- package/src/components/base/CkFeedbackDialog/CkFeedbackDialog.spec.ts +36 -0
- package/src/components/base/CkFeedbackDialog/CkFeedbackDialog.stories.ts +42 -0
- package/src/components/base/CkFeedbackDialog/CkFeedbackDialog.vue +11 -1
- package/src/components/base/CkFeedbackDialog/types.ts +20 -0
- package/src/components/base/CkUserMessage/CkUserMessage.vue +1 -1
- package/src/components/base/index.ts +2 -0
- package/src/components/composed/CkConversation/CkConversation.spec.ts +65 -2
- package/src/components/composed/CkConversation/CkConversation.stories.ts +136 -0
- package/src/components/index.ts +2 -0
- package/src/composables/useIsTruncated.ts +82 -0
- package/src/index.ts +2 -0
- package/src/types.ts +34 -4
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { CkCitationSource } from '../../base/CkCitation';
|
|
2
|
+
import { CkMarkdownRenderer } from '../../base/CkMarkdownRenderer';
|
|
1
3
|
import { CkCopyMessageButton } from '../../base/CkCopyMessageButton';
|
|
2
4
|
import { CkFeedbackButton } from '../../base/CkFeedbackButton';
|
|
3
5
|
import type { CkFeedbackValue } from '../../base/CkFeedbackButton';
|
|
@@ -65,6 +67,53 @@ const markdownContent = [
|
|
|
65
67
|
'| Feedback Integration | Planned | High |',
|
|
66
68
|
].join('\n');
|
|
67
69
|
|
|
70
|
+
const citedAnswer = [
|
|
71
|
+
'Based on a review of internal documents, the rollout produced two measurable effects:',
|
|
72
|
+
'',
|
|
73
|
+
'- **Adoption:** Departments that received customized training saw a **25% higher adoption rate** of the new tools than those with generic training.[1]',
|
|
74
|
+
'- **Rework:** A lack of initial stakeholder engagement led to significant process rework during the first wave.[2]',
|
|
75
|
+
'',
|
|
76
|
+
'Both findings are consistent across the quarterly reviews.[1][2]',
|
|
77
|
+
].join('\n');
|
|
78
|
+
|
|
79
|
+
/** One entry per `[n]` reference in `citedAnswer`, keyed by `index`. */
|
|
80
|
+
const citations: CkCitationSource[] = [
|
|
81
|
+
{
|
|
82
|
+
index: 1,
|
|
83
|
+
fileName: 'Q2_Business_Plan.pdf',
|
|
84
|
+
snippet:
|
|
85
|
+
'Departments that received customized training saw a 25% higher adoption rate of the new tools compared to those with generic training.',
|
|
86
|
+
locationLabel: 'Page 3',
|
|
87
|
+
url: '/api/v1/search-stores/ss_abc/files/file_123/public-urls',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
index: 2,
|
|
91
|
+
fileName: 'Goal-planning-26.pdf',
|
|
92
|
+
snippet:
|
|
93
|
+
'Early stakeholder involvement remains the single strongest predictor of a rollout that does not require process rework.',
|
|
94
|
+
locationLabel: 'Page 12',
|
|
95
|
+
},
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
const citedMessages: BaseMessage[] = [
|
|
99
|
+
{
|
|
100
|
+
id: 'c1',
|
|
101
|
+
role: 'user',
|
|
102
|
+
content: [
|
|
103
|
+
text('What did we learn from the Digital Transformation rollout?'),
|
|
104
|
+
],
|
|
105
|
+
createdAt: now,
|
|
106
|
+
status: 'completed',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
id: 'c2',
|
|
110
|
+
role: 'assistant',
|
|
111
|
+
content: [text(citedAnswer)],
|
|
112
|
+
createdAt: now,
|
|
113
|
+
status: 'completed',
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
|
|
68
117
|
const sampleMessages: BaseMessage[] = [
|
|
69
118
|
{
|
|
70
119
|
id: '1',
|
|
@@ -384,6 +433,51 @@ function getMessageText(message: BaseMessage): string {
|
|
|
384
433
|
</CkConversation>
|
|
385
434
|
</template>`;
|
|
386
435
|
|
|
436
|
+
const withCitationsTemplateSource = `<script setup lang="ts">
|
|
437
|
+
import { CkConversation, CkMarkdownRenderer } from '@aleph-alpha/chat-kit';
|
|
438
|
+
import type { BaseMessage, CkCitationSource } from '@aleph-alpha/chat-kit';
|
|
439
|
+
|
|
440
|
+
const messages: BaseMessage[] = [/* ... */];
|
|
441
|
+
|
|
442
|
+
// One entry per \`[n]\` reference in the answer, keyed by \`index\`. Keep the
|
|
443
|
+
// array reference stable so the markdown processor isn't rebuilt on every
|
|
444
|
+
// render.
|
|
445
|
+
const citations: CkCitationSource[] = [
|
|
446
|
+
{
|
|
447
|
+
index: 1,
|
|
448
|
+
fileName: 'Q2_Business_Plan.pdf',
|
|
449
|
+
snippet: 'Departments that received customized training saw a 25% higher adoption rate.',
|
|
450
|
+
locationLabel: 'Page 3',
|
|
451
|
+
url: '/api/v1/search-stores/ss_abc/files/file_123/public-urls',
|
|
452
|
+
},
|
|
453
|
+
];
|
|
454
|
+
|
|
455
|
+
function getMessageText(message: BaseMessage): string {
|
|
456
|
+
return message.content
|
|
457
|
+
.filter((c) => c.type === 'text')
|
|
458
|
+
.map((c) => c.text)
|
|
459
|
+
.join('');
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// The card's external-link action is only a request — the host performs the
|
|
463
|
+
// (often auth-proxied) navigation.
|
|
464
|
+
function openSource(url: string): void {
|
|
465
|
+
window.open(url, '_blank', 'noopener');
|
|
466
|
+
}
|
|
467
|
+
</script>
|
|
468
|
+
|
|
469
|
+
<template>
|
|
470
|
+
<CkConversation :messages="messages" agent-avatar-fallback="AI" style="height: 100%;">
|
|
471
|
+
<template #agent-message-content="{ message }">
|
|
472
|
+
<CkMarkdownRenderer
|
|
473
|
+
:content="getMessageText(message)"
|
|
474
|
+
:citations="citations"
|
|
475
|
+
@open-source="openSource"
|
|
476
|
+
/>
|
|
477
|
+
</template>
|
|
478
|
+
</CkConversation>
|
|
479
|
+
</template>`;
|
|
480
|
+
|
|
387
481
|
const streamingSimulationTemplateSource = `<script setup lang="ts">
|
|
388
482
|
import { CkConversation } from '@aleph-alpha/chat-kit';
|
|
389
483
|
import type { BaseMessage } from '@aleph-alpha/chat-kit';
|
|
@@ -910,6 +1004,48 @@ export const WithCustomAgentContent: Story = {
|
|
|
910
1004
|
},
|
|
911
1005
|
};
|
|
912
1006
|
|
|
1007
|
+
/**
|
|
1008
|
+
* Citations are opt-in: override `#agent-message-content` and hand the message's
|
|
1009
|
+
* sources to `CkMarkdownRenderer`. Every `[n]` in the answer whose number
|
|
1010
|
+
* matches a source's `index` becomes a marker that reveals the source on hover
|
|
1011
|
+
* or keyboard activation; unmatched markers stay plain text. `open-source` is
|
|
1012
|
+
* re-emitted for the host to perform the (often auth-proxied) navigation — the
|
|
1013
|
+
* second source here has no `url`, so its card omits the action.
|
|
1014
|
+
*
|
|
1015
|
+
* The footer copy button is unaffected: it copies the message text, so the
|
|
1016
|
+
* `[n]` references travel with a pasted answer.
|
|
1017
|
+
*/
|
|
1018
|
+
export const WithCitations: Story = {
|
|
1019
|
+
render: () => ({
|
|
1020
|
+
components: { CkConversation, CkMarkdownRenderer },
|
|
1021
|
+
setup() {
|
|
1022
|
+
function openSource(url: string) {
|
|
1023
|
+
window.open(url, '_blank', 'noopener');
|
|
1024
|
+
}
|
|
1025
|
+
return {
|
|
1026
|
+
messages: citedMessages,
|
|
1027
|
+
citations,
|
|
1028
|
+
getMessageText,
|
|
1029
|
+
openSource,
|
|
1030
|
+
};
|
|
1031
|
+
},
|
|
1032
|
+
template: `
|
|
1033
|
+
<CkConversation :messages="messages" agent-avatar-fallback="AI" style="height: 100%;">
|
|
1034
|
+
<template #agent-message-content="{ message }">
|
|
1035
|
+
<CkMarkdownRenderer
|
|
1036
|
+
:content="getMessageText(message)"
|
|
1037
|
+
:citations="citations"
|
|
1038
|
+
@open-source="openSource"
|
|
1039
|
+
/>
|
|
1040
|
+
</template>
|
|
1041
|
+
</CkConversation>
|
|
1042
|
+
`,
|
|
1043
|
+
}),
|
|
1044
|
+
parameters: {
|
|
1045
|
+
docs: { source: { code: withCitationsTemplateSource } },
|
|
1046
|
+
},
|
|
1047
|
+
};
|
|
1048
|
+
|
|
913
1049
|
/**
|
|
914
1050
|
* End-to-end streaming scenario: appending a new user message and then
|
|
915
1051
|
* streaming an assistant reply chunk-by-chunk. Use as a reference for wiring
|
package/src/components/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ export {
|
|
|
4
4
|
CkAgentMessageHeader,
|
|
5
5
|
CkHeaderActivityButton,
|
|
6
6
|
CkCitation,
|
|
7
|
+
CkCitationLabel,
|
|
7
8
|
CkCitationCard,
|
|
8
9
|
CkConversationLayout,
|
|
9
10
|
CkCopyMessageButton,
|
|
@@ -34,6 +35,7 @@ export type {
|
|
|
34
35
|
CkCitationProps,
|
|
35
36
|
CkCitationEmits,
|
|
36
37
|
CkCitationSource,
|
|
38
|
+
CkCitationLabelProps,
|
|
37
39
|
CkCitationCardProps,
|
|
38
40
|
CkCitationCardEmits,
|
|
39
41
|
CkConversationLayoutProps,
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local copy of ui-library's internal probe of the same name. chat-kit's
|
|
3
|
+
* supported ui-library range (^5.3.0) does not export it, and it is too small
|
|
4
|
+
* to justify widening that package's public API. Drop this file once the range
|
|
5
|
+
* moves up to a version that exports it.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { onScopeDispose, ref, watch, type Ref, type ShallowRef } from 'vue';
|
|
9
|
+
|
|
10
|
+
/** An element ref as produced by `useTemplateRef`. */
|
|
11
|
+
type ElementRef = Readonly<ShallowRef<HTMLElement | null>>;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* One observer for every caller. `ResizeObserver` is built to watch many
|
|
15
|
+
* targets and delivers them in a single batched callback, so a list of rows
|
|
16
|
+
* costs one callback and one layout pass rather than one per row. Created
|
|
17
|
+
* lazily so importing this module never touches the DOM.
|
|
18
|
+
*/
|
|
19
|
+
const measurers = new WeakMap<Element, () => void>();
|
|
20
|
+
let sharedObserver: ResizeObserver | undefined;
|
|
21
|
+
|
|
22
|
+
function getSharedObserver(): ResizeObserver | undefined {
|
|
23
|
+
if (typeof ResizeObserver === 'undefined') return undefined;
|
|
24
|
+
sharedObserver ??= new ResizeObserver((entries) => {
|
|
25
|
+
for (const entry of entries) measurers.get(entry.target)?.();
|
|
26
|
+
});
|
|
27
|
+
return sharedObserver;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function watchElement(el: Element, measure: () => void): void {
|
|
31
|
+
measurers.set(el, measure);
|
|
32
|
+
getSharedObserver()?.observe(el);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function unwatchElement(el: Element): void {
|
|
36
|
+
measurers.delete(el);
|
|
37
|
+
getSharedObserver()?.unobserve(el);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Whether an element's text is currently clipped by `text-overflow: ellipsis`.
|
|
42
|
+
*
|
|
43
|
+
* Re-measures when the element resizes and whenever `watchSource` changes, so
|
|
44
|
+
* it stays correct as the container narrows or the text is swapped out. Use it
|
|
45
|
+
* to show a tooltip only for names that are actually cut off.
|
|
46
|
+
* @param elementRef - The element whose text may be clipped
|
|
47
|
+
* @param watchSource - Value to re-measure on, e.g. the rendered text
|
|
48
|
+
* @returns Reactive truncation state
|
|
49
|
+
*/
|
|
50
|
+
export function useIsTruncated(
|
|
51
|
+
elementRef: ElementRef,
|
|
52
|
+
watchSource?: () => unknown,
|
|
53
|
+
): Ref<boolean> {
|
|
54
|
+
const isTruncated = ref(false);
|
|
55
|
+
|
|
56
|
+
function measure(): void {
|
|
57
|
+
const el = elementRef.value;
|
|
58
|
+
// Sub-pixel widths round differently per browser, so require a whole
|
|
59
|
+
// pixel of overflow before calling it truncated.
|
|
60
|
+
isTruncated.value = el ? el.scrollWidth - el.clientWidth >= 1 : false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// A resize alone doesn't cover a text swap that keeps the box the same size.
|
|
64
|
+
if (watchSource) watch(watchSource, measure, { flush: 'post' });
|
|
65
|
+
|
|
66
|
+
// Runs on mount too, when the template ref goes null -> element.
|
|
67
|
+
watch(
|
|
68
|
+
elementRef,
|
|
69
|
+
(el, previous) => {
|
|
70
|
+
if (previous) unwatchElement(previous);
|
|
71
|
+
if (el) watchElement(el, measure);
|
|
72
|
+
measure();
|
|
73
|
+
},
|
|
74
|
+
{ immediate: true, flush: 'post' },
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
onScopeDispose(() => {
|
|
78
|
+
if (elementRef.value) unwatchElement(elementRef.value);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return isTruncated;
|
|
82
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -74,6 +74,7 @@ export {
|
|
|
74
74
|
CkAgentMessageHeader,
|
|
75
75
|
CkHeaderActivityButton,
|
|
76
76
|
CkCitation,
|
|
77
|
+
CkCitationLabel,
|
|
77
78
|
CkCitationCard,
|
|
78
79
|
CkConversation,
|
|
79
80
|
CkConversationLayout,
|
|
@@ -106,6 +107,7 @@ export type {
|
|
|
106
107
|
CkCitationProps,
|
|
107
108
|
CkCitationEmits,
|
|
108
109
|
CkCitationSource,
|
|
110
|
+
CkCitationLabelProps,
|
|
109
111
|
CkCitationCardProps,
|
|
110
112
|
CkCitationCardEmits,
|
|
111
113
|
CkConversationLayoutProps,
|
package/src/types.ts
CHANGED
|
@@ -68,6 +68,36 @@ export type MessageContent =
|
|
|
68
68
|
| MessageToolContent
|
|
69
69
|
| MessageReasoningContent;
|
|
70
70
|
|
|
71
|
+
declare global {
|
|
72
|
+
/**
|
|
73
|
+
* Extension point for {@link MessageMetadata}. Consumers declare their
|
|
74
|
+
* well-known metadata keys here and get them typed on every message,
|
|
75
|
+
* without chat-kit knowing what any of them mean:
|
|
76
|
+
*
|
|
77
|
+
* ```ts
|
|
78
|
+
* // app/src/types/chat-kit.d.ts
|
|
79
|
+
* declare global {
|
|
80
|
+
* interface ChatKitMessageMetadata {
|
|
81
|
+
* responseId?: string;
|
|
82
|
+
* citations?: CitationManifest;
|
|
83
|
+
* }
|
|
84
|
+
* }
|
|
85
|
+
* export {};
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* Declare every key **optional**: chat-kit itself never populates them, and
|
|
89
|
+
* a message can reach a consumer before its host has stamped anything (mid
|
|
90
|
+
* stream, or on an optimistic node).
|
|
91
|
+
*
|
|
92
|
+
* This is a `declare global` interface rather than a module augmentation
|
|
93
|
+
* because `MessageMetadata` is re-exported through the package barrel —
|
|
94
|
+
* `declare module '@aleph-alpha/chat-kit'` does not merge across a
|
|
95
|
+
* re-export, and would silently type nothing.
|
|
96
|
+
*/
|
|
97
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
98
|
+
interface ChatKitMessageMetadata {}
|
|
99
|
+
}
|
|
100
|
+
|
|
71
101
|
/**
|
|
72
102
|
* Open-ended metadata bag carried alongside a message. chat-kit is
|
|
73
103
|
* intentionally agnostic about its contents — adapter authors
|
|
@@ -75,11 +105,11 @@ export type MessageContent =
|
|
|
75
105
|
* through the tree → linear path projection, but never inspect it.
|
|
76
106
|
*
|
|
77
107
|
* Consumers attach their own well-known keys (attachments, citations,
|
|
78
|
-
* ratings, …)
|
|
79
|
-
*
|
|
80
|
-
*
|
|
108
|
+
* ratings, …). Declaring them on {@link ChatKitMessageMetadata} types those
|
|
109
|
+
* reads everywhere; the retained index signature keeps any other key legal,
|
|
110
|
+
* so the handler API stays stable as the stored shape evolves.
|
|
81
111
|
*/
|
|
82
|
-
export type MessageMetadata = Record<string, unknown>;
|
|
112
|
+
export type MessageMetadata = ChatKitMessageMetadata & Record<string, unknown>;
|
|
83
113
|
|
|
84
114
|
export interface BaseMessage {
|
|
85
115
|
id: string;
|