@aleph-alpha/chat-kit 1.11.1 → 1.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/{CkInput.vue_vue_type_script_setup_true_lang-C1Jnn1fK.js → CkInput.vue_vue_type_script_setup_true_lang-DCZTSiBj.js} +371 -135
- package/dist/adapters/responses-api.d.ts +54 -5
- package/dist/adapters/responses-api.d.ts.map +1 -1
- package/dist/adapters/responses-api.js +43 -9
- package/dist/chat-kit.css +19 -0
- package/dist/components/base/CkFeedbackDialog/CkFeedbackDialog.stories.d.ts +30 -0
- package/dist/components/base/CkFeedbackDialog/CkFeedbackDialog.stories.d.ts.map +1 -0
- package/dist/components/base/CkFeedbackDialog/CkFeedbackDialog.vue.d.ts +13 -0
- package/dist/components/base/CkFeedbackDialog/CkFeedbackDialog.vue.d.ts.map +1 -0
- package/dist/components/base/CkFeedbackDialog/index.d.ts +3 -0
- package/dist/components/base/CkFeedbackDialog/index.d.ts.map +1 -0
- package/dist/components/base/CkFeedbackDialog/types.d.ts +152 -0
- package/dist/components/base/CkFeedbackDialog/types.d.ts.map +1 -0
- package/dist/components/base/index.d.ts +2 -0
- package/dist/components/base/index.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 +16 -15
- package/dist/composables/index.js +1 -1
- package/dist/handlers/index.js +2 -2
- package/dist/handlers/useChatKitLabels.d.ts +18 -0
- package/dist/handlers/useChatKitLabels.d.ts.map +1 -1
- package/dist/handlers/useMessageHandler.d.ts +6 -2
- package/dist/handlers/useMessageHandler.d.ts.map +1 -1
- package/dist/helpers/conversationTree.d.ts +10 -1
- package/dist/helpers/conversationTree.d.ts.map +1 -1
- package/dist/{index-BLq6_Lt2.js → index-Ct5hD214.js} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -18
- package/dist/types.d.ts +14 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/{useChatKitLabels-ftC52m7f.js → useChatKitLabels-DeHxZG2a.js} +9 -0
- package/dist/{useMessageHandler-ZRC-gIOJ.js → useMessageHandler-CMdy-lm0.js} +36 -9
- package/package.json +5 -5
- package/src/adapters/responses-api.spec.ts +70 -0
- package/src/adapters/responses-api.ts +123 -12
- package/src/components/base/CkFeedbackDialog/CkFeedbackDialog.spec.ts +177 -0
- package/src/components/base/CkFeedbackDialog/CkFeedbackDialog.stories.ts +258 -0
- package/src/components/base/CkFeedbackDialog/CkFeedbackDialog.vue +288 -0
- package/src/components/base/CkFeedbackDialog/index.ts +2 -0
- package/src/components/base/CkFeedbackDialog/types.ts +155 -0
- package/src/components/base/index.ts +8 -0
- package/src/components/index.ts +6 -0
- package/src/handlers/useChatKitLabels.spec.ts +11 -0
- package/src/handlers/useChatKitLabels.ts +29 -0
- package/src/handlers/useMessageHandler.spec.ts +214 -0
- package/src/handlers/useMessageHandler.ts +28 -3
- package/src/helpers/conversationTree.spec.ts +134 -0
- package/src/helpers/conversationTree.ts +32 -1
- package/src/index.ts +7 -0
- package/src/types.ts +15 -0
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { useChat, useConversationSessions, useConversations, } from './composabl
|
|
|
5
5
|
export type { ChatActions, ChatState, ConversationSession, CreateConversationInput, MessageHandler, MutationOptions, UseChatReturn, UseConversationSessionsReturn, UseConversationsOptions, UseConversationsReturn, } from './composables';
|
|
6
6
|
export { SdkError, createDocumentUploadProvider, defaultDocumentUploadConfig, defaultEndpoints, useDocumentUploadWithDefaultConfig, } from './composables/fileUpload';
|
|
7
7
|
export type { DocumentUploadConfig, DocumentUploadProvider, FileEntry, FileStatus, } from './composables/fileUpload';
|
|
8
|
-
export { CkAgentMessage, CkConversation, CkConversationLayout, CkCopyMessageActionButton, CkFeedbackButton, CkFileItemsList, CkHistory, CkHistoryItem, CkHistoryWrapper, CkInput, CkMarkdownRenderer, CkMessageActionButton, CkPromptActionButton, CkPromptStopButton, CkPromptInput, CkPromptInputDisclaimer, CkSendIcon, CkStopIcon, CkUserMessage, } from './components';
|
|
9
|
-
export type { CkConversationLayoutProps, CkConversationProps, CkFeedbackButtonProps, CkFeedbackValue, CkFileEntry, CkFileItemsListEmits, CkFileItemsListProps, CkHistoryEmits, CkHistoryItemEmits, CkHistoryItemProps, CkHistoryProps, CkHistoryWrapperProps, CkMarkdownElementClasses, CkMarkdownRendererProps, CkUserMessageProps, } from './components';
|
|
10
|
-
export type { BaseMessage, Conversation, ConversationTree, MessageContent, MessageContentStatus, MessageReasoningContent, MessageRole, MessageStatus, MessageTextContent, MessageToolContent, TreeMessage, } from './types';
|
|
8
|
+
export { CkAgentMessage, CkConversation, CkConversationLayout, CkCopyMessageActionButton, CkFeedbackButton, CkFeedbackDialog, CkFileItemsList, CkHistory, CkHistoryItem, CkHistoryWrapper, CkInput, CkMarkdownRenderer, CkMessageActionButton, CkPromptActionButton, CkPromptStopButton, CkPromptInput, CkPromptInputDisclaimer, CkSendIcon, CkStopIcon, CkUserMessage, } from './components';
|
|
9
|
+
export type { CkConversationLayoutProps, CkConversationProps, CkFeedbackButtonProps, CkFeedbackDialogEmits, CkFeedbackDialogProps, CkFeedbackDialogSubmitPayload, CkFeedbackReason, CkFeedbackSentiment, CkFeedbackValue, CkFileEntry, CkFileItemsListEmits, CkFileItemsListProps, CkHistoryEmits, CkHistoryItemEmits, CkHistoryItemProps, CkHistoryProps, CkHistoryWrapperProps, CkMarkdownElementClasses, CkMarkdownRendererProps, CkUserMessageProps, } from './components';
|
|
10
|
+
export type { BaseMessage, Conversation, ConversationTree, MessageContent, MessageContentStatus, MessageMetadata, MessageReasoningContent, MessageRole, MessageStatus, MessageTextContent, MessageToolContent, TreeMessage, } from './types';
|
|
11
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC;AASpB,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,OAAO,EACL,OAAO,EACP,uBAAuB,EACvB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,WAAW,EACX,SAAS,EACT,mBAAmB,EACnB,uBAAuB,EACvB,cAAc,EACd,eAAe,EACf,aAAa,EACb,6BAA6B,EAC7B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,QAAQ,EACR,4BAA4B,EAC5B,2BAA2B,EAC3B,gBAAgB,EAChB,kCAAkC,GACnC,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,oBAAoB,EACpB,sBAAsB,EACtB,SAAS,EACT,UAAU,GACX,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EACL,cAAc,EACd,cAAc,EACd,oBAAoB,EACpB,yBAAyB,EACzB,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,OAAO,EACP,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,EACb,uBAAuB,EACvB,UAAU,EACV,UAAU,EACV,aAAa,GACd,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,yBAAyB,EACzB,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,WAAW,EACX,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AAGtB,YAAY,EACV,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,uBAAuB,EACvB,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,GACZ,MAAM,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC;AASpB,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,OAAO,EACL,OAAO,EACP,uBAAuB,EACvB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,WAAW,EACX,SAAS,EACT,mBAAmB,EACnB,uBAAuB,EACvB,cAAc,EACd,eAAe,EACf,aAAa,EACb,6BAA6B,EAC7B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,QAAQ,EACR,4BAA4B,EAC5B,2BAA2B,EAC3B,gBAAgB,EAChB,kCAAkC,GACnC,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,oBAAoB,EACpB,sBAAsB,EACtB,SAAS,EACT,UAAU,GACX,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EACL,cAAc,EACd,cAAc,EACd,oBAAoB,EACpB,yBAAyB,EACzB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,OAAO,EACP,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,EACb,uBAAuB,EACvB,UAAU,EACV,UAAU,EACV,aAAa,GACd,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,yBAAyB,EACzB,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,6BAA6B,EAC7B,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,WAAW,EACX,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AAGtB,YAAY,EACV,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,uBAAuB,EACvB,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,GACZ,MAAM,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { u } from "./useMessageHandler-
|
|
2
|
-
import { C, d, p, u as u2, a } from "./useChatKitLabels-
|
|
3
|
-
import { S, c, d as d2, a as a2, u as u3, b, e, f } from "./index-
|
|
4
|
-
import { _, a as a3, b as b2, C as C2, c as c2, d as d3, e as e2, f as f2, g, h, i, j, k, l, m, n, o, p as p2, q } from "./CkInput.vue_vue_type_script_setup_true_lang-
|
|
1
|
+
import { u } from "./useMessageHandler-CMdy-lm0.js";
|
|
2
|
+
import { C, d, p, u as u2, a } from "./useChatKitLabels-DeHxZG2a.js";
|
|
3
|
+
import { S, c, d as d2, a as a2, u as u3, b, e, f } from "./index-Ct5hD214.js";
|
|
4
|
+
import { _, a as a3, b as b2, C as C2, c as c2, d as d3, e as e2, f as f2, g, h, i, j, k, l, m, n, o, p as p2, q, r } from "./CkInput.vue_vue_type_script_setup_true_lang-DCZTSiBj.js";
|
|
5
5
|
export {
|
|
6
6
|
C as CHAT_KIT_LABELS,
|
|
7
7
|
_ as CkAgentMessage,
|
|
@@ -9,20 +9,21 @@ export {
|
|
|
9
9
|
b2 as CkConversationLayout,
|
|
10
10
|
C2 as CkCopyMessageActionButton,
|
|
11
11
|
c2 as CkFeedbackButton,
|
|
12
|
-
d3 as
|
|
13
|
-
e2 as
|
|
14
|
-
f2 as
|
|
15
|
-
g as
|
|
16
|
-
h as
|
|
17
|
-
i as
|
|
18
|
-
j as
|
|
19
|
-
k as
|
|
20
|
-
l as
|
|
21
|
-
m as
|
|
22
|
-
n as
|
|
23
|
-
o as
|
|
24
|
-
p2 as
|
|
25
|
-
q as
|
|
12
|
+
d3 as CkFeedbackDialog,
|
|
13
|
+
e2 as CkFileItemsList,
|
|
14
|
+
f2 as CkHistory,
|
|
15
|
+
g as CkHistoryItem,
|
|
16
|
+
h as CkHistoryWrapper,
|
|
17
|
+
i as CkInput,
|
|
18
|
+
j as CkMarkdownRenderer,
|
|
19
|
+
k as CkMessageActionButton,
|
|
20
|
+
l as CkPromptActionButton,
|
|
21
|
+
m as CkPromptInput,
|
|
22
|
+
n as CkPromptInputDisclaimer,
|
|
23
|
+
o as CkPromptStopButton,
|
|
24
|
+
p2 as CkSendIcon,
|
|
25
|
+
q as CkStopIcon,
|
|
26
|
+
r as CkUserMessage,
|
|
26
27
|
S as SdkError,
|
|
27
28
|
c as createDocumentUploadProvider,
|
|
28
29
|
d as defaultChatKitLabels,
|
package/dist/types.d.ts
CHANGED
|
@@ -57,6 +57,18 @@ export interface MessageReasoningContent {
|
|
|
57
57
|
* Discriminated union of all content parts that can appear inside a message.
|
|
58
58
|
*/
|
|
59
59
|
export type MessageContent = MessageTextContent | MessageToolContent | MessageReasoningContent;
|
|
60
|
+
/**
|
|
61
|
+
* Open-ended metadata bag carried alongside a message. chat-kit is
|
|
62
|
+
* intentionally agnostic about its contents — adapter authors
|
|
63
|
+
* (`responsesToTree`, …) and message handlers preserve the value verbatim
|
|
64
|
+
* through the tree → linear path projection, but never inspect it.
|
|
65
|
+
*
|
|
66
|
+
* Consumers attach their own well-known keys (attachments, citations,
|
|
67
|
+
* ratings, …) and define their own typed projections at the read site
|
|
68
|
+
* rather than extending this base type. That keeps the handler API stable
|
|
69
|
+
* even as the shape of what gets stored on a message evolves.
|
|
70
|
+
*/
|
|
71
|
+
export type MessageMetadata = Record<string, unknown>;
|
|
60
72
|
export interface BaseMessage {
|
|
61
73
|
id: string;
|
|
62
74
|
role: MessageRole;
|
|
@@ -65,6 +77,7 @@ export interface BaseMessage {
|
|
|
65
77
|
status: MessageStatus;
|
|
66
78
|
siblingIds?: string[];
|
|
67
79
|
siblingIndex?: number;
|
|
80
|
+
metadata?: MessageMetadata;
|
|
68
81
|
}
|
|
69
82
|
export interface TreeMessage {
|
|
70
83
|
id: string;
|
|
@@ -75,6 +88,7 @@ export interface TreeMessage {
|
|
|
75
88
|
content: MessageContent[];
|
|
76
89
|
status: MessageStatus;
|
|
77
90
|
createdAt: Date;
|
|
91
|
+
metadata?: MessageMetadata;
|
|
78
92
|
}
|
|
79
93
|
export interface ConversationTree {
|
|
80
94
|
nodes: Record<string, TreeMessage>;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE1D,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;AAE1E;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,aAAa,GAAG,WAAW,GAAG,YAAY,CAAC;AAE9E;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,WAAW,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB,kBAAkB,GAClB,kBAAkB,GAClB,uBAAuB,CAAC;AAE5B,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE1D,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;AAE1E;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,aAAa,GAAG,WAAW,GAAG,YAAY,CAAC;AAE9E;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,WAAW,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB,kBAAkB,GAClB,kBAAkB,GAClB,uBAAuB,CAAC;AAE5B;;;;;;;;;;GAUG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEtD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACnC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB"}
|
|
@@ -12708,6 +12708,15 @@ const defaultChatKitLabels = {
|
|
|
12708
12708
|
feedbackThumbsUp: "Good response",
|
|
12709
12709
|
feedbackThumbsDown: "Bad response",
|
|
12710
12710
|
feedbackGroup: "Rate this response",
|
|
12711
|
+
feedbackDialogTitlePositive: "Give positive feedback",
|
|
12712
|
+
feedbackDialogTitleNegative: "Give negative feedback",
|
|
12713
|
+
feedbackDialogResponseHeading: "Response",
|
|
12714
|
+
feedbackDialogDescription: "Select a reason and optionally add a comment, then submit your feedback.",
|
|
12715
|
+
feedbackDialogOtherLabel: "Other",
|
|
12716
|
+
feedbackDialogOtherTooltip: "Add anything else you want to share about this response.",
|
|
12717
|
+
feedbackDialogFreeTextPlaceholder: "Write down some additional details",
|
|
12718
|
+
feedbackDialogCancelLabel: "Cancel",
|
|
12719
|
+
feedbackDialogSubmitLabel: "Submit",
|
|
12711
12720
|
historyItemUntitled: "Untitled conversation",
|
|
12712
12721
|
historyItemActionAriaLabel: "Conversation options",
|
|
12713
12722
|
historyItemEditAction: "Edit",
|
|
@@ -16,7 +16,8 @@ function getLinearPath(tree) {
|
|
|
16
16
|
role: node.role,
|
|
17
17
|
content: node.content,
|
|
18
18
|
createdAt: node.createdAt,
|
|
19
|
-
status: node.status
|
|
19
|
+
status: node.status,
|
|
20
|
+
...node.metadata !== void 0 ? { metadata: node.metadata } : {}
|
|
20
21
|
};
|
|
21
22
|
if (node.parentId !== null) {
|
|
22
23
|
const parent = nodes[node.parentId];
|
|
@@ -49,6 +50,7 @@ function updateNode(tree, id, updates) {
|
|
|
49
50
|
if (updates.content !== void 0) node.content = updates.content;
|
|
50
51
|
if (updates.status !== void 0) node.status = updates.status;
|
|
51
52
|
if (updates.role !== void 0) node.role = updates.role;
|
|
53
|
+
if ("metadata" in updates) node.metadata = updates.metadata;
|
|
52
54
|
}
|
|
53
55
|
function updateNodeId(tree, oldId, newId) {
|
|
54
56
|
const node = tree.nodes[oldId];
|
|
@@ -69,6 +71,20 @@ function updateNodeId(tree, oldId, newId) {
|
|
|
69
71
|
}
|
|
70
72
|
if (tree.rootId === oldId) tree.rootId = newId;
|
|
71
73
|
}
|
|
74
|
+
function cutBranchAfter(tree, id) {
|
|
75
|
+
const node = tree.nodes[id];
|
|
76
|
+
if (!node) return;
|
|
77
|
+
const stack = [...node.childrenIds];
|
|
78
|
+
while (stack.length > 0) {
|
|
79
|
+
const currentId = stack.pop();
|
|
80
|
+
const current = tree.nodes[currentId];
|
|
81
|
+
if (!current) continue;
|
|
82
|
+
stack.push(...current.childrenIds);
|
|
83
|
+
delete tree.nodes[currentId];
|
|
84
|
+
}
|
|
85
|
+
node.childrenIds = [];
|
|
86
|
+
node.activeChildIndex = 0;
|
|
87
|
+
}
|
|
72
88
|
function navigate(tree, targetId) {
|
|
73
89
|
const node = tree.nodes[targetId];
|
|
74
90
|
if (!node || node.parentId === null) return;
|
|
@@ -92,7 +108,7 @@ const useMessageHandler = () => {
|
|
|
92
108
|
function clearCurrentUserMessage() {
|
|
93
109
|
currentUserMessage.value = "";
|
|
94
110
|
}
|
|
95
|
-
function commitUserMessage() {
|
|
111
|
+
function commitUserMessage(opts) {
|
|
96
112
|
const id = generateId();
|
|
97
113
|
const text = currentUserMessage.value.trim();
|
|
98
114
|
if (!text) throw new Error("No message");
|
|
@@ -107,17 +123,20 @@ const useMessageHandler = () => {
|
|
|
107
123
|
role: "user",
|
|
108
124
|
content,
|
|
109
125
|
status: "completed",
|
|
110
|
-
createdAt: /* @__PURE__ */ new Date()
|
|
126
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
127
|
+
...opts?.metadata !== void 0 ? { metadata: opts.metadata } : {}
|
|
111
128
|
};
|
|
112
129
|
addNode(tree, node);
|
|
113
130
|
clearCurrentUserMessage();
|
|
114
|
-
|
|
131
|
+
const base = {
|
|
115
132
|
id: node.id,
|
|
116
133
|
role: node.role,
|
|
117
134
|
content: node.content,
|
|
118
135
|
createdAt: node.createdAt,
|
|
119
136
|
status: node.status
|
|
120
137
|
};
|
|
138
|
+
if (node.metadata !== void 0) base.metadata = node.metadata;
|
|
139
|
+
return base;
|
|
121
140
|
}
|
|
122
141
|
function updateMessage(message) {
|
|
123
142
|
const existing = tree.nodes[message.id];
|
|
@@ -125,7 +144,8 @@ const useMessageHandler = () => {
|
|
|
125
144
|
updateNode(tree, message.id, {
|
|
126
145
|
content: message.content,
|
|
127
146
|
role: message.role,
|
|
128
|
-
status: message.status
|
|
147
|
+
status: message.status,
|
|
148
|
+
...message.metadata !== void 0 ? { metadata: message.metadata } : {}
|
|
129
149
|
});
|
|
130
150
|
} else {
|
|
131
151
|
const node = {
|
|
@@ -136,7 +156,8 @@ const useMessageHandler = () => {
|
|
|
136
156
|
role: message.role,
|
|
137
157
|
content: message.content,
|
|
138
158
|
status: message.status,
|
|
139
|
-
createdAt: /* @__PURE__ */ new Date()
|
|
159
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
160
|
+
...message.metadata !== void 0 ? { metadata: message.metadata } : {}
|
|
140
161
|
};
|
|
141
162
|
addNode(tree, node);
|
|
142
163
|
}
|
|
@@ -144,13 +165,15 @@ const useMessageHandler = () => {
|
|
|
144
165
|
function getMessageById(id) {
|
|
145
166
|
const node = tree.nodes[id];
|
|
146
167
|
if (!node) return void 0;
|
|
147
|
-
|
|
168
|
+
const base = {
|
|
148
169
|
id: node.id,
|
|
149
170
|
role: node.role,
|
|
150
171
|
content: node.content,
|
|
151
172
|
createdAt: node.createdAt,
|
|
152
|
-
status: node.status
|
|
173
|
+
status: node.status,
|
|
174
|
+
...node.metadata !== void 0 ? { metadata: node.metadata } : {}
|
|
153
175
|
};
|
|
176
|
+
return base;
|
|
154
177
|
}
|
|
155
178
|
function updateMessageId(oldId, newId) {
|
|
156
179
|
updateNodeId(tree, oldId, newId);
|
|
@@ -165,6 +188,9 @@ const useMessageHandler = () => {
|
|
|
165
188
|
function navigate$1(targetId) {
|
|
166
189
|
navigate(tree, targetId);
|
|
167
190
|
}
|
|
191
|
+
function cutBranchAfter$1(messageId) {
|
|
192
|
+
cutBranchAfter(tree, messageId);
|
|
193
|
+
}
|
|
168
194
|
return {
|
|
169
195
|
messages,
|
|
170
196
|
currentUserMessage: readonly(currentUserMessage),
|
|
@@ -177,7 +203,8 @@ const useMessageHandler = () => {
|
|
|
177
203
|
updateMessageId,
|
|
178
204
|
clearMessages,
|
|
179
205
|
setTree,
|
|
180
|
-
navigate: navigate$1
|
|
206
|
+
navigate: navigate$1,
|
|
207
|
+
cutBranchAfter: cutBranchAfter$1
|
|
181
208
|
};
|
|
182
209
|
};
|
|
183
210
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aleph-alpha/chat-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "Chat kit package for building chat interfaces with Vue",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -65,15 +65,16 @@
|
|
|
65
65
|
"vue": "^3.5.27"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
+
"@aleph-alpha/ui-library": "^2.7.0",
|
|
68
69
|
"dompurify": "^3.3.2",
|
|
69
70
|
"rehype-stringify": "^10.0.1",
|
|
70
71
|
"remark-gfm": "^4.0.1",
|
|
71
72
|
"remark-parse": "^11.0.0",
|
|
72
73
|
"remark-rehype": "^11.1.2",
|
|
73
|
-
"unified": "^11.0.5"
|
|
74
|
-
"@aleph-alpha/ui-library": "2.6.2"
|
|
74
|
+
"unified": "^11.0.5"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
|
+
"@aleph-alpha/config-css": "^1.2.0",
|
|
77
78
|
"@storybook/addon-a11y": "10.2.17",
|
|
78
79
|
"@storybook/addon-docs": "10.2.17",
|
|
79
80
|
"@storybook/addon-themes": "10.2.17",
|
|
@@ -96,8 +97,7 @@
|
|
|
96
97
|
"vite": "^7.3.2",
|
|
97
98
|
"vitest": "4.0.15",
|
|
98
99
|
"vue": "^3.5.27",
|
|
99
|
-
"vue-tsc": "^3.2.4"
|
|
100
|
-
"@aleph-alpha/config-css": "1.2.0"
|
|
100
|
+
"vue-tsc": "^3.2.4"
|
|
101
101
|
},
|
|
102
102
|
"scripts": {
|
|
103
103
|
"build": "vite build && vue-tsc --project tsconfig.build.json --declaration --emitDeclarationOnly --outDir dist",
|
|
@@ -371,6 +371,76 @@ describe('responsesToTree', () => {
|
|
|
371
371
|
}
|
|
372
372
|
});
|
|
373
373
|
|
|
374
|
+
it('stamps the originating responseId onto every emitted node', () => {
|
|
375
|
+
const tree = responsesToTree([
|
|
376
|
+
makeResponse({
|
|
377
|
+
id: 'r1',
|
|
378
|
+
request_input: [userInput('Hello')],
|
|
379
|
+
output: [assistantOutput('msg-a1', 'Hi')],
|
|
380
|
+
}),
|
|
381
|
+
makeResponse({
|
|
382
|
+
id: 'r2',
|
|
383
|
+
previous_response_id: 'r1',
|
|
384
|
+
request_input: [userInput('Follow-up')],
|
|
385
|
+
output: [assistantOutput('msg-a2', 'Reply')],
|
|
386
|
+
}),
|
|
387
|
+
]);
|
|
388
|
+
|
|
389
|
+
expect(tree.nodes['user-r1-0']!.metadata.responseId).toBe('r1');
|
|
390
|
+
expect(tree.nodes['msg-a1']!.metadata.responseId).toBe('r1');
|
|
391
|
+
expect(tree.nodes['user-r2-0']!.metadata.responseId).toBe('r2');
|
|
392
|
+
expect(tree.nodes['msg-a2']!.metadata.responseId).toBe('r2');
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
it('parses metadata.attachments (JSON-encoded string) onto the first user node of a response', () => {
|
|
396
|
+
const tree = responsesToTree([
|
|
397
|
+
makeResponse({
|
|
398
|
+
id: 'r1',
|
|
399
|
+
request_input: [userInput('With files')],
|
|
400
|
+
output: [assistantOutput('msg-a1', 'OK')],
|
|
401
|
+
// The Responses API serialises attachments as a JSON-encoded
|
|
402
|
+
// string on the wire (transports flatten nested metadata).
|
|
403
|
+
metadata: {
|
|
404
|
+
attachments: JSON.stringify([
|
|
405
|
+
{ fileName: 'report.pdf', fileId: 'f1', searchStoreId: 's1' },
|
|
406
|
+
]),
|
|
407
|
+
},
|
|
408
|
+
}),
|
|
409
|
+
]);
|
|
410
|
+
|
|
411
|
+
expect(tree.nodes['user-r1-0']!.metadata).toEqual({
|
|
412
|
+
responseId: 'r1',
|
|
413
|
+
attachments: [{ name: 'report.pdf', fileId: 'f1', searchStoreId: 's1' }],
|
|
414
|
+
});
|
|
415
|
+
// The assistant turn does not inherit attachments but still carries
|
|
416
|
+
// its responseId stamp.
|
|
417
|
+
expect(tree.nodes['msg-a1']!.metadata).toEqual({ responseId: 'r1' });
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
it('skips malformed metadata.attachments without polluting the tree', () => {
|
|
421
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
|
|
422
|
+
try {
|
|
423
|
+
const tree = responsesToTree([
|
|
424
|
+
makeResponse({
|
|
425
|
+
id: 'r1',
|
|
426
|
+
request_input: [userInput('Hello')],
|
|
427
|
+
output: [assistantOutput('msg-a1', 'Hi')],
|
|
428
|
+
metadata: {
|
|
429
|
+
attachments: '{not json',
|
|
430
|
+
},
|
|
431
|
+
}),
|
|
432
|
+
]);
|
|
433
|
+
|
|
434
|
+
// The malformed attachments are dropped, but `responseId` is still
|
|
435
|
+
// stamped on every node the adapter emits.
|
|
436
|
+
expect(tree.nodes['user-r1-0']!.metadata).toEqual({ responseId: 'r1' });
|
|
437
|
+
expect(tree.nodes['user-r1-0']!.metadata.attachments).toBeUndefined();
|
|
438
|
+
expect(warn).toHaveBeenCalled();
|
|
439
|
+
} finally {
|
|
440
|
+
warn.mockRestore();
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
|
|
374
444
|
it('chains the next response under a reasoning-only assistant turn', () => {
|
|
375
445
|
const tree = responsesToTree([
|
|
376
446
|
makeResponse({
|
|
@@ -23,6 +23,7 @@ import { generateId } from '../helpers';
|
|
|
23
23
|
import type {
|
|
24
24
|
ConversationTree,
|
|
25
25
|
MessageContent,
|
|
26
|
+
MessageMetadata,
|
|
26
27
|
MessageRole,
|
|
27
28
|
TreeMessage,
|
|
28
29
|
} from '../types';
|
|
@@ -213,6 +214,22 @@ export interface ResponseAttachment {
|
|
|
213
214
|
searchStoreId: string;
|
|
214
215
|
}
|
|
215
216
|
|
|
217
|
+
/**
|
|
218
|
+
* Render-side attachment shape produced by `responsesToTree`. Stored under
|
|
219
|
+
* `metadata.attachments` on the user `TreeMessage` (chat-kit's `BaseMessage`
|
|
220
|
+
* /`TreeMessage` carry `metadata` as an opaque `Record<string, unknown>`).
|
|
221
|
+
*
|
|
222
|
+
* The shape is intentionally minimal — a human-readable `name` plus the
|
|
223
|
+
* optional ids needed to resolve a public URL for the file. Consumers
|
|
224
|
+
* using a different attachment shape can either skip this adapter or
|
|
225
|
+
* project this onto their own type at the read site.
|
|
226
|
+
*/
|
|
227
|
+
export interface ResponseMessageAttachment {
|
|
228
|
+
name: string;
|
|
229
|
+
fileId?: string;
|
|
230
|
+
searchStoreId?: string;
|
|
231
|
+
}
|
|
232
|
+
|
|
216
233
|
/**
|
|
217
234
|
* One stored response from the OpenAI-style Responses API, as returned by
|
|
218
235
|
* `GET /conversations/:id/responses`. `previous_response_id` chains
|
|
@@ -230,7 +247,7 @@ export interface StoredResponse {
|
|
|
230
247
|
output: ResponseOutput[];
|
|
231
248
|
request_input: Record<string, unknown>[];
|
|
232
249
|
metadata?: Record<string, unknown> & {
|
|
233
|
-
attachments?:
|
|
250
|
+
attachments?: string;
|
|
234
251
|
};
|
|
235
252
|
conversation?: { id: string };
|
|
236
253
|
ancestor_ids?: string[];
|
|
@@ -252,11 +269,47 @@ export interface ResponseList {
|
|
|
252
269
|
// Conversion: StoredResponse[] → ConversationTree
|
|
253
270
|
// ---------------------------------------------------------------------------
|
|
254
271
|
|
|
272
|
+
/**
|
|
273
|
+
* Per-node metadata produced by `responsesToTree`. The adapter is the
|
|
274
|
+
* single point that knows about the Responses-API wire format, so it
|
|
275
|
+
* stamps the originating `responseId` onto every node it emits. Anything
|
|
276
|
+
* downstream that reads it (typically a host app linking a tree message
|
|
277
|
+
* back to its server-side response) does so via this narrower metadata
|
|
278
|
+
* shape — chat-kit core stays oblivious to the field and treats it as
|
|
279
|
+
* opaque metadata.
|
|
280
|
+
*/
|
|
281
|
+
export type ResponseTreeMessageMetadata = MessageMetadata & {
|
|
282
|
+
responseId: string;
|
|
283
|
+
attachments?: ResponseMessageAttachment[];
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Tree node emitted by `responsesToTree`. Structurally a `TreeMessage`,
|
|
288
|
+
* but with `metadata` narrowed to {@link ResponseTreeMessageMetadata} and
|
|
289
|
+
* promoted from optional to required: every node carries at least the
|
|
290
|
+
* originating `responseId`. Assignable to `TreeMessage` so the resulting
|
|
291
|
+
* tree can be passed directly to `useMessageHandler().setTree(...)`.
|
|
292
|
+
*/
|
|
293
|
+
export type ResponseTreeMessage = Omit<TreeMessage, 'metadata'> & {
|
|
294
|
+
metadata: ResponseTreeMessageMetadata;
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* `ConversationTree` returned by `responsesToTree`. Same shape as the
|
|
299
|
+
* core `ConversationTree`, with every node typed as a
|
|
300
|
+
* {@link ResponseTreeMessage} so callers can read `metadata.responseId`
|
|
301
|
+
* without re-narrowing. Structurally assignable to `ConversationTree`.
|
|
302
|
+
*/
|
|
303
|
+
export interface ResponseConversationTree extends ConversationTree {
|
|
304
|
+
nodes: Record<string, ResponseTreeMessage>;
|
|
305
|
+
}
|
|
306
|
+
|
|
255
307
|
interface ResponseMessageNode {
|
|
256
308
|
id: string;
|
|
257
309
|
role: MessageRole;
|
|
258
310
|
content: MessageContent[];
|
|
259
311
|
createdAt: Date;
|
|
312
|
+
metadata: ResponseTreeMessageMetadata;
|
|
260
313
|
}
|
|
261
314
|
|
|
262
315
|
function extractMessageText(parts: ResponseOutputTextPart[]): string {
|
|
@@ -373,6 +426,38 @@ function extractInputText(rawContent: unknown): string {
|
|
|
373
426
|
return text.trim();
|
|
374
427
|
}
|
|
375
428
|
|
|
429
|
+
// Parse `resp.metadata.attachments` defensively. The Responses API
|
|
430
|
+
// serialises the value as a JSON-encoded string (transports that persist
|
|
431
|
+
// metadata flatten nested objects, so the array is stringified on the
|
|
432
|
+
// wire). Returns `null` when the payload is missing, empty, or malformed —
|
|
433
|
+
// callers treat that as "no attachments on this response". Malformed
|
|
434
|
+
// payloads are logged via `console.warn` so consumers can spot upstream
|
|
435
|
+
// serialisation issues.
|
|
436
|
+
function parseResponseAttachments(
|
|
437
|
+
resp: StoredResponse,
|
|
438
|
+
): ResponseAttachment[] | null {
|
|
439
|
+
const raw = resp.metadata?.attachments;
|
|
440
|
+
if (!raw) return null;
|
|
441
|
+
|
|
442
|
+
let attachments: unknown;
|
|
443
|
+
try {
|
|
444
|
+
attachments = JSON.parse(raw);
|
|
445
|
+
} catch {
|
|
446
|
+
// eslint-disable-next-line no-console
|
|
447
|
+
console.warn(
|
|
448
|
+
'[chat-kit] Failed to parse metadata.attachments as JSON; skipping.',
|
|
449
|
+
raw,
|
|
450
|
+
);
|
|
451
|
+
return null;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (!Array.isArray(attachments) || attachments.length === 0) {
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return attachments as ResponseAttachment[];
|
|
459
|
+
}
|
|
460
|
+
|
|
376
461
|
// Within a single response, the visible messages chain linearly: every user
|
|
377
462
|
// input is followed by exactly one assistant turn (whose reasoning, tool,
|
|
378
463
|
// and text outputs are merged into one node). Across responses, branching
|
|
@@ -380,21 +465,41 @@ function extractInputText(rawContent: unknown): string {
|
|
|
380
465
|
// same parent and form sibling subtrees.
|
|
381
466
|
function responseToMessageNodes(resp: StoredResponse): ResponseMessageNode[] {
|
|
382
467
|
const nodes: ResponseMessageNode[] = [];
|
|
468
|
+
// Attachments are stored at the response level but logically belong to
|
|
469
|
+
// the user turn that started the response. We bind them to the first
|
|
470
|
+
// user `request_input` (mirroring the existing wire convention).
|
|
471
|
+
const responseAttachments = parseResponseAttachments(resp);
|
|
472
|
+
let userNodesPushed = 0;
|
|
383
473
|
if (resp.request_input) {
|
|
384
474
|
for (const [idx, input] of resp.request_input.entries()) {
|
|
385
475
|
const role = (input as { role?: string }).role;
|
|
386
476
|
const rawContent = (input as { content?: unknown }).content;
|
|
387
477
|
const text = extractInputText(rawContent);
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
478
|
+
const userContent = text || responseAttachments?.length;
|
|
479
|
+
if (role !== 'user' || !userContent) continue;
|
|
480
|
+
|
|
481
|
+
const metadata: ResponseTreeMessageMetadata = { responseId: resp.id };
|
|
482
|
+
if (responseAttachments && userNodesPushed === 0) {
|
|
483
|
+
metadata.attachments = responseAttachments.map(
|
|
484
|
+
(a): ResponseMessageAttachment => ({
|
|
485
|
+
name: a.fileName,
|
|
486
|
+
fileId: a.fileId,
|
|
487
|
+
searchStoreId: a.searchStoreId,
|
|
488
|
+
}),
|
|
489
|
+
);
|
|
395
490
|
}
|
|
491
|
+
|
|
492
|
+
nodes.push({
|
|
493
|
+
id: `user-${resp.id}-${idx}`,
|
|
494
|
+
role: 'user',
|
|
495
|
+
content: [textPart(text)],
|
|
496
|
+
createdAt: new Date(resp.created_at * 1000),
|
|
497
|
+
metadata,
|
|
498
|
+
});
|
|
499
|
+
userNodesPushed += 1;
|
|
396
500
|
}
|
|
397
501
|
}
|
|
502
|
+
|
|
398
503
|
const assistantParts = toAssistantParts(resp);
|
|
399
504
|
if (assistantParts.length > 0) {
|
|
400
505
|
nodes.push({
|
|
@@ -402,6 +507,7 @@ function responseToMessageNodes(resp: StoredResponse): ResponseMessageNode[] {
|
|
|
402
507
|
role: 'assistant',
|
|
403
508
|
content: assistantParts,
|
|
404
509
|
createdAt: new Date((resp.completed_at ?? resp.created_at) * 1000),
|
|
510
|
+
metadata: { responseId: resp.id },
|
|
405
511
|
});
|
|
406
512
|
}
|
|
407
513
|
return nodes;
|
|
@@ -417,15 +523,19 @@ function responseToMessageNodes(resp: StoredResponse): ResponseMessageNode[] {
|
|
|
417
523
|
* last message immediately. Sibling responses (same `previous_response_id`)
|
|
418
524
|
* surface as branches; the latest one wins as the active branch.
|
|
419
525
|
*
|
|
420
|
-
*
|
|
421
|
-
*
|
|
526
|
+
* Every emitted node carries `metadata.responseId` pointing back to the
|
|
527
|
+
* originating `StoredResponse.id` (see {@link ResponseTreeMessage}). The
|
|
528
|
+
* return type is assignable to `ConversationTree`, so you can pipe it
|
|
529
|
+
* straight into `useMessageHandler().setTree(...)`.
|
|
422
530
|
*/
|
|
423
|
-
export function responsesToTree(
|
|
531
|
+
export function responsesToTree(
|
|
532
|
+
responses: StoredResponse[],
|
|
533
|
+
): ResponseConversationTree {
|
|
424
534
|
if (responses.length === 0) {
|
|
425
535
|
return { nodes: {}, rootId: null };
|
|
426
536
|
}
|
|
427
537
|
|
|
428
|
-
const treeNodes: Record<string,
|
|
538
|
+
const treeNodes: Record<string, ResponseTreeMessage> = {};
|
|
429
539
|
// For each response, the id of its last visible message — that's the
|
|
430
540
|
// attachment point for any future child response that chains onto it.
|
|
431
541
|
// Empty responses fall back to their parent's attachment point so the
|
|
@@ -443,6 +553,7 @@ export function responsesToTree(responses: StoredResponse[]): ConversationTree {
|
|
|
443
553
|
content: node.content,
|
|
444
554
|
status: 'completed',
|
|
445
555
|
createdAt: node.createdAt,
|
|
556
|
+
metadata: node.metadata,
|
|
446
557
|
};
|
|
447
558
|
if (parentId !== null) {
|
|
448
559
|
const parent = treeNodes[parentId];
|