@8wave/ai-elements 0.75.0 → 0.78.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 (141) hide show
  1. package/dist/_chunks/{PkStreamingMarkdown-rIdQh5_D.js → PkStreamingMarkdown-gIAvEY1t.js} +372 -303
  2. package/dist/_chunks/PkStreamingMarkdown-gIAvEY1t.js.map +1 -0
  3. package/dist/_chunks/{PkToolShowArtifact-CeLgwZBA.js → PkToolShowArtifact-BwW4Yn6k.js} +5 -5
  4. package/dist/_chunks/{PkToolShowArtifact-CeLgwZBA.js.map → PkToolShowArtifact-BwW4Yn6k.js.map} +1 -1
  5. package/dist/_chunks/{PkToolShowCalendarEvent-cQpAAE3a.js → PkToolShowCalendarEvent-BEqn5iEb.js} +6 -6
  6. package/dist/_chunks/{PkToolShowCalendarEvent-cQpAAE3a.js.map → PkToolShowCalendarEvent-BEqn5iEb.js.map} +1 -1
  7. package/dist/_chunks/{PkToolShowComparison-Cu-zT8-Z.js → PkToolShowComparison-p34r0Hhd.js} +4 -4
  8. package/dist/_chunks/{PkToolShowComparison-Cu-zT8-Z.js.map → PkToolShowComparison-p34r0Hhd.js.map} +1 -1
  9. package/dist/_chunks/{PkToolShowContactForm-CqoSVvjG.js → PkToolShowContactForm-DTE-iF_c.js} +18 -18
  10. package/dist/_chunks/{PkToolShowContactForm-CqoSVvjG.js.map → PkToolShowContactForm-DTE-iF_c.js.map} +1 -1
  11. package/dist/_chunks/{PkToolShowEmail-oLGym0R9.js → PkToolShowEmail-Be8FvWjw.js} +4 -4
  12. package/dist/_chunks/{PkToolShowEmail-oLGym0R9.js.map → PkToolShowEmail-Be8FvWjw.js.map} +1 -1
  13. package/dist/_chunks/PkToolShowImageGallery-CGL-HL6v.js +60 -0
  14. package/dist/_chunks/PkToolShowImageGallery-CGL-HL6v.js.map +1 -0
  15. package/dist/_chunks/{PkToolShowLocation-BtRUdoEw.js → PkToolShowLocation-DOoLCHzS.js} +6 -6
  16. package/dist/_chunks/{PkToolShowLocation-BtRUdoEw.js.map → PkToolShowLocation-DOoLCHzS.js.map} +1 -1
  17. package/dist/_chunks/{PkToolShowMessage-tJQGRhce.js → PkToolShowMessage-DgeULbdQ.js} +4 -4
  18. package/dist/_chunks/{PkToolShowMessage-tJQGRhce.js.map → PkToolShowMessage-DgeULbdQ.js.map} +1 -1
  19. package/dist/_chunks/{PkToolShowMultipleChoice-CtVvdyDg.js → PkToolShowMultipleChoice-CpGyn_bZ.js} +3 -3
  20. package/dist/_chunks/{PkToolShowMultipleChoice-CtVvdyDg.js.map → PkToolShowMultipleChoice-CpGyn_bZ.js.map} +1 -1
  21. package/dist/_chunks/{PkToolShowProductList-D_k6CDdb.js → PkToolShowProductList-C8YIh0Dw.js} +4 -4
  22. package/dist/_chunks/{PkToolShowProductList-D_k6CDdb.js.map → PkToolShowProductList-C8YIh0Dw.js.map} +1 -1
  23. package/dist/_chunks/{PkToolShowQrCode-S1j_T8wQ.js → PkToolShowQrCode-UE4uSyvJ.js} +4 -4
  24. package/dist/_chunks/{PkToolShowQrCode-S1j_T8wQ.js.map → PkToolShowQrCode-UE4uSyvJ.js.map} +1 -1
  25. package/dist/_chunks/{PkToolShowSources-CroItMtG.js → PkToolShowSources-TSjtd1ps.js} +7 -7
  26. package/dist/_chunks/PkToolShowSources-TSjtd1ps.js.map +1 -0
  27. package/dist/_chunks/{PkToolShowSuggestedReply-BRa5Lpti.js → PkToolShowSuggestedReply-c9sLv4n4.js} +4 -4
  28. package/dist/_chunks/{PkToolShowSuggestedReply-BRa5Lpti.js.map → PkToolShowSuggestedReply-c9sLv4n4.js.map} +1 -1
  29. package/dist/_chunks/{PkToolShowWeather-CUpCJ8Nj.js → PkToolShowWeather-ChJ5lB4K.js} +51 -51
  30. package/dist/_chunks/PkToolShowWeather-ChJ5lB4K.js.map +1 -0
  31. package/dist/_chunks/{PkToolShowWebPages-f-dHyxfD.js → PkToolShowWebPages-CL2mYxh-.js} +5 -5
  32. package/dist/_chunks/{PkToolShowWebPages-f-dHyxfD.js.map → PkToolShowWebPages-CL2mYxh-.js.map} +1 -1
  33. package/dist/_chunks/{PkUrl-CI17WkYu.js → PkUrl-CvztUywv.js} +3 -3
  34. package/dist/_chunks/{PkUrl-CI17WkYu.js.map → PkUrl-CvztUywv.js.map} +1 -1
  35. package/dist/_chunks/{VvCheckbox.es-BF8Mdg0O.js → VvCheckbox.es-ohF87NOe.js} +3 -3
  36. package/dist/_chunks/{VvCheckbox.es-BF8Mdg0O.js.map → VvCheckbox.es-ohF87NOe.js.map} +1 -1
  37. package/dist/_chunks/{VvCheckboxGroup.es-BJc8MmJ3.js → VvCheckboxGroup.es-DZCbyLN0.js} +4 -4
  38. package/dist/_chunks/{VvCheckboxGroup.es-BJc8MmJ3.js.map → VvCheckboxGroup.es-DZCbyLN0.js.map} +1 -1
  39. package/dist/_chunks/{VvCombobox.es-ILRHqAye.js → VvCombobox.es-YLPD7MpO.js} +6 -6
  40. package/dist/_chunks/{VvCombobox.es-ILRHqAye.js.map → VvCombobox.es-YLPD7MpO.js.map} +1 -1
  41. package/dist/_chunks/{VvInputText.es-CDnMeO26.js → VvInputText.es-DAnAXfBO.js} +7 -7
  42. package/dist/_chunks/{VvInputText.es-CDnMeO26.js.map → VvInputText.es-DAnAXfBO.js.map} +1 -1
  43. package/dist/_chunks/{VvRadio.es-C2p5vvAx.js → VvRadio.es-Do9oyNtV.js} +3 -3
  44. package/dist/_chunks/{VvRadio.es-C2p5vvAx.js.map → VvRadio.es-Do9oyNtV.js.map} +1 -1
  45. package/dist/_chunks/{VvRadioGroup.es-6GlWuDjY.js → VvRadioGroup.es-BHcqcJFC.js} +4 -4
  46. package/dist/_chunks/{VvRadioGroup.es-6GlWuDjY.js.map → VvRadioGroup.es-BHcqcJFC.js.map} +1 -1
  47. package/dist/_chunks/{VvSelect.es-i4lO9onq.js → VvSelect.es-CP_y02fy.js} +5 -5
  48. package/dist/_chunks/{VvSelect.es-i4lO9onq.js.map → VvSelect.es-CP_y02fy.js.map} +1 -1
  49. package/dist/_chunks/{VvTextarea.es-CGpiCS4S.js → VvTextarea.es-DetA_2DM.js} +6 -6
  50. package/dist/_chunks/{VvTextarea.es-CGpiCS4S.js.map → VvTextarea.es-DetA_2DM.js.map} +1 -1
  51. package/dist/_chunks/{dist-BTnzL-m0.js → dist-yqV26MWM.js} +4 -4
  52. package/dist/_chunks/{dist-BTnzL-m0.js.map → dist-yqV26MWM.js.map} +1 -1
  53. package/dist/_chunks/{esm-0nyRYwmP.js → esm-DLxNpT06.js} +7 -7
  54. package/dist/_chunks/{esm-0nyRYwmP.js.map → esm-DLxNpT06.js.map} +1 -1
  55. package/dist/_chunks/{floating-ui.vue-B5ZV-j8C.js → floating-ui.vue-tVPpNXUc.js} +3 -3
  56. package/dist/_chunks/{floating-ui.vue-B5ZV-j8C.js.map → floating-ui.vue-tVPpNXUc.js.map} +1 -1
  57. package/dist/_chunks/{iconify-C1EOwL90.js → iconify-y0w2FIJH.js} +3 -3
  58. package/dist/_chunks/{iconify-C1EOwL90.js.map → iconify-y0w2FIJH.js.map} +1 -1
  59. package/dist/_chunks/{index.es-CUjDCkXD.js → index.es-7fUi-rc0.js} +7 -7
  60. package/dist/_chunks/{index.es-CUjDCkXD.js.map → index.es-7fUi-rc0.js.map} +1 -1
  61. package/dist/_chunks/{src-C_wl-KYN.js → src-BfoQF6Z3.js} +2 -2
  62. package/dist/_chunks/{src-C_wl-KYN.js.map → src-BfoQF6Z3.js.map} +1 -1
  63. package/dist/_chunks/{useLightbox-CH1KeVqr.js → useLightbox-Ddvue042.js} +7 -5
  64. package/dist/_chunks/{useLightbox-CH1KeVqr.js.map → useLightbox-Ddvue042.js.map} +1 -1
  65. package/dist/_chunks/{vue-i18n-KvYvoek4.js → vue-i18n-DAH6nDTN.js} +3 -3
  66. package/dist/_chunks/{vue-i18n-KvYvoek4.js.map → vue-i18n-DAH6nDTN.js.map} +1 -1
  67. package/dist/_chunks/{vue.runtime.esm-bundler-BmggS4HU.js → vue.runtime.esm-bundler-Dq29dQrz.js} +16 -10
  68. package/dist/_chunks/vue.runtime.esm-bundler-Dq29dQrz.js.map +1 -0
  69. package/dist/ai-elements.es.js +3138 -3039
  70. package/dist/ai-elements.es.js.map +1 -1
  71. package/dist-vue/PkChatbot.js +1 -1
  72. package/dist-vue/PkChatbotFeedbackForm.js +1 -1
  73. package/dist-vue/PkChatbotFilePreview.js +1 -1
  74. package/dist-vue/PkChatbotInput.js +1 -1
  75. package/dist-vue/PkChatbotMessages.js +1 -1
  76. package/dist-vue/PkChatbotViewChat.js +1 -1
  77. package/dist-vue/PkChatbotViewConversations.js +1 -1
  78. package/dist-vue/PkChatbotViewProfile.js +1 -1
  79. package/dist-vue/_chunks/{Media-CXQSoKqt.js → Media-kK7BnZGr.js} +2 -2
  80. package/dist-vue/_chunks/Media-kK7BnZGr.js.map +1 -0
  81. package/dist-vue/_chunks/{PkChatbot-DAzGc7al.js → PkChatbot-BEJTYq-D.js} +7 -7
  82. package/dist-vue/_chunks/{PkChatbot-DAzGc7al.js.map → PkChatbot-BEJTYq-D.js.map} +1 -1
  83. package/dist-vue/_chunks/{PkChatbotFeedbackForm-DvUzirPP.js → PkChatbotFeedbackForm-lj9CHdhn.js} +2 -2
  84. package/dist-vue/_chunks/{PkChatbotFeedbackForm-DvUzirPP.js.map → PkChatbotFeedbackForm-lj9CHdhn.js.map} +1 -1
  85. package/dist-vue/_chunks/{PkChatbotFilePreview-DHzuGtz5.js → PkChatbotFilePreview-hRNtv2OJ.js} +2 -2
  86. package/dist-vue/_chunks/{PkChatbotFilePreview-DHzuGtz5.js.map → PkChatbotFilePreview-hRNtv2OJ.js.map} +1 -1
  87. package/dist-vue/_chunks/{PkChatbotInput-C5QSmt21.js → PkChatbotInput-BbGLBVim.js} +124 -116
  88. package/dist-vue/_chunks/PkChatbotInput-BbGLBVim.js.map +1 -0
  89. package/dist-vue/_chunks/PkChatbotMessages-j3ALQmGG.js +467 -0
  90. package/dist-vue/_chunks/PkChatbotMessages-j3ALQmGG.js.map +1 -0
  91. package/dist-vue/_chunks/{PkChatbotViewChat-CjoezIyz.js → PkChatbotViewChat-Z05fqNFE.js} +6 -6
  92. package/dist-vue/_chunks/{PkChatbotViewChat-CjoezIyz.js.map → PkChatbotViewChat-Z05fqNFE.js.map} +1 -1
  93. package/dist-vue/_chunks/{PkChatbotViewConversations-DSQu6vY1.js → PkChatbotViewConversations-2xc0o-fO.js} +2 -2
  94. package/dist-vue/_chunks/{PkChatbotViewConversations-DSQu6vY1.js.map → PkChatbotViewConversations-2xc0o-fO.js.map} +1 -1
  95. package/dist-vue/_chunks/{PkChatbotViewProfile-BJJiaG9H.js → PkChatbotViewProfile-CoT1JnMk.js} +2 -2
  96. package/dist-vue/_chunks/{PkChatbotViewProfile-BJJiaG9H.js.map → PkChatbotViewProfile-CoT1JnMk.js.map} +1 -1
  97. package/dist-vue/_chunks/{PkStreamingMarkdown-BAhC3uGK.js → PkStreamingMarkdown-BBTAwHd_.js} +311 -252
  98. package/dist-vue/_chunks/PkStreamingMarkdown-BBTAwHd_.js.map +1 -0
  99. package/dist-vue/_chunks/{PkToolShowArtifact-RzrDPcEQ.js → PkToolShowArtifact-CbqpjzCA.js} +2 -2
  100. package/dist-vue/_chunks/{PkToolShowArtifact-RzrDPcEQ.js.map → PkToolShowArtifact-CbqpjzCA.js.map} +1 -1
  101. package/dist-vue/_chunks/{PkToolShowContactForm-r_GgO-ZX.js → PkToolShowContactForm-BkgfSyw7.js} +3 -3
  102. package/dist-vue/_chunks/{PkToolShowContactForm-r_GgO-ZX.js.map → PkToolShowContactForm-BkgfSyw7.js.map} +1 -1
  103. package/dist-vue/_chunks/{PkToolShowImageGallery-B7Bt6ZGv.js → PkToolShowImageGallery-Ckyxa0mx.js} +18 -21
  104. package/dist-vue/_chunks/PkToolShowImageGallery-Ckyxa0mx.js.map +1 -0
  105. package/dist-vue/_chunks/{PkToolShowSources-DK2DCvU3.js → PkToolShowSources-7Xt3iK2Z.js} +3 -3
  106. package/dist-vue/_chunks/{PkToolShowSources-DK2DCvU3.js.map → PkToolShowSources-7Xt3iK2Z.js.map} +1 -1
  107. package/dist-vue/_chunks/{PkToolShowWeather-Coq6H0iv.js → PkToolShowWeather-B5Wp8WAt.js} +26 -26
  108. package/dist-vue/_chunks/PkToolShowWeather-B5Wp8WAt.js.map +1 -0
  109. package/dist-vue/_chunks/{createChatbotApiClient-f86KwRcq.js → createChatbotApiClient-CvDRMmDa.js} +2 -2
  110. package/dist-vue/_chunks/{createChatbotApiClient-f86KwRcq.js.map → createChatbotApiClient-CvDRMmDa.js.map} +1 -1
  111. package/dist-vue/_chunks/{index.es-_14zrNZB.js → index.es-Dk_HaA08.js} +2 -2
  112. package/dist-vue/_chunks/{index.es-_14zrNZB.js.map → index.es-Dk_HaA08.js.map} +1 -1
  113. package/dist-vue/_chunks/{useChatbotStore-CJlkoNn7.js → useChatbotStore-DMDbzuub.js} +5 -5
  114. package/dist-vue/_chunks/{useChatbotStore-CJlkoNn7.js.map → useChatbotStore-DMDbzuub.js.map} +1 -1
  115. package/dist-vue/_chunks/{useLightbox-1sB7fmFb.js → useLightbox-Cl8REkfc.js} +5 -3
  116. package/dist-vue/_chunks/{useLightbox-1sB7fmFb.js.map → useLightbox-Cl8REkfc.js.map} +1 -1
  117. package/dist-vue/api.js +1 -1
  118. package/dist-vue/composables.js +2 -2
  119. package/dist-vue/index.js +24 -24
  120. package/dist-vue/index.js.map +1 -1
  121. package/dist-vue/packages/components/src/chat/PkChatbotMessages.d.ts +4 -5
  122. package/dist-vue/packages/components/src/chat/PkStreamingMarkdown.d.ts +9 -1
  123. package/dist-vue/packages/components/src/chat/useChatScroll.d.ts +15 -0
  124. package/dist-vue/packages/models/src/schema/AgentEndpoint.d.ts +1 -1
  125. package/dist-vue/packages/models/src/schema/constants.d.ts +3 -1
  126. package/dist-vue/style.css +1 -1
  127. package/package.json +2 -2
  128. package/dist/_chunks/PkStreamingMarkdown-rIdQh5_D.js.map +0 -1
  129. package/dist/_chunks/PkToolShowImageGallery-CDXSL1Mg.js +0 -63
  130. package/dist/_chunks/PkToolShowImageGallery-CDXSL1Mg.js.map +0 -1
  131. package/dist/_chunks/PkToolShowSources-CroItMtG.js.map +0 -1
  132. package/dist/_chunks/PkToolShowWeather-CUpCJ8Nj.js.map +0 -1
  133. package/dist/_chunks/vue.runtime.esm-bundler-BmggS4HU.js.map +0 -1
  134. package/dist-vue/_chunks/Media-CXQSoKqt.js.map +0 -1
  135. package/dist-vue/_chunks/PkChatbotInput-C5QSmt21.js.map +0 -1
  136. package/dist-vue/_chunks/PkChatbotMessages-dsjB0-26.js +0 -388
  137. package/dist-vue/_chunks/PkChatbotMessages-dsjB0-26.js.map +0 -1
  138. package/dist-vue/_chunks/PkStreamingMarkdown-BAhC3uGK.js.map +0 -1
  139. package/dist-vue/_chunks/PkToolShowImageGallery-B7Bt6ZGv.js.map +0 -1
  140. package/dist-vue/_chunks/PkToolShowWeather-Coq6H0iv.js.map +0 -1
  141. /package/dist/_chunks/{_plugin-vue_export-helper-BI3pHb34.js → _plugin-vue_export-helper-C6kC663S.js} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PkChatbotMessages-j3ALQmGG.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/useChatScroll.ts","../../../../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 showCalendarEvent: defineAsyncComponent(\n () => import('./PkToolShowCalendarEvent.vue'),\n ),\n showComparison: defineAsyncComponent(\n () => import('./PkToolShowComparison.vue'),\n ),\n showContactForm: defineAsyncComponent(\n () => import('./PkToolShowContactForm.vue'),\n ),\n showEmail: defineAsyncComponent(() => import('./PkToolShowEmail.vue')),\n showImageGallery: defineAsyncComponent(\n () => import('./PkToolShowImageGallery.vue'),\n ),\n showLocation: defineAsyncComponent(\n () => import('./PkToolShowLocation.vue'),\n ),\n showMessage: defineAsyncComponent(() => import('./PkToolShowMessage.vue')),\n showMultipleChoice: defineAsyncComponent(\n () => import('./PkToolShowMultipleChoice.vue'),\n ),\n showProductList: defineAsyncComponent(\n () => import('./PkToolShowProductList.vue'),\n ),\n showQrCode: defineAsyncComponent(() => import('./PkToolShowQrCode.vue')),\n showSources: defineAsyncComponent(() => import('./PkToolShowSources.vue')),\n showSuggestedReply: defineAsyncComponent(\n () => import('./PkToolShowSuggestedReply.vue'),\n ),\n showWeather: defineAsyncComponent(() => import('./PkToolShowWeather.vue')),\n showWebPages: defineAsyncComponent(\n () => import('./PkToolShowWebPages.vue'),\n ),\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","import type { Ref, ShallowRef } from 'vue'\nimport { ref, watch, onMounted, onBeforeUnmount, nextTick } from 'vue'\n\nconst NEAR_BOTTOM_THRESHOLD = 30\nconst SCROLL_UP_THRESHOLD = 50\nconst SMOOTH_SCROLL_DURATION = 500\n\ninterface UseChatScrollOptions {\n scrollEl:\n | Readonly<ShallowRef<HTMLDivElement | null>>\n | Ref<HTMLDivElement | undefined>\n status: () => string | undefined\n messagesLength: () => number | undefined\n lastMessageRole: () => string | undefined\n onScrollUp?: () => void\n onScrollDown?: () => void\n}\n\nexport function useChatScroll(options: UseChatScrollOptions) {\n const {\n scrollEl,\n status,\n messagesLength,\n lastMessageRole,\n onScrollUp,\n onScrollDown,\n } = options\n\n const userScrolledUp = ref(false)\n let isAutoScrolling = false\n let mutationObserver: MutationObserver | null = null\n let resizeObserver: ResizeObserver | null = null\n let initMutationObserver: MutationObserver | null = null\n let lastScrollTop = 0\n\n // --- Core scroll ---\n\n const scrollToBottom = (behavior: ScrollBehavior = 'smooth') => {\n if (!scrollEl.value || userScrolledUp.value) {\n return\n }\n isAutoScrolling = true\n scrollEl.value.scrollTo({\n top: scrollEl.value.scrollHeight,\n behavior,\n })\n const unlockDelay = behavior === 'instant' ? 0 : SMOOTH_SCROLL_DURATION\n setTimeout(() => {\n isAutoScrolling = false\n }, unlockDelay)\n }\n\n // --- User scroll detection ---\n\n const handleScroll = () => {\n if (!scrollEl.value) {\n return\n }\n const currentScrollTop = scrollEl.value.scrollTop\n if (isAutoScrolling) {\n lastScrollTop = currentScrollTop\n return\n }\n\n if (currentScrollTop < lastScrollTop) {\n if (lastScrollTop - currentScrollTop < SCROLL_UP_THRESHOLD) {\n userScrolledUp.value = true\n }\n onScrollUp?.()\n }\n\n if (currentScrollTop > lastScrollTop) {\n const { scrollHeight, clientHeight } = scrollEl.value\n if (\n scrollHeight - clientHeight - currentScrollTop <\n NEAR_BOTTOM_THRESHOLD\n ) {\n userScrolledUp.value = false\n }\n onScrollDown?.()\n }\n\n lastScrollTop = currentScrollTop\n }\n\n // --- Streaming auto-scroll ---\n\n const startMutationScroll = () => {\n if (mutationObserver || !scrollEl.value) {\n return\n }\n mutationObserver = new MutationObserver(() => {\n if (isAutoScrolling || userScrolledUp.value || !scrollEl.value) {\n return\n }\n isAutoScrolling = true\n scrollEl.value.scrollTop = scrollEl.value.scrollHeight\n requestAnimationFrame(() => {\n isAutoScrolling = false\n })\n })\n mutationObserver.observe(scrollEl.value, {\n childList: true,\n subtree: true,\n characterData: true,\n })\n }\n\n const stopMutationScroll = () => {\n mutationObserver?.disconnect()\n mutationObserver = null\n }\n\n // --- Status watcher ---\n\n watch(status, (newStatus, oldStatus) => {\n if (newStatus === 'streaming' || newStatus === 'submitted') {\n startMutationScroll()\n return\n }\n if (newStatus === 'ready' && oldStatus === 'streaming') {\n // Keep observer active to catch footer buttons rendering\n return\n }\n stopMutationScroll()\n })\n\n // --- New message watcher ---\n\n watch(messagesLength, async () => {\n if (!messagesLength()) {\n return\n }\n if (lastMessageRole() === 'assistant') {\n return\n }\n userScrolledUp.value = false\n isAutoScrolling = true\n await nextTick()\n scrollToBottom()\n })\n\n // --- Initial scroll ---\n\n let initialScrollTimer: ReturnType<typeof setTimeout> | null = null\n const INITIAL_SCROLL_SETTLE_MS = 300\n\n const tryInitialScroll = () => {\n if (!scrollEl.value) {\n return\n }\n if (scrollEl.value.scrollHeight <= scrollEl.value.clientHeight) {\n return\n }\n scrollEl.value.scrollTop = scrollEl.value.scrollHeight\n\n // Reset the settle timer on each mutation — disconnect only after stability\n if (initialScrollTimer) {\n clearTimeout(initialScrollTimer)\n }\n initialScrollTimer = setTimeout(\n cleanupInitialObservers,\n INITIAL_SCROLL_SETTLE_MS,\n )\n }\n\n const cleanupInitialObservers = () => {\n resizeObserver?.disconnect()\n resizeObserver = null\n initMutationObserver?.disconnect()\n initMutationObserver = null\n if (initialScrollTimer) {\n clearTimeout(initialScrollTimer)\n initialScrollTimer = null\n }\n }\n\n onMounted(() => {\n if (!scrollEl.value) {\n return\n }\n resizeObserver = new ResizeObserver(tryInitialScroll)\n resizeObserver.observe(scrollEl.value)\n\n initMutationObserver = new MutationObserver(tryInitialScroll)\n initMutationObserver.observe(scrollEl.value, {\n childList: true,\n subtree: true,\n })\n\n tryInitialScroll()\n })\n\n onBeforeUnmount(() => {\n stopMutationScroll()\n cleanupInitialObservers()\n })\n\n return {\n handleScroll,\n scrollToBottom,\n userScrolledUp,\n }\n}\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 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 import { useChatScroll } from './useChatScroll'\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 contrastColor = computed(() =>\n resolveContrastColor(props.textColor, props.mainColor),\n )\n\n // --- Scroll ---\n\n const { handleScroll, scrollToBottom } = useChatScroll({\n scrollEl,\n status: () => props.status,\n messagesLength: () => props.messages?.length,\n lastMessageRole: () =>\n props.messages?.[props.messages.length - 1]?.role,\n onScrollUp: () => emit('scroll-up'),\n onScrollDown: () => emit('scroll-down'),\n })\n\n // --- Height adjustment ---\n\n const messagesElRefs = useTemplateRef<HTMLDivElement[]>('messagesEl')\n const height = ref<number>(0)\n\n watch(\n () => props.messages,\n async (messages) => {\n if (!messages?.length || props.disableHeightAdjustment) {\n return\n }\n await nextTick()\n const scrollElHeight = (scrollEl.value?.clientHeight ?? 0) - 48\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 { deep: true },\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 isLastMessage = (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 isLastMessage(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 ((isLastMessage(index) && props.status === 'ready') ||\n !isLastMessage(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 isAssistant = (message: UIChatMessage) => message.role === 'assistant'\n const isUser = (message: UIChatMessage) => message.role === 'user'\n const getPreviousAssistantMessage = (index: number) => {\n return props.messages\n ?.slice(0, index)\n .reverse()\n .find((message) => isAssistant(message))\n }\n const getNextAssistantMessage = (index: number) => {\n return props.messages\n ?.slice(index + 1)\n .find((message) => isAssistant(message))\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 if (!props.feedbackMessageId) {\n return\n }\n const el = feedbackMessageEl.value?.[0]?.$el\n if (!el) {\n return\n }\n if (isLastMessage(getMessageIndexById(props.feedbackMessageId))) {\n scrollToBottom()\n return\n }\n el.scrollIntoView({ behavior: 'smooth', block: 'center' })\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=\"index > 0 && isUser(message) && isDayChanged(index)\"\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 v-if=\"\n message.parts.length ||\n (isLastMessage(index) &&\n isLoading &&\n isAssistant(message))\n \"\n ref=\"messagesEl\"\n class=\"pk-chatbot-message\"\n :class=\"[\n `pk-chatbot-message--${message.role}`,\n {\n 'pk-chatbot-message--loading':\n isLoading &&\n isLastMessage(index) &&\n isAssistant(message),\n },\n ]\"\n :style=\"{\n minHeight:\n isLastMessage(index) &&\n isAssistant(message) &&\n !isError\n ? `${height}px`\n : undefined,\n }\">\n <template\n v-for=\"(part, partIndex) in message.parts\"\n :key=\"partIndex\">\n <transition\n v-if=\"isTextPart(part) && part.text.trim()\"\n appear\n name=\"pk-chatbot-part\">\n <div class=\"pk-chatbot-message__text\">\n <slot\n v-bind=\"{\n message,\n part,\n index,\n isLoading,\n }\"\n name=\"text\">\n <PkStreamingMarkdown\n v-if=\"isAssistant(message)\"\n class=\"wysiwyg\"\n :markdown=\"part.text\"\n :loading=\"\n index ===\n (messages?.length ?? 0) - 1 &&\n status === 'streaming'\n \" />\n <template v-else>\n {{ part.text }}\n </template>\n </slot>\n </div>\n </transition>\n <transition\n v-else-if=\"isFilePart(part)\"\n appear\n name=\"pk-chatbot-part\">\n <PkChatbotFilePreview\n :media-type=\"part.mediaType\"\n :url=\"part.url\"\n :filename=\"part.filename\" />\n </transition>\n <transition\n v-else-if=\"\n isToolPart(part) &&\n !isStreamingPart(part) &&\n (toolComponentMap[getToolPartName(part)] ||\n slots[part.type] ||\n showAllMessageParts)\n \"\n appear\n name=\"pk-chatbot-part\">\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 :name=\"part.type\"\n v-bind=\"{\n message,\n part,\n index,\n isLoading,\n }\">\n <div\n v-if=\"showAllMessageParts\"\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 class=\"font-mono rounded text-10\">\n {{ toKebabCase(part.type) }}\n </code>\n </div>\n </div>\n </slot>\n </transition>\n </template>\n <transition name=\"pk-chatbot-fade\" mode=\"out-in\">\n <div\n v-if=\"\n isLoading &&\n isLastMessage(index) &&\n !isLastTextPart(message) &&\n isAssistant(message)\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 <transition appear name=\"pk-chatbot-part\">\n <PkChatbotError\n v-if=\"isError\"\n :error\n @retry=\"$emit('auto-retry')\"\n @reset=\"$emit('reset-chat')\" />\n </transition>\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\n .pk-chatbot-part-enter-active {\n transition:\n opacity 0.25s ease,\n transform 0.25s ease;\n }\n\n .pk-chatbot-part-enter-from {\n opacity: 0;\n transform: translateY(8px);\n }\n\n .pk-chatbot-fade-enter-active,\n .pk-chatbot-fade-leave-active {\n transition: opacity 0.2s ease;\n }\n\n .pk-chatbot-fade-enter-from,\n .pk-chatbot-fade-leave-to {\n opacity: 0;\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 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 import { useChatScroll } from './useChatScroll'\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 contrastColor = computed(() =>\n resolveContrastColor(props.textColor, props.mainColor),\n )\n\n // --- Scroll ---\n\n const { handleScroll, scrollToBottom } = useChatScroll({\n scrollEl,\n status: () => props.status,\n messagesLength: () => props.messages?.length,\n lastMessageRole: () =>\n props.messages?.[props.messages.length - 1]?.role,\n onScrollUp: () => emit('scroll-up'),\n onScrollDown: () => emit('scroll-down'),\n })\n\n // --- Height adjustment ---\n\n const messagesElRefs = useTemplateRef<HTMLDivElement[]>('messagesEl')\n const height = ref<number>(0)\n\n watch(\n () => props.messages,\n async (messages) => {\n if (!messages?.length || props.disableHeightAdjustment) {\n return\n }\n await nextTick()\n const scrollElHeight = (scrollEl.value?.clientHeight ?? 0) - 48\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 { deep: true },\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 isLastMessage = (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 isLastMessage(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 ((isLastMessage(index) && props.status === 'ready') ||\n !isLastMessage(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 isAssistant = (message: UIChatMessage) => message.role === 'assistant'\n const isUser = (message: UIChatMessage) => message.role === 'user'\n const getPreviousAssistantMessage = (index: number) => {\n return props.messages\n ?.slice(0, index)\n .reverse()\n .find((message) => isAssistant(message))\n }\n const getNextAssistantMessage = (index: number) => {\n return props.messages\n ?.slice(index + 1)\n .find((message) => isAssistant(message))\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 if (!props.feedbackMessageId) {\n return\n }\n const el = feedbackMessageEl.value?.[0]?.$el\n if (!el) {\n return\n }\n if (isLastMessage(getMessageIndexById(props.feedbackMessageId))) {\n scrollToBottom()\n return\n }\n el.scrollIntoView({ behavior: 'smooth', block: 'center' })\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=\"index > 0 && isUser(message) && isDayChanged(index)\"\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 v-if=\"\n message.parts.length ||\n (isLastMessage(index) &&\n isLoading &&\n isAssistant(message))\n \"\n ref=\"messagesEl\"\n class=\"pk-chatbot-message\"\n :class=\"[\n `pk-chatbot-message--${message.role}`,\n {\n 'pk-chatbot-message--loading':\n isLoading &&\n isLastMessage(index) &&\n isAssistant(message),\n },\n ]\"\n :style=\"{\n minHeight:\n isLastMessage(index) &&\n isAssistant(message) &&\n !isError\n ? `${height}px`\n : undefined,\n }\">\n <template\n v-for=\"(part, partIndex) in message.parts\"\n :key=\"partIndex\">\n <transition\n v-if=\"isTextPart(part) && part.text.trim()\"\n appear\n name=\"pk-chatbot-part\">\n <div class=\"pk-chatbot-message__text\">\n <slot\n v-bind=\"{\n message,\n part,\n index,\n isLoading,\n }\"\n name=\"text\">\n <PkStreamingMarkdown\n v-if=\"isAssistant(message)\"\n class=\"wysiwyg\"\n :markdown=\"part.text\"\n :loading=\"\n index ===\n (messages?.length ?? 0) - 1 &&\n status === 'streaming'\n \" />\n <template v-else>\n {{ part.text }}\n </template>\n </slot>\n </div>\n </transition>\n <transition\n v-else-if=\"isFilePart(part)\"\n appear\n name=\"pk-chatbot-part\">\n <PkChatbotFilePreview\n :media-type=\"part.mediaType\"\n :url=\"part.url\"\n :filename=\"part.filename\" />\n </transition>\n <transition\n v-else-if=\"\n isToolPart(part) &&\n !isStreamingPart(part) &&\n (toolComponentMap[getToolPartName(part)] ||\n slots[part.type] ||\n showAllMessageParts)\n \"\n appear\n name=\"pk-chatbot-part\">\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 :name=\"part.type\"\n v-bind=\"{\n message,\n part,\n index,\n isLoading,\n }\">\n <div\n v-if=\"showAllMessageParts\"\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 class=\"font-mono rounded text-10\">\n {{ toKebabCase(part.type) }}\n </code>\n </div>\n </div>\n </slot>\n </transition>\n </template>\n <transition name=\"pk-chatbot-fade\" mode=\"out-in\">\n <div\n v-if=\"\n isLoading &&\n isLastMessage(index) &&\n !isLastTextPart(message) &&\n isAssistant(message)\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 <transition appear name=\"pk-chatbot-part\">\n <PkChatbotError\n v-if=\"isError\"\n :error\n @retry=\"$emit('auto-retry')\"\n @reset=\"$emit('reset-chat')\" />\n </transition>\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\n .pk-chatbot-part-enter-active {\n transition:\n opacity 0.25s ease,\n transform 0.25s ease;\n }\n\n .pk-chatbot-part-enter-from {\n opacity: 0;\n transform: translateY(8px);\n }\n\n .pk-chatbot-fade-enter-active,\n .pk-chatbot-fade-leave-active {\n transition: opacity 0.2s ease;\n }\n\n .pk-chatbot-fade-enter-from,\n .pk-chatbot-fade-leave-to {\n opacity: 0;\n }\n</style>\n"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
- import { t as e } from "./PkToolShowSources-DK2DCvU3.js";
2
- import { t } from "./useChatbotStore-CJlkoNn7.js";
3
- import { t as n } from "./PkChatbotMessages-dsjB0-26.js";
4
- import { t as r } from "./PkChatbotInput-C5QSmt21.js";
1
+ import { t as e } from "./PkToolShowSources-7Xt3iK2Z.js";
2
+ import { t } from "./useChatbotStore-DMDbzuub.js";
3
+ import { t as n } from "./PkChatbotMessages-j3ALQmGG.js";
4
+ import { t as r } from "./PkChatbotInput-BbGLBVim.js";
5
5
  import { t as i } from "./PkToolShowMultipleChoice-DZXfWtQp.js";
6
- import { r as a, t as o } from "./PkToolShowContactForm-r_GgO-ZX.js";
6
+ import { r as a, t as o } from "./PkToolShowContactForm-BkgfSyw7.js";
7
7
  import { t as s } from "./PkToolShowSuggestedReply-30m9yWDL.js";
8
8
  import { t as c } from "./PkToolShowLocation-DteWf0Cs.js";
9
9
  import { Fragment as l, Transition as u, computed as d, createBlock as f, createCommentVNode as p, createElementBlock as m, createElementVNode as h, createTextVNode as g, createVNode as _, defineComponent as v, isRef as y, normalizeClass as ee, onMounted as b, openBlock as x, toDisplayString as S, unref as C, useTemplateRef as te, withCtx as w } from "vue";
@@ -243,4 +243,4 @@ var D = { class: "flex items-center gap-6 text-12 text-word-3 border border-surf
243
243
  //#endregion
244
244
  export { A as t };
245
245
 
246
- //# sourceMappingURL=PkChatbotViewChat-CjoezIyz.js.map
246
+ //# sourceMappingURL=PkChatbotViewChat-Z05fqNFE.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PkChatbotViewChat-CjoezIyz.js","names":["$n","$t"],"sources":["../../../../packages/components/src/chat/PkToolRequestGeolocation.vue","../../../../packages/components/src/chat/PkToolRequestGeolocation.vue","../../../../packages/components/src/chat/PkChatbotViewChat.vue","../../../../packages/components/src/chat/PkChatbotViewChat.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed, onMounted } from 'vue'\n import { useI18n } from 'vue-i18n'\n\n import type { ReverseGeocodeFn } from 'utils/src/device-context'\n\n type GeolocationOutput =\n | {\n latitude: number\n longitude: number\n accuracy?: number\n city?: string\n }\n | { error: 'permission_denied' | 'position_unavailable' | 'timeout' }\n\n const props = defineProps<{\n part: unknown\n reverseGeocode?: ReverseGeocodeFn\n }>()\n\n const emit = defineEmits<{\n result: [output: GeolocationOutput]\n }>()\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const toolPart = computed(() => {\n return props.part as {\n state?: string\n input?: { reason?: string }\n output?: GeolocationOutput\n }\n })\n\n const state = computed(() => toolPart.value.state ?? 'unknown')\n\n const isOutputAvailable = computed(() => state.value === 'output-available')\n\n const successOutput = computed(() => {\n const out = toolPart.value.output\n if (!out || 'error' in out) {\n return undefined\n }\n return out\n })\n\n const errorOutput = computed(() => {\n const out = toolPart.value.output\n if (!out || !('error' in out)) {\n return undefined\n }\n return out\n })\n\n /** Maps GeolocationPositionError.code to a typed string */\n function mapGeolocationError(\n code: number,\n ): 'permission_denied' | 'position_unavailable' | 'timeout' {\n if (code === 1) {\n return 'permission_denied'\n }\n if (code === 3) {\n return 'timeout'\n }\n return 'position_unavailable'\n }\n\n onMounted(() => {\n if (state.value !== 'input-available') {\n return\n }\n\n if (!navigator.geolocation) {\n emit('result', { error: 'position_unavailable' })\n return\n }\n\n navigator.geolocation.getCurrentPosition(\n async (position) => {\n const { latitude, longitude, accuracy } = position.coords\n const city = props.reverseGeocode\n ? await props\n .reverseGeocode(latitude, longitude)\n .catch(() => undefined)\n : undefined\n emit('result', { latitude, longitude, accuracy, city })\n },\n (error) => {\n emit('result', { error: mapGeolocationError(error.code) })\n },\n { timeout: 15000 },\n )\n })\n</script>\n\n<template>\n <div\n class=\"flex items-center gap-6 text-12 text-word-3 border border-surface-3 rounded-xl px-sm py-10\">\n <!-- Loading state -->\n <template v-if=\"!isOutputAvailable\">\n <VvIcon name=\"line-md:loading-loop\" class=\"text-16\" />\n <span>{{ $t('messagePart.requestGeolocation') }}</span>\n </template>\n\n <!-- Success state -->\n <template v-else-if=\"successOutput\">\n <VvIcon name=\"ri:map-pin-line\" class=\"text-16\" />\n <span>\n {{\n $n(successOutput.latitude, {\n style: 'decimal',\n minimumFractionDigits: 5,\n maximumFractionDigits: 5,\n })\n }},\n {{\n $n(successOutput.longitude, {\n style: 'decimal',\n minimumFractionDigits: 5,\n maximumFractionDigits: 5,\n })\n }}\n <template v-if=\"successOutput.accuracy !== undefined\">\n (±{{\n $n(successOutput.accuracy, {\n style: 'unit',\n unit: 'meter',\n })\n }})\n </template>\n </span>\n </template>\n\n <!-- Error state -->\n <template v-else-if=\"errorOutput\">\n <span class=\"i-vv-alert-circle text-16 shrink-0 text-danger\" />\n <span>\n {{\n errorOutput.error === 'permission_denied'\n ? $t('message.geolocationPermissionDenied')\n : $t('message.geolocationUnavailable')\n }}\n </span>\n </template>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, onMounted } from 'vue'\n import { useI18n } from 'vue-i18n'\n\n import type { ReverseGeocodeFn } from 'utils/src/device-context'\n\n type GeolocationOutput =\n | {\n latitude: number\n longitude: number\n accuracy?: number\n city?: string\n }\n | { error: 'permission_denied' | 'position_unavailable' | 'timeout' }\n\n const props = defineProps<{\n part: unknown\n reverseGeocode?: ReverseGeocodeFn\n }>()\n\n const emit = defineEmits<{\n result: [output: GeolocationOutput]\n }>()\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const toolPart = computed(() => {\n return props.part as {\n state?: string\n input?: { reason?: string }\n output?: GeolocationOutput\n }\n })\n\n const state = computed(() => toolPart.value.state ?? 'unknown')\n\n const isOutputAvailable = computed(() => state.value === 'output-available')\n\n const successOutput = computed(() => {\n const out = toolPart.value.output\n if (!out || 'error' in out) {\n return undefined\n }\n return out\n })\n\n const errorOutput = computed(() => {\n const out = toolPart.value.output\n if (!out || !('error' in out)) {\n return undefined\n }\n return out\n })\n\n /** Maps GeolocationPositionError.code to a typed string */\n function mapGeolocationError(\n code: number,\n ): 'permission_denied' | 'position_unavailable' | 'timeout' {\n if (code === 1) {\n return 'permission_denied'\n }\n if (code === 3) {\n return 'timeout'\n }\n return 'position_unavailable'\n }\n\n onMounted(() => {\n if (state.value !== 'input-available') {\n return\n }\n\n if (!navigator.geolocation) {\n emit('result', { error: 'position_unavailable' })\n return\n }\n\n navigator.geolocation.getCurrentPosition(\n async (position) => {\n const { latitude, longitude, accuracy } = position.coords\n const city = props.reverseGeocode\n ? await props\n .reverseGeocode(latitude, longitude)\n .catch(() => undefined)\n : undefined\n emit('result', { latitude, longitude, accuracy, city })\n },\n (error) => {\n emit('result', { error: mapGeolocationError(error.code) })\n },\n { timeout: 15000 },\n )\n })\n</script>\n\n<template>\n <div\n class=\"flex items-center gap-6 text-12 text-word-3 border border-surface-3 rounded-xl px-sm py-10\">\n <!-- Loading state -->\n <template v-if=\"!isOutputAvailable\">\n <VvIcon name=\"line-md:loading-loop\" class=\"text-16\" />\n <span>{{ $t('messagePart.requestGeolocation') }}</span>\n </template>\n\n <!-- Success state -->\n <template v-else-if=\"successOutput\">\n <VvIcon name=\"ri:map-pin-line\" class=\"text-16\" />\n <span>\n {{\n $n(successOutput.latitude, {\n style: 'decimal',\n minimumFractionDigits: 5,\n maximumFractionDigits: 5,\n })\n }},\n {{\n $n(successOutput.longitude, {\n style: 'decimal',\n minimumFractionDigits: 5,\n maximumFractionDigits: 5,\n })\n }}\n <template v-if=\"successOutput.accuracy !== undefined\">\n (±{{\n $n(successOutput.accuracy, {\n style: 'unit',\n unit: 'meter',\n })\n }})\n </template>\n </span>\n </template>\n\n <!-- Error state -->\n <template v-else-if=\"errorOutput\">\n <span class=\"i-vv-alert-circle text-16 shrink-0 text-danger\" />\n <span>\n {{\n errorOutput.error === 'permission_denied'\n ? $t('message.geolocationPermissionDenied')\n : $t('message.geolocationUnavailable')\n }}\n </span>\n </template>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, useTemplateRef } from 'vue'\n import { useDropZone } from '@vueuse/core'\n import { storeToRefs } from 'pinia'\n import PkChatbotMessages from './PkChatbotMessages.vue'\n import PkChatbotInput from './PkChatbotInput.vue'\n import PkToolShowMultipleChoice from './PkToolShowMultipleChoice.vue'\n import PkToolShowContactForm from './PkToolShowContactForm.vue'\n import PkToolShowSuggestedReply from './PkToolShowSuggestedReply.vue'\n import PkToolShowSources from './PkToolShowSources.vue'\n import PkToolRequestGeolocation from './PkToolRequestGeolocation.vue'\n import PkToolShowLocation from './PkToolShowLocation.vue'\n import { useLocalizedString } from '../composables/useLocalizedString'\n import { useChatbotStore } from 'composables'\n import type { UIChatMessage } from 'models'\n\n const props = defineProps<{ agentId: string }>()\n\n const emit = defineEmits<{\n 'show-info': [message: UIChatMessage]\n revise: [message: UIChatMessage]\n }>()\n\n const store = useChatbotStore(props.agentId)\n\n const {\n name,\n agentInterface,\n agentFileUpload,\n actions,\n revisedAnswers,\n messages,\n chat,\n messageFeedbacks,\n feedbackDialogMessage,\n isFeedbackSubmitting,\n isFeedbackSubmitted,\n feedbackSubmitError,\n isLeadSubmitted,\n isLoadingSubmitLead,\n submitLeadError,\n input,\n inputMessagePlaceholder,\n isConversationBlocked,\n baseUrl,\n pendingAttachments,\n apiClient,\n } = storeToRefs(store)\n\n const {\n handleSubmit: storeHandleSubmit,\n stopGeneration,\n regenerate,\n onUpvote,\n onDownvote,\n onFeedback,\n onFeedbackSubmit,\n onLeadSubmit,\n startNewChat,\n addToolOutput,\n handleFileSelect,\n } = store\n\n const dismissableNotice = useLocalizedString(\n () => agentInterface.value?.dismissableNotice,\n )\n\n const chatViewEl = useTemplateRef<HTMLDivElement>('chatViewEl')\n\n const handleExpandSourceContext = async (payload: {\n documentId: string\n chunkIndex: number\n }) => {\n const result = await apiClient.value.expandSourceContext(\n props.agentId,\n payload.documentId,\n payload.chunkIndex,\n )\n return result.content\n }\n\n const handleDownloadSource = async (documentId: string) => {\n const result = await apiClient.value.downloadSourceDocument(\n props.agentId,\n documentId,\n )\n window.open(result.downloadUrl, '_blank')\n }\n\n const handleFileDrop = (files: File[] | null) => {\n if (!agentFileUpload.value?.enabled || !files) {\n return\n }\n for (const file of files) {\n handleFileSelect(file)\n }\n }\n\n const { isOverDropZone } = useDropZone(chatViewEl, {\n dataTypes: computed(\n () => agentFileUpload.value?.allowedMimeTypes ?? [],\n ),\n onDrop: handleFileDrop,\n })\n</script>\n\n<template>\n <div\n ref=\"chatViewEl\"\n class=\"pk-chatbot-view-chat\"\n :class=\"{\n 'pk-chatbot-view-chat--dragover':\n isOverDropZone && agentFileUpload?.enabled,\n }\">\n <!-- #region messages -->\n <PkChatbotMessages\n class=\"flex flex-col flex-1 min-h-0 p-md overflow-y-auto\"\n :name=\"name\"\n :messages=\"messages\"\n :status=\"chat.status\"\n :error=\"chat.error\"\n :main-color=\"agentInterface?.mainColor\"\n :text-color=\"agentInterface?.textColor\"\n :revised-answers=\"revisedAnswers\"\n :actions=\"actions\"\n :logo=\"agentInterface?.logo\"\n :message-feedbacks=\"messageFeedbacks\"\n :feedback-message-id=\"feedbackDialogMessage?.id\"\n :feedback-loading=\"isFeedbackSubmitting\"\n :feedback-submitted=\"isFeedbackSubmitted\"\n :feedback-error=\"feedbackSubmitError\"\n @feedback-submit=\"onFeedbackSubmit($event)\"\n @feedback-close=\"feedbackDialogMessage = undefined\"\n @regenerate=\"regenerate\"\n @auto-retry=\"regenerate\"\n @reset-chat=\"startNewChat\"\n @show-info=\"emit('show-info', $event)\"\n @revise=\"emit('revise', $event)\"\n @upvote=\"onUpvote\"\n @downvote=\"onDownvote\"\n @feedback=\"onFeedback\">\n <template #tool-showContactForm=\"{ part }\">\n <PkToolShowContactForm\n :part\n :readonly=\"!baseUrl\"\n :submitted=\"isLeadSubmitted\"\n :loading=\"isLoadingSubmitLead\"\n :error=\"submitLeadError\"\n :privacy-policy-notice=\"agentInterface?.privacyPolicyNotice\"\n @submit=\"onLeadSubmit\" />\n </template>\n <template #tool-showSuggestedReply=\"{ part }\">\n <PkToolShowSuggestedReply\n :part\n @select=\"\n ($event) => {\n input = $event\n storeHandleSubmit()\n }\n \" />\n </template>\n <template #tool-showSources=\"{ part }\">\n <PkToolShowSources\n :part\n :on-expand-context=\"handleExpandSourceContext\"\n :on-download=\"handleDownloadSource\" />\n </template>\n <template #tool-showMultipleChoice=\"{ part }\">\n <transition mode=\"out-in\">\n <PkToolShowMultipleChoice\n :part\n @select=\"\n addToolOutput({\n tool: 'showMultipleChoice',\n toolCallId: (part as any).toolCallId,\n output: $event,\n })\n \" />\n </transition>\n </template>\n <template #tool-requestGeolocation=\"{ part }\">\n <PkToolRequestGeolocation\n :part\n :reverse-geocode=\"\n (lat: number, lon: number) =>\n apiClient.reverseGeocode(lat, lon)\n \"\n @result=\"\n addToolOutput({\n tool: 'requestGeolocation',\n toolCallId: (part as any).toolCallId,\n output: $event,\n })\n \" />\n </template>\n <template #tool-showLocation=\"{ part }\">\n <PkToolShowLocation\n :part\n :forward-geocode=\"\n (query: string, lang?: string) =>\n apiClient.forwardGeocode(query, lang)\n \" />\n </template>\n </PkChatbotMessages>\n <!-- #endregion -->\n\n <!-- #region input -->\n <div\n v-if=\"isConversationBlocked\"\n class=\"p-md border-t border-surface-3 text-center text-12 text-danger-darken-2 bg-surface-danger\">\n {{ $t('message.chatErrorConversationBlocked') }}\n </div>\n <PkChatbotInput\n v-else\n v-model=\"input\"\n v-model:pending-attachments=\"pendingAttachments\"\n :placeholder=\"inputMessagePlaceholder\"\n :dismissable-notice=\"\n dismissableNotice && chat.messages.length <= 1\n ? dismissableNotice\n : undefined\n \"\n :status=\"chat.status\"\n :max-message-length=\"agentInterface?.maxMessageLength\"\n :file-upload=\"agentFileUpload\"\n @stop-generation=\"stopGeneration\"\n @submit=\"storeHandleSubmit\"\n @file-select=\"handleFileSelect\" />\n <!-- #endregion -->\n <Transition>\n <div\n v-if=\"isOverDropZone && agentFileUpload?.enabled\"\n class=\"pk-chatbot-view-chat__drop-overlay\">\n <VvIcon\n name=\"ri:upload-cloud-2-line\"\n class=\"pk-chatbot-view-chat__drop-overlay-icon\" />\n <span>{{ $t('action.dropFile') }}</span>\n </div>\n </Transition>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-view-chat {\n position: relative;\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n\n &__drop-overlay {\n position: absolute;\n inset: var(--spacing-sm) var(--spacing-sm) var(--spacing-sm)\n var(--spacing-sm);\n z-index: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--spacing-xs);\n background-color: color-mix(\n in srgb,\n var(--color-surface) 85%,\n transparent\n );\n border-radius: var(--rounded-xl);\n border: var(--spacing-2) dashed var(--color-surface-5);\n pointer-events: none;\n color: var(--color-word-3);\n\n &-icon {\n font-size: var(--spacing-32);\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, useTemplateRef } from 'vue'\n import { useDropZone } from '@vueuse/core'\n import { storeToRefs } from 'pinia'\n import PkChatbotMessages from './PkChatbotMessages.vue'\n import PkChatbotInput from './PkChatbotInput.vue'\n import PkToolShowMultipleChoice from './PkToolShowMultipleChoice.vue'\n import PkToolShowContactForm from './PkToolShowContactForm.vue'\n import PkToolShowSuggestedReply from './PkToolShowSuggestedReply.vue'\n import PkToolShowSources from './PkToolShowSources.vue'\n import PkToolRequestGeolocation from './PkToolRequestGeolocation.vue'\n import PkToolShowLocation from './PkToolShowLocation.vue'\n import { useLocalizedString } from '../composables/useLocalizedString'\n import { useChatbotStore } from 'composables'\n import type { UIChatMessage } from 'models'\n\n const props = defineProps<{ agentId: string }>()\n\n const emit = defineEmits<{\n 'show-info': [message: UIChatMessage]\n revise: [message: UIChatMessage]\n }>()\n\n const store = useChatbotStore(props.agentId)\n\n const {\n name,\n agentInterface,\n agentFileUpload,\n actions,\n revisedAnswers,\n messages,\n chat,\n messageFeedbacks,\n feedbackDialogMessage,\n isFeedbackSubmitting,\n isFeedbackSubmitted,\n feedbackSubmitError,\n isLeadSubmitted,\n isLoadingSubmitLead,\n submitLeadError,\n input,\n inputMessagePlaceholder,\n isConversationBlocked,\n baseUrl,\n pendingAttachments,\n apiClient,\n } = storeToRefs(store)\n\n const {\n handleSubmit: storeHandleSubmit,\n stopGeneration,\n regenerate,\n onUpvote,\n onDownvote,\n onFeedback,\n onFeedbackSubmit,\n onLeadSubmit,\n startNewChat,\n addToolOutput,\n handleFileSelect,\n } = store\n\n const dismissableNotice = useLocalizedString(\n () => agentInterface.value?.dismissableNotice,\n )\n\n const chatViewEl = useTemplateRef<HTMLDivElement>('chatViewEl')\n\n const handleExpandSourceContext = async (payload: {\n documentId: string\n chunkIndex: number\n }) => {\n const result = await apiClient.value.expandSourceContext(\n props.agentId,\n payload.documentId,\n payload.chunkIndex,\n )\n return result.content\n }\n\n const handleDownloadSource = async (documentId: string) => {\n const result = await apiClient.value.downloadSourceDocument(\n props.agentId,\n documentId,\n )\n window.open(result.downloadUrl, '_blank')\n }\n\n const handleFileDrop = (files: File[] | null) => {\n if (!agentFileUpload.value?.enabled || !files) {\n return\n }\n for (const file of files) {\n handleFileSelect(file)\n }\n }\n\n const { isOverDropZone } = useDropZone(chatViewEl, {\n dataTypes: computed(\n () => agentFileUpload.value?.allowedMimeTypes ?? [],\n ),\n onDrop: handleFileDrop,\n })\n</script>\n\n<template>\n <div\n ref=\"chatViewEl\"\n class=\"pk-chatbot-view-chat\"\n :class=\"{\n 'pk-chatbot-view-chat--dragover':\n isOverDropZone && agentFileUpload?.enabled,\n }\">\n <!-- #region messages -->\n <PkChatbotMessages\n class=\"flex flex-col flex-1 min-h-0 p-md overflow-y-auto\"\n :name=\"name\"\n :messages=\"messages\"\n :status=\"chat.status\"\n :error=\"chat.error\"\n :main-color=\"agentInterface?.mainColor\"\n :text-color=\"agentInterface?.textColor\"\n :revised-answers=\"revisedAnswers\"\n :actions=\"actions\"\n :logo=\"agentInterface?.logo\"\n :message-feedbacks=\"messageFeedbacks\"\n :feedback-message-id=\"feedbackDialogMessage?.id\"\n :feedback-loading=\"isFeedbackSubmitting\"\n :feedback-submitted=\"isFeedbackSubmitted\"\n :feedback-error=\"feedbackSubmitError\"\n @feedback-submit=\"onFeedbackSubmit($event)\"\n @feedback-close=\"feedbackDialogMessage = undefined\"\n @regenerate=\"regenerate\"\n @auto-retry=\"regenerate\"\n @reset-chat=\"startNewChat\"\n @show-info=\"emit('show-info', $event)\"\n @revise=\"emit('revise', $event)\"\n @upvote=\"onUpvote\"\n @downvote=\"onDownvote\"\n @feedback=\"onFeedback\">\n <template #tool-showContactForm=\"{ part }\">\n <PkToolShowContactForm\n :part\n :readonly=\"!baseUrl\"\n :submitted=\"isLeadSubmitted\"\n :loading=\"isLoadingSubmitLead\"\n :error=\"submitLeadError\"\n :privacy-policy-notice=\"agentInterface?.privacyPolicyNotice\"\n @submit=\"onLeadSubmit\" />\n </template>\n <template #tool-showSuggestedReply=\"{ part }\">\n <PkToolShowSuggestedReply\n :part\n @select=\"\n ($event) => {\n input = $event\n storeHandleSubmit()\n }\n \" />\n </template>\n <template #tool-showSources=\"{ part }\">\n <PkToolShowSources\n :part\n :on-expand-context=\"handleExpandSourceContext\"\n :on-download=\"handleDownloadSource\" />\n </template>\n <template #tool-showMultipleChoice=\"{ part }\">\n <transition mode=\"out-in\">\n <PkToolShowMultipleChoice\n :part\n @select=\"\n addToolOutput({\n tool: 'showMultipleChoice',\n toolCallId: (part as any).toolCallId,\n output: $event,\n })\n \" />\n </transition>\n </template>\n <template #tool-requestGeolocation=\"{ part }\">\n <PkToolRequestGeolocation\n :part\n :reverse-geocode=\"\n (lat: number, lon: number) =>\n apiClient.reverseGeocode(lat, lon)\n \"\n @result=\"\n addToolOutput({\n tool: 'requestGeolocation',\n toolCallId: (part as any).toolCallId,\n output: $event,\n })\n \" />\n </template>\n <template #tool-showLocation=\"{ part }\">\n <PkToolShowLocation\n :part\n :forward-geocode=\"\n (query: string, lang?: string) =>\n apiClient.forwardGeocode(query, lang)\n \" />\n </template>\n </PkChatbotMessages>\n <!-- #endregion -->\n\n <!-- #region input -->\n <div\n v-if=\"isConversationBlocked\"\n class=\"p-md border-t border-surface-3 text-center text-12 text-danger-darken-2 bg-surface-danger\">\n {{ $t('message.chatErrorConversationBlocked') }}\n </div>\n <PkChatbotInput\n v-else\n v-model=\"input\"\n v-model:pending-attachments=\"pendingAttachments\"\n :placeholder=\"inputMessagePlaceholder\"\n :dismissable-notice=\"\n dismissableNotice && chat.messages.length <= 1\n ? dismissableNotice\n : undefined\n \"\n :status=\"chat.status\"\n :max-message-length=\"agentInterface?.maxMessageLength\"\n :file-upload=\"agentFileUpload\"\n @stop-generation=\"stopGeneration\"\n @submit=\"storeHandleSubmit\"\n @file-select=\"handleFileSelect\" />\n <!-- #endregion -->\n <Transition>\n <div\n v-if=\"isOverDropZone && agentFileUpload?.enabled\"\n class=\"pk-chatbot-view-chat__drop-overlay\">\n <VvIcon\n name=\"ri:upload-cloud-2-line\"\n class=\"pk-chatbot-view-chat__drop-overlay-icon\" />\n <span>{{ $t('action.dropFile') }}</span>\n </div>\n </Transition>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-view-chat {\n position: relative;\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n\n &__drop-overlay {\n position: absolute;\n inset: var(--spacing-sm) var(--spacing-sm) var(--spacing-sm)\n var(--spacing-sm);\n z-index: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--spacing-xs);\n background-color: color-mix(\n in srgb,\n var(--color-surface) 85%,\n transparent\n );\n border-radius: var(--rounded-xl);\n border: var(--spacing-2) dashed var(--color-surface-5);\n pointer-events: none;\n color: var(--color-word-3);\n\n &-icon {\n font-size: var(--spacing-32);\n }\n }\n }\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"PkChatbotViewChat-Z05fqNFE.js","names":["$n","$t"],"sources":["../../../../packages/components/src/chat/PkToolRequestGeolocation.vue","../../../../packages/components/src/chat/PkToolRequestGeolocation.vue","../../../../packages/components/src/chat/PkChatbotViewChat.vue","../../../../packages/components/src/chat/PkChatbotViewChat.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed, onMounted } from 'vue'\n import { useI18n } from 'vue-i18n'\n\n import type { ReverseGeocodeFn } from 'utils/src/device-context'\n\n type GeolocationOutput =\n | {\n latitude: number\n longitude: number\n accuracy?: number\n city?: string\n }\n | { error: 'permission_denied' | 'position_unavailable' | 'timeout' }\n\n const props = defineProps<{\n part: unknown\n reverseGeocode?: ReverseGeocodeFn\n }>()\n\n const emit = defineEmits<{\n result: [output: GeolocationOutput]\n }>()\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const toolPart = computed(() => {\n return props.part as {\n state?: string\n input?: { reason?: string }\n output?: GeolocationOutput\n }\n })\n\n const state = computed(() => toolPart.value.state ?? 'unknown')\n\n const isOutputAvailable = computed(() => state.value === 'output-available')\n\n const successOutput = computed(() => {\n const out = toolPart.value.output\n if (!out || 'error' in out) {\n return undefined\n }\n return out\n })\n\n const errorOutput = computed(() => {\n const out = toolPart.value.output\n if (!out || !('error' in out)) {\n return undefined\n }\n return out\n })\n\n /** Maps GeolocationPositionError.code to a typed string */\n function mapGeolocationError(\n code: number,\n ): 'permission_denied' | 'position_unavailable' | 'timeout' {\n if (code === 1) {\n return 'permission_denied'\n }\n if (code === 3) {\n return 'timeout'\n }\n return 'position_unavailable'\n }\n\n onMounted(() => {\n if (state.value !== 'input-available') {\n return\n }\n\n if (!navigator.geolocation) {\n emit('result', { error: 'position_unavailable' })\n return\n }\n\n navigator.geolocation.getCurrentPosition(\n async (position) => {\n const { latitude, longitude, accuracy } = position.coords\n const city = props.reverseGeocode\n ? await props\n .reverseGeocode(latitude, longitude)\n .catch(() => undefined)\n : undefined\n emit('result', { latitude, longitude, accuracy, city })\n },\n (error) => {\n emit('result', { error: mapGeolocationError(error.code) })\n },\n { timeout: 15000 },\n )\n })\n</script>\n\n<template>\n <div\n class=\"flex items-center gap-6 text-12 text-word-3 border border-surface-3 rounded-xl px-sm py-10\">\n <!-- Loading state -->\n <template v-if=\"!isOutputAvailable\">\n <VvIcon name=\"line-md:loading-loop\" class=\"text-16\" />\n <span>{{ $t('messagePart.requestGeolocation') }}</span>\n </template>\n\n <!-- Success state -->\n <template v-else-if=\"successOutput\">\n <VvIcon name=\"ri:map-pin-line\" class=\"text-16\" />\n <span>\n {{\n $n(successOutput.latitude, {\n style: 'decimal',\n minimumFractionDigits: 5,\n maximumFractionDigits: 5,\n })\n }},\n {{\n $n(successOutput.longitude, {\n style: 'decimal',\n minimumFractionDigits: 5,\n maximumFractionDigits: 5,\n })\n }}\n <template v-if=\"successOutput.accuracy !== undefined\">\n (±{{\n $n(successOutput.accuracy, {\n style: 'unit',\n unit: 'meter',\n })\n }})\n </template>\n </span>\n </template>\n\n <!-- Error state -->\n <template v-else-if=\"errorOutput\">\n <span class=\"i-vv-alert-circle text-16 shrink-0 text-danger\" />\n <span>\n {{\n errorOutput.error === 'permission_denied'\n ? $t('message.geolocationPermissionDenied')\n : $t('message.geolocationUnavailable')\n }}\n </span>\n </template>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, onMounted } from 'vue'\n import { useI18n } from 'vue-i18n'\n\n import type { ReverseGeocodeFn } from 'utils/src/device-context'\n\n type GeolocationOutput =\n | {\n latitude: number\n longitude: number\n accuracy?: number\n city?: string\n }\n | { error: 'permission_denied' | 'position_unavailable' | 'timeout' }\n\n const props = defineProps<{\n part: unknown\n reverseGeocode?: ReverseGeocodeFn\n }>()\n\n const emit = defineEmits<{\n result: [output: GeolocationOutput]\n }>()\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const toolPart = computed(() => {\n return props.part as {\n state?: string\n input?: { reason?: string }\n output?: GeolocationOutput\n }\n })\n\n const state = computed(() => toolPart.value.state ?? 'unknown')\n\n const isOutputAvailable = computed(() => state.value === 'output-available')\n\n const successOutput = computed(() => {\n const out = toolPart.value.output\n if (!out || 'error' in out) {\n return undefined\n }\n return out\n })\n\n const errorOutput = computed(() => {\n const out = toolPart.value.output\n if (!out || !('error' in out)) {\n return undefined\n }\n return out\n })\n\n /** Maps GeolocationPositionError.code to a typed string */\n function mapGeolocationError(\n code: number,\n ): 'permission_denied' | 'position_unavailable' | 'timeout' {\n if (code === 1) {\n return 'permission_denied'\n }\n if (code === 3) {\n return 'timeout'\n }\n return 'position_unavailable'\n }\n\n onMounted(() => {\n if (state.value !== 'input-available') {\n return\n }\n\n if (!navigator.geolocation) {\n emit('result', { error: 'position_unavailable' })\n return\n }\n\n navigator.geolocation.getCurrentPosition(\n async (position) => {\n const { latitude, longitude, accuracy } = position.coords\n const city = props.reverseGeocode\n ? await props\n .reverseGeocode(latitude, longitude)\n .catch(() => undefined)\n : undefined\n emit('result', { latitude, longitude, accuracy, city })\n },\n (error) => {\n emit('result', { error: mapGeolocationError(error.code) })\n },\n { timeout: 15000 },\n )\n })\n</script>\n\n<template>\n <div\n class=\"flex items-center gap-6 text-12 text-word-3 border border-surface-3 rounded-xl px-sm py-10\">\n <!-- Loading state -->\n <template v-if=\"!isOutputAvailable\">\n <VvIcon name=\"line-md:loading-loop\" class=\"text-16\" />\n <span>{{ $t('messagePart.requestGeolocation') }}</span>\n </template>\n\n <!-- Success state -->\n <template v-else-if=\"successOutput\">\n <VvIcon name=\"ri:map-pin-line\" class=\"text-16\" />\n <span>\n {{\n $n(successOutput.latitude, {\n style: 'decimal',\n minimumFractionDigits: 5,\n maximumFractionDigits: 5,\n })\n }},\n {{\n $n(successOutput.longitude, {\n style: 'decimal',\n minimumFractionDigits: 5,\n maximumFractionDigits: 5,\n })\n }}\n <template v-if=\"successOutput.accuracy !== undefined\">\n (±{{\n $n(successOutput.accuracy, {\n style: 'unit',\n unit: 'meter',\n })\n }})\n </template>\n </span>\n </template>\n\n <!-- Error state -->\n <template v-else-if=\"errorOutput\">\n <span class=\"i-vv-alert-circle text-16 shrink-0 text-danger\" />\n <span>\n {{\n errorOutput.error === 'permission_denied'\n ? $t('message.geolocationPermissionDenied')\n : $t('message.geolocationUnavailable')\n }}\n </span>\n </template>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, useTemplateRef } from 'vue'\n import { useDropZone } from '@vueuse/core'\n import { storeToRefs } from 'pinia'\n import PkChatbotMessages from './PkChatbotMessages.vue'\n import PkChatbotInput from './PkChatbotInput.vue'\n import PkToolShowMultipleChoice from './PkToolShowMultipleChoice.vue'\n import PkToolShowContactForm from './PkToolShowContactForm.vue'\n import PkToolShowSuggestedReply from './PkToolShowSuggestedReply.vue'\n import PkToolShowSources from './PkToolShowSources.vue'\n import PkToolRequestGeolocation from './PkToolRequestGeolocation.vue'\n import PkToolShowLocation from './PkToolShowLocation.vue'\n import { useLocalizedString } from '../composables/useLocalizedString'\n import { useChatbotStore } from 'composables'\n import type { UIChatMessage } from 'models'\n\n const props = defineProps<{ agentId: string }>()\n\n const emit = defineEmits<{\n 'show-info': [message: UIChatMessage]\n revise: [message: UIChatMessage]\n }>()\n\n const store = useChatbotStore(props.agentId)\n\n const {\n name,\n agentInterface,\n agentFileUpload,\n actions,\n revisedAnswers,\n messages,\n chat,\n messageFeedbacks,\n feedbackDialogMessage,\n isFeedbackSubmitting,\n isFeedbackSubmitted,\n feedbackSubmitError,\n isLeadSubmitted,\n isLoadingSubmitLead,\n submitLeadError,\n input,\n inputMessagePlaceholder,\n isConversationBlocked,\n baseUrl,\n pendingAttachments,\n apiClient,\n } = storeToRefs(store)\n\n const {\n handleSubmit: storeHandleSubmit,\n stopGeneration,\n regenerate,\n onUpvote,\n onDownvote,\n onFeedback,\n onFeedbackSubmit,\n onLeadSubmit,\n startNewChat,\n addToolOutput,\n handleFileSelect,\n } = store\n\n const dismissableNotice = useLocalizedString(\n () => agentInterface.value?.dismissableNotice,\n )\n\n const chatViewEl = useTemplateRef<HTMLDivElement>('chatViewEl')\n\n const handleExpandSourceContext = async (payload: {\n documentId: string\n chunkIndex: number\n }) => {\n const result = await apiClient.value.expandSourceContext(\n props.agentId,\n payload.documentId,\n payload.chunkIndex,\n )\n return result.content\n }\n\n const handleDownloadSource = async (documentId: string) => {\n const result = await apiClient.value.downloadSourceDocument(\n props.agentId,\n documentId,\n )\n window.open(result.downloadUrl, '_blank')\n }\n\n const handleFileDrop = (files: File[] | null) => {\n if (!agentFileUpload.value?.enabled || !files) {\n return\n }\n for (const file of files) {\n handleFileSelect(file)\n }\n }\n\n const { isOverDropZone } = useDropZone(chatViewEl, {\n dataTypes: computed(\n () => agentFileUpload.value?.allowedMimeTypes ?? [],\n ),\n onDrop: handleFileDrop,\n })\n</script>\n\n<template>\n <div\n ref=\"chatViewEl\"\n class=\"pk-chatbot-view-chat\"\n :class=\"{\n 'pk-chatbot-view-chat--dragover':\n isOverDropZone && agentFileUpload?.enabled,\n }\">\n <!-- #region messages -->\n <PkChatbotMessages\n class=\"flex flex-col flex-1 min-h-0 p-md overflow-y-auto\"\n :name=\"name\"\n :messages=\"messages\"\n :status=\"chat.status\"\n :error=\"chat.error\"\n :main-color=\"agentInterface?.mainColor\"\n :text-color=\"agentInterface?.textColor\"\n :revised-answers=\"revisedAnswers\"\n :actions=\"actions\"\n :logo=\"agentInterface?.logo\"\n :message-feedbacks=\"messageFeedbacks\"\n :feedback-message-id=\"feedbackDialogMessage?.id\"\n :feedback-loading=\"isFeedbackSubmitting\"\n :feedback-submitted=\"isFeedbackSubmitted\"\n :feedback-error=\"feedbackSubmitError\"\n @feedback-submit=\"onFeedbackSubmit($event)\"\n @feedback-close=\"feedbackDialogMessage = undefined\"\n @regenerate=\"regenerate\"\n @auto-retry=\"regenerate\"\n @reset-chat=\"startNewChat\"\n @show-info=\"emit('show-info', $event)\"\n @revise=\"emit('revise', $event)\"\n @upvote=\"onUpvote\"\n @downvote=\"onDownvote\"\n @feedback=\"onFeedback\">\n <template #tool-showContactForm=\"{ part }\">\n <PkToolShowContactForm\n :part\n :readonly=\"!baseUrl\"\n :submitted=\"isLeadSubmitted\"\n :loading=\"isLoadingSubmitLead\"\n :error=\"submitLeadError\"\n :privacy-policy-notice=\"agentInterface?.privacyPolicyNotice\"\n @submit=\"onLeadSubmit\" />\n </template>\n <template #tool-showSuggestedReply=\"{ part }\">\n <PkToolShowSuggestedReply\n :part\n @select=\"\n ($event) => {\n input = $event\n storeHandleSubmit()\n }\n \" />\n </template>\n <template #tool-showSources=\"{ part }\">\n <PkToolShowSources\n :part\n :on-expand-context=\"handleExpandSourceContext\"\n :on-download=\"handleDownloadSource\" />\n </template>\n <template #tool-showMultipleChoice=\"{ part }\">\n <transition mode=\"out-in\">\n <PkToolShowMultipleChoice\n :part\n @select=\"\n addToolOutput({\n tool: 'showMultipleChoice',\n toolCallId: (part as any).toolCallId,\n output: $event,\n })\n \" />\n </transition>\n </template>\n <template #tool-requestGeolocation=\"{ part }\">\n <PkToolRequestGeolocation\n :part\n :reverse-geocode=\"\n (lat: number, lon: number) =>\n apiClient.reverseGeocode(lat, lon)\n \"\n @result=\"\n addToolOutput({\n tool: 'requestGeolocation',\n toolCallId: (part as any).toolCallId,\n output: $event,\n })\n \" />\n </template>\n <template #tool-showLocation=\"{ part }\">\n <PkToolShowLocation\n :part\n :forward-geocode=\"\n (query: string, lang?: string) =>\n apiClient.forwardGeocode(query, lang)\n \" />\n </template>\n </PkChatbotMessages>\n <!-- #endregion -->\n\n <!-- #region input -->\n <div\n v-if=\"isConversationBlocked\"\n class=\"p-md border-t border-surface-3 text-center text-12 text-danger-darken-2 bg-surface-danger\">\n {{ $t('message.chatErrorConversationBlocked') }}\n </div>\n <PkChatbotInput\n v-else\n v-model=\"input\"\n v-model:pending-attachments=\"pendingAttachments\"\n :placeholder=\"inputMessagePlaceholder\"\n :dismissable-notice=\"\n dismissableNotice && chat.messages.length <= 1\n ? dismissableNotice\n : undefined\n \"\n :status=\"chat.status\"\n :max-message-length=\"agentInterface?.maxMessageLength\"\n :file-upload=\"agentFileUpload\"\n @stop-generation=\"stopGeneration\"\n @submit=\"storeHandleSubmit\"\n @file-select=\"handleFileSelect\" />\n <!-- #endregion -->\n <Transition>\n <div\n v-if=\"isOverDropZone && agentFileUpload?.enabled\"\n class=\"pk-chatbot-view-chat__drop-overlay\">\n <VvIcon\n name=\"ri:upload-cloud-2-line\"\n class=\"pk-chatbot-view-chat__drop-overlay-icon\" />\n <span>{{ $t('action.dropFile') }}</span>\n </div>\n </Transition>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-view-chat {\n position: relative;\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n\n &__drop-overlay {\n position: absolute;\n inset: var(--spacing-sm) var(--spacing-sm) var(--spacing-sm)\n var(--spacing-sm);\n z-index: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--spacing-xs);\n background-color: color-mix(\n in srgb,\n var(--color-surface) 85%,\n transparent\n );\n border-radius: var(--rounded-xl);\n border: var(--spacing-2) dashed var(--color-surface-5);\n pointer-events: none;\n color: var(--color-word-3);\n\n &-icon {\n font-size: var(--spacing-32);\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, useTemplateRef } from 'vue'\n import { useDropZone } from '@vueuse/core'\n import { storeToRefs } from 'pinia'\n import PkChatbotMessages from './PkChatbotMessages.vue'\n import PkChatbotInput from './PkChatbotInput.vue'\n import PkToolShowMultipleChoice from './PkToolShowMultipleChoice.vue'\n import PkToolShowContactForm from './PkToolShowContactForm.vue'\n import PkToolShowSuggestedReply from './PkToolShowSuggestedReply.vue'\n import PkToolShowSources from './PkToolShowSources.vue'\n import PkToolRequestGeolocation from './PkToolRequestGeolocation.vue'\n import PkToolShowLocation from './PkToolShowLocation.vue'\n import { useLocalizedString } from '../composables/useLocalizedString'\n import { useChatbotStore } from 'composables'\n import type { UIChatMessage } from 'models'\n\n const props = defineProps<{ agentId: string }>()\n\n const emit = defineEmits<{\n 'show-info': [message: UIChatMessage]\n revise: [message: UIChatMessage]\n }>()\n\n const store = useChatbotStore(props.agentId)\n\n const {\n name,\n agentInterface,\n agentFileUpload,\n actions,\n revisedAnswers,\n messages,\n chat,\n messageFeedbacks,\n feedbackDialogMessage,\n isFeedbackSubmitting,\n isFeedbackSubmitted,\n feedbackSubmitError,\n isLeadSubmitted,\n isLoadingSubmitLead,\n submitLeadError,\n input,\n inputMessagePlaceholder,\n isConversationBlocked,\n baseUrl,\n pendingAttachments,\n apiClient,\n } = storeToRefs(store)\n\n const {\n handleSubmit: storeHandleSubmit,\n stopGeneration,\n regenerate,\n onUpvote,\n onDownvote,\n onFeedback,\n onFeedbackSubmit,\n onLeadSubmit,\n startNewChat,\n addToolOutput,\n handleFileSelect,\n } = store\n\n const dismissableNotice = useLocalizedString(\n () => agentInterface.value?.dismissableNotice,\n )\n\n const chatViewEl = useTemplateRef<HTMLDivElement>('chatViewEl')\n\n const handleExpandSourceContext = async (payload: {\n documentId: string\n chunkIndex: number\n }) => {\n const result = await apiClient.value.expandSourceContext(\n props.agentId,\n payload.documentId,\n payload.chunkIndex,\n )\n return result.content\n }\n\n const handleDownloadSource = async (documentId: string) => {\n const result = await apiClient.value.downloadSourceDocument(\n props.agentId,\n documentId,\n )\n window.open(result.downloadUrl, '_blank')\n }\n\n const handleFileDrop = (files: File[] | null) => {\n if (!agentFileUpload.value?.enabled || !files) {\n return\n }\n for (const file of files) {\n handleFileSelect(file)\n }\n }\n\n const { isOverDropZone } = useDropZone(chatViewEl, {\n dataTypes: computed(\n () => agentFileUpload.value?.allowedMimeTypes ?? [],\n ),\n onDrop: handleFileDrop,\n })\n</script>\n\n<template>\n <div\n ref=\"chatViewEl\"\n class=\"pk-chatbot-view-chat\"\n :class=\"{\n 'pk-chatbot-view-chat--dragover':\n isOverDropZone && agentFileUpload?.enabled,\n }\">\n <!-- #region messages -->\n <PkChatbotMessages\n class=\"flex flex-col flex-1 min-h-0 p-md overflow-y-auto\"\n :name=\"name\"\n :messages=\"messages\"\n :status=\"chat.status\"\n :error=\"chat.error\"\n :main-color=\"agentInterface?.mainColor\"\n :text-color=\"agentInterface?.textColor\"\n :revised-answers=\"revisedAnswers\"\n :actions=\"actions\"\n :logo=\"agentInterface?.logo\"\n :message-feedbacks=\"messageFeedbacks\"\n :feedback-message-id=\"feedbackDialogMessage?.id\"\n :feedback-loading=\"isFeedbackSubmitting\"\n :feedback-submitted=\"isFeedbackSubmitted\"\n :feedback-error=\"feedbackSubmitError\"\n @feedback-submit=\"onFeedbackSubmit($event)\"\n @feedback-close=\"feedbackDialogMessage = undefined\"\n @regenerate=\"regenerate\"\n @auto-retry=\"regenerate\"\n @reset-chat=\"startNewChat\"\n @show-info=\"emit('show-info', $event)\"\n @revise=\"emit('revise', $event)\"\n @upvote=\"onUpvote\"\n @downvote=\"onDownvote\"\n @feedback=\"onFeedback\">\n <template #tool-showContactForm=\"{ part }\">\n <PkToolShowContactForm\n :part\n :readonly=\"!baseUrl\"\n :submitted=\"isLeadSubmitted\"\n :loading=\"isLoadingSubmitLead\"\n :error=\"submitLeadError\"\n :privacy-policy-notice=\"agentInterface?.privacyPolicyNotice\"\n @submit=\"onLeadSubmit\" />\n </template>\n <template #tool-showSuggestedReply=\"{ part }\">\n <PkToolShowSuggestedReply\n :part\n @select=\"\n ($event) => {\n input = $event\n storeHandleSubmit()\n }\n \" />\n </template>\n <template #tool-showSources=\"{ part }\">\n <PkToolShowSources\n :part\n :on-expand-context=\"handleExpandSourceContext\"\n :on-download=\"handleDownloadSource\" />\n </template>\n <template #tool-showMultipleChoice=\"{ part }\">\n <transition mode=\"out-in\">\n <PkToolShowMultipleChoice\n :part\n @select=\"\n addToolOutput({\n tool: 'showMultipleChoice',\n toolCallId: (part as any).toolCallId,\n output: $event,\n })\n \" />\n </transition>\n </template>\n <template #tool-requestGeolocation=\"{ part }\">\n <PkToolRequestGeolocation\n :part\n :reverse-geocode=\"\n (lat: number, lon: number) =>\n apiClient.reverseGeocode(lat, lon)\n \"\n @result=\"\n addToolOutput({\n tool: 'requestGeolocation',\n toolCallId: (part as any).toolCallId,\n output: $event,\n })\n \" />\n </template>\n <template #tool-showLocation=\"{ part }\">\n <PkToolShowLocation\n :part\n :forward-geocode=\"\n (query: string, lang?: string) =>\n apiClient.forwardGeocode(query, lang)\n \" />\n </template>\n </PkChatbotMessages>\n <!-- #endregion -->\n\n <!-- #region input -->\n <div\n v-if=\"isConversationBlocked\"\n class=\"p-md border-t border-surface-3 text-center text-12 text-danger-darken-2 bg-surface-danger\">\n {{ $t('message.chatErrorConversationBlocked') }}\n </div>\n <PkChatbotInput\n v-else\n v-model=\"input\"\n v-model:pending-attachments=\"pendingAttachments\"\n :placeholder=\"inputMessagePlaceholder\"\n :dismissable-notice=\"\n dismissableNotice && chat.messages.length <= 1\n ? dismissableNotice\n : undefined\n \"\n :status=\"chat.status\"\n :max-message-length=\"agentInterface?.maxMessageLength\"\n :file-upload=\"agentFileUpload\"\n @stop-generation=\"stopGeneration\"\n @submit=\"storeHandleSubmit\"\n @file-select=\"handleFileSelect\" />\n <!-- #endregion -->\n <Transition>\n <div\n v-if=\"isOverDropZone && agentFileUpload?.enabled\"\n class=\"pk-chatbot-view-chat__drop-overlay\">\n <VvIcon\n name=\"ri:upload-cloud-2-line\"\n class=\"pk-chatbot-view-chat__drop-overlay-icon\" />\n <span>{{ $t('action.dropFile') }}</span>\n </div>\n </Transition>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-view-chat {\n position: relative;\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n\n &__drop-overlay {\n position: absolute;\n inset: var(--spacing-sm) var(--spacing-sm) var(--spacing-sm)\n var(--spacing-sm);\n z-index: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--spacing-xs);\n background-color: color-mix(\n in srgb,\n var(--color-surface) 85%,\n transparent\n );\n border-radius: var(--rounded-xl);\n border: var(--spacing-2) dashed var(--color-surface-5);\n pointer-events: none;\n color: var(--color-word-3);\n\n &-icon {\n font-size: var(--spacing-32);\n }\n }\n }\n</style>\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { m as e, s as t } from "./src-EtGd6cRz.js";
2
- import { t as n } from "./useChatbotStore-CJlkoNn7.js";
2
+ import { t as n } from "./useChatbotStore-DMDbzuub.js";
3
3
  import { t as r } from "./PkRelativeTime-WZ2aPcp_.js";
4
4
  import { Fragment as i, createCommentVNode as a, createElementBlock as o, createElementVNode as s, createTextVNode as c, createVNode as l, defineComponent as u, h as d, mergeProps as f, nextTick as p, normalizeClass as m, openBlock as h, ref as g, renderList as _, toDisplayString as v, unref as y, vModelText as ee, withCtx as b, withDirectives as te, withKeys as x, withModifiers as S } from "vue";
5
5
  import { VvButton as C, VvButtonGroup as w, VvDialog as T, VvDropdown as E, VvDropdownAction as D, VvIcon as O, VvInputText as k } from "@volverjs/ui-vue/components";
@@ -160,4 +160,4 @@ var M = g(!1), N = g(), P = g(), F = g(), I = g(!1), L = g(), R = g(), z = () =>
160
160
  //#endregion
161
161
  export { B as n, X as t };
162
162
 
163
- //# sourceMappingURL=PkChatbotViewConversations-DSQu6vY1.js.map
163
+ //# sourceMappingURL=PkChatbotViewConversations-2xc0o-fO.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PkChatbotViewConversations-DSQu6vY1.js","names":[],"sources":["../../../../packages/composable/src/useDialog.ts","../../../../packages/composable/src/useDialogConfirm.ts","../../../../packages/components/src/chat/PkChatbotViewConversations.vue","../../../../packages/components/src/chat/PkChatbotViewConversations.vue"],"sourcesContent":["import { VvDialog } from '@volverjs/ui-vue/components'\nimport { defineComponent, h, nextTick, ref, type VNode } from 'vue'\n\ntype DialogProps = {\n title?: string\n transition?: string\n size?: 'small' | 'standard' | 'fullscreen'\n role?: 'alert' | 'alertdialog'\n keepOpen?: boolean\n}\n\ntype DialogSlots = {\n footer?: () => VNode | string\n header?: () => VNode | string\n default?: () => VNode | string | VNode[] | string[]\n}\n\nconst isOpen = ref(false)\nconst title = ref<DialogProps['title']>()\nconst transition = ref<DialogProps['transition']>()\nconst size = ref<DialogProps['size']>()\nconst keepOpen = ref<DialogProps['keepOpen']>(false)\nconst role = ref<DialogProps['role']>()\nconst slots = ref<DialogSlots>()\n\nexport const useDialog = () => {\n const onUpdateModelValue = (value: boolean) => {\n isOpen.value = value\n }\n\n const onAfterLeave = () => {\n title.value = undefined\n transition.value = undefined\n size.value = undefined\n keepOpen.value = undefined\n role.value = undefined\n slots.value = undefined\n }\n\n const PkGlobalDialog = defineComponent({\n name: 'PkGlobalDialog',\n render: () =>\n h(\n VvDialog,\n {\n modelValue: isOpen.value,\n title: title.value,\n transition: transition.value,\n size: size.value,\n keepOpen: keepOpen.value,\n role: role.value,\n 'onUpdate:modelValue': onUpdateModelValue,\n onAfterLeave: onAfterLeave,\n },\n slots.value,\n ),\n })\n\n const openDialog = (newProps: DialogProps, newSlots?: DialogSlots) => {\n title.value = newProps?.title\n transition.value = newProps?.transition\n size.value = newProps?.size\n keepOpen.value = newProps?.keepOpen ?? false\n role.value = newProps?.role\n slots.value = newSlots\n nextTick(() => {\n isOpen.value = true\n })\n return isOpen\n }\n\n return { PkGlobalDialog, openDialog, isOpen }\n}\n","import { h, ref, VNode } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport {\n VvButton,\n VvButtonGroup,\n VvInputText,\n} from '@volverjs/ui-vue/components'\nimport { useDialog } from './useDialog'\n\nexport const useDialogConfirm = () => {\n const { openDialog } = useDialog()\n const { t: $t } = useI18n({\n useScope: 'global',\n })\n\n const openDialogConfirm = ({\n emitReject = false,\n confirmLabel,\n cancelLabel,\n questionLabel,\n onlyConfirm = false,\n passphrase,\n passphraseLabel,\n passphraseHint,\n }: {\n emitReject?: boolean\n confirmLabel?: string\n cancelLabel?: string\n questionLabel?: string\n onlyConfirm?: boolean\n passphrase?: string\n passphraseLabel?: string\n passphraseHint?: string\n } = {}) => {\n return new Promise<boolean>((resolve, reject) => {\n const passphraseText = ref<string>()\n const isOpen = openDialog(\n {\n role: 'alertdialog',\n size: 'small',\n keepOpen: true,\n },\n {\n default: () =>\n h('div', [\n h(\n 'div',\n { class: 'mb-sm' },\n questionLabel ?? $t('message.confirm'),\n ),\n passphrase\n ? h(VvInputText, {\n modelValue: passphraseText.value,\n 'onUpdate:modelValue': (\n value: string,\n ) => {\n passphraseText.value = value\n },\n type: 'text',\n name: 'passphrase',\n class: 'mb-0',\n floating: true,\n label:\n passphraseLabel ??\n $t('label.passphrase'),\n hintLabel:\n passphraseHint ??\n $t('hint.passphrase', { passphrase }),\n })\n : undefined,\n ]),\n footer: () =>\n h(VvButtonGroup, () => {\n const toReturn: VNode[] = []\n if (!onlyConfirm) {\n toReturn.push(\n h(VvButton, {\n label:\n cancelLabel ?? $t('action.cancel'),\n modifiers: 'ghost',\n onClick: () => {\n if (emitReject) {\n reject()\n }\n resolve(false)\n isOpen.value = false\n },\n }),\n )\n }\n toReturn.push(\n h(VvButton, {\n label: confirmLabel ?? $t('action.proceed'),\n disabled: passphrase\n ? passphrase !== passphraseText.value\n : false,\n onClick: () => {\n resolve(true)\n isOpen.value = false\n },\n }),\n )\n return toReturn\n }),\n },\n )\n })\n }\n\n return { openDialogConfirm }\n}\n","<script setup lang=\"ts\">\n import { ref, nextTick } from 'vue'\n import { storeToRefs } from 'pinia'\n import { useI18n } from 'vue-i18n'\n import type { Chat as Conversation, UIChatMessage } from 'models'\n import { stripMarkdown, getTextPart } from 'utils'\n import { useChatbotStore, useDialogConfirm } from 'composables'\n import PkRelativeTime from '../PkRelativeTime.vue'\n\n const props = defineProps<{ agentId: string }>()\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const store = useChatbotStore(props.agentId)\n const { conversations, localChatId } = storeToRefs(store)\n const { navigate, startNewChat, renameChatTitle, deleteChat } = store\n\n const editingId = ref<string | null>(null)\n const editingTitle = ref('')\n const renameInputEl = ref<HTMLInputElement[]>()\n\n const openConversation = (id: string) => {\n if (editingId.value) {\n return\n }\n localChatId.value = id\n navigate('chat')\n }\n\n const isCurrentConversation = (conversation: Conversation) => {\n return localChatId.value === conversation.id\n }\n\n const getLastMessage = (\n messages: UIChatMessage[],\n role: 'user' | 'assistant',\n ) => {\n return stripMarkdown(\n getTextPart(messages.filter((m) => m.role === role).slice(-1)[0]) ||\n '',\n )\n }\n\n const startEdit = (conversation: Conversation) => {\n editingId.value = conversation.id\n editingTitle.value =\n stripMarkdown(conversation.title) ||\n getLastMessage(conversation.messages, 'assistant') ||\n ''\n nextTick(() => {\n if (renameInputEl.value?.[0]) {\n renameInputEl.value?.[0]?.focus()\n renameInputEl.value?.[0]?.select()\n }\n })\n }\n\n const confirmEdit = async (id: string) => {\n const trimmed = editingTitle.value.trim()\n editingId.value = null\n if (trimmed && trimmed.length <= 255) {\n try {\n await renameChatTitle(id, trimmed)\n } catch {\n // Revert optimistically: reload will pick up server state\n }\n }\n }\n\n const cancelEdit = () => {\n editingId.value = null\n }\n\n const { openDialogConfirm } = useDialogConfirm()\n const handleDelete = async (id: string) => {\n try {\n const proceed = await openDialogConfirm()\n if (!proceed) {\n return\n }\n await deleteChat(id)\n } catch {\n // Silently fail: next load will reconcile\n }\n }\n</script>\n\n<template>\n <div\n class=\"flex flex-col flex-1 min-h-0 overflow-y-auto p-md gap-sm relative\">\n <div\n v-if=\"conversations.length === 0\"\n class=\"flex justify-center p-lg text-word-3 text-sm\">\n {{ $t('message.noConversations') }}\n </div>\n <ul\n v-else\n class=\"flex flex-col min-h-0 gap-8 overflow-auto px-8 pb-8 light-scrollbar pb-64\">\n <li v-for=\"conversation in conversations\" :key=\"conversation.id\">\n <button\n type=\"button\"\n class=\"rounded-md border p-10 cursor-pointer block w-full transition-colors text-14 leading-relaxed border-b border-surface-3 hover:border-surface-5 hover:bg-surface-1 focus-within:border-word\"\n :class=\"{\n 'bg-surface-2 border-surface-5':\n isCurrentConversation(conversation),\n }\"\n @click=\"openConversation(conversation.id)\">\n <div class=\"flex items-center gap-8\">\n <template v-if=\"editingId === conversation.id\">\n <input\n ref=\"renameInputEl\"\n v-model=\"editingTitle\"\n class=\"flex-1 placeholder:text-word-4 leading-none\"\n :placeholder=\"$t('placeholder.insert')\"\n :maxlength=\"255\"\n @click.stop\n @keydown.enter.prevent=\"\n confirmEdit(conversation.id)\n \"\n @keydown.esc.prevent=\"cancelEdit()\" />\n <VvButton\n icon=\"ri:save-line\"\n :label=\"$t('action.save')\"\n modifiers=\"action-small\"\n @click.stop=\"confirmEdit(conversation.id)\" />\n </template>\n <template v-else>\n <strong class=\"font-bold truncate block flex-1\">\n {{\n stripMarkdown(conversation.title) ||\n getLastMessage(\n conversation.messages,\n 'assistant',\n )\n }}\n </strong>\n <PkRelativeTime\n class=\"text-word-4 text-smaller shrink-0\"\n :date=\"conversation.lastMessageAt\" />\n <div @click.stop>\n <VvDropdown\n v-bind=\"{\n placement: 'bottom-end',\n modifiers: 'menu',\n flip: true,\n offset: 3,\n }\">\n <VvButton\n icon=\"ri:more-2-fill\"\n :title=\"$t('action.moreActions')\"\n modifiers=\"action-quiet-small\" />\n <template #items>\n <VvDropdownAction\n @click=\"startEdit(conversation)\">\n <VvIcon name=\"ri:pencil-line\" />\n {{ $t('action.renameChat') }}\n </VvDropdownAction>\n <VvDropdownAction\n @click=\"\n handleDelete(conversation.id)\n \">\n <VvIcon name=\"ri:delete-bin-line\" />\n {{ $t('action.delete') }}\n </VvDropdownAction>\n </template>\n </VvDropdown>\n </div>\n </template>\n </div>\n <span\n v-if=\"editingId !== conversation.id\"\n class=\"text-12 text-word-4 line-clamp-2\">\n {{\n stripMarkdown(conversation.summary) ||\n getLastMessage(conversation.messages, 'user')\n }}\n </span>\n </button>\n </li>\n </ul>\n <div\n class=\"absolute bottom-0 left-0 right-0 flex justify-center px-16 pb-16 pt-32 bg-gradient-to-t\">\n <VvButton\n class=\"text-14\"\n modifiers=\"rounded\"\n :label=\"$t('action.startNewChat')\"\n @click.stop=\"startNewChat()\" />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { ref, nextTick } from 'vue'\n import { storeToRefs } from 'pinia'\n import { useI18n } from 'vue-i18n'\n import type { Chat as Conversation, UIChatMessage } from 'models'\n import { stripMarkdown, getTextPart } from 'utils'\n import { useChatbotStore, useDialogConfirm } from 'composables'\n import PkRelativeTime from '../PkRelativeTime.vue'\n\n const props = defineProps<{ agentId: string }>()\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const store = useChatbotStore(props.agentId)\n const { conversations, localChatId } = storeToRefs(store)\n const { navigate, startNewChat, renameChatTitle, deleteChat } = store\n\n const editingId = ref<string | null>(null)\n const editingTitle = ref('')\n const renameInputEl = ref<HTMLInputElement[]>()\n\n const openConversation = (id: string) => {\n if (editingId.value) {\n return\n }\n localChatId.value = id\n navigate('chat')\n }\n\n const isCurrentConversation = (conversation: Conversation) => {\n return localChatId.value === conversation.id\n }\n\n const getLastMessage = (\n messages: UIChatMessage[],\n role: 'user' | 'assistant',\n ) => {\n return stripMarkdown(\n getTextPart(messages.filter((m) => m.role === role).slice(-1)[0]) ||\n '',\n )\n }\n\n const startEdit = (conversation: Conversation) => {\n editingId.value = conversation.id\n editingTitle.value =\n stripMarkdown(conversation.title) ||\n getLastMessage(conversation.messages, 'assistant') ||\n ''\n nextTick(() => {\n if (renameInputEl.value?.[0]) {\n renameInputEl.value?.[0]?.focus()\n renameInputEl.value?.[0]?.select()\n }\n })\n }\n\n const confirmEdit = async (id: string) => {\n const trimmed = editingTitle.value.trim()\n editingId.value = null\n if (trimmed && trimmed.length <= 255) {\n try {\n await renameChatTitle(id, trimmed)\n } catch {\n // Revert optimistically: reload will pick up server state\n }\n }\n }\n\n const cancelEdit = () => {\n editingId.value = null\n }\n\n const { openDialogConfirm } = useDialogConfirm()\n const handleDelete = async (id: string) => {\n try {\n const proceed = await openDialogConfirm()\n if (!proceed) {\n return\n }\n await deleteChat(id)\n } catch {\n // Silently fail: next load will reconcile\n }\n }\n</script>\n\n<template>\n <div\n class=\"flex flex-col flex-1 min-h-0 overflow-y-auto p-md gap-sm relative\">\n <div\n v-if=\"conversations.length === 0\"\n class=\"flex justify-center p-lg text-word-3 text-sm\">\n {{ $t('message.noConversations') }}\n </div>\n <ul\n v-else\n class=\"flex flex-col min-h-0 gap-8 overflow-auto px-8 pb-8 light-scrollbar pb-64\">\n <li v-for=\"conversation in conversations\" :key=\"conversation.id\">\n <button\n type=\"button\"\n class=\"rounded-md border p-10 cursor-pointer block w-full transition-colors text-14 leading-relaxed border-b border-surface-3 hover:border-surface-5 hover:bg-surface-1 focus-within:border-word\"\n :class=\"{\n 'bg-surface-2 border-surface-5':\n isCurrentConversation(conversation),\n }\"\n @click=\"openConversation(conversation.id)\">\n <div class=\"flex items-center gap-8\">\n <template v-if=\"editingId === conversation.id\">\n <input\n ref=\"renameInputEl\"\n v-model=\"editingTitle\"\n class=\"flex-1 placeholder:text-word-4 leading-none\"\n :placeholder=\"$t('placeholder.insert')\"\n :maxlength=\"255\"\n @click.stop\n @keydown.enter.prevent=\"\n confirmEdit(conversation.id)\n \"\n @keydown.esc.prevent=\"cancelEdit()\" />\n <VvButton\n icon=\"ri:save-line\"\n :label=\"$t('action.save')\"\n modifiers=\"action-small\"\n @click.stop=\"confirmEdit(conversation.id)\" />\n </template>\n <template v-else>\n <strong class=\"font-bold truncate block flex-1\">\n {{\n stripMarkdown(conversation.title) ||\n getLastMessage(\n conversation.messages,\n 'assistant',\n )\n }}\n </strong>\n <PkRelativeTime\n class=\"text-word-4 text-smaller shrink-0\"\n :date=\"conversation.lastMessageAt\" />\n <div @click.stop>\n <VvDropdown\n v-bind=\"{\n placement: 'bottom-end',\n modifiers: 'menu',\n flip: true,\n offset: 3,\n }\">\n <VvButton\n icon=\"ri:more-2-fill\"\n :title=\"$t('action.moreActions')\"\n modifiers=\"action-quiet-small\" />\n <template #items>\n <VvDropdownAction\n @click=\"startEdit(conversation)\">\n <VvIcon name=\"ri:pencil-line\" />\n {{ $t('action.renameChat') }}\n </VvDropdownAction>\n <VvDropdownAction\n @click=\"\n handleDelete(conversation.id)\n \">\n <VvIcon name=\"ri:delete-bin-line\" />\n {{ $t('action.delete') }}\n </VvDropdownAction>\n </template>\n </VvDropdown>\n </div>\n </template>\n </div>\n <span\n v-if=\"editingId !== conversation.id\"\n class=\"text-12 text-word-4 line-clamp-2\">\n {{\n stripMarkdown(conversation.summary) ||\n getLastMessage(conversation.messages, 'user')\n }}\n </span>\n </button>\n </li>\n </ul>\n <div\n class=\"absolute bottom-0 left-0 right-0 flex justify-center px-16 pb-16 pt-32 bg-gradient-to-t\">\n <VvButton\n class=\"text-14\"\n modifiers=\"rounded\"\n :label=\"$t('action.startNewChat')\"\n @click.stop=\"startNewChat()\" />\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;AAiBA,IAAM,IAAS,EAAI,GAAM,EACnB,IAAQ,GAA2B,EACnC,IAAa,GAAgC,EAC7C,IAAO,GAA0B,EACjC,IAAW,EAA6B,GAAM,EAC9C,IAAO,GAA0B,EACjC,IAAQ,GAAkB,EAEnB,UAAkB;CAC3B,IAAM,KAAsB,MAAmB;AAC3C,IAAO,QAAQ;IAGb,UAAqB;AAMvB,EALA,EAAM,QAAQ,KAAA,GACd,EAAW,QAAQ,KAAA,GACnB,EAAK,QAAQ,KAAA,GACb,EAAS,QAAQ,KAAA,GACjB,EAAK,QAAQ,KAAA,GACb,EAAM,QAAQ,KAAA;;AAmClB,QAAO;EAAE,gBAhCc,EAAgB;GACnC,MAAM;GACN,cACI,EACI,GACA;IACI,YAAY,EAAO;IACnB,OAAO,EAAM;IACb,YAAY,EAAW;IACvB,MAAM,EAAK;IACX,UAAU,EAAS;IACnB,MAAM,EAAK;IACX,uBAAuB;IACT;IACjB,EACD,EAAM,MACT;GACR,CAeQ;EAAgB,aAbL,GAAuB,OACvC,EAAM,QAAQ,GAAU,OACxB,EAAW,QAAQ,GAAU,YAC7B,EAAK,QAAQ,GAAU,MACvB,EAAS,QAAQ,GAAU,YAAY,IACvC,EAAK,QAAQ,GAAU,MACvB,EAAM,QAAQ,GACd,QAAe;AACX,KAAO,QAAQ;IACjB,EACK;EAG0B;EAAQ;GC9DpC,UAAyB;CAClC,IAAM,EAAE,kBAAe,GAAW,EAC5B,EAAK,MAAO,EAAQ,EACtB,UAAU,UACb,CAAC;AAgGF,QAAO,EAAE,oBA9FkB,EACvB,gBAAa,IACb,iBACA,gBACA,kBACA,iBAAc,IACd,eACA,oBACA,sBAUA,EAAE,KACK,IAAI,SAAkB,GAAS,MAAW;EAC7C,IAAM,IAAiB,GAAa,EAC9B,IAAS,EACX;GACI,MAAM;GACN,MAAM;GACN,UAAU;GACb,EACD;GACI,eACI,EAAE,OAAO,CACL,EACI,OACA,EAAE,OAAO,SAAS,EAClB,KAAiB,EAAG,kBAAkB,CACzC,EACD,IACM,EAAE,GAAa;IACX,YAAY,EAAe;IAC3B,wBACI,MACC;AACD,OAAe,QAAQ;;IAE3B,MAAM;IACN,MAAM;IACN,OAAO;IACP,UAAU;IACV,OACI,KACA,EAAG,mBAAmB;IAC1B,WACI,KACA,EAAG,mBAAmB,EAAE,eAAY,CAAC;IAC5C,CAAC,GACF,KAAA,EACT,CAAC;GACN,cACI,EAAE,SAAqB;IACnB,IAAM,IAAoB,EAAE;AA6B5B,WA5BK,KACD,EAAS,KACL,EAAE,GAAU;KACR,OACI,KAAe,EAAG,gBAAgB;KACtC,WAAW;KACX,eAAe;AAKX,MAJI,KACA,GAAQ,EAEZ,EAAQ,GAAM,EACd,EAAO,QAAQ;;KAEtB,CAAC,CACL,EAEL,EAAS,KACL,EAAE,GAAU;KACR,OAAO,KAAgB,EAAG,iBAAiB;KAC3C,UAAU,IACJ,MAAe,EAAe,QAC9B;KACN,eAAe;AAEX,MADA,EAAQ,GAAK,EACb,EAAO,QAAQ;;KAEtB,CAAC,CACL,EACM;KACT;GACT,CACJ;GACH,EAGsB;;;;;;;;;;;;;;ECpG5B,IAAM,IAAQ,GAER,EAAE,GAAG,MAAO,EAAQ,EAAE,UAAU,UAAU,CAAA,EAE1C,IAAQ,EAAgB,EAAM,QAAO,EACrC,EAAE,kBAAe,mBAAgB,EAAY,EAAK,EAClD,EAAE,aAAU,iBAAc,oBAAiB,kBAAe,GAE1D,IAAY,EAAmB,KAAI,EACnC,IAAe,EAAI,GAAE,EACrB,IAAgB,GAAwB,EAExC,KAAoB,MAAe;AACjC,KAAU,UAGd,EAAY,QAAQ,GACpB,EAAS,OAAM;KAGb,KAAyB,MACpB,EAAY,UAAU,EAAa,IAGxC,KACF,GACA,MAEO,EACH,EAAY,EAAS,QAAQ,MAAM,EAAE,SAAS,EAAK,CAAC,MAAM,GAAG,CAAC,GAAG,IAC7D,GACR,EAGE,MAAa,MAA+B;AAM9C,GALA,EAAU,QAAQ,EAAa,IAC/B,EAAa,QACT,EAAc,EAAa,MAAM,IACjC,EAAe,EAAa,UAAU,YAAY,IAClD,IACJ,QAAe;AACX,IAAI,EAAc,QAAQ,OACtB,EAAc,QAAQ,IAAI,OAAM,EAChC,EAAc,QAAQ,IAAI,QAAO;KAExC;KAGC,IAAc,OAAO,MAAe;GACtC,IAAM,IAAU,EAAa,MAAM,MAAK;AAExC,OADA,EAAU,QAAQ,MACd,KAAW,EAAQ,UAAU,IAC7B,KAAI;AACA,UAAM,EAAgB,GAAI,EAAO;WAC7B;KAMV,WAAmB;AACrB,KAAU,QAAQ;KAGhB,EAAE,0BAAsB,GAAiB,EACzC,KAAe,OAAO,MAAe;AACvC,OAAI;AAEA,QAAI,CAAC,MADiB,IAAkB,CAEpC;AAEJ,UAAM,EAAW,EAAE;WACf;;;;eAOZ,EAoGM,OApGN,GAoGM,CAjGQ,EAAA,EAAa,CAAC,WAAM,KAAA,GAAA,EAD9B,EAIM,OAJN,GAIM,EADC,EAAA,EAAE,CAAA,0BAAA,CAAA,EAAA,EAAA,KAAA,GAAA,EAET,EAoFK,MApFL,GAoFK,EAAA,EAAA,GAAA,EAjFD,EAgFK,GAAA,MAAA,EAhFsB,EAAA,EAAa,GAA7B,YAAX,EAgFK,MAAA,EAhFsC,KAAK,EAAa,IAAA,EAAA,CACzD,EA8ES,UAAA;IA7EL,MAAK;IACL,OAAK,EAAA,CAAC,6LAA2L,EAAA,iCAClG,EAAsB,EAAY,EAAA,CAAA,CAAA;IAIhI,UAAK,MAAE,EAAiB,EAAa,GAAA;OACtC,EA6DM,OA7DN,GA6DM,CA5Dc,EAAA,UAAc,EAAa,MAAA,GAAA,EAA3C,EAiBW,GAAA,EAAA,KAAA,GAAA,EAAA,CAAA,GAhBP,EAU0C,SAAA;;aATlC;IAAJ,KAAI;6CACiB,QAAA;IACrB,OAAM;IACL,aAAa,EAAA,EAAE,CAAA,qBAAA;IACf,WAAW;IACX,SAAK,AAAA,EAAA,OAAA,QAAN,IAAW,CAAA,OAAA,CAAA;IACV,WAAO,CAAA,EAAA,GAAA,MAAqD,EAAY,EAAa,GAAE,EAAA,CAAA,UAAA,CAAA,EAAA,CAAA,QAAA,CAAA,EAAA,AAAA,EAAA,OAAA,EAAA,GAAA,MAGlE,IAAU,EAAA,CAAA,UAAA,CAAA,EAAA,CAAA,MAAA,CAAA,CAAA;0BARvB,EAAA,MAAY,CAAA,CAAA,EASzB,EAIiD,GAAA;IAH7C,MAAK;IACJ,OAAO,EAAA,EAAE,CAAA,cAAA;IACV,WAAU;IACT,SAAK,GAAA,MAAO,EAAY,EAAa,GAAE,EAAA,CAAA,OAAA,CAAA;oDAEhD,EAyCW,GAAA,EAAA,KAAA,GAAA,EAAA;IAxCP,EAQS,UART,GAQS,EAND,EAAA,EAAa,CAAC,EAAa,MAAK,IAAyC,EAAwD,EAAa,UAAA,YAAA,CAAA,EAAA,EAAA;IAOtJ,EAEyC,GAAA;KADrC,OAAM;KACL,MAAM,EAAa;;IACxB,EA2BM,OAAA,EA3BA,SAAK,AAAA,EAAA,OAAA,QAAN,IAAW,CAAA,OAAA,CAAA,EAAA,EAAA,CACZ,EAyBa,GAzBb,EAyBa,EAAA,SAAA,IAAA,EAxBD;;;;;KAKP,CAAA,EAAA;KAKU,OAAK,QAKO,CAJnB,EAImB,GAAA,EAHd,UAAK,MAAE,GAAU,EAAY,EAAA,EAAA;uBACE,CAAhC,EAAgC,GAAA,EAAxB,MAAK,kBAAgB,CAAA,EAAA,EAAG,MAChC,EAAG,EAAA,EAAE,CAAA,oBAAA,CAAA,EAAA,EAAA,CAAA,CAAA;;yBAET,EAMmB,GAAA,EALd,UAAK,MAAmD,GAAa,EAAa,GAAE,EAAA,EAAA;uBAGjD,CAApC,EAAoC,GAAA,EAA5B,MAAK,sBAAoB,CAAA,EAAA,EAAG,MACpC,EAAG,EAAA,EAAE,CAAA,gBAAA,CAAA,EAAA,EAAA,CAAA,CAAA;;;sBAZwB,CAHrC,EAGqC,GAAA;MAFjC,MAAK;MACJ,OAAO,EAAA,EAAE,CAAA,qBAAA;MACV,WAAU;;;;cAoBpB,EAAA,UAAc,EAAa,KAG0E,EAAA,IAAA,GAAA,IAH1E,GAAA,EADrC,EAOO,QAPP,GAOO,EAHC,EAAA,EAAa,CAAC,EAAa,QAAO,IAAiC,EAAe,EAAa,UAAQ,OAAA,CAAA,EAAA,EAAA,EAAA,EAAA,IAAA,EAAA,CAAA,CAAA,cAO3H,EAOM,OAPN,GAOM,CALF,EAImC,GAAA;IAH/B,OAAM;IACN,WAAU;IACT,OAAO,EAAA,EAAE,CAAA,sBAAA;IACT,SAAK,AAAA,EAAA,OAAA,GAAA,MAAO,EAAA,EAAY,EAAA,EAAA,CAAA,OAAA,CAAA"}
1
+ {"version":3,"file":"PkChatbotViewConversations-2xc0o-fO.js","names":[],"sources":["../../../../packages/composable/src/useDialog.ts","../../../../packages/composable/src/useDialogConfirm.ts","../../../../packages/components/src/chat/PkChatbotViewConversations.vue","../../../../packages/components/src/chat/PkChatbotViewConversations.vue"],"sourcesContent":["import { VvDialog } from '@volverjs/ui-vue/components'\nimport { defineComponent, h, nextTick, ref, type VNode } from 'vue'\n\ntype DialogProps = {\n title?: string\n transition?: string\n size?: 'small' | 'standard' | 'fullscreen'\n role?: 'alert' | 'alertdialog'\n keepOpen?: boolean\n}\n\ntype DialogSlots = {\n footer?: () => VNode | string\n header?: () => VNode | string\n default?: () => VNode | string | VNode[] | string[]\n}\n\nconst isOpen = ref(false)\nconst title = ref<DialogProps['title']>()\nconst transition = ref<DialogProps['transition']>()\nconst size = ref<DialogProps['size']>()\nconst keepOpen = ref<DialogProps['keepOpen']>(false)\nconst role = ref<DialogProps['role']>()\nconst slots = ref<DialogSlots>()\n\nexport const useDialog = () => {\n const onUpdateModelValue = (value: boolean) => {\n isOpen.value = value\n }\n\n const onAfterLeave = () => {\n title.value = undefined\n transition.value = undefined\n size.value = undefined\n keepOpen.value = undefined\n role.value = undefined\n slots.value = undefined\n }\n\n const PkGlobalDialog = defineComponent({\n name: 'PkGlobalDialog',\n render: () =>\n h(\n VvDialog,\n {\n modelValue: isOpen.value,\n title: title.value,\n transition: transition.value,\n size: size.value,\n keepOpen: keepOpen.value,\n role: role.value,\n 'onUpdate:modelValue': onUpdateModelValue,\n onAfterLeave: onAfterLeave,\n },\n slots.value,\n ),\n })\n\n const openDialog = (newProps: DialogProps, newSlots?: DialogSlots) => {\n title.value = newProps?.title\n transition.value = newProps?.transition\n size.value = newProps?.size\n keepOpen.value = newProps?.keepOpen ?? false\n role.value = newProps?.role\n slots.value = newSlots\n nextTick(() => {\n isOpen.value = true\n })\n return isOpen\n }\n\n return { PkGlobalDialog, openDialog, isOpen }\n}\n","import { h, ref, VNode } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport {\n VvButton,\n VvButtonGroup,\n VvInputText,\n} from '@volverjs/ui-vue/components'\nimport { useDialog } from './useDialog'\n\nexport const useDialogConfirm = () => {\n const { openDialog } = useDialog()\n const { t: $t } = useI18n({\n useScope: 'global',\n })\n\n const openDialogConfirm = ({\n emitReject = false,\n confirmLabel,\n cancelLabel,\n questionLabel,\n onlyConfirm = false,\n passphrase,\n passphraseLabel,\n passphraseHint,\n }: {\n emitReject?: boolean\n confirmLabel?: string\n cancelLabel?: string\n questionLabel?: string\n onlyConfirm?: boolean\n passphrase?: string\n passphraseLabel?: string\n passphraseHint?: string\n } = {}) => {\n return new Promise<boolean>((resolve, reject) => {\n const passphraseText = ref<string>()\n const isOpen = openDialog(\n {\n role: 'alertdialog',\n size: 'small',\n keepOpen: true,\n },\n {\n default: () =>\n h('div', [\n h(\n 'div',\n { class: 'mb-sm' },\n questionLabel ?? $t('message.confirm'),\n ),\n passphrase\n ? h(VvInputText, {\n modelValue: passphraseText.value,\n 'onUpdate:modelValue': (\n value: string,\n ) => {\n passphraseText.value = value\n },\n type: 'text',\n name: 'passphrase',\n class: 'mb-0',\n floating: true,\n label:\n passphraseLabel ??\n $t('label.passphrase'),\n hintLabel:\n passphraseHint ??\n $t('hint.passphrase', { passphrase }),\n })\n : undefined,\n ]),\n footer: () =>\n h(VvButtonGroup, () => {\n const toReturn: VNode[] = []\n if (!onlyConfirm) {\n toReturn.push(\n h(VvButton, {\n label:\n cancelLabel ?? $t('action.cancel'),\n modifiers: 'ghost',\n onClick: () => {\n if (emitReject) {\n reject()\n }\n resolve(false)\n isOpen.value = false\n },\n }),\n )\n }\n toReturn.push(\n h(VvButton, {\n label: confirmLabel ?? $t('action.proceed'),\n disabled: passphrase\n ? passphrase !== passphraseText.value\n : false,\n onClick: () => {\n resolve(true)\n isOpen.value = false\n },\n }),\n )\n return toReturn\n }),\n },\n )\n })\n }\n\n return { openDialogConfirm }\n}\n","<script setup lang=\"ts\">\n import { ref, nextTick } from 'vue'\n import { storeToRefs } from 'pinia'\n import { useI18n } from 'vue-i18n'\n import type { Chat as Conversation, UIChatMessage } from 'models'\n import { stripMarkdown, getTextPart } from 'utils'\n import { useChatbotStore, useDialogConfirm } from 'composables'\n import PkRelativeTime from '../PkRelativeTime.vue'\n\n const props = defineProps<{ agentId: string }>()\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const store = useChatbotStore(props.agentId)\n const { conversations, localChatId } = storeToRefs(store)\n const { navigate, startNewChat, renameChatTitle, deleteChat } = store\n\n const editingId = ref<string | null>(null)\n const editingTitle = ref('')\n const renameInputEl = ref<HTMLInputElement[]>()\n\n const openConversation = (id: string) => {\n if (editingId.value) {\n return\n }\n localChatId.value = id\n navigate('chat')\n }\n\n const isCurrentConversation = (conversation: Conversation) => {\n return localChatId.value === conversation.id\n }\n\n const getLastMessage = (\n messages: UIChatMessage[],\n role: 'user' | 'assistant',\n ) => {\n return stripMarkdown(\n getTextPart(messages.filter((m) => m.role === role).slice(-1)[0]) ||\n '',\n )\n }\n\n const startEdit = (conversation: Conversation) => {\n editingId.value = conversation.id\n editingTitle.value =\n stripMarkdown(conversation.title) ||\n getLastMessage(conversation.messages, 'assistant') ||\n ''\n nextTick(() => {\n if (renameInputEl.value?.[0]) {\n renameInputEl.value?.[0]?.focus()\n renameInputEl.value?.[0]?.select()\n }\n })\n }\n\n const confirmEdit = async (id: string) => {\n const trimmed = editingTitle.value.trim()\n editingId.value = null\n if (trimmed && trimmed.length <= 255) {\n try {\n await renameChatTitle(id, trimmed)\n } catch {\n // Revert optimistically: reload will pick up server state\n }\n }\n }\n\n const cancelEdit = () => {\n editingId.value = null\n }\n\n const { openDialogConfirm } = useDialogConfirm()\n const handleDelete = async (id: string) => {\n try {\n const proceed = await openDialogConfirm()\n if (!proceed) {\n return\n }\n await deleteChat(id)\n } catch {\n // Silently fail: next load will reconcile\n }\n }\n</script>\n\n<template>\n <div\n class=\"flex flex-col flex-1 min-h-0 overflow-y-auto p-md gap-sm relative\">\n <div\n v-if=\"conversations.length === 0\"\n class=\"flex justify-center p-lg text-word-3 text-sm\">\n {{ $t('message.noConversations') }}\n </div>\n <ul\n v-else\n class=\"flex flex-col min-h-0 gap-8 overflow-auto px-8 pb-8 light-scrollbar pb-64\">\n <li v-for=\"conversation in conversations\" :key=\"conversation.id\">\n <button\n type=\"button\"\n class=\"rounded-md border p-10 cursor-pointer block w-full transition-colors text-14 leading-relaxed border-b border-surface-3 hover:border-surface-5 hover:bg-surface-1 focus-within:border-word\"\n :class=\"{\n 'bg-surface-2 border-surface-5':\n isCurrentConversation(conversation),\n }\"\n @click=\"openConversation(conversation.id)\">\n <div class=\"flex items-center gap-8\">\n <template v-if=\"editingId === conversation.id\">\n <input\n ref=\"renameInputEl\"\n v-model=\"editingTitle\"\n class=\"flex-1 placeholder:text-word-4 leading-none\"\n :placeholder=\"$t('placeholder.insert')\"\n :maxlength=\"255\"\n @click.stop\n @keydown.enter.prevent=\"\n confirmEdit(conversation.id)\n \"\n @keydown.esc.prevent=\"cancelEdit()\" />\n <VvButton\n icon=\"ri:save-line\"\n :label=\"$t('action.save')\"\n modifiers=\"action-small\"\n @click.stop=\"confirmEdit(conversation.id)\" />\n </template>\n <template v-else>\n <strong class=\"font-bold truncate block flex-1\">\n {{\n stripMarkdown(conversation.title) ||\n getLastMessage(\n conversation.messages,\n 'assistant',\n )\n }}\n </strong>\n <PkRelativeTime\n class=\"text-word-4 text-smaller shrink-0\"\n :date=\"conversation.lastMessageAt\" />\n <div @click.stop>\n <VvDropdown\n v-bind=\"{\n placement: 'bottom-end',\n modifiers: 'menu',\n flip: true,\n offset: 3,\n }\">\n <VvButton\n icon=\"ri:more-2-fill\"\n :title=\"$t('action.moreActions')\"\n modifiers=\"action-quiet-small\" />\n <template #items>\n <VvDropdownAction\n @click=\"startEdit(conversation)\">\n <VvIcon name=\"ri:pencil-line\" />\n {{ $t('action.renameChat') }}\n </VvDropdownAction>\n <VvDropdownAction\n @click=\"\n handleDelete(conversation.id)\n \">\n <VvIcon name=\"ri:delete-bin-line\" />\n {{ $t('action.delete') }}\n </VvDropdownAction>\n </template>\n </VvDropdown>\n </div>\n </template>\n </div>\n <span\n v-if=\"editingId !== conversation.id\"\n class=\"text-12 text-word-4 line-clamp-2\">\n {{\n stripMarkdown(conversation.summary) ||\n getLastMessage(conversation.messages, 'user')\n }}\n </span>\n </button>\n </li>\n </ul>\n <div\n class=\"absolute bottom-0 left-0 right-0 flex justify-center px-16 pb-16 pt-32 bg-gradient-to-t\">\n <VvButton\n class=\"text-14\"\n modifiers=\"rounded\"\n :label=\"$t('action.startNewChat')\"\n @click.stop=\"startNewChat()\" />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { ref, nextTick } from 'vue'\n import { storeToRefs } from 'pinia'\n import { useI18n } from 'vue-i18n'\n import type { Chat as Conversation, UIChatMessage } from 'models'\n import { stripMarkdown, getTextPart } from 'utils'\n import { useChatbotStore, useDialogConfirm } from 'composables'\n import PkRelativeTime from '../PkRelativeTime.vue'\n\n const props = defineProps<{ agentId: string }>()\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const store = useChatbotStore(props.agentId)\n const { conversations, localChatId } = storeToRefs(store)\n const { navigate, startNewChat, renameChatTitle, deleteChat } = store\n\n const editingId = ref<string | null>(null)\n const editingTitle = ref('')\n const renameInputEl = ref<HTMLInputElement[]>()\n\n const openConversation = (id: string) => {\n if (editingId.value) {\n return\n }\n localChatId.value = id\n navigate('chat')\n }\n\n const isCurrentConversation = (conversation: Conversation) => {\n return localChatId.value === conversation.id\n }\n\n const getLastMessage = (\n messages: UIChatMessage[],\n role: 'user' | 'assistant',\n ) => {\n return stripMarkdown(\n getTextPart(messages.filter((m) => m.role === role).slice(-1)[0]) ||\n '',\n )\n }\n\n const startEdit = (conversation: Conversation) => {\n editingId.value = conversation.id\n editingTitle.value =\n stripMarkdown(conversation.title) ||\n getLastMessage(conversation.messages, 'assistant') ||\n ''\n nextTick(() => {\n if (renameInputEl.value?.[0]) {\n renameInputEl.value?.[0]?.focus()\n renameInputEl.value?.[0]?.select()\n }\n })\n }\n\n const confirmEdit = async (id: string) => {\n const trimmed = editingTitle.value.trim()\n editingId.value = null\n if (trimmed && trimmed.length <= 255) {\n try {\n await renameChatTitle(id, trimmed)\n } catch {\n // Revert optimistically: reload will pick up server state\n }\n }\n }\n\n const cancelEdit = () => {\n editingId.value = null\n }\n\n const { openDialogConfirm } = useDialogConfirm()\n const handleDelete = async (id: string) => {\n try {\n const proceed = await openDialogConfirm()\n if (!proceed) {\n return\n }\n await deleteChat(id)\n } catch {\n // Silently fail: next load will reconcile\n }\n }\n</script>\n\n<template>\n <div\n class=\"flex flex-col flex-1 min-h-0 overflow-y-auto p-md gap-sm relative\">\n <div\n v-if=\"conversations.length === 0\"\n class=\"flex justify-center p-lg text-word-3 text-sm\">\n {{ $t('message.noConversations') }}\n </div>\n <ul\n v-else\n class=\"flex flex-col min-h-0 gap-8 overflow-auto px-8 pb-8 light-scrollbar pb-64\">\n <li v-for=\"conversation in conversations\" :key=\"conversation.id\">\n <button\n type=\"button\"\n class=\"rounded-md border p-10 cursor-pointer block w-full transition-colors text-14 leading-relaxed border-b border-surface-3 hover:border-surface-5 hover:bg-surface-1 focus-within:border-word\"\n :class=\"{\n 'bg-surface-2 border-surface-5':\n isCurrentConversation(conversation),\n }\"\n @click=\"openConversation(conversation.id)\">\n <div class=\"flex items-center gap-8\">\n <template v-if=\"editingId === conversation.id\">\n <input\n ref=\"renameInputEl\"\n v-model=\"editingTitle\"\n class=\"flex-1 placeholder:text-word-4 leading-none\"\n :placeholder=\"$t('placeholder.insert')\"\n :maxlength=\"255\"\n @click.stop\n @keydown.enter.prevent=\"\n confirmEdit(conversation.id)\n \"\n @keydown.esc.prevent=\"cancelEdit()\" />\n <VvButton\n icon=\"ri:save-line\"\n :label=\"$t('action.save')\"\n modifiers=\"action-small\"\n @click.stop=\"confirmEdit(conversation.id)\" />\n </template>\n <template v-else>\n <strong class=\"font-bold truncate block flex-1\">\n {{\n stripMarkdown(conversation.title) ||\n getLastMessage(\n conversation.messages,\n 'assistant',\n )\n }}\n </strong>\n <PkRelativeTime\n class=\"text-word-4 text-smaller shrink-0\"\n :date=\"conversation.lastMessageAt\" />\n <div @click.stop>\n <VvDropdown\n v-bind=\"{\n placement: 'bottom-end',\n modifiers: 'menu',\n flip: true,\n offset: 3,\n }\">\n <VvButton\n icon=\"ri:more-2-fill\"\n :title=\"$t('action.moreActions')\"\n modifiers=\"action-quiet-small\" />\n <template #items>\n <VvDropdownAction\n @click=\"startEdit(conversation)\">\n <VvIcon name=\"ri:pencil-line\" />\n {{ $t('action.renameChat') }}\n </VvDropdownAction>\n <VvDropdownAction\n @click=\"\n handleDelete(conversation.id)\n \">\n <VvIcon name=\"ri:delete-bin-line\" />\n {{ $t('action.delete') }}\n </VvDropdownAction>\n </template>\n </VvDropdown>\n </div>\n </template>\n </div>\n <span\n v-if=\"editingId !== conversation.id\"\n class=\"text-12 text-word-4 line-clamp-2\">\n {{\n stripMarkdown(conversation.summary) ||\n getLastMessage(conversation.messages, 'user')\n }}\n </span>\n </button>\n </li>\n </ul>\n <div\n class=\"absolute bottom-0 left-0 right-0 flex justify-center px-16 pb-16 pt-32 bg-gradient-to-t\">\n <VvButton\n class=\"text-14\"\n modifiers=\"rounded\"\n :label=\"$t('action.startNewChat')\"\n @click.stop=\"startNewChat()\" />\n </div>\n </div>\n</template>\n"],"mappings":"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"}