@aleph-alpha/chat-kit 5.8.0 → 5.9.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 (24) hide show
  1. package/dist/{CkHistory.vue_vue_type_script_setup_true_lang-DG96wNug.js → CkHistory.vue_vue_type_script_setup_true_lang-CEqJtMuI.js} +61 -40
  2. package/dist/adapters/responses-api.d.ts.map +1 -1
  3. package/dist/adapters/responses-api.js +46 -33
  4. package/dist/chat-kit.css +1 -1
  5. package/dist/components/base/CkConversationLayout/CkConversationLayout.stories.d.ts +7 -0
  6. package/dist/components/base/CkConversationLayout/CkConversationLayout.stories.d.ts.map +1 -1
  7. package/dist/components/base/CkConversationLayout/CkConversationLayout.vue.d.ts +3 -1
  8. package/dist/components/base/CkConversationLayout/CkConversationLayout.vue.d.ts.map +1 -1
  9. package/dist/components/composed/CkConversation/CkConversation.stories.d.ts +23 -3
  10. package/dist/components/composed/CkConversation/CkConversation.stories.d.ts.map +1 -1
  11. package/dist/components/composed/CkConversation/CkConversation.vue.d.ts +17 -2
  12. package/dist/components/composed/CkConversation/CkConversation.vue.d.ts.map +1 -1
  13. package/dist/components/composed/CkHistory/CkHistory.vue.d.ts +1 -1
  14. package/dist/components/index.js +1 -1
  15. package/dist/index.js +1 -1
  16. package/package.json +1 -1
  17. package/src/adapters/responses-api.spec.ts +6 -3
  18. package/src/adapters/responses-api.ts +62 -35
  19. package/src/components/base/CkConversationLayout/CkConversationLayout.spec.ts +209 -1
  20. package/src/components/base/CkConversationLayout/CkConversationLayout.stories.ts +84 -0
  21. package/src/components/base/CkConversationLayout/CkConversationLayout.vue +59 -21
  22. package/src/components/composed/CkConversation/CkConversation.spec.ts +96 -5
  23. package/src/components/composed/CkConversation/CkConversation.stories.ts +328 -4
  24. package/src/components/composed/CkConversation/CkConversation.vue +38 -8
@@ -1,5 +1,5 @@
1
1
  import { defineComponent, openBlock, createBlock, unref, createElementBlock, createElementVNode, normalizeClass, renderSlot, createCommentVNode, mergeProps, withCtx, computed, createVNode, toDisplayString, ref, onBeforeUnmount, useSlots, onMounted, nextTick, onUnmounted, watch, Fragment, renderList, normalizeStyle, Transition, createStaticVNode, Teleport, withModifiers, toValue, h, toRefs, useId, createTextVNode, useAttrs, resolveDynamicComponent, useTemplateRef, onUpdated, createSlots, normalizeProps, guardReactiveProps, Comment, Text } from "vue";
2
- import { UiIcon, UiButton, UiFileType, UiPopover, UiPopoverTrigger, UiPopoverContent, UiTooltip, formatFileSize, UiDialog, UiDialogContent, UiDialogDescription, UiFieldLabel, UiToggleGroup, UiToggleGroupItem, UiField, UiTextarea, UiFileItem, UiProgress, Primitive, UiFloatActions, UiFloatActionItems, UiAvatar, UiAvatarImage, UiSpinner, UiAvatarFallback, UiSidebarPopoverMenu, UiSidebarPopoverMenuItem } from "@aleph-alpha/ui-library";
2
+ import { UiIcon, UiButton, UiFileType, UiPopover, UiPopoverTrigger, UiPopoverContent, UiTooltip, formatFileSize, UiDialog, UiDialogContent, UiDialogDescription, UiFieldLabel, UiToggleGroup, UiToggleGroupItem, UiField, UiTextarea, UiFileItem, UiProgress, Primitive, UiFloatActions, UiFloatActionItems, UiCodeBlock, UiAvatar, UiAvatarImage, UiSpinner, UiAvatarFallback, UiSidebarPopoverMenu, UiSidebarPopoverMenuItem } from "@aleph-alpha/ui-library";
3
3
  import { u as useChatKitLabels, d as defaultChatKitLabels, r as remarkCitations, b as useMarkdownParser } from "./useChatKitLabels-CMOr3Kjq.js";
4
4
  const MINUTE = 60;
5
5
  const HOUR = 60 * MINUTE;
@@ -185,7 +185,7 @@ const _hoisted_1$e = { class: "ck-citation-card flex w-[22.5rem] max-w-[90vw] fl
185
185
  const _hoisted_2$8 = { class: "flex items-center gap-2" };
186
186
  const _hoisted_3$7 = ["title"];
187
187
  const _hoisted_4$7 = { class: "line-clamp-6 break-words text-sm leading-5 text-content-on-surface-secondary" };
188
- const _hoisted_5$5 = {
188
+ const _hoisted_5$4 = {
189
189
  key: 0,
190
190
  class: "text-sm leading-5 text-content-on-surface-muted"
191
191
  };
@@ -244,7 +244,7 @@ const _sfc_main$o = /* @__PURE__ */ defineComponent({
244
244
  }, 8, ["aria-label"])) : createCommentVNode("", true)
245
245
  ]),
246
246
  createElementVNode("p", _hoisted_4$7, toDisplayString(__props.snippet), 1),
247
- __props.locationLabel ? (openBlock(), createElementBlock("p", _hoisted_5$5, toDisplayString(__props.locationLabel), 1)) : createCommentVNode("", true)
247
+ __props.locationLabel ? (openBlock(), createElementBlock("p", _hoisted_5$4, toDisplayString(__props.locationLabel), 1)) : createCommentVNode("", true)
248
248
  ]);
249
249
  };
250
250
  }
@@ -388,18 +388,13 @@ const _hoisted_4$6 = {
388
388
  key: 1,
389
389
  class: "flex min-w-0 justify-start"
390
390
  };
391
- const _hoisted_5$4 = {
392
- key: 0,
393
- "data-message-row": "agent",
394
- class: "flex min-w-0 justify-start"
395
- };
396
391
  const _sfc_main$m = /* @__PURE__ */ defineComponent({
397
392
  ...{ name: "CkConversationLayout" },
398
393
  __name: "CkConversationLayout",
399
394
  props: {
400
395
  messages: {}
401
396
  },
402
- setup(__props) {
397
+ setup(__props, { expose: __expose }) {
403
398
  const props = __props;
404
399
  const slots = useSlots();
405
400
  const scrollContainerRef = ref(null);
@@ -475,26 +470,36 @@ const _sfc_main$m = /* @__PURE__ */ defineComponent({
475
470
  const lastUserTop = lastUserRow.offsetTop;
476
471
  const lastRowBottom = lastRow.offsetTop + lastRow.offsetHeight;
477
472
  const contentFromUserToEnd = lastRowBottom - lastUserTop;
478
- const gap = parseFloat(getComputedStyle(container).rowGap) || 0;
473
+ const topMargin = parseFloat(getComputedStyle(lastUserRow).marginTop) || 0;
479
474
  spacerHeight.value = Math.max(
480
475
  0,
481
- containerHeight.value - contentFromUserToEnd - gap
476
+ containerHeight.value - contentFromUserToEnd - topMargin
482
477
  );
483
478
  }
484
- function scrollUserMessageToTop() {
479
+ function scrollMessageToTop(index) {
485
480
  const container = scrollContainerRef.value;
486
481
  if (!container) return;
487
- hasBottomSpacer.value = true;
488
- spacerHeight.value = containerHeight.value;
482
+ const rows = container.querySelectorAll("[data-message-row]");
483
+ if (rows.length === 0) return;
484
+ const targetIndex = index ?? rows.length - 1;
485
+ const targetRow = rows[targetIndex];
486
+ if (!targetRow) return;
487
+ const topMargin = parseFloat(getComputedStyle(targetRow).marginTop) || 0;
488
+ const targetTop = targetRow.offsetTop - topMargin;
489
+ const lastRow = rows[rows.length - 1];
490
+ const contentBottom = lastRow.offsetTop + lastRow.offsetHeight;
491
+ const contentBelowTarget = contentBottom - targetTop;
492
+ const needsSpacer = contentBelowTarget < containerHeight.value;
493
+ if (needsSpacer) {
494
+ hasBottomSpacer.value = true;
495
+ spacerHeight.value = containerHeight.value - contentBelowTarget;
496
+ } else {
497
+ hasBottomSpacer.value = false;
498
+ spacerHeight.value = 0;
499
+ }
489
500
  nextTick(() => {
490
- const userRows = container.querySelectorAll(
491
- '[data-message-row="user"]'
492
- );
493
- const lastUserRow = userRows[userRows.length - 1];
494
- if (lastUserRow) {
495
- lastUserRow.scrollIntoView({ behavior: "smooth", block: "start" });
496
- }
497
- isAutoScrollEnabled.value = true;
501
+ container.scrollTo({ top: targetTop, behavior: "smooth" });
502
+ isAutoScrollEnabled.value = needsSpacer;
498
503
  });
499
504
  }
500
505
  function scrollToEndOfContent() {
@@ -516,7 +521,7 @@ const _sfc_main$m = /* @__PURE__ */ defineComponent({
516
521
  const lastMessage = props.messages[newLen - 1];
517
522
  if (lastMessage?.role === "user") {
518
523
  nextTick(() => {
519
- scrollUserMessageToTop();
524
+ scrollMessageToTop(newLen - 1);
520
525
  updateFades();
521
526
  });
522
527
  }
@@ -540,6 +545,7 @@ const _sfc_main$m = /* @__PURE__ */ defineComponent({
540
545
  },
541
546
  { deep: true }
542
547
  );
548
+ __expose({ scrollToMessage: scrollMessageToTop });
543
549
  return (_ctx, _cache) => {
544
550
  return openBlock(), createElementBlock("div", _hoisted_1$c, [
545
551
  createElementVNode("div", {
@@ -549,25 +555,29 @@ const _sfc_main$m = /* @__PURE__ */ defineComponent({
549
555
  createElementVNode("div", {
550
556
  ref_key: "scrollContainerRef",
551
557
  ref: scrollContainerRef,
552
- class: "relative flex min-h-0 flex-1 flex-col gap-8 overflow-y-auto",
558
+ class: "relative flex min-h-0 flex-1 flex-col overflow-y-auto",
553
559
  onScroll: handleScroll
554
560
  }, [
555
- (openBlock(true), createElementBlock(Fragment, null, renderList(__props.messages, (message) => {
561
+ (openBlock(true), createElementBlock(Fragment, null, renderList(__props.messages, (message, index) => {
556
562
  return openBlock(), createElementBlock("div", {
557
563
  key: message.id,
558
564
  "data-message-row": message.role,
559
- class: "min-w-0"
565
+ class: normalizeClass(["min-w-0", index === 0 ? "mt-2xl" : "mt-3xl"])
560
566
  }, [
561
567
  message.role === "user" ? (openBlock(), createElementBlock("div", _hoisted_3$6, [
562
568
  renderSlot(_ctx.$slots, "user-message", { message })
563
569
  ])) : (openBlock(), createElementBlock("div", _hoisted_4$6, [
564
570
  renderSlot(_ctx.$slots, "agent-message", { message })
565
571
  ]))
566
- ], 8, _hoisted_2$7);
572
+ ], 10, _hoisted_2$7);
567
573
  }), 128)),
568
- _ctx.$slots["thread-footer"] ? (openBlock(), createElementBlock("div", _hoisted_5$4, [
574
+ _ctx.$slots["thread-footer"] ? (openBlock(), createElementBlock("div", {
575
+ key: 0,
576
+ "data-message-row": "agent",
577
+ class: normalizeClass(["flex min-w-0 justify-start", __props.messages.length === 0 ? "mt-2xl" : "mt-3xl"])
578
+ }, [
569
579
  renderSlot(_ctx.$slots, "thread-footer")
570
- ])) : createCommentVNode("", true),
580
+ ], 2)) : createCommentVNode("", true),
571
581
  hasBottomSpacer.value ? (openBlock(), createElementBlock("div", {
572
582
  key: 1,
573
583
  "aria-hidden": "true",
@@ -2579,7 +2589,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
2579
2589
  agentLoadingImage: { default: "" },
2580
2590
  agentMarkdownClasses: {}
2581
2591
  },
2582
- setup(__props) {
2592
+ setup(__props, { expose: __expose }) {
2583
2593
  const props = __props;
2584
2594
  const slots = useSlots();
2585
2595
  const labels = useChatKitLabels();
@@ -2609,8 +2619,17 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
2609
2619
  const slot = slots["agent-message-header-activity"];
2610
2620
  return slot ? slot({ message }).some((vnode) => !isVNodeEmpty(vnode)) : false;
2611
2621
  }
2622
+ const layoutRef = useTemplateRef("layoutRef");
2623
+ function scrollToMessage(index) {
2624
+ layoutRef.value?.scrollToMessage(index);
2625
+ }
2626
+ __expose({ scrollToMessage });
2612
2627
  return (_ctx, _cache) => {
2613
- return openBlock(), createBlock(_sfc_main$m, { messages: __props.messages }, createSlots({
2628
+ return openBlock(), createBlock(_sfc_main$m, {
2629
+ ref_key: "layoutRef",
2630
+ ref: layoutRef,
2631
+ messages: __props.messages
2632
+ }, createSlots({
2614
2633
  "user-message": withCtx(({ message }) => [
2615
2634
  createElementVNode("div", {
2616
2635
  class: normalizeClass({ "ml-8": hasIcon.value })
@@ -2647,15 +2666,17 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
2647
2666
  createVNode(_sfc_main$g, {
2648
2667
  content: getMessageText(message),
2649
2668
  classes: __props.agentMarkdownClasses
2650
- }, createSlots({ _: 2 }, [
2651
- _ctx.$slots["agent-message-code-block"] ? {
2652
- name: "code-block",
2653
- fn: withCtx((codeBlockProps) => [
2654
- renderSlot(_ctx.$slots, "agent-message-code-block", normalizeProps(guardReactiveProps(codeBlockProps)))
2655
- ]),
2656
- key: "0"
2657
- } : void 0
2658
- ]), 1032, ["content", "classes"])
2669
+ }, {
2670
+ "code-block": withCtx((codeBlockProps) => [
2671
+ renderSlot(_ctx.$slots, "agent-message-code-block", normalizeProps(guardReactiveProps(codeBlockProps)), () => [
2672
+ createVNode(unref(UiCodeBlock), {
2673
+ code: codeBlockProps.code,
2674
+ language: codeBlockProps.language || "text"
2675
+ }, null, 8, ["code", "language"])
2676
+ ])
2677
+ ]),
2678
+ _: 3
2679
+ }, 8, ["content", "classes"])
2659
2680
  ])
2660
2681
  ]),
2661
2682
  _: 2
@@ -1 +1 @@
1
- {"version":3,"file":"responses-api.d.ts","sourceRoot":"","sources":["../../src/adapters/responses-api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"responses-api.d.ts","sourceRoot":"","sources":["../../src/adapters/responses-api.ts"],"names":[],"mappings":"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"}
@@ -101,41 +101,49 @@ function parseResponseAttachments(resp) {
101
101
  }
102
102
  return attachments;
103
103
  }
104
+ function toMessageAttachments(attachments) {
105
+ return attachments.map(
106
+ (a) => ({
107
+ name: a.fileName,
108
+ fileId: a.fileId,
109
+ fileName: a.fileName,
110
+ searchStoreId: a.searchStoreId,
111
+ ...a.documentId ? { documentId: a.documentId } : {}
112
+ })
113
+ );
114
+ }
115
+ function buildUserNode(resp, input, idx, responseAttachments, isFirstUserNode) {
116
+ const role = input.role;
117
+ const text = extractInputText(input.content);
118
+ const hasContent = text || responseAttachments?.length;
119
+ if (role !== "user" || !hasContent) return null;
120
+ const metadata = {
121
+ responseId: resp.id,
122
+ ...resp.model ? { model: resp.model } : {}
123
+ };
124
+ if (responseAttachments && isFirstUserNode) {
125
+ metadata.attachments = toMessageAttachments(responseAttachments);
126
+ }
127
+ return {
128
+ id: `user-${resp.id}-${idx}`,
129
+ role: "user",
130
+ content: [textPart(text)],
131
+ createdAt: new Date(resp.created_at * 1e3),
132
+ metadata
133
+ };
134
+ }
104
135
  function responseToMessageNodes(resp) {
105
136
  const nodes = [];
106
137
  const responseAttachments = parseResponseAttachments(resp);
107
- let userNodesPushed = 0;
108
- if (resp.request_input) {
109
- for (const [idx, input] of resp.request_input.entries()) {
110
- const role = input.role;
111
- const rawContent = input.content;
112
- const text = extractInputText(rawContent);
113
- const userContent = text || responseAttachments?.length;
114
- if (role !== "user" || !userContent) continue;
115
- const metadata = {
116
- responseId: resp.id,
117
- ...resp.model ? { model: resp.model } : {}
118
- };
119
- if (responseAttachments && userNodesPushed === 0) {
120
- metadata.attachments = responseAttachments.map(
121
- (a) => ({
122
- name: a.fileName,
123
- fileId: a.fileId,
124
- fileName: a.fileName,
125
- searchStoreId: a.searchStoreId,
126
- ...a.documentId ? { documentId: a.documentId } : {}
127
- })
128
- );
129
- }
130
- nodes.push({
131
- id: `user-${resp.id}-${idx}`,
132
- role: "user",
133
- content: [textPart(text)],
134
- createdAt: new Date(resp.created_at * 1e3),
135
- metadata
136
- });
137
- userNodesPushed += 1;
138
- }
138
+ for (const [idx, input] of resp.request_input?.entries() ?? []) {
139
+ const userNode = buildUserNode(
140
+ resp,
141
+ input,
142
+ idx,
143
+ responseAttachments,
144
+ nodes.length === 0
145
+ );
146
+ if (userNode) nodes.push(userNode);
139
147
  }
140
148
  const assistantParts = toAssistantParts(resp);
141
149
  if (assistantParts.length > 0) {
@@ -144,7 +152,12 @@ function responseToMessageNodes(resp) {
144
152
  role: "assistant",
145
153
  content: assistantParts,
146
154
  createdAt: new Date((resp.completed_at ?? resp.created_at) * 1e3),
147
- metadata: { responseId: resp.id }
155
+ // A stored response carries a single `model` covering both its input and
156
+ // output, so the assistant node gets the same model id as its user node.
157
+ metadata: {
158
+ responseId: resp.id,
159
+ ...resp.model ? { model: resp.model } : {}
160
+ }
148
161
  });
149
162
  }
150
163
  return nodes;