@8wave/ai-elements 0.68.0 → 0.69.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 (74) hide show
  1. package/dist/_chunks/{PkStreamingMarkdown-D3MJ5dfu.js → PkStreamingMarkdown-C0BpOvli.js} +2 -2
  2. package/dist/_chunks/{PkStreamingMarkdown-D3MJ5dfu.js.map → PkStreamingMarkdown-C0BpOvli.js.map} +1 -1
  3. package/dist/_chunks/{PkToolShowArtifact-BFe_MhNr.js → PkToolShowArtifact-DzNIkKvZ.js} +3 -3
  4. package/dist/_chunks/{PkToolShowArtifact-BFe_MhNr.js.map → PkToolShowArtifact-DzNIkKvZ.js.map} +1 -1
  5. package/dist/_chunks/{PkToolShowLocation-DN57lKN1.js → PkToolShowLocation-BsBiA4jV.js} +2 -2
  6. package/dist/_chunks/{PkToolShowLocation-DN57lKN1.js.map → PkToolShowLocation-BsBiA4jV.js.map} +1 -1
  7. package/dist/_chunks/src-BRYn66N3.js.map +1 -1
  8. package/dist/_chunks/{vue-leaflet.es-7LObg4WN.js → vue-leaflet.es-BT-uRmMx.js} +5 -5
  9. package/dist/_chunks/{vue-leaflet.es-7LObg4WN.js.map → vue-leaflet.es-BT-uRmMx.js.map} +1 -1
  10. package/dist/ai-elements.es.js +293 -299
  11. package/dist/ai-elements.es.js.map +1 -1
  12. package/dist-vue/PkChatbot.js +1 -1
  13. package/dist-vue/PkChatbotMessages.js +1 -1
  14. package/dist-vue/PkChatbotViewChat.js +1 -1
  15. package/dist-vue/PkChatbotViewConversations.js +1 -1
  16. package/dist-vue/PkChatbotViewProfile.js +1 -1
  17. package/dist-vue/_chunks/{PkChatbot-C_ASB2zq.js → PkChatbot-Cy7p5UI_.js} +5 -5
  18. package/dist-vue/_chunks/{PkChatbot-C_ASB2zq.js.map → PkChatbot-Cy7p5UI_.js.map} +1 -1
  19. package/dist-vue/_chunks/{PkChatbotMessages-CQdxH86L.js → PkChatbotMessages-C7-ZtU0-.js} +11 -11
  20. package/dist-vue/_chunks/{PkChatbotMessages-CQdxH86L.js.map → PkChatbotMessages-C7-ZtU0-.js.map} +1 -1
  21. package/dist-vue/_chunks/{PkChatbotViewChat-DHOeNxnR.js → PkChatbotViewChat-EWotdJkz.js} +3 -3
  22. package/dist-vue/_chunks/{PkChatbotViewChat-DHOeNxnR.js.map → PkChatbotViewChat-EWotdJkz.js.map} +1 -1
  23. package/dist-vue/_chunks/{PkChatbotViewConversations-DFv_8-8K.js → PkChatbotViewConversations-Ct0TbDrg.js} +2 -2
  24. package/dist-vue/_chunks/{PkChatbotViewConversations-DFv_8-8K.js.map → PkChatbotViewConversations-Ct0TbDrg.js.map} +1 -1
  25. package/dist-vue/_chunks/{PkChatbotViewProfile-BUj0YnIi.js → PkChatbotViewProfile-BhdCxVSX.js} +2 -2
  26. package/dist-vue/_chunks/{PkChatbotViewProfile-BUj0YnIi.js.map → PkChatbotViewProfile-BhdCxVSX.js.map} +1 -1
  27. package/dist-vue/_chunks/{PkToolShowArtifact-DIw-_JPA.js → PkToolShowArtifact-pTS7wzhw.js} +2 -2
  28. package/dist-vue/_chunks/{PkToolShowArtifact-DIw-_JPA.js.map → PkToolShowArtifact-pTS7wzhw.js.map} +1 -1
  29. package/dist-vue/_chunks/{PkToolShowCalendarEvent-ZZM8p7wu.js → PkToolShowCalendarEvent-DQ--fzwb.js} +2 -2
  30. package/dist-vue/_chunks/{PkToolShowCalendarEvent-ZZM8p7wu.js.map → PkToolShowCalendarEvent-DQ--fzwb.js.map} +1 -1
  31. package/dist-vue/_chunks/{PkToolShowComparison-7akNsf1w.js → PkToolShowComparison-CzRUrjbP.js} +2 -2
  32. package/dist-vue/_chunks/{PkToolShowComparison-7akNsf1w.js.map → PkToolShowComparison-CzRUrjbP.js.map} +1 -1
  33. package/dist-vue/_chunks/{PkToolShowEmail-CpiAbmr0.js → PkToolShowEmail-htn0ivwY.js} +2 -2
  34. package/dist-vue/_chunks/{PkToolShowEmail-CpiAbmr0.js.map → PkToolShowEmail-htn0ivwY.js.map} +1 -1
  35. package/dist-vue/_chunks/{PkToolShowImageGallery-jY7iYqTv.js → PkToolShowImageGallery-CpU183SC.js} +2 -2
  36. package/dist-vue/_chunks/{PkToolShowImageGallery-jY7iYqTv.js.map → PkToolShowImageGallery-CpU183SC.js.map} +1 -1
  37. package/dist-vue/_chunks/{PkToolShowLocation-BeOkj0Q2.js → PkToolShowLocation-DSZvW68g.js} +2 -2
  38. package/dist-vue/_chunks/{PkToolShowLocation-BeOkj0Q2.js.map → PkToolShowLocation-DSZvW68g.js.map} +1 -1
  39. package/dist-vue/_chunks/{PkToolShowMessage-AS8VNcYP.js → PkToolShowMessage-DtGDm3pq.js} +2 -2
  40. package/dist-vue/_chunks/{PkToolShowMessage-AS8VNcYP.js.map → PkToolShowMessage-DtGDm3pq.js.map} +1 -1
  41. package/dist-vue/_chunks/{PkToolShowProductList-FEq8sFxW.js → PkToolShowProductList-BlkUdbtV.js} +2 -2
  42. package/dist-vue/_chunks/{PkToolShowProductList-FEq8sFxW.js.map → PkToolShowProductList-BlkUdbtV.js.map} +1 -1
  43. package/dist-vue/_chunks/{PkToolShowQrCode-DAt8tBHK.js → PkToolShowQrCode-BUyhM_MN.js} +2 -2
  44. package/dist-vue/_chunks/{PkToolShowQrCode-DAt8tBHK.js.map → PkToolShowQrCode-BUyhM_MN.js.map} +1 -1
  45. package/dist-vue/_chunks/{PkToolShowWebPages-jA5eZRdi.js → PkToolShowWebPages-BQp9A4vb.js} +2 -2
  46. package/dist-vue/_chunks/{PkToolShowWebPages-jA5eZRdi.js.map → PkToolShowWebPages-BQp9A4vb.js.map} +1 -1
  47. package/dist-vue/_chunks/{dist-C-yeiSHm.js → dist-BHuX2VvC.js} +2 -2
  48. package/dist-vue/_chunks/{dist-C-yeiSHm.js.map → dist-BHuX2VvC.js.map} +1 -1
  49. package/dist-vue/_chunks/{dist-D2-23M8l.js → dist-BWXfA4NS.js} +4 -4
  50. package/dist-vue/_chunks/{dist-D2-23M8l.js.map → dist-BWXfA4NS.js.map} +1 -1
  51. package/dist-vue/_chunks/{dist-DJ_vDk0q.js → dist-CAXUIcdd.js} +3 -3
  52. package/dist-vue/_chunks/{dist-DJ_vDk0q.js.map → dist-CAXUIcdd.js.map} +1 -1
  53. package/dist-vue/_chunks/{dist-C38fHUMa.js → dist-D-VT7gvP.js} +2 -2
  54. package/dist-vue/_chunks/{dist-C38fHUMa.js.map → dist-D-VT7gvP.js.map} +1 -1
  55. package/dist-vue/_chunks/{dist-BrsWoii-.js → dist-DEe8jwtO.js} +2 -2
  56. package/dist-vue/_chunks/{dist-BrsWoii-.js.map → dist-DEe8jwtO.js.map} +1 -1
  57. package/dist-vue/_chunks/{dist-BmqFgHbN.js → dist-DV82RztV.js} +2 -2
  58. package/dist-vue/_chunks/{dist-BmqFgHbN.js.map → dist-DV82RztV.js.map} +1 -1
  59. package/dist-vue/_chunks/{dist-ByzpJpuj.js → dist-DVM_p-M1.js} +3 -3
  60. package/dist-vue/_chunks/{dist-ByzpJpuj.js.map → dist-DVM_p-M1.js.map} +1 -1
  61. package/dist-vue/_chunks/{dist-D3coexrW.js → dist-DfEAZDKB.js} +2 -2
  62. package/dist-vue/_chunks/{dist-D3coexrW.js.map → dist-DfEAZDKB.js.map} +1 -1
  63. package/dist-vue/_chunks/{dist-veLX58Me.js → dist-QbFF3eM_.js} +2 -2
  64. package/dist-vue/_chunks/{dist-veLX58Me.js.map → dist-QbFF3eM_.js.map} +1 -1
  65. package/dist-vue/_chunks/{dist-B65AhbTK.js → dist-bUGhZmKp.js} +3 -3
  66. package/dist-vue/_chunks/{dist-B65AhbTK.js.map → dist-bUGhZmKp.js.map} +1 -1
  67. package/dist-vue/_chunks/{dist-DmKzgdbO.js → dist-jVwgEJDw.js} +2 -2
  68. package/dist-vue/_chunks/{dist-DmKzgdbO.js.map → dist-jVwgEJDw.js.map} +1 -1
  69. package/dist-vue/_chunks/src-DjRNH9vV.js.map +1 -1
  70. package/dist-vue/_chunks/{useChatbotStore-B9BUWM4O.js → useChatbotStore-ys9uGP5v.js} +4 -10
  71. package/dist-vue/_chunks/{useChatbotStore-B9BUWM4O.js.map → useChatbotStore-ys9uGP5v.js.map} +1 -1
  72. package/dist-vue/composables.js +1 -1
  73. package/dist-vue/index.js +32 -32
  74. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PkChatbotMessages-CQdxH86L.js","names":["$d","$emit","$n"],"sources":["../../../../packages/components/src/chat/toolComponentMap.ts","../../../../packages/components/src/chat/PkStreamingMarkdownAutoscroll.vue","../../../../packages/components/src/chat/PkStreamingMarkdownAutoscroll.vue","../../../../packages/components/src/chat/PkChatbotMessages.vue","../../../../packages/components/src/chat/PkChatbotMessages.vue"],"sourcesContent":["import { defineAsyncComponent } from 'vue'\n\n/**\n * Maps tool `part.type` to the corresponding component for auto-rendering.\n * Only includes simple tools that accept only a `:part` prop.\n * Interactive tools (showContactForm, showSuggestedReply, showSources,\n * showMultipleChoice) must be wired explicitly in the parent with their\n * required callbacks/events.\n */\nexport const toolComponentMap: Record<\n string,\n ReturnType<typeof defineAsyncComponent>\n> = {\n showArtifact: defineAsyncComponent(\n () => import('./PkToolShowArtifact.vue'),\n ),\n showEmail: defineAsyncComponent(() => import('./PkToolShowEmail.vue')),\n showMessage: defineAsyncComponent(() => import('./PkToolShowMessage.vue')),\n showWebPages: defineAsyncComponent(\n () => import('./PkToolShowWebPages.vue'),\n ),\n showProductList: defineAsyncComponent(\n () => import('./PkToolShowProductList.vue'),\n ),\n showCalendarEvent: defineAsyncComponent(\n () => import('./PkToolShowCalendarEvent.vue'),\n ),\n showComparison: defineAsyncComponent(\n () => import('./PkToolShowComparison.vue'),\n ),\n showLocation: defineAsyncComponent(\n () => import('./PkToolShowLocation.vue'),\n ),\n showQrCode: defineAsyncComponent(() => import('./PkToolShowQrCode.vue')),\n showImageGallery: defineAsyncComponent(\n () => import('./PkToolShowImageGallery.vue'),\n ),\n showWeather: defineAsyncComponent(() => import('./PkToolShowWeather.vue')),\n}\n","<script lang=\"ts\" setup>\n import { nextTick, ref, watch } from 'vue'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n\n const props = defineProps<{\n markdown?: string\n innerClass?: string\n }>()\n\n const scrollEl = ref<HTMLDivElement>()\n const lastScrollTop = ref<number>(0)\n const stopAutoScroll = ref<boolean>(false)\n\n const handleScroll = () => {\n if (!scrollEl.value) {\n return\n }\n const currentScrollTop = scrollEl.value.scrollTop\n if (currentScrollTop < lastScrollTop.value) {\n const delta = lastScrollTop.value - currentScrollTop\n if (delta < 50) {\n stopAutoScroll.value = true\n }\n }\n if (currentScrollTop > lastScrollTop.value) {\n if (\n currentScrollTop ===\n scrollEl.value.scrollHeight - scrollEl.value.clientHeight\n ) {\n stopAutoScroll.value = false\n }\n }\n lastScrollTop.value = currentScrollTop\n }\n\n watch(\n () => props.markdown,\n async () => {\n await nextTick()\n if (scrollEl.value && !stopAutoScroll.value) {\n scrollEl.value.scrollTop = scrollEl.value.scrollHeight\n }\n },\n { immediate: true },\n )\n</script>\n\n<template>\n <div\n ref=\"scrollEl\"\n class=\"overflow-auto light-scrollbar\"\n @scroll=\"handleScroll\">\n <PkStreamingMarkdown :markdown=\"markdown\" :class=\"innerClass\" />\n </div>\n</template>\n","<script lang=\"ts\" setup>\n import { nextTick, ref, watch } from 'vue'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n\n const props = defineProps<{\n markdown?: string\n innerClass?: string\n }>()\n\n const scrollEl = ref<HTMLDivElement>()\n const lastScrollTop = ref<number>(0)\n const stopAutoScroll = ref<boolean>(false)\n\n const handleScroll = () => {\n if (!scrollEl.value) {\n return\n }\n const currentScrollTop = scrollEl.value.scrollTop\n if (currentScrollTop < lastScrollTop.value) {\n const delta = lastScrollTop.value - currentScrollTop\n if (delta < 50) {\n stopAutoScroll.value = true\n }\n }\n if (currentScrollTop > lastScrollTop.value) {\n if (\n currentScrollTop ===\n scrollEl.value.scrollHeight - scrollEl.value.clientHeight\n ) {\n stopAutoScroll.value = false\n }\n }\n lastScrollTop.value = currentScrollTop\n }\n\n watch(\n () => props.markdown,\n async () => {\n await nextTick()\n if (scrollEl.value && !stopAutoScroll.value) {\n scrollEl.value.scrollTop = scrollEl.value.scrollHeight\n }\n },\n { immediate: true },\n )\n</script>\n\n<template>\n <div\n ref=\"scrollEl\"\n class=\"overflow-auto light-scrollbar\"\n @scroll=\"handleScroll\">\n <PkStreamingMarkdown :markdown=\"markdown\" :class=\"innerClass\" />\n </div>\n</template>\n","<script lang=\"ts\" setup>\n import type {\n ChatMessageActions,\n MessageFeedback,\n RevisedAnswer,\n UIChatMessage,\n } from 'models'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n import PkChatbotError from './PkChatbotError.vue'\n import PkChatbotFeedbackForm from './PkChatbotFeedbackForm.vue'\n import PkChatbotFilePreview from './PkChatbotFilePreview.vue'\n import PkRelativeTime from '../PkRelativeTime.vue'\n import { useI18n } from 'vue-i18n'\n import {\n useTemplateRef,\n ref,\n watch,\n onMounted,\n computed,\n nextTick,\n useSlots,\n } from 'vue'\n import { toolComponentMap } from './toolComponentMap'\n import {\n resolveContrastColor,\n getPartState,\n isTextPart,\n isFilePart,\n isToolPart,\n isStreamingPart,\n getPartIcon,\n getToolPartLabel,\n } from './utils'\n import { getToolPartName, toKebabCase } from 'utils'\n import PkStreamingMarkdownAutoscroll from './PkStreamingMarkdownAutoscroll.vue'\n\n const props = defineProps<{\n status?: 'submitted' | 'streaming' | 'ready' | 'error'\n messages?: UIChatMessage[]\n logo?: string\n name?: string\n error?: Error\n actions?: ChatMessageActions[]\n mainColor?: string\n textColor?: 'auto' | 'white' | 'black'\n revisedAnswers?: RevisedAnswer[]\n messageFeedbacks?: MessageFeedback[]\n disableHeightAdjustment?: boolean\n showMessageDateTime?: boolean\n showMessageTokensCount?: boolean\n showAllMessageParts?: boolean\n // TODO: move feedback in a separate component to avoid passing these props\n feedbackMessageId?: string\n feedbackLoading?: boolean\n feedbackSubmitted?: boolean\n feedbackError?: string\n }>()\n\n const emit = defineEmits<{\n (e: 'show-info', message: UIChatMessage): void\n (e: 'regenerate'): void\n (e: 'revise', message: UIChatMessage): void\n (e: 'upvote', message: UIChatMessage): void\n (e: 'downvote', message: UIChatMessage): void\n (e: 'feedback', message: UIChatMessage): void\n (e: 'feedback-submit', comment: string): void\n (e: 'feedback-close'): void\n (e: 'scroll-up'): void\n (e: 'scroll-down'): void\n (e: 'auto-retry'): void\n (e: 'reset-chat'): void\n }>()\n\n const { t: $t } = useI18n({\n useScope: 'global',\n })\n\n const slots = useSlots()\n\n const scrollEl = useTemplateRef<HTMLDivElement>('scrollEl')\n const scrollTimeout = ref<NodeJS.Timeout>()\n const lastScrollTop = ref<number>(0)\n const stopAutoScroll = ref<boolean>(false)\n const contrastColor = computed(() =>\n resolveContrastColor(props.textColor, props.mainColor),\n )\n\n const handleScroll = () => {\n if (!scrollEl.value) {\n return\n }\n const currentScrollTop = scrollEl.value.scrollTop\n if (currentScrollTop < lastScrollTop.value) {\n const delta = lastScrollTop.value - currentScrollTop\n if (delta < 50) {\n stopAutoScroll.value = true\n }\n emit('scroll-up')\n }\n if (currentScrollTop > lastScrollTop.value) {\n emit('scroll-down')\n if (\n currentScrollTop ===\n scrollEl.value.scrollHeight - scrollEl.value.clientHeight\n ) {\n stopAutoScroll.value = false\n }\n }\n lastScrollTop.value = currentScrollTop\n }\n\n const smootScrollToBottom = () => {\n if (!scrollEl.value) {\n return\n }\n if (scrollTimeout.value) {\n clearTimeout(scrollTimeout.value)\n }\n if (stopAutoScroll.value) {\n return\n }\n scrollTimeout.value = setTimeout(() => {\n scrollEl.value?.scrollTo({\n top: scrollEl.value.scrollHeight,\n behavior: 'smooth',\n })\n }, 10)\n }\n\n watch(\n () => props.status,\n (newStatus) => {\n if (newStatus === 'ready') {\n smootScrollToBottom()\n }\n },\n )\n\n const messagesElRefs = useTemplateRef<HTMLDivElement[]>('messagesEl')\n const height = ref<number>(0)\n watch(\n () => props.messages,\n async (messages) => {\n if (messages?.[messages.length - 1]?.role !== 'assistant') {\n stopAutoScroll.value = false\n return\n }\n\n // Wait for DOM to update before calculating heights\n await nextTick()\n smootScrollToBottom()\n\n if (props.disableHeightAdjustment) {\n return\n }\n\n const scrollElHeight = (scrollEl.value?.clientHeight ?? 0) - 48\n // last user message index\n const lastUserMessageIndex = messages\n .map((message) => message.role)\n .lastIndexOf('user')\n const lastUserMessageHeight =\n messagesElRefs.value?.[lastUserMessageIndex]?.clientHeight ?? 0\n const newHeight = scrollElHeight - lastUserMessageHeight\n if (newHeight) {\n height.value = newHeight\n }\n },\n {\n deep: true,\n },\n )\n\n onMounted(() => {\n smootScrollToBottom()\n })\n\n const isRevised = (messageId: string) => {\n return props.revisedAnswers?.some((r) => r.messageId === messageId)\n }\n\n const getMessageFeedback = (messageId: string) =>\n props.messageFeedbacks?.find((f) => f.messageId === messageId)\n\n const activeMessage = computed(() => {\n return props.messages?.[props.messages.length - 1]\n })\n const activeMessageLastPart = computed(() => {\n const active = activeMessage.value\n if (!active) {\n return null\n }\n return active.parts[active.parts.length - 1]\n })\n const isLoading = computed(() => {\n return props.status === 'submitted' || props.status === 'streaming'\n })\n const isError = computed(() => props.status === 'error')\n\n const activeMessageLastPartLabel = computed(() => {\n const part = activeMessageLastPart.value\n return getToolPartLabel($t, part)\n })\n const activeMessageLastPartIcon = computed(() => {\n const part = activeMessageLastPart.value\n return getPartIcon(part)\n })\n\n const getMessageIndexById = (messageId: string) => {\n return props.messages?.findIndex((m) => m.id === messageId)\n }\n const isLastUserMessageIndex = (index?: number) => {\n if (index === undefined || !props.messages) {\n return false\n }\n return index === (props.messages?.length ?? 0) - 1\n }\n const isMessageRegenerateButtonVisible = (index: number) => {\n return (\n isLastUserMessageIndex(index) &&\n props.status === 'ready' &&\n props.actions?.includes('regenerate')\n )\n }\n const isActionButtonVisible = (\n action: ChatMessageActions,\n index: number,\n ) => {\n return (\n ((isLastUserMessageIndex(index) && props.status === 'ready') ||\n !isLastUserMessageIndex(index)) &&\n props.actions?.includes(action)\n )\n }\n const isLastTextPart = (message: UIChatMessage) => {\n const lastPart = message.parts[message.parts.length - 1]\n return isTextPart(lastPart)\n }\n const getPreviousAssistantMessage = (index: number) => {\n return props.messages\n ?.slice(0, index)\n .reverse()\n .find((message) => message.role === 'assistant')\n }\n const getNextAssistantMessage = (index: number) => {\n return props.messages\n ?.slice(index + 1)\n .find((message) => message.role === 'assistant')\n }\n const isDayChanged = (index: number) => {\n const previousAssistantMessage = getPreviousAssistantMessage(index)\n const nextAssistantMessage = getNextAssistantMessage(index)\n if (\n !previousAssistantMessage?.metadata?.createdAt ||\n !nextAssistantMessage?.metadata?.createdAt\n ) {\n return false\n }\n const currentDate = new Date(\n previousAssistantMessage.metadata.createdAt,\n )\n const previousDate = new Date(nextAssistantMessage.metadata.createdAt)\n return (\n currentDate.getFullYear() !== previousDate.getFullYear() ||\n currentDate.getMonth() !== previousDate.getMonth() ||\n currentDate.getDate() !== previousDate.getDate()\n )\n }\n const showMessageFooter = (message: UIChatMessage, index: number) => {\n if (index === 0 || message.role !== 'assistant') {\n return false\n }\n return (\n props.actions?.length ||\n (props.showMessageDateTime &&\n message.metadata?.createdAt !== undefined) ||\n (props.showMessageTokensCount &&\n message.metadata?.totalTokens !== undefined)\n )\n }\n // feedback message auto scroll\n const feedbackMessageEl = ref<(typeof PkChatbotFeedbackForm)[]>()\n watch(\n () => props.feedbackMessageId,\n async () => {\n await nextTick()\n setTimeout(() => {\n if (props.feedbackMessageId) {\n if (feedbackMessageEl.value?.[0]?.$el) {\n if (\n isLastUserMessageIndex(\n getMessageIndexById(props.feedbackMessageId),\n )\n ) {\n smootScrollToBottom()\n return\n }\n feedbackMessageEl.value[0].$el.scrollIntoView({\n behavior: 'smooth',\n block: 'center',\n })\n }\n }\n }, 10)\n },\n )\n</script>\n\n<template>\n <div\n ref=\"scrollEl\"\n class=\"pk-chatbot-messages\"\n :style=\"{\n '--chatbot-main-color': mainColor,\n '--chatbot-contrast-color': contrastColor,\n }\"\n @scroll=\"handleScroll\">\n <div class=\"pk-chatbot-messages__wrapper\">\n <template v-for=\"(message, index) in messages\" :key=\"message.id\">\n <div\n v-if=\"\n index > 0 &&\n message.role === 'user' &&\n isDayChanged(index)\n \"\n class=\"pk-chatbot-divider\">\n <span class=\"pk-chatbot-divider__label\">\n {{\n $d(\n new Date(\n getNextAssistantMessage(index)?.metadata\n ?.createdAt ?? '',\n ),\n 'short',\n )\n }}\n </span>\n </div>\n <div\n ref=\"messagesEl\"\n class=\"pk-chatbot-message\"\n :class=\"[\n `pk-chatbot-message--${message.role}`,\n {\n 'pk-chatbot-message--loading':\n isLastUserMessageIndex(index) &&\n isLoading &&\n message.role === 'assistant',\n },\n ]\"\n :style=\"{\n minHeight:\n isLastUserMessageIndex(index) &&\n message.role === 'assistant' &&\n !isError\n ? `${height}px`\n : undefined,\n }\">\n <template\n v-for=\"(part, partIndex) in message.parts\"\n :key=\"partIndex\">\n <div\n v-if=\"isTextPart(part)\"\n class=\"pk-chatbot-message__text\">\n <PkStreamingMarkdown\n v-if=\"message.role === 'assistant'\"\n class=\"wysiwyg\"\n :markdown=\"part.text\"\n :loading=\"\n index === (messages?.length ?? 0) - 1 &&\n status === 'streaming'\n \" />\n <template v-else>\n {{ part.text }}\n </template>\n </div>\n <PkChatbotFilePreview\n v-else-if=\"isFilePart(part)\"\n :media-type=\"part.mediaType\"\n :url=\"part.url\"\n :filename=\"part.filename\" />\n <template\n v-else-if=\"\n isToolPart(part) && !isStreamingPart(part)\n \">\n <component\n :is=\"toolComponentMap[getToolPartName(part)]\"\n v-if=\"\n !slots[part.type] &&\n toolComponentMap[getToolPartName(part)]\n \"\n :key=\"`component-${partIndex}-${getPartState(part)}`\"\n :part />\n <slot\n v-else\n :key=\"`slot-${partIndex}-${getPartState(part)}`\"\n :name=\"part.type\"\n v-bind=\"{\n message,\n part,\n index,\n isLoading,\n }\">\n <template v-if=\"showAllMessageParts\">\n <div\n class=\"pk-chatbot-message__loading-info\">\n <div class=\"flex gap-8 items-center\">\n <VvIcon\n v-if=\"getPartIcon(part)\"\n :name=\"getPartIcon(part)!\"\n class=\"shrink-0\" />\n <code\n class=\"font-mono rounded text-10\">\n {{ toKebabCase(part.type) }}\n </code>\n </div>\n </div>\n </template>\n </slot>\n </template>\n </template>\n <transition mode=\"out-in\">\n <div\n v-if=\"\n isLoading &&\n isLastUserMessageIndex(index) &&\n !isLastTextPart(message) &&\n message.role === 'assistant'\n \"\n :key=\"`loading-info-${message.id}`\"\n class=\"pk-chatbot-message__loading-info\">\n <div class=\"flex gap-8 items-center\">\n <VvIcon\n name=\"line-md:loading-loop\"\n class=\"shrink-0\" />\n <transition mode=\"out-in\">\n <VvIcon\n v-if=\"activeMessageLastPartIcon\"\n :key=\"activeMessageLastPartIcon\"\n class=\"shrink-0\"\n :name=\"activeMessageLastPartIcon\" />\n </transition>\n <transition mode=\"out-in\">\n <span\n v-if=\"activeMessageLastPartLabel\"\n :key=\"activeMessageLastPartLabel\"\n class=\"text-10\">\n {{ activeMessageLastPartLabel }}\n </span>\n </transition>\n </div>\n <transition mode=\"out-in\">\n <PkStreamingMarkdownAutoscroll\n v-if=\"\n activeMessageLastPart &&\n 'text' in activeMessageLastPart &&\n activeMessageLastPart.text.trim()\n \"\n :markdown=\"activeMessageLastPart.text\"\n inner-class=\"wysiwyg\"\n class=\"border border-surface-4 rounded p-4 mt-8 bg-surface-1 max-h-64 text-10 w-full\" />\n </transition>\n </div>\n </transition>\n <transition mode=\"out-in\">\n <div\n v-if=\"showMessageFooter(message, index)\"\n class=\"pk-chatbot-message__footer\">\n <VvButtonGroup modifiers=\"compact\" class=\"mr-auto\">\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isMessageRegenerateButtonVisible(\n index,\n )\n \"\n icon=\"ri:reset-right-line\"\n modifiers=\"action-quiet-small\"\n :title=\"$t('action.regenerate')\"\n @click.stop=\"$emit('regenerate')\" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'show-info',\n index,\n )\n \"\n icon=\"ri:information-line\"\n :title=\"$t('action.getMoreInfo')\"\n modifiers=\"action-quiet-small\"\n @click.stop=\"\n $emit('show-info', message)\n \" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'revise',\n index,\n )\n \"\n :icon=\"\n isRevised(message.id)\n ? 'ri:file-edit-fill'\n : 'ri:file-edit-line'\n \"\n :title=\"\n isRevised(message.id)\n ? $t('action.editRevise')\n : $t('action.createRevise')\n \"\n modifiers=\"action-quiet-small\"\n :class=\"{\n 'text-brand': isRevised(message.id),\n }\"\n @click.stop=\"\n $emit('revise', message)\n \" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'upvote',\n index,\n )\n \"\n :icon=\"\n getMessageFeedback(message.id)\n ?.vote === 'upvote'\n ? 'ri:thumb-up-fill'\n : 'ri:thumb-up-line'\n \"\n :title=\"$t('action.upvote')\"\n modifiers=\"action-quiet-small\"\n @click.stop=\"\n $emit('upvote', message)\n \" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'downvote',\n index,\n )\n \"\n :icon=\"\n getMessageFeedback(message.id)\n ?.vote === 'downvote'\n ? 'ri:thumb-down-fill'\n : 'ri:thumb-down-line'\n \"\n :title=\"$t('action.downvote')\"\n modifiers=\"action-quiet-small\"\n @click.stop=\"\n $emit('downvote', message)\n \" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'feedback',\n index,\n )\n \"\n :icon=\"\n getMessageFeedback(message.id)\n ?.comment\n ? 'ri:feedback-fill'\n : 'ri:feedback-line'\n \"\n :title=\"$t('action.feedback')\"\n modifiers=\"action-quiet-small\"\n @click.stop=\"\n $emit('feedback', message)\n \" />\n </transition>\n </VvButtonGroup>\n <span\n v-if=\"\n showMessageTokensCount &&\n message.metadata?.totalTokens\n \"\n class=\"flex items-center gap-4 text-12 text-word-3\">\n <VvIcon name=\"ri:ai-generate-2-line\" />\n {{\n $n(message.metadata.totalTokens, 'integer')\n }}\n {{ $t('label.tokens') }}\n </span>\n <time\n v-if=\"\n showMessageDateTime &&\n message.metadata?.createdAt\n \"\n :datetime=\"\n new Date(\n message.metadata?.createdAt,\n ).toISOString()\n \"\n class=\"flex items-center gap-4 text-12 text-word-3\">\n <VvIcon name=\"ri:time-line\" />\n {{\n $d(\n new Date(message.metadata?.createdAt),\n 'date-time',\n )\n }}\n </time>\n <div\n v-if=\"\n showMessageDateTime &&\n message?.metadata?.completedAt &&\n message?.metadata?.createdAt\n \"\n class=\"flex items-center gap-4 text-12 text-word-3\">\n <VvIcon name=\"ri:hourglass-line\" />\n <PkRelativeTime\n :date=\"message.metadata?.createdAt\"\n :end-date=\"message.metadata?.completedAt\" />\n </div>\n </div>\n </transition>\n <transition mode=\"out-in\">\n <PkChatbotFeedbackForm\n v-if=\"message.id === feedbackMessageId\"\n ref=\"feedbackMessageEl\"\n :loading=\"feedbackLoading\"\n :submitted=\"feedbackSubmitted\"\n :error=\"feedbackError\"\n @submit=\"$emit('feedback-submit', $event)\"\n @close=\"$emit('feedback-close')\" />\n </transition>\n </div>\n </template>\n <PkChatbotError\n v-if=\"isError\"\n :error\n @retry=\"$emit('auto-retry')\"\n @reset=\"$emit('reset-chat')\" />\n <div\n v-if=\"activeMessage?.role === 'user' || isError\"\n :style=\"{ minHeight: `${height}px` }\"></div>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-messages {\n overflow-y: auto;\n flex: 1;\n min-width: 0;\n font-size: var(--spacing-14);\n\n scrollbar-width: thin;\n scrollbar-gutter: auto;\n scrollbar-color: var(--color-word-5) var(--color-surface-1);\n\n &__wrapper {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-16);\n min-width: 0;\n }\n\n &__divider {\n border-bottom: 1px solid var(--color-surface-3);\n }\n }\n\n .pk-chatbot-divider {\n position: relative;\n border-bottom: 1px solid var(--color-surface-3);\n\n &__label {\n position: absolute;\n padding-inline: var(--spacing-8);\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: var(--color-surface);\n color: var(--color-word-4);\n font-size: var(--text-12);\n }\n }\n\n .pk-chatbot-message {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-sm);\n min-width: 0;\n align-items: flex-start;\n\n &__text {\n color: var(--color-word-2);\n line-height: var(--leading-normal);\n border-width: var(--spacing-px);\n border-color: var(--color-surface-3);\n padding: var(--spacing-sm);\n border-radius: var(--rounded-xl) var(--rounded-xl) var(--rounded-xl)\n 0;\n }\n\n &__loading-info {\n line-height: var(--leading-normal);\n border-width: var(--spacing-px);\n border-color: var(--color-surface-3);\n padding: var(--spacing-sm);\n border-radius: var(--rounded-xl) var(--rounded-xl) var(--rounded-xl)\n 0;\n font-size: var(--text-12);\n color: var(--color-word-3);\n }\n\n &__footer {\n width: 100%;\n display: flex;\n gap: var(--spacing-8);\n align-items: center;\n }\n\n &--user {\n align-items: flex-end;\n\n .pk-chatbot-message__text {\n background-color: var(\n --chatbot-main-color,\n var(--color-surface-1)\n );\n border-width: var(--spacing-px);\n border-color: var(--chatbot-main-color, var(--color-surface-4));\n color: var(--chatbot-contrast-color, var(--color-word-1));\n border-radius: var(--rounded-xl) var(--rounded-xl) 0\n var(--rounded-xl);\n }\n }\n\n &--assistant {\n width: 100%;\n display: flex;\n min-width: 0;\n flex-direction: column;\n gap: var(--spacing-16);\n overflow: hidden;\n\n .pk-chatbot-message__text {\n width: 100%;\n }\n }\n\n &--system {\n align-items: flex-end;\n\n .pk-chatbot-message__text {\n display: flex;\n gap: var(--spacing-8);\n font-size: var(--text-12);\n padding: var(--spacing-8) var(--spacing-sm);\n align-items: center;\n border-width: var(--spacing-px);\n border-color: var(--chatbot-main-color, var(--color-surface-4));\n color: var(--chatbot-main-color, var(--color-word-1));\n border-radius: var(--rounded-xl) var(--rounded-xl) 0\n var(--rounded-xl);\n }\n }\n }\n</style>\n","<script lang=\"ts\" setup>\n import type {\n ChatMessageActions,\n MessageFeedback,\n RevisedAnswer,\n UIChatMessage,\n } from 'models'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n import PkChatbotError from './PkChatbotError.vue'\n import PkChatbotFeedbackForm from './PkChatbotFeedbackForm.vue'\n import PkChatbotFilePreview from './PkChatbotFilePreview.vue'\n import PkRelativeTime from '../PkRelativeTime.vue'\n import { useI18n } from 'vue-i18n'\n import {\n useTemplateRef,\n ref,\n watch,\n onMounted,\n computed,\n nextTick,\n useSlots,\n } from 'vue'\n import { toolComponentMap } from './toolComponentMap'\n import {\n resolveContrastColor,\n getPartState,\n isTextPart,\n isFilePart,\n isToolPart,\n isStreamingPart,\n getPartIcon,\n getToolPartLabel,\n } from './utils'\n import { getToolPartName, toKebabCase } from 'utils'\n import PkStreamingMarkdownAutoscroll from './PkStreamingMarkdownAutoscroll.vue'\n\n const props = defineProps<{\n status?: 'submitted' | 'streaming' | 'ready' | 'error'\n messages?: UIChatMessage[]\n logo?: string\n name?: string\n error?: Error\n actions?: ChatMessageActions[]\n mainColor?: string\n textColor?: 'auto' | 'white' | 'black'\n revisedAnswers?: RevisedAnswer[]\n messageFeedbacks?: MessageFeedback[]\n disableHeightAdjustment?: boolean\n showMessageDateTime?: boolean\n showMessageTokensCount?: boolean\n showAllMessageParts?: boolean\n // TODO: move feedback in a separate component to avoid passing these props\n feedbackMessageId?: string\n feedbackLoading?: boolean\n feedbackSubmitted?: boolean\n feedbackError?: string\n }>()\n\n const emit = defineEmits<{\n (e: 'show-info', message: UIChatMessage): void\n (e: 'regenerate'): void\n (e: 'revise', message: UIChatMessage): void\n (e: 'upvote', message: UIChatMessage): void\n (e: 'downvote', message: UIChatMessage): void\n (e: 'feedback', message: UIChatMessage): void\n (e: 'feedback-submit', comment: string): void\n (e: 'feedback-close'): void\n (e: 'scroll-up'): void\n (e: 'scroll-down'): void\n (e: 'auto-retry'): void\n (e: 'reset-chat'): void\n }>()\n\n const { t: $t } = useI18n({\n useScope: 'global',\n })\n\n const slots = useSlots()\n\n const scrollEl = useTemplateRef<HTMLDivElement>('scrollEl')\n const scrollTimeout = ref<NodeJS.Timeout>()\n const lastScrollTop = ref<number>(0)\n const stopAutoScroll = ref<boolean>(false)\n const contrastColor = computed(() =>\n resolveContrastColor(props.textColor, props.mainColor),\n )\n\n const handleScroll = () => {\n if (!scrollEl.value) {\n return\n }\n const currentScrollTop = scrollEl.value.scrollTop\n if (currentScrollTop < lastScrollTop.value) {\n const delta = lastScrollTop.value - currentScrollTop\n if (delta < 50) {\n stopAutoScroll.value = true\n }\n emit('scroll-up')\n }\n if (currentScrollTop > lastScrollTop.value) {\n emit('scroll-down')\n if (\n currentScrollTop ===\n scrollEl.value.scrollHeight - scrollEl.value.clientHeight\n ) {\n stopAutoScroll.value = false\n }\n }\n lastScrollTop.value = currentScrollTop\n }\n\n const smootScrollToBottom = () => {\n if (!scrollEl.value) {\n return\n }\n if (scrollTimeout.value) {\n clearTimeout(scrollTimeout.value)\n }\n if (stopAutoScroll.value) {\n return\n }\n scrollTimeout.value = setTimeout(() => {\n scrollEl.value?.scrollTo({\n top: scrollEl.value.scrollHeight,\n behavior: 'smooth',\n })\n }, 10)\n }\n\n watch(\n () => props.status,\n (newStatus) => {\n if (newStatus === 'ready') {\n smootScrollToBottom()\n }\n },\n )\n\n const messagesElRefs = useTemplateRef<HTMLDivElement[]>('messagesEl')\n const height = ref<number>(0)\n watch(\n () => props.messages,\n async (messages) => {\n if (messages?.[messages.length - 1]?.role !== 'assistant') {\n stopAutoScroll.value = false\n return\n }\n\n // Wait for DOM to update before calculating heights\n await nextTick()\n smootScrollToBottom()\n\n if (props.disableHeightAdjustment) {\n return\n }\n\n const scrollElHeight = (scrollEl.value?.clientHeight ?? 0) - 48\n // last user message index\n const lastUserMessageIndex = messages\n .map((message) => message.role)\n .lastIndexOf('user')\n const lastUserMessageHeight =\n messagesElRefs.value?.[lastUserMessageIndex]?.clientHeight ?? 0\n const newHeight = scrollElHeight - lastUserMessageHeight\n if (newHeight) {\n height.value = newHeight\n }\n },\n {\n deep: true,\n },\n )\n\n onMounted(() => {\n smootScrollToBottom()\n })\n\n const isRevised = (messageId: string) => {\n return props.revisedAnswers?.some((r) => r.messageId === messageId)\n }\n\n const getMessageFeedback = (messageId: string) =>\n props.messageFeedbacks?.find((f) => f.messageId === messageId)\n\n const activeMessage = computed(() => {\n return props.messages?.[props.messages.length - 1]\n })\n const activeMessageLastPart = computed(() => {\n const active = activeMessage.value\n if (!active) {\n return null\n }\n return active.parts[active.parts.length - 1]\n })\n const isLoading = computed(() => {\n return props.status === 'submitted' || props.status === 'streaming'\n })\n const isError = computed(() => props.status === 'error')\n\n const activeMessageLastPartLabel = computed(() => {\n const part = activeMessageLastPart.value\n return getToolPartLabel($t, part)\n })\n const activeMessageLastPartIcon = computed(() => {\n const part = activeMessageLastPart.value\n return getPartIcon(part)\n })\n\n const getMessageIndexById = (messageId: string) => {\n return props.messages?.findIndex((m) => m.id === messageId)\n }\n const isLastUserMessageIndex = (index?: number) => {\n if (index === undefined || !props.messages) {\n return false\n }\n return index === (props.messages?.length ?? 0) - 1\n }\n const isMessageRegenerateButtonVisible = (index: number) => {\n return (\n isLastUserMessageIndex(index) &&\n props.status === 'ready' &&\n props.actions?.includes('regenerate')\n )\n }\n const isActionButtonVisible = (\n action: ChatMessageActions,\n index: number,\n ) => {\n return (\n ((isLastUserMessageIndex(index) && props.status === 'ready') ||\n !isLastUserMessageIndex(index)) &&\n props.actions?.includes(action)\n )\n }\n const isLastTextPart = (message: UIChatMessage) => {\n const lastPart = message.parts[message.parts.length - 1]\n return isTextPart(lastPart)\n }\n const getPreviousAssistantMessage = (index: number) => {\n return props.messages\n ?.slice(0, index)\n .reverse()\n .find((message) => message.role === 'assistant')\n }\n const getNextAssistantMessage = (index: number) => {\n return props.messages\n ?.slice(index + 1)\n .find((message) => message.role === 'assistant')\n }\n const isDayChanged = (index: number) => {\n const previousAssistantMessage = getPreviousAssistantMessage(index)\n const nextAssistantMessage = getNextAssistantMessage(index)\n if (\n !previousAssistantMessage?.metadata?.createdAt ||\n !nextAssistantMessage?.metadata?.createdAt\n ) {\n return false\n }\n const currentDate = new Date(\n previousAssistantMessage.metadata.createdAt,\n )\n const previousDate = new Date(nextAssistantMessage.metadata.createdAt)\n return (\n currentDate.getFullYear() !== previousDate.getFullYear() ||\n currentDate.getMonth() !== previousDate.getMonth() ||\n currentDate.getDate() !== previousDate.getDate()\n )\n }\n const showMessageFooter = (message: UIChatMessage, index: number) => {\n if (index === 0 || message.role !== 'assistant') {\n return false\n }\n return (\n props.actions?.length ||\n (props.showMessageDateTime &&\n message.metadata?.createdAt !== undefined) ||\n (props.showMessageTokensCount &&\n message.metadata?.totalTokens !== undefined)\n )\n }\n // feedback message auto scroll\n const feedbackMessageEl = ref<(typeof PkChatbotFeedbackForm)[]>()\n watch(\n () => props.feedbackMessageId,\n async () => {\n await nextTick()\n setTimeout(() => {\n if (props.feedbackMessageId) {\n if (feedbackMessageEl.value?.[0]?.$el) {\n if (\n isLastUserMessageIndex(\n getMessageIndexById(props.feedbackMessageId),\n )\n ) {\n smootScrollToBottom()\n return\n }\n feedbackMessageEl.value[0].$el.scrollIntoView({\n behavior: 'smooth',\n block: 'center',\n })\n }\n }\n }, 10)\n },\n )\n</script>\n\n<template>\n <div\n ref=\"scrollEl\"\n class=\"pk-chatbot-messages\"\n :style=\"{\n '--chatbot-main-color': mainColor,\n '--chatbot-contrast-color': contrastColor,\n }\"\n @scroll=\"handleScroll\">\n <div class=\"pk-chatbot-messages__wrapper\">\n <template v-for=\"(message, index) in messages\" :key=\"message.id\">\n <div\n v-if=\"\n index > 0 &&\n message.role === 'user' &&\n isDayChanged(index)\n \"\n class=\"pk-chatbot-divider\">\n <span class=\"pk-chatbot-divider__label\">\n {{\n $d(\n new Date(\n getNextAssistantMessage(index)?.metadata\n ?.createdAt ?? '',\n ),\n 'short',\n )\n }}\n </span>\n </div>\n <div\n ref=\"messagesEl\"\n class=\"pk-chatbot-message\"\n :class=\"[\n `pk-chatbot-message--${message.role}`,\n {\n 'pk-chatbot-message--loading':\n isLastUserMessageIndex(index) &&\n isLoading &&\n message.role === 'assistant',\n },\n ]\"\n :style=\"{\n minHeight:\n isLastUserMessageIndex(index) &&\n message.role === 'assistant' &&\n !isError\n ? `${height}px`\n : undefined,\n }\">\n <template\n v-for=\"(part, partIndex) in message.parts\"\n :key=\"partIndex\">\n <div\n v-if=\"isTextPart(part)\"\n class=\"pk-chatbot-message__text\">\n <PkStreamingMarkdown\n v-if=\"message.role === 'assistant'\"\n class=\"wysiwyg\"\n :markdown=\"part.text\"\n :loading=\"\n index === (messages?.length ?? 0) - 1 &&\n status === 'streaming'\n \" />\n <template v-else>\n {{ part.text }}\n </template>\n </div>\n <PkChatbotFilePreview\n v-else-if=\"isFilePart(part)\"\n :media-type=\"part.mediaType\"\n :url=\"part.url\"\n :filename=\"part.filename\" />\n <template\n v-else-if=\"\n isToolPart(part) && !isStreamingPart(part)\n \">\n <component\n :is=\"toolComponentMap[getToolPartName(part)]\"\n v-if=\"\n !slots[part.type] &&\n toolComponentMap[getToolPartName(part)]\n \"\n :key=\"`component-${partIndex}-${getPartState(part)}`\"\n :part />\n <slot\n v-else\n :key=\"`slot-${partIndex}-${getPartState(part)}`\"\n :name=\"part.type\"\n v-bind=\"{\n message,\n part,\n index,\n isLoading,\n }\">\n <template v-if=\"showAllMessageParts\">\n <div\n class=\"pk-chatbot-message__loading-info\">\n <div class=\"flex gap-8 items-center\">\n <VvIcon\n v-if=\"getPartIcon(part)\"\n :name=\"getPartIcon(part)!\"\n class=\"shrink-0\" />\n <code\n class=\"font-mono rounded text-10\">\n {{ toKebabCase(part.type) }}\n </code>\n </div>\n </div>\n </template>\n </slot>\n </template>\n </template>\n <transition mode=\"out-in\">\n <div\n v-if=\"\n isLoading &&\n isLastUserMessageIndex(index) &&\n !isLastTextPart(message) &&\n message.role === 'assistant'\n \"\n :key=\"`loading-info-${message.id}`\"\n class=\"pk-chatbot-message__loading-info\">\n <div class=\"flex gap-8 items-center\">\n <VvIcon\n name=\"line-md:loading-loop\"\n class=\"shrink-0\" />\n <transition mode=\"out-in\">\n <VvIcon\n v-if=\"activeMessageLastPartIcon\"\n :key=\"activeMessageLastPartIcon\"\n class=\"shrink-0\"\n :name=\"activeMessageLastPartIcon\" />\n </transition>\n <transition mode=\"out-in\">\n <span\n v-if=\"activeMessageLastPartLabel\"\n :key=\"activeMessageLastPartLabel\"\n class=\"text-10\">\n {{ activeMessageLastPartLabel }}\n </span>\n </transition>\n </div>\n <transition mode=\"out-in\">\n <PkStreamingMarkdownAutoscroll\n v-if=\"\n activeMessageLastPart &&\n 'text' in activeMessageLastPart &&\n activeMessageLastPart.text.trim()\n \"\n :markdown=\"activeMessageLastPart.text\"\n inner-class=\"wysiwyg\"\n class=\"border border-surface-4 rounded p-4 mt-8 bg-surface-1 max-h-64 text-10 w-full\" />\n </transition>\n </div>\n </transition>\n <transition mode=\"out-in\">\n <div\n v-if=\"showMessageFooter(message, index)\"\n class=\"pk-chatbot-message__footer\">\n <VvButtonGroup modifiers=\"compact\" class=\"mr-auto\">\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isMessageRegenerateButtonVisible(\n index,\n )\n \"\n icon=\"ri:reset-right-line\"\n modifiers=\"action-quiet-small\"\n :title=\"$t('action.regenerate')\"\n @click.stop=\"$emit('regenerate')\" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'show-info',\n index,\n )\n \"\n icon=\"ri:information-line\"\n :title=\"$t('action.getMoreInfo')\"\n modifiers=\"action-quiet-small\"\n @click.stop=\"\n $emit('show-info', message)\n \" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'revise',\n index,\n )\n \"\n :icon=\"\n isRevised(message.id)\n ? 'ri:file-edit-fill'\n : 'ri:file-edit-line'\n \"\n :title=\"\n isRevised(message.id)\n ? $t('action.editRevise')\n : $t('action.createRevise')\n \"\n modifiers=\"action-quiet-small\"\n :class=\"{\n 'text-brand': isRevised(message.id),\n }\"\n @click.stop=\"\n $emit('revise', message)\n \" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'upvote',\n index,\n )\n \"\n :icon=\"\n getMessageFeedback(message.id)\n ?.vote === 'upvote'\n ? 'ri:thumb-up-fill'\n : 'ri:thumb-up-line'\n \"\n :title=\"$t('action.upvote')\"\n modifiers=\"action-quiet-small\"\n @click.stop=\"\n $emit('upvote', message)\n \" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'downvote',\n index,\n )\n \"\n :icon=\"\n getMessageFeedback(message.id)\n ?.vote === 'downvote'\n ? 'ri:thumb-down-fill'\n : 'ri:thumb-down-line'\n \"\n :title=\"$t('action.downvote')\"\n modifiers=\"action-quiet-small\"\n @click.stop=\"\n $emit('downvote', message)\n \" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'feedback',\n index,\n )\n \"\n :icon=\"\n getMessageFeedback(message.id)\n ?.comment\n ? 'ri:feedback-fill'\n : 'ri:feedback-line'\n \"\n :title=\"$t('action.feedback')\"\n modifiers=\"action-quiet-small\"\n @click.stop=\"\n $emit('feedback', message)\n \" />\n </transition>\n </VvButtonGroup>\n <span\n v-if=\"\n showMessageTokensCount &&\n message.metadata?.totalTokens\n \"\n class=\"flex items-center gap-4 text-12 text-word-3\">\n <VvIcon name=\"ri:ai-generate-2-line\" />\n {{\n $n(message.metadata.totalTokens, 'integer')\n }}\n {{ $t('label.tokens') }}\n </span>\n <time\n v-if=\"\n showMessageDateTime &&\n message.metadata?.createdAt\n \"\n :datetime=\"\n new Date(\n message.metadata?.createdAt,\n ).toISOString()\n \"\n class=\"flex items-center gap-4 text-12 text-word-3\">\n <VvIcon name=\"ri:time-line\" />\n {{\n $d(\n new Date(message.metadata?.createdAt),\n 'date-time',\n )\n }}\n </time>\n <div\n v-if=\"\n showMessageDateTime &&\n message?.metadata?.completedAt &&\n message?.metadata?.createdAt\n \"\n class=\"flex items-center gap-4 text-12 text-word-3\">\n <VvIcon name=\"ri:hourglass-line\" />\n <PkRelativeTime\n :date=\"message.metadata?.createdAt\"\n :end-date=\"message.metadata?.completedAt\" />\n </div>\n </div>\n </transition>\n <transition mode=\"out-in\">\n <PkChatbotFeedbackForm\n v-if=\"message.id === feedbackMessageId\"\n ref=\"feedbackMessageEl\"\n :loading=\"feedbackLoading\"\n :submitted=\"feedbackSubmitted\"\n :error=\"feedbackError\"\n @submit=\"$emit('feedback-submit', $event)\"\n @close=\"$emit('feedback-close')\" />\n </transition>\n </div>\n </template>\n <PkChatbotError\n v-if=\"isError\"\n :error\n @retry=\"$emit('auto-retry')\"\n @reset=\"$emit('reset-chat')\" />\n <div\n v-if=\"activeMessage?.role === 'user' || isError\"\n :style=\"{ minHeight: `${height}px` }\"></div>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-messages {\n overflow-y: auto;\n flex: 1;\n min-width: 0;\n font-size: var(--spacing-14);\n\n scrollbar-width: thin;\n scrollbar-gutter: auto;\n scrollbar-color: var(--color-word-5) var(--color-surface-1);\n\n &__wrapper {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-16);\n min-width: 0;\n }\n\n &__divider {\n border-bottom: 1px solid var(--color-surface-3);\n }\n }\n\n .pk-chatbot-divider {\n position: relative;\n border-bottom: 1px solid var(--color-surface-3);\n\n &__label {\n position: absolute;\n padding-inline: var(--spacing-8);\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: var(--color-surface);\n color: var(--color-word-4);\n font-size: var(--text-12);\n }\n }\n\n .pk-chatbot-message {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-sm);\n min-width: 0;\n align-items: flex-start;\n\n &__text {\n color: var(--color-word-2);\n line-height: var(--leading-normal);\n border-width: var(--spacing-px);\n border-color: var(--color-surface-3);\n padding: var(--spacing-sm);\n border-radius: var(--rounded-xl) var(--rounded-xl) var(--rounded-xl)\n 0;\n }\n\n &__loading-info {\n line-height: var(--leading-normal);\n border-width: var(--spacing-px);\n border-color: var(--color-surface-3);\n padding: var(--spacing-sm);\n border-radius: var(--rounded-xl) var(--rounded-xl) var(--rounded-xl)\n 0;\n font-size: var(--text-12);\n color: var(--color-word-3);\n }\n\n &__footer {\n width: 100%;\n display: flex;\n gap: var(--spacing-8);\n align-items: center;\n }\n\n &--user {\n align-items: flex-end;\n\n .pk-chatbot-message__text {\n background-color: var(\n --chatbot-main-color,\n var(--color-surface-1)\n );\n border-width: var(--spacing-px);\n border-color: var(--chatbot-main-color, var(--color-surface-4));\n color: var(--chatbot-contrast-color, var(--color-word-1));\n border-radius: var(--rounded-xl) var(--rounded-xl) 0\n var(--rounded-xl);\n }\n }\n\n &--assistant {\n width: 100%;\n display: flex;\n min-width: 0;\n flex-direction: column;\n gap: var(--spacing-16);\n overflow: hidden;\n\n .pk-chatbot-message__text {\n width: 100%;\n }\n }\n\n &--system {\n align-items: flex-end;\n\n .pk-chatbot-message__text {\n display: flex;\n gap: var(--spacing-8);\n font-size: var(--text-12);\n padding: var(--spacing-8) var(--spacing-sm);\n align-items: center;\n border-width: var(--spacing-px);\n border-color: var(--chatbot-main-color, var(--color-surface-4));\n color: var(--chatbot-main-color, var(--color-word-1));\n border-radius: var(--rounded-xl) var(--rounded-xl) 0\n var(--rounded-xl);\n }\n }\n }\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"PkChatbotMessages-C7-ZtU0-.js","names":["$d","$emit","$n"],"sources":["../../../../packages/components/src/chat/toolComponentMap.ts","../../../../packages/components/src/chat/PkStreamingMarkdownAutoscroll.vue","../../../../packages/components/src/chat/PkStreamingMarkdownAutoscroll.vue","../../../../packages/components/src/chat/PkChatbotMessages.vue","../../../../packages/components/src/chat/PkChatbotMessages.vue"],"sourcesContent":["import { defineAsyncComponent } from 'vue'\n\n/**\n * Maps tool `part.type` to the corresponding component for auto-rendering.\n * Only includes simple tools that accept only a `:part` prop.\n * Interactive tools (showContactForm, showSuggestedReply, showSources,\n * showMultipleChoice) must be wired explicitly in the parent with their\n * required callbacks/events.\n */\nexport const toolComponentMap: Record<\n string,\n ReturnType<typeof defineAsyncComponent>\n> = {\n showArtifact: defineAsyncComponent(\n () => import('./PkToolShowArtifact.vue'),\n ),\n showEmail: defineAsyncComponent(() => import('./PkToolShowEmail.vue')),\n showMessage: defineAsyncComponent(() => import('./PkToolShowMessage.vue')),\n showWebPages: defineAsyncComponent(\n () => import('./PkToolShowWebPages.vue'),\n ),\n showProductList: defineAsyncComponent(\n () => import('./PkToolShowProductList.vue'),\n ),\n showCalendarEvent: defineAsyncComponent(\n () => import('./PkToolShowCalendarEvent.vue'),\n ),\n showComparison: defineAsyncComponent(\n () => import('./PkToolShowComparison.vue'),\n ),\n showLocation: defineAsyncComponent(\n () => import('./PkToolShowLocation.vue'),\n ),\n showQrCode: defineAsyncComponent(() => import('./PkToolShowQrCode.vue')),\n showImageGallery: defineAsyncComponent(\n () => import('./PkToolShowImageGallery.vue'),\n ),\n showWeather: defineAsyncComponent(() => import('./PkToolShowWeather.vue')),\n}\n","<script lang=\"ts\" setup>\n import { nextTick, ref, watch } from 'vue'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n\n const props = defineProps<{\n markdown?: string\n innerClass?: string\n }>()\n\n const scrollEl = ref<HTMLDivElement>()\n const lastScrollTop = ref<number>(0)\n const stopAutoScroll = ref<boolean>(false)\n\n const handleScroll = () => {\n if (!scrollEl.value) {\n return\n }\n const currentScrollTop = scrollEl.value.scrollTop\n if (currentScrollTop < lastScrollTop.value) {\n const delta = lastScrollTop.value - currentScrollTop\n if (delta < 50) {\n stopAutoScroll.value = true\n }\n }\n if (currentScrollTop > lastScrollTop.value) {\n if (\n currentScrollTop ===\n scrollEl.value.scrollHeight - scrollEl.value.clientHeight\n ) {\n stopAutoScroll.value = false\n }\n }\n lastScrollTop.value = currentScrollTop\n }\n\n watch(\n () => props.markdown,\n async () => {\n await nextTick()\n if (scrollEl.value && !stopAutoScroll.value) {\n scrollEl.value.scrollTop = scrollEl.value.scrollHeight\n }\n },\n { immediate: true },\n )\n</script>\n\n<template>\n <div\n ref=\"scrollEl\"\n class=\"overflow-auto light-scrollbar\"\n @scroll=\"handleScroll\">\n <PkStreamingMarkdown :markdown=\"markdown\" :class=\"innerClass\" />\n </div>\n</template>\n","<script lang=\"ts\" setup>\n import { nextTick, ref, watch } from 'vue'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n\n const props = defineProps<{\n markdown?: string\n innerClass?: string\n }>()\n\n const scrollEl = ref<HTMLDivElement>()\n const lastScrollTop = ref<number>(0)\n const stopAutoScroll = ref<boolean>(false)\n\n const handleScroll = () => {\n if (!scrollEl.value) {\n return\n }\n const currentScrollTop = scrollEl.value.scrollTop\n if (currentScrollTop < lastScrollTop.value) {\n const delta = lastScrollTop.value - currentScrollTop\n if (delta < 50) {\n stopAutoScroll.value = true\n }\n }\n if (currentScrollTop > lastScrollTop.value) {\n if (\n currentScrollTop ===\n scrollEl.value.scrollHeight - scrollEl.value.clientHeight\n ) {\n stopAutoScroll.value = false\n }\n }\n lastScrollTop.value = currentScrollTop\n }\n\n watch(\n () => props.markdown,\n async () => {\n await nextTick()\n if (scrollEl.value && !stopAutoScroll.value) {\n scrollEl.value.scrollTop = scrollEl.value.scrollHeight\n }\n },\n { immediate: true },\n )\n</script>\n\n<template>\n <div\n ref=\"scrollEl\"\n class=\"overflow-auto light-scrollbar\"\n @scroll=\"handleScroll\">\n <PkStreamingMarkdown :markdown=\"markdown\" :class=\"innerClass\" />\n </div>\n</template>\n","<script lang=\"ts\" setup>\n import type {\n ChatMessageActions,\n MessageFeedback,\n RevisedAnswer,\n UIChatMessage,\n } from 'models'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n import PkChatbotError from './PkChatbotError.vue'\n import PkChatbotFeedbackForm from './PkChatbotFeedbackForm.vue'\n import PkChatbotFilePreview from './PkChatbotFilePreview.vue'\n import PkRelativeTime from '../PkRelativeTime.vue'\n import { useI18n } from 'vue-i18n'\n import {\n useTemplateRef,\n ref,\n watch,\n onMounted,\n computed,\n nextTick,\n useSlots,\n } from 'vue'\n import { toolComponentMap } from './toolComponentMap'\n import {\n resolveContrastColor,\n getPartState,\n isTextPart,\n isFilePart,\n isToolPart,\n isStreamingPart,\n getPartIcon,\n getToolPartLabel,\n } from './utils'\n import { getToolPartName, toKebabCase } from 'utils'\n import PkStreamingMarkdownAutoscroll from './PkStreamingMarkdownAutoscroll.vue'\n\n const props = defineProps<{\n status?: 'submitted' | 'streaming' | 'ready' | 'error'\n messages?: UIChatMessage[]\n logo?: string\n name?: string\n error?: Error\n actions?: ChatMessageActions[]\n mainColor?: string\n textColor?: 'auto' | 'white' | 'black'\n revisedAnswers?: RevisedAnswer[]\n messageFeedbacks?: MessageFeedback[]\n disableHeightAdjustment?: boolean\n showMessageDateTime?: boolean\n showMessageTokensCount?: boolean\n showAllMessageParts?: boolean\n // TODO: move feedback in a separate component to avoid passing these props\n feedbackMessageId?: string\n feedbackLoading?: boolean\n feedbackSubmitted?: boolean\n feedbackError?: string\n }>()\n\n const emit = defineEmits<{\n (e: 'show-info', message: UIChatMessage): void\n (e: 'regenerate'): void\n (e: 'revise', message: UIChatMessage): void\n (e: 'upvote', message: UIChatMessage): void\n (e: 'downvote', message: UIChatMessage): void\n (e: 'feedback', message: UIChatMessage): void\n (e: 'feedback-submit', comment: string): void\n (e: 'feedback-close'): void\n (e: 'scroll-up'): void\n (e: 'scroll-down'): void\n (e: 'auto-retry'): void\n (e: 'reset-chat'): void\n }>()\n\n const { t: $t } = useI18n({\n useScope: 'global',\n })\n\n const slots = useSlots()\n\n const scrollEl = useTemplateRef<HTMLDivElement>('scrollEl')\n const scrollTimeout = ref<NodeJS.Timeout>()\n const lastScrollTop = ref<number>(0)\n const stopAutoScroll = ref<boolean>(false)\n const contrastColor = computed(() =>\n resolveContrastColor(props.textColor, props.mainColor),\n )\n\n const handleScroll = () => {\n if (!scrollEl.value) {\n return\n }\n const currentScrollTop = scrollEl.value.scrollTop\n if (currentScrollTop < lastScrollTop.value) {\n const delta = lastScrollTop.value - currentScrollTop\n if (delta < 50) {\n stopAutoScroll.value = true\n }\n emit('scroll-up')\n }\n if (currentScrollTop > lastScrollTop.value) {\n emit('scroll-down')\n if (\n currentScrollTop ===\n scrollEl.value.scrollHeight - scrollEl.value.clientHeight\n ) {\n stopAutoScroll.value = false\n }\n }\n lastScrollTop.value = currentScrollTop\n }\n\n const smootScrollToBottom = () => {\n if (!scrollEl.value) {\n return\n }\n if (scrollTimeout.value) {\n clearTimeout(scrollTimeout.value)\n }\n if (stopAutoScroll.value) {\n return\n }\n scrollTimeout.value = setTimeout(() => {\n scrollEl.value?.scrollTo({\n top: scrollEl.value.scrollHeight,\n behavior: 'smooth',\n })\n }, 10)\n }\n\n watch(\n () => props.status,\n (newStatus) => {\n if (newStatus === 'ready') {\n smootScrollToBottom()\n }\n },\n )\n\n const messagesElRefs = useTemplateRef<HTMLDivElement[]>('messagesEl')\n const height = ref<number>(0)\n watch(\n () => props.messages,\n async (messages) => {\n if (messages?.[messages.length - 1]?.role !== 'assistant') {\n stopAutoScroll.value = false\n return\n }\n\n // Wait for DOM to update before calculating heights\n await nextTick()\n smootScrollToBottom()\n\n if (props.disableHeightAdjustment) {\n return\n }\n\n const scrollElHeight = (scrollEl.value?.clientHeight ?? 0) - 48\n // last user message index\n const lastUserMessageIndex = messages\n .map((message) => message.role)\n .lastIndexOf('user')\n const lastUserMessageHeight =\n messagesElRefs.value?.[lastUserMessageIndex]?.clientHeight ?? 0\n const newHeight = scrollElHeight - lastUserMessageHeight\n if (newHeight) {\n height.value = newHeight\n }\n },\n {\n deep: true,\n },\n )\n\n onMounted(() => {\n smootScrollToBottom()\n })\n\n const isRevised = (messageId: string) => {\n return props.revisedAnswers?.some((r) => r.messageId === messageId)\n }\n\n const getMessageFeedback = (messageId: string) =>\n props.messageFeedbacks?.find((f) => f.messageId === messageId)\n\n const activeMessage = computed(() => {\n return props.messages?.[props.messages.length - 1]\n })\n const activeMessageLastPart = computed(() => {\n const active = activeMessage.value\n if (!active) {\n return null\n }\n return active.parts[active.parts.length - 1]\n })\n const isLoading = computed(() => {\n return props.status === 'submitted' || props.status === 'streaming'\n })\n const isError = computed(() => props.status === 'error')\n\n const activeMessageLastPartLabel = computed(() => {\n const part = activeMessageLastPart.value\n return getToolPartLabel($t, part)\n })\n const activeMessageLastPartIcon = computed(() => {\n const part = activeMessageLastPart.value\n return getPartIcon(part)\n })\n\n const getMessageIndexById = (messageId: string) => {\n return props.messages?.findIndex((m) => m.id === messageId)\n }\n const isLastUserMessageIndex = (index?: number) => {\n if (index === undefined || !props.messages) {\n return false\n }\n return index === (props.messages?.length ?? 0) - 1\n }\n const isMessageRegenerateButtonVisible = (index: number) => {\n return (\n isLastUserMessageIndex(index) &&\n props.status === 'ready' &&\n props.actions?.includes('regenerate')\n )\n }\n const isActionButtonVisible = (\n action: ChatMessageActions,\n index: number,\n ) => {\n return (\n ((isLastUserMessageIndex(index) && props.status === 'ready') ||\n !isLastUserMessageIndex(index)) &&\n props.actions?.includes(action)\n )\n }\n const isLastTextPart = (message: UIChatMessage) => {\n const lastPart = message.parts[message.parts.length - 1]\n return isTextPart(lastPart)\n }\n const getPreviousAssistantMessage = (index: number) => {\n return props.messages\n ?.slice(0, index)\n .reverse()\n .find((message) => message.role === 'assistant')\n }\n const getNextAssistantMessage = (index: number) => {\n return props.messages\n ?.slice(index + 1)\n .find((message) => message.role === 'assistant')\n }\n const isDayChanged = (index: number) => {\n const previousAssistantMessage = getPreviousAssistantMessage(index)\n const nextAssistantMessage = getNextAssistantMessage(index)\n if (\n !previousAssistantMessage?.metadata?.createdAt ||\n !nextAssistantMessage?.metadata?.createdAt\n ) {\n return false\n }\n const currentDate = new Date(\n previousAssistantMessage.metadata.createdAt,\n )\n const previousDate = new Date(nextAssistantMessage.metadata.createdAt)\n return (\n currentDate.getFullYear() !== previousDate.getFullYear() ||\n currentDate.getMonth() !== previousDate.getMonth() ||\n currentDate.getDate() !== previousDate.getDate()\n )\n }\n const showMessageFooter = (message: UIChatMessage, index: number) => {\n if (index === 0 || message.role !== 'assistant') {\n return false\n }\n return (\n props.actions?.length ||\n (props.showMessageDateTime &&\n message.metadata?.createdAt !== undefined) ||\n (props.showMessageTokensCount &&\n message.metadata?.totalTokens !== undefined)\n )\n }\n // feedback message auto scroll\n const feedbackMessageEl = ref<(typeof PkChatbotFeedbackForm)[]>()\n watch(\n () => props.feedbackMessageId,\n async () => {\n await nextTick()\n setTimeout(() => {\n if (props.feedbackMessageId) {\n if (feedbackMessageEl.value?.[0]?.$el) {\n if (\n isLastUserMessageIndex(\n getMessageIndexById(props.feedbackMessageId),\n )\n ) {\n smootScrollToBottom()\n return\n }\n feedbackMessageEl.value[0].$el.scrollIntoView({\n behavior: 'smooth',\n block: 'center',\n })\n }\n }\n }, 10)\n },\n )\n</script>\n\n<template>\n <div\n ref=\"scrollEl\"\n class=\"pk-chatbot-messages\"\n :style=\"{\n '--chatbot-main-color': mainColor,\n '--chatbot-contrast-color': contrastColor,\n }\"\n @scroll=\"handleScroll\">\n <div class=\"pk-chatbot-messages__wrapper\">\n <template v-for=\"(message, index) in messages\" :key=\"message.id\">\n <div\n v-if=\"\n index > 0 &&\n message.role === 'user' &&\n isDayChanged(index)\n \"\n class=\"pk-chatbot-divider\">\n <span class=\"pk-chatbot-divider__label\">\n {{\n $d(\n new Date(\n getNextAssistantMessage(index)?.metadata\n ?.createdAt ?? '',\n ),\n 'short',\n )\n }}\n </span>\n </div>\n <div\n ref=\"messagesEl\"\n class=\"pk-chatbot-message\"\n :class=\"[\n `pk-chatbot-message--${message.role}`,\n {\n 'pk-chatbot-message--loading':\n isLastUserMessageIndex(index) &&\n isLoading &&\n message.role === 'assistant',\n },\n ]\"\n :style=\"{\n minHeight:\n isLastUserMessageIndex(index) &&\n message.role === 'assistant' &&\n !isError\n ? `${height}px`\n : undefined,\n }\">\n <template\n v-for=\"(part, partIndex) in message.parts\"\n :key=\"partIndex\">\n <div\n v-if=\"isTextPart(part)\"\n class=\"pk-chatbot-message__text\">\n <PkStreamingMarkdown\n v-if=\"message.role === 'assistant'\"\n class=\"wysiwyg\"\n :markdown=\"part.text\"\n :loading=\"\n index === (messages?.length ?? 0) - 1 &&\n status === 'streaming'\n \" />\n <template v-else>\n {{ part.text }}\n </template>\n </div>\n <PkChatbotFilePreview\n v-else-if=\"isFilePart(part)\"\n :media-type=\"part.mediaType\"\n :url=\"part.url\"\n :filename=\"part.filename\" />\n <template\n v-else-if=\"\n isToolPart(part) && !isStreamingPart(part)\n \">\n <component\n :is=\"toolComponentMap[getToolPartName(part)]\"\n v-if=\"\n !slots[part.type] &&\n toolComponentMap[getToolPartName(part)]\n \"\n :key=\"`component-${partIndex}-${getPartState(part)}`\"\n :part />\n <slot\n v-else\n :key=\"`slot-${partIndex}-${getPartState(part)}`\"\n :name=\"part.type\"\n v-bind=\"{\n message,\n part,\n index,\n isLoading,\n }\">\n <template v-if=\"showAllMessageParts\">\n <div\n class=\"pk-chatbot-message__loading-info\">\n <div class=\"flex gap-8 items-center\">\n <VvIcon\n v-if=\"getPartIcon(part)\"\n :name=\"getPartIcon(part)!\"\n class=\"shrink-0\" />\n <code\n class=\"font-mono rounded text-10\">\n {{ toKebabCase(part.type) }}\n </code>\n </div>\n </div>\n </template>\n </slot>\n </template>\n </template>\n <transition mode=\"out-in\">\n <div\n v-if=\"\n isLoading &&\n isLastUserMessageIndex(index) &&\n !isLastTextPart(message) &&\n message.role === 'assistant'\n \"\n :key=\"`loading-info-${message.id}`\"\n class=\"pk-chatbot-message__loading-info\">\n <div class=\"flex gap-8 items-center\">\n <VvIcon\n name=\"line-md:loading-loop\"\n class=\"shrink-0\" />\n <transition mode=\"out-in\">\n <VvIcon\n v-if=\"activeMessageLastPartIcon\"\n :key=\"activeMessageLastPartIcon\"\n class=\"shrink-0\"\n :name=\"activeMessageLastPartIcon\" />\n </transition>\n <transition mode=\"out-in\">\n <span\n v-if=\"activeMessageLastPartLabel\"\n :key=\"activeMessageLastPartLabel\"\n class=\"text-10\">\n {{ activeMessageLastPartLabel }}\n </span>\n </transition>\n </div>\n <transition mode=\"out-in\">\n <PkStreamingMarkdownAutoscroll\n v-if=\"\n activeMessageLastPart &&\n 'text' in activeMessageLastPart &&\n activeMessageLastPart.text.trim()\n \"\n :markdown=\"activeMessageLastPart.text\"\n inner-class=\"wysiwyg\"\n class=\"border border-surface-4 rounded p-4 mt-8 bg-surface-1 max-h-64 text-10 w-full\" />\n </transition>\n </div>\n </transition>\n <transition mode=\"out-in\">\n <div\n v-if=\"showMessageFooter(message, index)\"\n class=\"pk-chatbot-message__footer\">\n <VvButtonGroup modifiers=\"compact\" class=\"mr-auto\">\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isMessageRegenerateButtonVisible(\n index,\n )\n \"\n icon=\"ri:reset-right-line\"\n modifiers=\"action-quiet-small\"\n :title=\"$t('action.regenerate')\"\n @click.stop=\"$emit('regenerate')\" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'show-info',\n index,\n )\n \"\n icon=\"ri:information-line\"\n :title=\"$t('action.getMoreInfo')\"\n modifiers=\"action-quiet-small\"\n @click.stop=\"\n $emit('show-info', message)\n \" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'revise',\n index,\n )\n \"\n :icon=\"\n isRevised(message.id)\n ? 'ri:file-edit-fill'\n : 'ri:file-edit-line'\n \"\n :title=\"\n isRevised(message.id)\n ? $t('action.editRevise')\n : $t('action.createRevise')\n \"\n modifiers=\"action-quiet-small\"\n :class=\"{\n 'text-brand': isRevised(message.id),\n }\"\n @click.stop=\"\n $emit('revise', message)\n \" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'upvote',\n index,\n )\n \"\n :icon=\"\n getMessageFeedback(message.id)\n ?.vote === 'upvote'\n ? 'ri:thumb-up-fill'\n : 'ri:thumb-up-line'\n \"\n :title=\"$t('action.upvote')\"\n modifiers=\"action-quiet-small\"\n @click.stop=\"\n $emit('upvote', message)\n \" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'downvote',\n index,\n )\n \"\n :icon=\"\n getMessageFeedback(message.id)\n ?.vote === 'downvote'\n ? 'ri:thumb-down-fill'\n : 'ri:thumb-down-line'\n \"\n :title=\"$t('action.downvote')\"\n modifiers=\"action-quiet-small\"\n @click.stop=\"\n $emit('downvote', message)\n \" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'feedback',\n index,\n )\n \"\n :icon=\"\n getMessageFeedback(message.id)\n ?.comment\n ? 'ri:feedback-fill'\n : 'ri:feedback-line'\n \"\n :title=\"$t('action.feedback')\"\n modifiers=\"action-quiet-small\"\n @click.stop=\"\n $emit('feedback', message)\n \" />\n </transition>\n </VvButtonGroup>\n <span\n v-if=\"\n showMessageTokensCount &&\n message.metadata?.totalTokens\n \"\n class=\"flex items-center gap-4 text-12 text-word-3\">\n <VvIcon name=\"ri:ai-generate-2-line\" />\n {{\n $n(message.metadata.totalTokens, 'integer')\n }}\n {{ $t('label.tokens') }}\n </span>\n <time\n v-if=\"\n showMessageDateTime &&\n message.metadata?.createdAt\n \"\n :datetime=\"\n new Date(\n message.metadata?.createdAt,\n ).toISOString()\n \"\n class=\"flex items-center gap-4 text-12 text-word-3\">\n <VvIcon name=\"ri:time-line\" />\n {{\n $d(\n new Date(message.metadata?.createdAt),\n 'date-time',\n )\n }}\n </time>\n <div\n v-if=\"\n showMessageDateTime &&\n message?.metadata?.completedAt &&\n message?.metadata?.createdAt\n \"\n class=\"flex items-center gap-4 text-12 text-word-3\">\n <VvIcon name=\"ri:hourglass-line\" />\n <PkRelativeTime\n :date=\"message.metadata?.createdAt\"\n :end-date=\"message.metadata?.completedAt\" />\n </div>\n </div>\n </transition>\n <transition mode=\"out-in\">\n <PkChatbotFeedbackForm\n v-if=\"message.id === feedbackMessageId\"\n ref=\"feedbackMessageEl\"\n :loading=\"feedbackLoading\"\n :submitted=\"feedbackSubmitted\"\n :error=\"feedbackError\"\n @submit=\"$emit('feedback-submit', $event)\"\n @close=\"$emit('feedback-close')\" />\n </transition>\n </div>\n </template>\n <PkChatbotError\n v-if=\"isError\"\n :error\n @retry=\"$emit('auto-retry')\"\n @reset=\"$emit('reset-chat')\" />\n <div\n v-if=\"activeMessage?.role === 'user' || isError\"\n :style=\"{ minHeight: `${height}px` }\"></div>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-messages {\n overflow-y: auto;\n flex: 1;\n min-width: 0;\n font-size: var(--spacing-14);\n\n scrollbar-width: thin;\n scrollbar-gutter: auto;\n scrollbar-color: var(--color-word-5) var(--color-surface-1);\n\n &__wrapper {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-16);\n min-width: 0;\n }\n\n &__divider {\n border-bottom: 1px solid var(--color-surface-3);\n }\n }\n\n .pk-chatbot-divider {\n position: relative;\n border-bottom: 1px solid var(--color-surface-3);\n\n &__label {\n position: absolute;\n padding-inline: var(--spacing-8);\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: var(--color-surface);\n color: var(--color-word-4);\n font-size: var(--text-12);\n }\n }\n\n .pk-chatbot-message {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-sm);\n min-width: 0;\n align-items: flex-start;\n\n &__text {\n color: var(--color-word-2);\n line-height: var(--leading-normal);\n border-width: var(--spacing-px);\n border-color: var(--color-surface-3);\n padding: var(--spacing-sm);\n border-radius: var(--rounded-xl) var(--rounded-xl) var(--rounded-xl)\n 0;\n }\n\n &__loading-info {\n line-height: var(--leading-normal);\n border-width: var(--spacing-px);\n border-color: var(--color-surface-3);\n padding: var(--spacing-sm);\n border-radius: var(--rounded-xl) var(--rounded-xl) var(--rounded-xl)\n 0;\n font-size: var(--text-12);\n color: var(--color-word-3);\n }\n\n &__footer {\n width: 100%;\n display: flex;\n gap: var(--spacing-8);\n align-items: center;\n }\n\n &--user {\n align-items: flex-end;\n\n .pk-chatbot-message__text {\n background-color: var(\n --chatbot-main-color,\n var(--color-surface-1)\n );\n border-width: var(--spacing-px);\n border-color: var(--chatbot-main-color, var(--color-surface-4));\n color: var(--chatbot-contrast-color, var(--color-word-1));\n border-radius: var(--rounded-xl) var(--rounded-xl) 0\n var(--rounded-xl);\n }\n }\n\n &--assistant {\n width: 100%;\n display: flex;\n min-width: 0;\n flex-direction: column;\n gap: var(--spacing-16);\n overflow: hidden;\n\n .pk-chatbot-message__text {\n width: 100%;\n }\n }\n\n &--system {\n align-items: flex-end;\n\n .pk-chatbot-message__text {\n display: flex;\n gap: var(--spacing-8);\n font-size: var(--text-12);\n padding: var(--spacing-8) var(--spacing-sm);\n align-items: center;\n border-width: var(--spacing-px);\n border-color: var(--chatbot-main-color, var(--color-surface-4));\n color: var(--chatbot-main-color, var(--color-word-1));\n border-radius: var(--rounded-xl) var(--rounded-xl) 0\n var(--rounded-xl);\n }\n }\n }\n</style>\n","<script lang=\"ts\" setup>\n import type {\n ChatMessageActions,\n MessageFeedback,\n RevisedAnswer,\n UIChatMessage,\n } from 'models'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n import PkChatbotError from './PkChatbotError.vue'\n import PkChatbotFeedbackForm from './PkChatbotFeedbackForm.vue'\n import PkChatbotFilePreview from './PkChatbotFilePreview.vue'\n import PkRelativeTime from '../PkRelativeTime.vue'\n import { useI18n } from 'vue-i18n'\n import {\n useTemplateRef,\n ref,\n watch,\n onMounted,\n computed,\n nextTick,\n useSlots,\n } from 'vue'\n import { toolComponentMap } from './toolComponentMap'\n import {\n resolveContrastColor,\n getPartState,\n isTextPart,\n isFilePart,\n isToolPart,\n isStreamingPart,\n getPartIcon,\n getToolPartLabel,\n } from './utils'\n import { getToolPartName, toKebabCase } from 'utils'\n import PkStreamingMarkdownAutoscroll from './PkStreamingMarkdownAutoscroll.vue'\n\n const props = defineProps<{\n status?: 'submitted' | 'streaming' | 'ready' | 'error'\n messages?: UIChatMessage[]\n logo?: string\n name?: string\n error?: Error\n actions?: ChatMessageActions[]\n mainColor?: string\n textColor?: 'auto' | 'white' | 'black'\n revisedAnswers?: RevisedAnswer[]\n messageFeedbacks?: MessageFeedback[]\n disableHeightAdjustment?: boolean\n showMessageDateTime?: boolean\n showMessageTokensCount?: boolean\n showAllMessageParts?: boolean\n // TODO: move feedback in a separate component to avoid passing these props\n feedbackMessageId?: string\n feedbackLoading?: boolean\n feedbackSubmitted?: boolean\n feedbackError?: string\n }>()\n\n const emit = defineEmits<{\n (e: 'show-info', message: UIChatMessage): void\n (e: 'regenerate'): void\n (e: 'revise', message: UIChatMessage): void\n (e: 'upvote', message: UIChatMessage): void\n (e: 'downvote', message: UIChatMessage): void\n (e: 'feedback', message: UIChatMessage): void\n (e: 'feedback-submit', comment: string): void\n (e: 'feedback-close'): void\n (e: 'scroll-up'): void\n (e: 'scroll-down'): void\n (e: 'auto-retry'): void\n (e: 'reset-chat'): void\n }>()\n\n const { t: $t } = useI18n({\n useScope: 'global',\n })\n\n const slots = useSlots()\n\n const scrollEl = useTemplateRef<HTMLDivElement>('scrollEl')\n const scrollTimeout = ref<NodeJS.Timeout>()\n const lastScrollTop = ref<number>(0)\n const stopAutoScroll = ref<boolean>(false)\n const contrastColor = computed(() =>\n resolveContrastColor(props.textColor, props.mainColor),\n )\n\n const handleScroll = () => {\n if (!scrollEl.value) {\n return\n }\n const currentScrollTop = scrollEl.value.scrollTop\n if (currentScrollTop < lastScrollTop.value) {\n const delta = lastScrollTop.value - currentScrollTop\n if (delta < 50) {\n stopAutoScroll.value = true\n }\n emit('scroll-up')\n }\n if (currentScrollTop > lastScrollTop.value) {\n emit('scroll-down')\n if (\n currentScrollTop ===\n scrollEl.value.scrollHeight - scrollEl.value.clientHeight\n ) {\n stopAutoScroll.value = false\n }\n }\n lastScrollTop.value = currentScrollTop\n }\n\n const smootScrollToBottom = () => {\n if (!scrollEl.value) {\n return\n }\n if (scrollTimeout.value) {\n clearTimeout(scrollTimeout.value)\n }\n if (stopAutoScroll.value) {\n return\n }\n scrollTimeout.value = setTimeout(() => {\n scrollEl.value?.scrollTo({\n top: scrollEl.value.scrollHeight,\n behavior: 'smooth',\n })\n }, 10)\n }\n\n watch(\n () => props.status,\n (newStatus) => {\n if (newStatus === 'ready') {\n smootScrollToBottom()\n }\n },\n )\n\n const messagesElRefs = useTemplateRef<HTMLDivElement[]>('messagesEl')\n const height = ref<number>(0)\n watch(\n () => props.messages,\n async (messages) => {\n if (messages?.[messages.length - 1]?.role !== 'assistant') {\n stopAutoScroll.value = false\n return\n }\n\n // Wait for DOM to update before calculating heights\n await nextTick()\n smootScrollToBottom()\n\n if (props.disableHeightAdjustment) {\n return\n }\n\n const scrollElHeight = (scrollEl.value?.clientHeight ?? 0) - 48\n // last user message index\n const lastUserMessageIndex = messages\n .map((message) => message.role)\n .lastIndexOf('user')\n const lastUserMessageHeight =\n messagesElRefs.value?.[lastUserMessageIndex]?.clientHeight ?? 0\n const newHeight = scrollElHeight - lastUserMessageHeight\n if (newHeight) {\n height.value = newHeight\n }\n },\n {\n deep: true,\n },\n )\n\n onMounted(() => {\n smootScrollToBottom()\n })\n\n const isRevised = (messageId: string) => {\n return props.revisedAnswers?.some((r) => r.messageId === messageId)\n }\n\n const getMessageFeedback = (messageId: string) =>\n props.messageFeedbacks?.find((f) => f.messageId === messageId)\n\n const activeMessage = computed(() => {\n return props.messages?.[props.messages.length - 1]\n })\n const activeMessageLastPart = computed(() => {\n const active = activeMessage.value\n if (!active) {\n return null\n }\n return active.parts[active.parts.length - 1]\n })\n const isLoading = computed(() => {\n return props.status === 'submitted' || props.status === 'streaming'\n })\n const isError = computed(() => props.status === 'error')\n\n const activeMessageLastPartLabel = computed(() => {\n const part = activeMessageLastPart.value\n return getToolPartLabel($t, part)\n })\n const activeMessageLastPartIcon = computed(() => {\n const part = activeMessageLastPart.value\n return getPartIcon(part)\n })\n\n const getMessageIndexById = (messageId: string) => {\n return props.messages?.findIndex((m) => m.id === messageId)\n }\n const isLastUserMessageIndex = (index?: number) => {\n if (index === undefined || !props.messages) {\n return false\n }\n return index === (props.messages?.length ?? 0) - 1\n }\n const isMessageRegenerateButtonVisible = (index: number) => {\n return (\n isLastUserMessageIndex(index) &&\n props.status === 'ready' &&\n props.actions?.includes('regenerate')\n )\n }\n const isActionButtonVisible = (\n action: ChatMessageActions,\n index: number,\n ) => {\n return (\n ((isLastUserMessageIndex(index) && props.status === 'ready') ||\n !isLastUserMessageIndex(index)) &&\n props.actions?.includes(action)\n )\n }\n const isLastTextPart = (message: UIChatMessage) => {\n const lastPart = message.parts[message.parts.length - 1]\n return isTextPart(lastPart)\n }\n const getPreviousAssistantMessage = (index: number) => {\n return props.messages\n ?.slice(0, index)\n .reverse()\n .find((message) => message.role === 'assistant')\n }\n const getNextAssistantMessage = (index: number) => {\n return props.messages\n ?.slice(index + 1)\n .find((message) => message.role === 'assistant')\n }\n const isDayChanged = (index: number) => {\n const previousAssistantMessage = getPreviousAssistantMessage(index)\n const nextAssistantMessage = getNextAssistantMessage(index)\n if (\n !previousAssistantMessage?.metadata?.createdAt ||\n !nextAssistantMessage?.metadata?.createdAt\n ) {\n return false\n }\n const currentDate = new Date(\n previousAssistantMessage.metadata.createdAt,\n )\n const previousDate = new Date(nextAssistantMessage.metadata.createdAt)\n return (\n currentDate.getFullYear() !== previousDate.getFullYear() ||\n currentDate.getMonth() !== previousDate.getMonth() ||\n currentDate.getDate() !== previousDate.getDate()\n )\n }\n const showMessageFooter = (message: UIChatMessage, index: number) => {\n if (index === 0 || message.role !== 'assistant') {\n return false\n }\n return (\n props.actions?.length ||\n (props.showMessageDateTime &&\n message.metadata?.createdAt !== undefined) ||\n (props.showMessageTokensCount &&\n message.metadata?.totalTokens !== undefined)\n )\n }\n // feedback message auto scroll\n const feedbackMessageEl = ref<(typeof PkChatbotFeedbackForm)[]>()\n watch(\n () => props.feedbackMessageId,\n async () => {\n await nextTick()\n setTimeout(() => {\n if (props.feedbackMessageId) {\n if (feedbackMessageEl.value?.[0]?.$el) {\n if (\n isLastUserMessageIndex(\n getMessageIndexById(props.feedbackMessageId),\n )\n ) {\n smootScrollToBottom()\n return\n }\n feedbackMessageEl.value[0].$el.scrollIntoView({\n behavior: 'smooth',\n block: 'center',\n })\n }\n }\n }, 10)\n },\n )\n</script>\n\n<template>\n <div\n ref=\"scrollEl\"\n class=\"pk-chatbot-messages\"\n :style=\"{\n '--chatbot-main-color': mainColor,\n '--chatbot-contrast-color': contrastColor,\n }\"\n @scroll=\"handleScroll\">\n <div class=\"pk-chatbot-messages__wrapper\">\n <template v-for=\"(message, index) in messages\" :key=\"message.id\">\n <div\n v-if=\"\n index > 0 &&\n message.role === 'user' &&\n isDayChanged(index)\n \"\n class=\"pk-chatbot-divider\">\n <span class=\"pk-chatbot-divider__label\">\n {{\n $d(\n new Date(\n getNextAssistantMessage(index)?.metadata\n ?.createdAt ?? '',\n ),\n 'short',\n )\n }}\n </span>\n </div>\n <div\n ref=\"messagesEl\"\n class=\"pk-chatbot-message\"\n :class=\"[\n `pk-chatbot-message--${message.role}`,\n {\n 'pk-chatbot-message--loading':\n isLastUserMessageIndex(index) &&\n isLoading &&\n message.role === 'assistant',\n },\n ]\"\n :style=\"{\n minHeight:\n isLastUserMessageIndex(index) &&\n message.role === 'assistant' &&\n !isError\n ? `${height}px`\n : undefined,\n }\">\n <template\n v-for=\"(part, partIndex) in message.parts\"\n :key=\"partIndex\">\n <div\n v-if=\"isTextPart(part)\"\n class=\"pk-chatbot-message__text\">\n <PkStreamingMarkdown\n v-if=\"message.role === 'assistant'\"\n class=\"wysiwyg\"\n :markdown=\"part.text\"\n :loading=\"\n index === (messages?.length ?? 0) - 1 &&\n status === 'streaming'\n \" />\n <template v-else>\n {{ part.text }}\n </template>\n </div>\n <PkChatbotFilePreview\n v-else-if=\"isFilePart(part)\"\n :media-type=\"part.mediaType\"\n :url=\"part.url\"\n :filename=\"part.filename\" />\n <template\n v-else-if=\"\n isToolPart(part) && !isStreamingPart(part)\n \">\n <component\n :is=\"toolComponentMap[getToolPartName(part)]\"\n v-if=\"\n !slots[part.type] &&\n toolComponentMap[getToolPartName(part)]\n \"\n :key=\"`component-${partIndex}-${getPartState(part)}`\"\n :part />\n <slot\n v-else\n :key=\"`slot-${partIndex}-${getPartState(part)}`\"\n :name=\"part.type\"\n v-bind=\"{\n message,\n part,\n index,\n isLoading,\n }\">\n <template v-if=\"showAllMessageParts\">\n <div\n class=\"pk-chatbot-message__loading-info\">\n <div class=\"flex gap-8 items-center\">\n <VvIcon\n v-if=\"getPartIcon(part)\"\n :name=\"getPartIcon(part)!\"\n class=\"shrink-0\" />\n <code\n class=\"font-mono rounded text-10\">\n {{ toKebabCase(part.type) }}\n </code>\n </div>\n </div>\n </template>\n </slot>\n </template>\n </template>\n <transition mode=\"out-in\">\n <div\n v-if=\"\n isLoading &&\n isLastUserMessageIndex(index) &&\n !isLastTextPart(message) &&\n message.role === 'assistant'\n \"\n :key=\"`loading-info-${message.id}`\"\n class=\"pk-chatbot-message__loading-info\">\n <div class=\"flex gap-8 items-center\">\n <VvIcon\n name=\"line-md:loading-loop\"\n class=\"shrink-0\" />\n <transition mode=\"out-in\">\n <VvIcon\n v-if=\"activeMessageLastPartIcon\"\n :key=\"activeMessageLastPartIcon\"\n class=\"shrink-0\"\n :name=\"activeMessageLastPartIcon\" />\n </transition>\n <transition mode=\"out-in\">\n <span\n v-if=\"activeMessageLastPartLabel\"\n :key=\"activeMessageLastPartLabel\"\n class=\"text-10\">\n {{ activeMessageLastPartLabel }}\n </span>\n </transition>\n </div>\n <transition mode=\"out-in\">\n <PkStreamingMarkdownAutoscroll\n v-if=\"\n activeMessageLastPart &&\n 'text' in activeMessageLastPart &&\n activeMessageLastPart.text.trim()\n \"\n :markdown=\"activeMessageLastPart.text\"\n inner-class=\"wysiwyg\"\n class=\"border border-surface-4 rounded p-4 mt-8 bg-surface-1 max-h-64 text-10 w-full\" />\n </transition>\n </div>\n </transition>\n <transition mode=\"out-in\">\n <div\n v-if=\"showMessageFooter(message, index)\"\n class=\"pk-chatbot-message__footer\">\n <VvButtonGroup modifiers=\"compact\" class=\"mr-auto\">\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isMessageRegenerateButtonVisible(\n index,\n )\n \"\n icon=\"ri:reset-right-line\"\n modifiers=\"action-quiet-small\"\n :title=\"$t('action.regenerate')\"\n @click.stop=\"$emit('regenerate')\" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'show-info',\n index,\n )\n \"\n icon=\"ri:information-line\"\n :title=\"$t('action.getMoreInfo')\"\n modifiers=\"action-quiet-small\"\n @click.stop=\"\n $emit('show-info', message)\n \" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'revise',\n index,\n )\n \"\n :icon=\"\n isRevised(message.id)\n ? 'ri:file-edit-fill'\n : 'ri:file-edit-line'\n \"\n :title=\"\n isRevised(message.id)\n ? $t('action.editRevise')\n : $t('action.createRevise')\n \"\n modifiers=\"action-quiet-small\"\n :class=\"{\n 'text-brand': isRevised(message.id),\n }\"\n @click.stop=\"\n $emit('revise', message)\n \" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'upvote',\n index,\n )\n \"\n :icon=\"\n getMessageFeedback(message.id)\n ?.vote === 'upvote'\n ? 'ri:thumb-up-fill'\n : 'ri:thumb-up-line'\n \"\n :title=\"$t('action.upvote')\"\n modifiers=\"action-quiet-small\"\n @click.stop=\"\n $emit('upvote', message)\n \" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'downvote',\n index,\n )\n \"\n :icon=\"\n getMessageFeedback(message.id)\n ?.vote === 'downvote'\n ? 'ri:thumb-down-fill'\n : 'ri:thumb-down-line'\n \"\n :title=\"$t('action.downvote')\"\n modifiers=\"action-quiet-small\"\n @click.stop=\"\n $emit('downvote', message)\n \" />\n </transition>\n <transition mode=\"out-in\">\n <VvButton\n v-if=\"\n isActionButtonVisible(\n 'feedback',\n index,\n )\n \"\n :icon=\"\n getMessageFeedback(message.id)\n ?.comment\n ? 'ri:feedback-fill'\n : 'ri:feedback-line'\n \"\n :title=\"$t('action.feedback')\"\n modifiers=\"action-quiet-small\"\n @click.stop=\"\n $emit('feedback', message)\n \" />\n </transition>\n </VvButtonGroup>\n <span\n v-if=\"\n showMessageTokensCount &&\n message.metadata?.totalTokens\n \"\n class=\"flex items-center gap-4 text-12 text-word-3\">\n <VvIcon name=\"ri:ai-generate-2-line\" />\n {{\n $n(message.metadata.totalTokens, 'integer')\n }}\n {{ $t('label.tokens') }}\n </span>\n <time\n v-if=\"\n showMessageDateTime &&\n message.metadata?.createdAt\n \"\n :datetime=\"\n new Date(\n message.metadata?.createdAt,\n ).toISOString()\n \"\n class=\"flex items-center gap-4 text-12 text-word-3\">\n <VvIcon name=\"ri:time-line\" />\n {{\n $d(\n new Date(message.metadata?.createdAt),\n 'date-time',\n )\n }}\n </time>\n <div\n v-if=\"\n showMessageDateTime &&\n message?.metadata?.completedAt &&\n message?.metadata?.createdAt\n \"\n class=\"flex items-center gap-4 text-12 text-word-3\">\n <VvIcon name=\"ri:hourglass-line\" />\n <PkRelativeTime\n :date=\"message.metadata?.createdAt\"\n :end-date=\"message.metadata?.completedAt\" />\n </div>\n </div>\n </transition>\n <transition mode=\"out-in\">\n <PkChatbotFeedbackForm\n v-if=\"message.id === feedbackMessageId\"\n ref=\"feedbackMessageEl\"\n :loading=\"feedbackLoading\"\n :submitted=\"feedbackSubmitted\"\n :error=\"feedbackError\"\n @submit=\"$emit('feedback-submit', $event)\"\n @close=\"$emit('feedback-close')\" />\n </transition>\n </div>\n </template>\n <PkChatbotError\n v-if=\"isError\"\n :error\n @retry=\"$emit('auto-retry')\"\n @reset=\"$emit('reset-chat')\" />\n <div\n v-if=\"activeMessage?.role === 'user' || isError\"\n :style=\"{ minHeight: `${height}px` }\"></div>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-messages {\n overflow-y: auto;\n flex: 1;\n min-width: 0;\n font-size: var(--spacing-14);\n\n scrollbar-width: thin;\n scrollbar-gutter: auto;\n scrollbar-color: var(--color-word-5) var(--color-surface-1);\n\n &__wrapper {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-16);\n min-width: 0;\n }\n\n &__divider {\n border-bottom: 1px solid var(--color-surface-3);\n }\n }\n\n .pk-chatbot-divider {\n position: relative;\n border-bottom: 1px solid var(--color-surface-3);\n\n &__label {\n position: absolute;\n padding-inline: var(--spacing-8);\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: var(--color-surface);\n color: var(--color-word-4);\n font-size: var(--text-12);\n }\n }\n\n .pk-chatbot-message {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-sm);\n min-width: 0;\n align-items: flex-start;\n\n &__text {\n color: var(--color-word-2);\n line-height: var(--leading-normal);\n border-width: var(--spacing-px);\n border-color: var(--color-surface-3);\n padding: var(--spacing-sm);\n border-radius: var(--rounded-xl) var(--rounded-xl) var(--rounded-xl)\n 0;\n }\n\n &__loading-info {\n line-height: var(--leading-normal);\n border-width: var(--spacing-px);\n border-color: var(--color-surface-3);\n padding: var(--spacing-sm);\n border-radius: var(--rounded-xl) var(--rounded-xl) var(--rounded-xl)\n 0;\n font-size: var(--text-12);\n color: var(--color-word-3);\n }\n\n &__footer {\n width: 100%;\n display: flex;\n gap: var(--spacing-8);\n align-items: center;\n }\n\n &--user {\n align-items: flex-end;\n\n .pk-chatbot-message__text {\n background-color: var(\n --chatbot-main-color,\n var(--color-surface-1)\n );\n border-width: var(--spacing-px);\n border-color: var(--chatbot-main-color, var(--color-surface-4));\n color: var(--chatbot-contrast-color, var(--color-word-1));\n border-radius: var(--rounded-xl) var(--rounded-xl) 0\n var(--rounded-xl);\n }\n }\n\n &--assistant {\n width: 100%;\n display: flex;\n min-width: 0;\n flex-direction: column;\n gap: var(--spacing-16);\n overflow: hidden;\n\n .pk-chatbot-message__text {\n width: 100%;\n }\n }\n\n &--system {\n align-items: flex-end;\n\n .pk-chatbot-message__text {\n display: flex;\n gap: var(--spacing-8);\n font-size: var(--text-12);\n padding: var(--spacing-8) var(--spacing-sm);\n align-items: center;\n border-width: var(--spacing-px);\n border-color: var(--chatbot-main-color, var(--color-surface-4));\n color: var(--chatbot-main-color, var(--color-word-1));\n border-radius: var(--rounded-xl) var(--rounded-xl) 0\n var(--rounded-xl);\n }\n }\n }\n</style>\n"],"mappings":"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"}
@@ -1,11 +1,11 @@
1
- import { t as e } from "./useChatbotStore-B9BUWM4O.js";
1
+ import { t as e } from "./useChatbotStore-ys9uGP5v.js";
2
2
  import { f as t, l as n, m as r, p as i, s as a, u as o } from "./createChatbotApiClient-BJL1_AVi.js";
3
3
  import { a as s, b as c, g as l, l as u, m as d, n as f, o as p, p as m, v as h, x as g, y as _ } from "./schemas-sa2dDEGb.js";
4
4
  import { m as ee } from "./src-DjRNH9vV.js";
5
5
  import { t as v } from "./PkUrl-C9annqfF.js";
6
6
  import { t as y } from "./PkStreamingMarkdown-C-XHB63C.js";
7
7
  import { n as b } from "./PkChatbotFeedbackForm-Dl1pWKbb.js";
8
- import { t as te } from "./PkChatbotMessages-CQdxH86L.js";
8
+ import { t as te } from "./PkChatbotMessages-C7-ZtU0-.js";
9
9
  import { t as ne } from "./PkChatbotInput-CXydKByS.js";
10
10
  import { Fragment as x, Transition as S, computed as C, createBlock as w, createCommentVNode as T, createElementBlock as E, createElementVNode as D, createTextVNode as O, createVNode as k, defineComponent as A, isRef as j, normalizeClass as M, onMounted as N, openBlock as P, reactive as F, ref as I, renderList as L, toDisplayString as R, toValue as z, unref as B, useTemplateRef as re, watch as V, withCtx as H, withModifiers as U } from "vue";
11
11
  import { VvButton as W, VvButtonGroup as ie, VvIcon as G } from "@volverjs/ui-vue/components";
@@ -789,4 +789,4 @@ var de = { class: "border border-surface-3 rounded-xl w-full overflow-hidden" },
789
789
  //#endregion
790
790
  export { we as a, ue as c, De as i, Xe as n, xe as o, Me as r, $ as s, tt as t };
791
791
 
792
- //# sourceMappingURL=PkChatbotViewChat-DHOeNxnR.js.map
792
+ //# sourceMappingURL=PkChatbotViewChat-EWotdJkz.js.map