@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.
Files changed (52) hide show
  1. package/dist/{CkInput.vue_vue_type_script_setup_true_lang-C1Jnn1fK.js → CkInput.vue_vue_type_script_setup_true_lang-DCZTSiBj.js} +371 -135
  2. package/dist/adapters/responses-api.d.ts +54 -5
  3. package/dist/adapters/responses-api.d.ts.map +1 -1
  4. package/dist/adapters/responses-api.js +43 -9
  5. package/dist/chat-kit.css +19 -0
  6. package/dist/components/base/CkFeedbackDialog/CkFeedbackDialog.stories.d.ts +30 -0
  7. package/dist/components/base/CkFeedbackDialog/CkFeedbackDialog.stories.d.ts.map +1 -0
  8. package/dist/components/base/CkFeedbackDialog/CkFeedbackDialog.vue.d.ts +13 -0
  9. package/dist/components/base/CkFeedbackDialog/CkFeedbackDialog.vue.d.ts.map +1 -0
  10. package/dist/components/base/CkFeedbackDialog/index.d.ts +3 -0
  11. package/dist/components/base/CkFeedbackDialog/index.d.ts.map +1 -0
  12. package/dist/components/base/CkFeedbackDialog/types.d.ts +152 -0
  13. package/dist/components/base/CkFeedbackDialog/types.d.ts.map +1 -0
  14. package/dist/components/base/index.d.ts +2 -0
  15. package/dist/components/base/index.d.ts.map +1 -1
  16. package/dist/components/index.d.ts +2 -2
  17. package/dist/components/index.d.ts.map +1 -1
  18. package/dist/components/index.js +16 -15
  19. package/dist/composables/index.js +1 -1
  20. package/dist/handlers/index.js +2 -2
  21. package/dist/handlers/useChatKitLabels.d.ts +18 -0
  22. package/dist/handlers/useChatKitLabels.d.ts.map +1 -1
  23. package/dist/handlers/useMessageHandler.d.ts +6 -2
  24. package/dist/handlers/useMessageHandler.d.ts.map +1 -1
  25. package/dist/helpers/conversationTree.d.ts +10 -1
  26. package/dist/helpers/conversationTree.d.ts.map +1 -1
  27. package/dist/{index-BLq6_Lt2.js → index-Ct5hD214.js} +1 -1
  28. package/dist/index.d.ts +3 -3
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +19 -18
  31. package/dist/types.d.ts +14 -0
  32. package/dist/types.d.ts.map +1 -1
  33. package/dist/{useChatKitLabels-ftC52m7f.js → useChatKitLabels-DeHxZG2a.js} +9 -0
  34. package/dist/{useMessageHandler-ZRC-gIOJ.js → useMessageHandler-CMdy-lm0.js} +36 -9
  35. package/package.json +5 -5
  36. package/src/adapters/responses-api.spec.ts +70 -0
  37. package/src/adapters/responses-api.ts +123 -12
  38. package/src/components/base/CkFeedbackDialog/CkFeedbackDialog.spec.ts +177 -0
  39. package/src/components/base/CkFeedbackDialog/CkFeedbackDialog.stories.ts +258 -0
  40. package/src/components/base/CkFeedbackDialog/CkFeedbackDialog.vue +288 -0
  41. package/src/components/base/CkFeedbackDialog/index.ts +2 -0
  42. package/src/components/base/CkFeedbackDialog/types.ts +155 -0
  43. package/src/components/base/index.ts +8 -0
  44. package/src/components/index.ts +6 -0
  45. package/src/handlers/useChatKitLabels.spec.ts +11 -0
  46. package/src/handlers/useChatKitLabels.ts +29 -0
  47. package/src/handlers/useMessageHandler.spec.ts +214 -0
  48. package/src/handlers/useMessageHandler.ts +28 -3
  49. package/src/helpers/conversationTree.spec.ts +134 -0
  50. package/src/helpers/conversationTree.ts +32 -1
  51. package/src/index.ts +7 -0
  52. 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
@@ -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-ZRC-gIOJ.js";
2
- import { C, d, p, u as u2, a } from "./useChatKitLabels-ftC52m7f.js";
3
- import { S, c, d as d2, a as a2, u as u3, b, e, f } from "./index-BLq6_Lt2.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 } from "./CkInput.vue_vue_type_script_setup_true_lang-C1Jnn1fK.js";
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 CkFileItemsList,
13
- e2 as CkHistory,
14
- f2 as CkHistoryItem,
15
- g as CkHistoryWrapper,
16
- h as CkInput,
17
- i as CkMarkdownRenderer,
18
- j as CkMessageActionButton,
19
- k as CkPromptActionButton,
20
- l as CkPromptInput,
21
- m as CkPromptInputDisclaimer,
22
- n as CkPromptStopButton,
23
- o as CkSendIcon,
24
- p2 as CkStopIcon,
25
- q as CkUserMessage,
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>;
@@ -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;CACvB;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;CACjB;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"}
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
- return {
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
- return {
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.11.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?: ResponseAttachment[];
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
- if (role === 'user' && text) {
389
- nodes.push({
390
- id: `user-${resp.id}-${idx}`,
391
- role: 'user',
392
- content: [textPart(text)],
393
- createdAt: new Date(resp.created_at * 1000),
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
- * Pair with `useMessageHandler().setTree(responsesToTree(responses))` when
421
- * you want to hydrate a handler.
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(responses: StoredResponse[]): ConversationTree {
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, TreeMessage> = {};
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];