@8wave/ai-elements 0.110.0-beta.4 → 0.111.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/_chunks/{Agent-Su_LDF9_.js → Agent-tE7ZJPxG.js} +80 -78
- package/dist/_chunks/Agent-tE7ZJPxG.js.map +1 -0
- package/dist/_chunks/{Document-DecVclEe.js → Document-Bmx6774B.js} +33 -21
- package/dist/_chunks/Document-Bmx6774B.js.map +1 -0
- package/dist/_chunks/Media-Cft7Pwrh.js +108 -0
- package/dist/_chunks/Media-Cft7Pwrh.js.map +1 -0
- package/dist/_chunks/{PkLazyImg-ClL4nr95.js → PkLazyImg-Dbj2dDXA.js} +2 -2
- package/dist/_chunks/{PkLazyImg-ClL4nr95.js.map → PkLazyImg-Dbj2dDXA.js.map} +1 -1
- package/dist/_chunks/{PkStreamingMarkdown-CwqsJnJJ.js → PkStreamingMarkdown-CNI8aV8t.js} +636 -427
- package/dist/_chunks/PkStreamingMarkdown-CNI8aV8t.js.map +1 -0
- package/dist/_chunks/{PkToolRequestGeolocation-CEVpl50q.js → PkToolRequestGeolocation-Bzy4IYSp.js} +4 -4
- package/dist/_chunks/PkToolRequestGeolocation-Bzy4IYSp.js.map +1 -0
- package/dist/_chunks/{PkToolRequestOAuthConnection-CncDU-Kl.js → PkToolRequestOAuthConnection-13CQH07t.js} +5 -5
- package/dist/_chunks/PkToolRequestOAuthConnection-13CQH07t.js.map +1 -0
- package/dist/_chunks/{PkToolShowArtifact-M6jlSmyJ.js → PkToolShowArtifact-CGbHDEie.js} +4 -4
- package/dist/_chunks/{PkToolShowArtifact-M6jlSmyJ.js.map → PkToolShowArtifact-CGbHDEie.js.map} +1 -1
- package/dist/_chunks/{PkToolShowCalendarEvent-C41JgOUA.js → PkToolShowCalendarEvent-DIFX_rUz.js} +3 -3
- package/dist/_chunks/{PkToolShowCalendarEvent-C41JgOUA.js.map → PkToolShowCalendarEvent-DIFX_rUz.js.map} +1 -1
- package/dist/_chunks/{PkToolShowComparison-DbbUD9pg.js → PkToolShowComparison-CWLFWT9h.js} +7 -7
- package/dist/_chunks/PkToolShowComparison-CWLFWT9h.js.map +1 -0
- package/dist/_chunks/{PkToolShowContactForm-D_dW59Dl.js → PkToolShowContactForm-CYxgatUA.js} +5 -5
- package/dist/_chunks/PkToolShowContactForm-CYxgatUA.js.map +1 -0
- package/dist/_chunks/{PkToolShowDiagram-Hy9qh68O.js → PkToolShowDiagram-Dx1Ba0PG.js} +4 -4
- package/dist/_chunks/PkToolShowDiagram-Dx1Ba0PG.js.map +1 -0
- package/dist/_chunks/{PkToolShowEmail-Dn3JHYIR.js → PkToolShowEmail-DnFFgzom.js} +3 -3
- package/dist/_chunks/{PkToolShowEmail-Dn3JHYIR.js.map → PkToolShowEmail-DnFFgzom.js.map} +1 -1
- package/dist/_chunks/{PkToolShowForm-DbJHMDbt.js → PkToolShowForm-B6x3Lp2i.js} +7 -8
- package/dist/_chunks/PkToolShowForm-B6x3Lp2i.js.map +1 -0
- package/dist/_chunks/{PkToolShowImageGallery-C1lzlO0y.js → PkToolShowImageGallery-D99N_Plf.js} +2 -2
- package/dist/_chunks/{PkToolShowImageGallery-C1lzlO0y.js.map → PkToolShowImageGallery-D99N_Plf.js.map} +1 -1
- package/dist/_chunks/{PkToolShowLocation-CKhPxKFA.js → PkToolShowLocation-AfnrtFVJ.js} +3 -3
- package/dist/_chunks/{PkToolShowLocation-CKhPxKFA.js.map → PkToolShowLocation-AfnrtFVJ.js.map} +1 -1
- package/dist/_chunks/{PkToolShowMessage-U9CCU7eG.js → PkToolShowMessage-DUo2c-im.js} +3 -3
- package/dist/_chunks/{PkToolShowMessage-U9CCU7eG.js.map → PkToolShowMessage-DUo2c-im.js.map} +1 -1
- package/dist/_chunks/{PkToolShowProductList-UeiRMLHu.js → PkToolShowProductList-BN6Qk1_y.js} +3 -3
- package/dist/_chunks/{PkToolShowProductList-UeiRMLHu.js.map → PkToolShowProductList-BN6Qk1_y.js.map} +1 -1
- package/dist/_chunks/{PkToolShowQrCode-CypLrfh5.js → PkToolShowQrCode-BLqeBecX.js} +3 -3
- package/dist/_chunks/{PkToolShowQrCode-CypLrfh5.js.map → PkToolShowQrCode-BLqeBecX.js.map} +1 -1
- package/dist/_chunks/{PkToolShowSources-B69JmwbZ.js → PkToolShowSources-DpZb5FUP.js} +5 -5
- package/dist/_chunks/PkToolShowSources-DpZb5FUP.js.map +1 -0
- package/dist/_chunks/{PkToolShowSuggestedReply-CKxSH0Y9.js → PkToolShowSuggestedReply-C10nNgBs.js} +3 -3
- package/dist/_chunks/{PkToolShowSuggestedReply-CKxSH0Y9.js.map → PkToolShowSuggestedReply-C10nNgBs.js.map} +1 -1
- package/dist/_chunks/{PkToolShowVideo-BgKxdBcC.js → PkToolShowVideo-S9b4QHUj.js} +2 -2
- package/dist/_chunks/{PkToolShowVideo-BgKxdBcC.js.map → PkToolShowVideo-S9b4QHUj.js.map} +1 -1
- package/dist/_chunks/{PkToolShowWeather-LPd3tC77.js → PkToolShowWeather-CqhG430w.js} +2 -2
- package/dist/_chunks/PkToolShowWeather-CqhG430w.js.map +1 -0
- package/dist/_chunks/{PkToolShowWebPages-ep_erFF0.js → PkToolShowWebPages-txAZi_iG.js} +3 -3
- package/dist/_chunks/{PkToolShowWebPages-ep_erFF0.js.map → PkToolShowWebPages-txAZi_iG.js.map} +1 -1
- package/dist/_chunks/PkUrl-BPbjZJ1A.js.map +1 -1
- package/dist/_chunks/{VvCheckboxGroup.es-Bdu2gFLN.js → VvCheckboxGroup.es-CTrF3pue.js} +2 -2
- package/dist/_chunks/{VvCheckboxGroup.es-Bdu2gFLN.js.map → VvCheckboxGroup.es-CTrF3pue.js.map} +1 -1
- package/dist/_chunks/{VvCombobox.es-C0wpJIr_.js → VvCombobox.es-BWiXmQ_S.js} +10 -10
- package/dist/_chunks/{VvCombobox.es-C0wpJIr_.js.map → VvCombobox.es-BWiXmQ_S.js.map} +1 -1
- package/dist/_chunks/{VvInputText.es-Zgtw2YNw.js → VvInputText.es-Bo9I6g8H.js} +6 -6
- package/dist/_chunks/{VvInputText.es-Zgtw2YNw.js.map → VvInputText.es-Bo9I6g8H.js.map} +1 -1
- package/dist/_chunks/{VvRadioGroup.es-DZLL19SC.js → VvRadioGroup.es-9ooHCuik.js} +2 -2
- package/dist/_chunks/{VvRadioGroup.es-DZLL19SC.js.map → VvRadioGroup.es-9ooHCuik.js.map} +1 -1
- package/dist/_chunks/{VvSelect.es-ovnZRHG5.js → VvSelect.es-DG0VuWtP.js} +2 -2
- package/dist/_chunks/{VvSelect.es-ovnZRHG5.js.map → VvSelect.es-DG0VuWtP.js.map} +1 -1
- package/dist/_chunks/{VvTextarea.es-DbP5Lt2T.js → VvTextarea.es-Dg3pxdZy.js} +6 -6
- package/dist/_chunks/{VvTextarea.es-DbP5Lt2T.js.map → VvTextarea.es-Dg3pxdZy.js.map} +1 -1
- package/dist/_chunks/{browser-NgY6LXg-.js → browser-B0Xnbqi7.js} +726 -751
- package/dist/_chunks/browser-B0Xnbqi7.js.map +1 -0
- package/dist/_chunks/{dist-n5iFNYf-.js → dist-QdjZA6MJ.js} +143 -133
- package/dist/_chunks/{dist-n5iFNYf-.js.map → dist-QdjZA6MJ.js.map} +1 -1
- package/dist/_chunks/{index.es-dtdl3VFG.js → index.es-0YpCa4c5.js} +6 -6
- package/dist/_chunks/{index.es-dtdl3VFG.js.map → index.es-0YpCa4c5.js.map} +1 -1
- package/dist/_chunks/{index.es-BJnUA_36.js → index.es-CHkJ2TMJ.js} +10 -10
- package/dist/_chunks/{index.es-BJnUA_36.js.map → index.es-CHkJ2TMJ.js.map} +1 -1
- package/dist/_chunks/text-DbSEK8si.js.map +1 -1
- package/dist/ai-elements.es.js +3077 -3134
- package/dist/ai-elements.es.js.map +1 -1
- package/dist-vue/PkChatbot.js +1 -1
- package/dist-vue/PkChatbotEmptyState.js +1 -1
- package/dist-vue/PkChatbotError.js +1 -1
- package/dist-vue/PkChatbotFeedbackForm.js +1 -1
- package/dist-vue/PkChatbotFilePreview.js +1 -1
- package/dist-vue/PkChatbotInput.js +1 -1
- package/dist-vue/PkChatbotMessages.js +1 -1
- package/dist-vue/PkChatbotStepPayload.js +1 -1
- package/dist-vue/PkChatbotStepToolDetail.js +1 -1
- package/dist-vue/PkChatbotSteps.js +1 -1
- package/dist-vue/PkChatbotViewChat.js +1 -1
- package/dist-vue/PkChatbotViewConversations.js +1 -1
- package/dist-vue/PkChatbotViewFiles.js +1 -1
- package/dist-vue/PkChatbotViewProfile.js +1 -1
- package/dist-vue/_chunks/{Agent-C8BsTAxk.js → Agent-De2gFNjR.js} +165 -176
- package/dist-vue/_chunks/Agent-De2gFNjR.js.map +1 -0
- package/dist-vue/_chunks/{Document-CaUfI_SZ.js → Document-8umjeTVS.js} +84 -72
- package/dist-vue/_chunks/Document-8umjeTVS.js.map +1 -0
- package/dist-vue/_chunks/Media-_HfFLHGD.js.map +1 -1
- package/dist-vue/_chunks/{PkChatbot-o7k7d-fj.js → PkChatbot-CMajc7tE.js} +61 -61
- package/dist-vue/_chunks/PkChatbot-CMajc7tE.js.map +1 -0
- package/dist-vue/_chunks/{PkChatbotEmptyState-BvaeBxhx.js → PkChatbotEmptyState-BtzBYOHJ.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotEmptyState-BvaeBxhx.js.map → PkChatbotEmptyState-BtzBYOHJ.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotError-CBP2mf-n.js → PkChatbotError-gvDpRcEz.js} +21 -19
- package/dist-vue/_chunks/PkChatbotError-gvDpRcEz.js.map +1 -0
- package/dist-vue/_chunks/{PkChatbotFeedbackForm-DO1QIgmo.js → PkChatbotFeedbackForm-CxLOdwkm.js} +2 -2
- package/dist-vue/_chunks/PkChatbotFeedbackForm-CxLOdwkm.js.map +1 -0
- package/dist-vue/_chunks/{PkChatbotFilePreview-DO1wZPPj.js → PkChatbotFilePreview-CwiVQDF2.js} +3 -3
- package/dist-vue/_chunks/PkChatbotFilePreview-CwiVQDF2.js.map +1 -0
- package/dist-vue/_chunks/{PkChatbotInput-D8x52cVm.js → PkChatbotInput-MSpF6SB6.js} +140 -125
- package/dist-vue/_chunks/PkChatbotInput-MSpF6SB6.js.map +1 -0
- package/dist-vue/_chunks/PkChatbotMessages-Bz5q8EtT.js +776 -0
- package/dist-vue/_chunks/PkChatbotMessages-Bz5q8EtT.js.map +1 -0
- package/dist-vue/_chunks/{PkChatbotStepPayload-BH6piqOi.js → PkChatbotStepPayload-XW4gT9AZ.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotStepPayload-BH6piqOi.js.map → PkChatbotStepPayload-XW4gT9AZ.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotStepToolDetail-BJ7xUvgi.js → PkChatbotStepToolDetail-C4-K6Glw.js} +3 -3
- package/dist-vue/_chunks/{PkChatbotStepToolDetail-BJ7xUvgi.js.map → PkChatbotStepToolDetail-C4-K6Glw.js.map} +1 -1
- package/dist-vue/_chunks/PkChatbotSteps-CrqjWpv0.js +190 -0
- package/dist-vue/_chunks/PkChatbotSteps-CrqjWpv0.js.map +1 -0
- package/dist-vue/_chunks/{PkChatbotViewChat-CNH_glPI.js → PkChatbotViewChat-DXu5ncaU.js} +10 -10
- package/dist-vue/_chunks/{PkChatbotViewChat-CNH_glPI.js.map → PkChatbotViewChat-DXu5ncaU.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotViewConversations-BENvHLZt.js → PkChatbotViewConversations-3LaZPFyw.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotViewConversations-BENvHLZt.js.map → PkChatbotViewConversations-3LaZPFyw.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotViewFiles-qmLESi1V.js → PkChatbotViewFiles-CTqnbsCj.js} +3 -3
- package/dist-vue/_chunks/{PkChatbotViewFiles-qmLESi1V.js.map → PkChatbotViewFiles-CTqnbsCj.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotViewProfile-DzfZnitQ.js → PkChatbotViewProfile-B-Mp1jGQ.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotViewProfile-DzfZnitQ.js.map → PkChatbotViewProfile-B-Mp1jGQ.js.map} +1 -1
- package/dist-vue/_chunks/PkRelativeTime--1cIphlA.js.map +1 -1
- package/dist-vue/_chunks/{PkStreamingMarkdown-D8_LwZMR.js → PkStreamingMarkdown-D0IOaETI.js} +432 -419
- package/dist-vue/_chunks/PkStreamingMarkdown-D0IOaETI.js.map +1 -0
- package/dist-vue/_chunks/{PkSvgViewer-DPpE9fiz.js → PkSvgViewer-D-0M5bqg.js} +2 -2
- package/dist-vue/_chunks/PkSvgViewer-D-0M5bqg.js.map +1 -0
- package/dist-vue/_chunks/{PkToolRequestGeolocation-D1ZPmWiB.js → PkToolRequestGeolocation-Q3N3jlO8.js} +3 -3
- package/dist-vue/_chunks/PkToolRequestGeolocation-Q3N3jlO8.js.map +1 -0
- package/dist-vue/_chunks/{PkToolRequestOAuthConnection-CoJyKEE6.js → PkToolRequestOAuthConnection-lYoTJIF_.js} +4 -4
- package/dist-vue/_chunks/PkToolRequestOAuthConnection-lYoTJIF_.js.map +1 -0
- package/dist-vue/_chunks/{PkToolShowArtifact-CEXdfOGG.js → PkToolShowArtifact-DHdJuzDi.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowArtifact-CEXdfOGG.js.map → PkToolShowArtifact-DHdJuzDi.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowComparison-DMSjIpCR.js → PkToolShowComparison-BLn4pkno.js} +5 -5
- package/dist-vue/_chunks/PkToolShowComparison-BLn4pkno.js.map +1 -0
- package/dist-vue/_chunks/{PkToolShowContactForm-DHmzAIVF.js → PkToolShowContactForm-DceSyuX8.js} +3 -3
- package/dist-vue/_chunks/PkToolShowContactForm-DceSyuX8.js.map +1 -0
- package/dist-vue/_chunks/{PkToolShowDiagram-DuDp5EHd.js → PkToolShowDiagram-pwc0wpNo.js} +4 -4
- package/dist-vue/_chunks/PkToolShowDiagram-pwc0wpNo.js.map +1 -0
- package/dist-vue/_chunks/{PkToolShowEmail-CavhsPvi.js → PkToolShowEmail-DF__nKpR.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowEmail-CavhsPvi.js.map → PkToolShowEmail-DF__nKpR.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowForm-CO5A_j9L.js → PkToolShowForm-Dx10jOXm.js} +7 -7
- package/dist-vue/_chunks/PkToolShowForm-Dx10jOXm.js.map +1 -0
- package/dist-vue/_chunks/{PkToolShowImageGallery-V9U3LJfF.js → PkToolShowImageGallery-DudQzBx4.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowImageGallery-V9U3LJfF.js.map → PkToolShowImageGallery-DudQzBx4.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowMessage-DQojxDiV.js → PkToolShowMessage-Ck6VP-gw.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowMessage-DQojxDiV.js.map → PkToolShowMessage-Ck6VP-gw.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowProductList-Cn0yewM3.js → PkToolShowProductList-zfM8cx-l.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowProductList-Cn0yewM3.js.map → PkToolShowProductList-zfM8cx-l.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowSources-BvWOzVkQ.js → PkToolShowSources-Dlaz2Y77.js} +5 -5
- package/dist-vue/_chunks/PkToolShowSources-Dlaz2Y77.js.map +1 -0
- package/dist-vue/_chunks/{PkToolShowSuggestedReply-DQFOVonE.js → PkToolShowSuggestedReply-DWLkUh2L.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowSuggestedReply-DQFOVonE.js.map → PkToolShowSuggestedReply-DWLkUh2L.js.map} +1 -1
- package/dist-vue/_chunks/PkToolShowWeather-Bzqalzh8.js.map +1 -1
- package/dist-vue/_chunks/{PkToolShowWebPages-Bzkkn9GV.js → PkToolShowWebPages-CosBYLrE.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowWebPages-Bzkkn9GV.js.map → PkToolShowWebPages-CosBYLrE.js.map} +1 -1
- package/dist-vue/_chunks/{PkUrl-xUBKVJCv.js → PkUrl-B5CNTQj9.js} +2 -2
- package/dist-vue/_chunks/PkUrl-B5CNTQj9.js.map +1 -0
- package/dist-vue/_chunks/{createChatbotApiClient-CJ_5_3IT.js → createChatbotApiClient-MkaPbGWB.js} +6 -3
- package/dist-vue/_chunks/createChatbotApiClient-MkaPbGWB.js.map +1 -0
- package/dist-vue/_chunks/{useChatbotStore-CiRAuq7v.js → useChatbotStore-BzfqjiYz.js} +6 -3
- package/dist-vue/_chunks/useChatbotStore-BzfqjiYz.js.map +1 -0
- package/dist-vue/_chunks/useDialogConfirm-KWz0ohCQ.js.map +1 -1
- package/dist-vue/_chunks/{utils-Coqik0XI.js → utils-C1666_6C.js} +58 -43
- package/dist-vue/_chunks/utils-C1666_6C.js.map +1 -0
- package/dist-vue/api.js +1 -1
- package/dist-vue/composables.js +3 -3
- package/dist-vue/index.js +3867 -3488
- package/dist-vue/index.js.map +1 -1
- package/dist-vue/locales.js +36 -8
- package/dist-vue/packages/components/src/chat/PkAgentSettingsPanel.d.ts +20 -3
- package/dist-vue/packages/components/src/chat/PkChatButton.d.ts +3 -2
- package/dist-vue/packages/components/src/chat/PkLanguageModel.d.ts +26 -2
- package/dist-vue/packages/components/src/chat/PkLanguageModelCombobox.d.ts +53 -1
- package/dist-vue/packages/components/src/chat/PkModelOption.d.ts +19 -0
- package/dist-vue/packages/components/src/chat/PkReasoningSettings.d.ts +6 -0
- package/dist-vue/packages/components/src/chat/PkStreamingMarkdown.d.ts +6 -0
- package/dist-vue/packages/components/src/chat/PkStreamingMarkdownAutoscroll.d.ts +1 -0
- package/dist-vue/packages/components/src/chat/constants.d.ts +5 -18
- package/dist-vue/packages/components/src/chat/index.d.ts +3 -1
- package/dist-vue/packages/components/src/chat/modelCatalog.d.ts +46 -0
- package/dist-vue/packages/components/src/chat/utils.d.ts +16 -0
- package/dist-vue/packages/components/src/table/PkTableSortable.d.ts +13 -1
- package/dist-vue/packages/composable/src/chatbot/useChatbotStore.d.ts +18 -0
- package/dist-vue/packages/composable/src/useChatbotError.d.ts +2 -0
- package/dist-vue/packages/models/src/schema/Agent.d.ts +70 -10
- package/dist-vue/packages/models/src/schema/Chat.d.ts +31 -0
- package/dist-vue/packages/models/src/schema/ModelProvider.d.ts +316 -0
- package/dist-vue/packages/models/src/schema/Organization.d.ts +142 -2
- package/dist-vue/packages/models/src/schema/ReasoningChat.d.ts +20 -0
- package/dist-vue/packages/models/src/schema/SubAgent.d.ts +20 -0
- package/dist-vue/packages/models/src/schema/UserOverview.d.ts +41 -0
- package/dist-vue/packages/models/src/schema/constants.d.ts +56 -91
- package/dist-vue/packages/models/src/schema/index.d.ts +1 -0
- package/dist-vue/style.css +1 -1
- package/package.json +1 -1
- package/dist/_chunks/Agent-Su_LDF9_.js.map +0 -1
- package/dist/_chunks/Document-DecVclEe.js.map +0 -1
- package/dist/_chunks/Media-C6SOQfJZ.js +0 -122
- package/dist/_chunks/Media-C6SOQfJZ.js.map +0 -1
- package/dist/_chunks/PkStreamingMarkdown-CwqsJnJJ.js.map +0 -1
- package/dist/_chunks/PkToolRequestGeolocation-CEVpl50q.js.map +0 -1
- package/dist/_chunks/PkToolRequestOAuthConnection-CncDU-Kl.js.map +0 -1
- package/dist/_chunks/PkToolShowComparison-DbbUD9pg.js.map +0 -1
- package/dist/_chunks/PkToolShowContactForm-D_dW59Dl.js.map +0 -1
- package/dist/_chunks/PkToolShowDiagram-Hy9qh68O.js.map +0 -1
- package/dist/_chunks/PkToolShowForm-DbJHMDbt.js.map +0 -1
- package/dist/_chunks/PkToolShowSources-B69JmwbZ.js.map +0 -1
- package/dist/_chunks/PkToolShowWeather-LPd3tC77.js.map +0 -1
- package/dist/_chunks/browser-NgY6LXg-.js.map +0 -1
- package/dist/_chunks/utils-YJ0ZOLDG.js +0 -185
- package/dist/_chunks/utils-YJ0ZOLDG.js.map +0 -1
- package/dist-vue/_chunks/Agent-C8BsTAxk.js.map +0 -1
- package/dist-vue/_chunks/Document-CaUfI_SZ.js.map +0 -1
- package/dist-vue/_chunks/PkChatbot-o7k7d-fj.js.map +0 -1
- package/dist-vue/_chunks/PkChatbotError-CBP2mf-n.js.map +0 -1
- package/dist-vue/_chunks/PkChatbotFeedbackForm-DO1QIgmo.js.map +0 -1
- package/dist-vue/_chunks/PkChatbotFilePreview-DO1wZPPj.js.map +0 -1
- package/dist-vue/_chunks/PkChatbotInput-D8x52cVm.js.map +0 -1
- package/dist-vue/_chunks/PkChatbotMessages-BFlU046I.js +0 -771
- package/dist-vue/_chunks/PkChatbotMessages-BFlU046I.js.map +0 -1
- package/dist-vue/_chunks/PkChatbotSteps-DtV1beDc.js +0 -180
- package/dist-vue/_chunks/PkChatbotSteps-DtV1beDc.js.map +0 -1
- package/dist-vue/_chunks/PkStreamingMarkdown-D8_LwZMR.js.map +0 -1
- package/dist-vue/_chunks/PkSvgViewer-DPpE9fiz.js.map +0 -1
- package/dist-vue/_chunks/PkToolRequestGeolocation-D1ZPmWiB.js.map +0 -1
- package/dist-vue/_chunks/PkToolRequestOAuthConnection-CoJyKEE6.js.map +0 -1
- package/dist-vue/_chunks/PkToolShowComparison-DMSjIpCR.js.map +0 -1
- package/dist-vue/_chunks/PkToolShowContactForm-DHmzAIVF.js.map +0 -1
- package/dist-vue/_chunks/PkToolShowDiagram-DuDp5EHd.js.map +0 -1
- package/dist-vue/_chunks/PkToolShowForm-CO5A_j9L.js.map +0 -1
- package/dist-vue/_chunks/PkToolShowSources-BvWOzVkQ.js.map +0 -1
- package/dist-vue/_chunks/PkUrl-xUBKVJCv.js.map +0 -1
- package/dist-vue/_chunks/createChatbotApiClient-CJ_5_3IT.js.map +0 -1
- package/dist-vue/_chunks/useChatbotStore-CiRAuq7v.js.map +0 -1
- package/dist-vue/_chunks/utils-Coqik0XI.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PkToolShowWeather-Bzqalzh8.js","names":[],"sources":["../../../../packages/utils/src/weather.ts","../../../../packages/components/src/chat/PkToolShowWeather.vue","../../../../packages/components/src/chat/PkToolShowWeather.vue"],"sourcesContent":["/**\n * Framework-agnostic weather presentation primitives. They classify raw\n * open-meteo values into canonical categories; each consumer (web widget,\n * platform card renderer) maps a category to its own representation (an\n * Iconify name, an emoji, a CSS class, an i18n key). Keeping the classification\n * here means the WMO code bands and AQI thresholds live in exactly one place.\n */\n\n/** Canonical WMO weather-code category (resolution matches the web widget). */\nexport type WmoCategory =\n | 'clear'\n | 'mainlyClear'\n | 'partlyCloudy'\n | 'overcast'\n | 'fog'\n | 'drizzle'\n | 'freezingDrizzle'\n | 'rain'\n | 'freezingRain'\n | 'snow'\n | 'rainShowers'\n | 'snowShowers'\n | 'thunderstorm'\n | 'thunderstormHail'\n | 'unknown'\n\n/** Map a WMO weather interpretation code to a canonical category. */\nexport function wmoCategory(code: number | undefined): WmoCategory {\n if (code === undefined) return 'unknown'\n if (code === 0) return 'clear'\n if (code === 1) return 'mainlyClear'\n if (code === 2) return 'partlyCloudy'\n if (code === 3) return 'overcast'\n if (code === 45 || code === 48) return 'fog'\n if (code >= 51 && code <= 55) return 'drizzle'\n if (code === 56 || code === 57) return 'freezingDrizzle'\n if (code >= 61 && code <= 65) return 'rain'\n if (code === 66 || code === 67) return 'freezingRain'\n if (code >= 71 && code <= 77) return 'snow'\n if (code >= 80 && code <= 82) return 'rainShowers'\n if (code === 85 || code === 86) return 'snowShowers'\n if (code === 95) return 'thunderstorm'\n if (code === 96 || code === 99) return 'thunderstormHail'\n return 'unknown'\n}\n\n/** Emoji per category (used by the language-neutral platform card renderer). */\nconst WMO_EMOJI: Record<WmoCategory, string> = {\n clear: '☀️',\n mainlyClear: '⛅',\n partlyCloudy: '⛅',\n overcast: '⛅',\n fog: '🌫️',\n drizzle: '🌦️',\n freezingDrizzle: '🌦️',\n rain: '🌧️',\n freezingRain: '🌧️',\n snow: '❄️',\n rainShowers: '🌧️',\n snowShowers: '🌨️',\n thunderstorm: '⛈️',\n thunderstormHail: '⛈️',\n unknown: '🌡️',\n}\n\n/** WMO code → emoji (convenience for non-UI consumers). */\nexport function wmoEmoji(code: number | undefined): string {\n return WMO_EMOJI[wmoCategory(code)]\n}\n\n/** Canonical European-AQI band, ordered best → worst. */\nexport type AqiBandKey =\n 'good' | 'fair' | 'moderate' | 'poor' | 'veryPoor' | 'hazardous'\n\n/** Classify a European AQI value into a band (index + canonical key). */\nexport function aqiBand(aqi: number): { index: number; key: AqiBandKey } {\n if (aqi <= 20) return { index: 0, key: 'good' }\n if (aqi <= 40) return { index: 1, key: 'fair' }\n if (aqi <= 60) return { index: 2, key: 'moderate' }\n if (aqi <= 80) return { index: 3, key: 'poor' }\n if (aqi <= 100) return { index: 4, key: 'veryPoor' }\n return { index: 5, key: 'hazardous' }\n}\n\n/** Colored dot per AQI band index (used by the platform card renderer). */\nconst AQI_DOTS = ['🟢', '🟡', '🟠', '🔴', '🟣', '⚫']\n\n/** AQI value → colored dot (convenience for non-UI consumers). */\nexport function aqiDot(aqi: number): string {\n return AQI_DOTS[aqiBand(aqi).index]\n}\n","<script setup lang=\"ts\">\n import { computed, ref, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n import type { WeatherData } from 'models'\n import {\n aqiBand,\n wmoCategory,\n type AqiBandKey,\n type WmoCategory,\n } from 'utils'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const { t: $t, d: $d, n: $n } = useI18n({ useScope: 'global' })\n\n const toolPart = computed(() => {\n return props.part as { input?: WeatherData; output?: WeatherData }\n })\n\n const data = computed(\n () => toolPart.value.output ?? toolPart.value.input ?? null,\n )\n\n const selectedDayIndex = ref(0)\n\n const dailyOpen = ref(!data.value?.current)\n\n watch(selectedDayIndex, (index) => {\n if (index > 0) {\n dailyOpen.value = true\n }\n })\n\n const selectedDay = computed(\n () => data.value?.daily?.[selectedDayIndex.value],\n )\n\n /** Hourly entries filtered to the selected day's date */\n const filteredHourly = computed(() => {\n if (!data.value?.hourly?.length || !selectedDay.value) {\n return data.value?.hourly ?? []\n }\n const dayDate = selectedDay.value.date\n return data.value.hourly.filter((h) => h.time.startsWith(dayDate))\n })\n\n /**\n * Parses a date/time string in various formats the LLM might produce.\n * Tries ISO, space-separated, time-only, and common human-readable formats.\n */\n function safeDate(value: string): Date {\n // 1. Try native parsing (works for ISO 8601 and many standard formats)\n const direct = new Date(value)\n if (!Number.isNaN(direct.getTime())) {\n return direct\n }\n\n // 2. Replace space separator → T (\"2024-04-15 14:00\" → \"2024-04-15T14:00\")\n if (/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}/.test(value)) {\n const withT = new Date(value.replace(' ', 'T'))\n if (!Number.isNaN(withT.getTime())) {\n return withT\n }\n }\n\n // 3. Time-only (\"14:00\" or \"14:00:00\") → today at that hour\n const timeOnly = value.match(/^(\\d{1,2}):(\\d{2})(?::(\\d{2}))?$/)\n if (timeOnly) {\n const today = new Date()\n today.setHours(\n Number(timeOnly[1]),\n Number(timeOnly[2]),\n Number(timeOnly[3] ?? 0),\n 0,\n )\n return today\n }\n\n // 4. Date-only (\"2024-04-15\") → noon to avoid timezone edge\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) {\n const noon = new Date(value + 'T12:00:00')\n if (!Number.isNaN(noon.getTime())) {\n return noon\n }\n }\n\n // Last resort: return an obviously invalid sentinel so callers can handle it\n return new Date(NaN)\n }\n\n /** Iconify `wi:` icon per canonical WMO category. */\n const WMO_ICON: Record<WmoCategory, string> = {\n clear: 'wi:day-sunny',\n mainlyClear: 'wi:day-sunny-overcast',\n partlyCloudy: 'wi:day-cloudy',\n overcast: 'wi:cloudy',\n fog: 'wi:fog',\n drizzle: 'wi:sprinkle',\n freezingDrizzle: 'wi:sleet',\n rain: 'wi:rain',\n freezingRain: 'wi:rain-mix',\n snow: 'wi:snow',\n rainShowers: 'wi:showers',\n snowShowers: 'wi:snow-wind',\n thunderstorm: 'wi:thunderstorm',\n thunderstormHail: 'wi:storm-showers',\n unknown: 'wi:na',\n }\n\n /** Maps WMO weather code to an Iconify wi: icon name */\n function wmoToIcon(code: number): string {\n return WMO_ICON[wmoCategory(code)]\n }\n\n /**\n * Returns a formatted day label for daily forecast.\n * When daily has 1-2 entries, use the date string directly.\n * Otherwise, use index-based computation from today.\n */\n function formatDay(isoDate: string, index: number, total: number): string {\n const parsed = safeDate(isoDate + 'T12:00:00')\n if (!Number.isNaN(parsed.getTime())) {\n const today = new Date()\n today.setHours(12, 0, 0, 0)\n const diffDays = Math.round(\n (parsed.getTime() - today.getTime()) / 86_400_000,\n )\n if (diffDays === 0) {\n return $t('weather.today')\n }\n return $d(parsed, 'weekday-day')\n }\n if (index === 0 && total <= 7) {\n return $t('weather.today')\n }\n const fallback = new Date()\n fallback.setDate(fallback.getDate() + index)\n return $d(fallback, 'weekday-day')\n }\n\n const headerDate = computed(() => {\n if (selectedDay.value) {\n const parsed = safeDate(selectedDay.value.date + 'T12:00:00')\n if (!Number.isNaN(parsed.getTime())) {\n return formatDay(\n selectedDay.value.date,\n selectedDayIndex.value,\n data.value?.daily?.length ?? 1,\n )\n }\n }\n return formatDay(new Date().toISOString().slice(0, 10), 0, 1)\n })\n\n /** i18n label key + CSS class per canonical AQI band. */\n const AQI_PRESENTATION: Record<\n AqiBandKey,\n { labelKey: string; class: string }\n > = {\n good: {\n labelKey: 'weather.aqiGood',\n class: 'text-green-600 bg-green-50',\n },\n fair: {\n labelKey: 'weather.aqiFair',\n class: 'text-lime-600 bg-lime-50',\n },\n moderate: {\n labelKey: 'weather.aqiModerate',\n class: 'text-yellow-600 bg-yellow-50',\n },\n poor: {\n labelKey: 'weather.aqiPoor',\n class: 'text-orange-600 bg-orange-50',\n },\n veryPoor: {\n labelKey: 'weather.aqiVeryPoor',\n class: 'text-red-600 bg-red-50',\n },\n hazardous: {\n labelKey: 'weather.aqiHazardous',\n class: 'text-purple-700 bg-purple-50',\n },\n }\n\n /** Returns AQI label and CSS class for European AQI */\n function aqiInfo(aqi: number): { label: string; class: string } {\n const { labelKey, class: cssClass } = AQI_PRESENTATION[aqiBand(aqi).key]\n return { label: $t(labelKey), class: cssClass }\n }\n\n /** Formats wind direction degrees to compass label */\n function windDirectionLabel(deg: number): string {\n const dirs = ['N', 'NE', 'E', 'SE', 'S', 'SO', 'O', 'NO']\n return dirs[Math.round(deg / 45) % 8]\n }\n</script>\n\n<template>\n <div\n v-if=\"data\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden bg-surface\">\n <!-- Header -->\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8 min-h-40\">\n <VvIcon name=\"ri:temp-cold-line\" class=\"text-16\" />\n <strong class=\"font-bold truncate\">\n {{ data.locationName }}\n </strong>\n <span class=\"ml-auto shrink-0 capitalize\">\n {{ headerDate }}\n </span>\n </div>\n\n <!-- Current conditions (only when real-time current is available AND first day is selected) -->\n <div\n v-if=\"data.current && selectedDayIndex === 0\"\n class=\"px-sm py-md flex items-center gap-md flex-wrap\">\n <div class=\"flex items-center gap-8\">\n <VvIcon\n :name=\"wmoToIcon(data.current.weatherCode)\"\n class=\"text-48 text-word-2 shrink-0\" />\n <span class=\"text-48 font-light leading-none text-word-1\">\n {{ $n(data.current.temperature, 'integer') }}°\n </span>\n </div>\n <div class=\"flex flex-col gap-4 text-12 text-word-3\">\n <div class=\"flex items-center gap-6\">\n {{ $t('weather.feelsLike') }}\n {{ $n(data.current.feelsLike, 'integer') }}°\n </div>\n <div class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:water-percent-line\" class=\"text-14\" />\n {{ data.current.humidity }}%\n </div>\n <div class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:windy-line\" class=\"text-14\" />\n {{ $n(data.current.windSpeed, 'integer') }} km/h\n {{ windDirectionLabel(data.current.windDirection) }}\n </div>\n <div\n v-if=\"data.current.uvIndex > 0\"\n class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:sun-line\" class=\"text-14\" />\n UV {{ $n(data.current.uvIndex, 'integer') }}\n </div>\n </div>\n </div>\n\n <!-- Day summary (when no real-time current, or a non-today day is selected) -->\n <div\n v-else-if=\"selectedDay\"\n class=\"px-sm py-md flex items-center gap-md flex-wrap\">\n <div class=\"flex items-center gap-8\">\n <VvIcon\n :name=\"wmoToIcon(selectedDay.weatherCode)\"\n class=\"text-48 text-word-2 shrink-0\" />\n <div class=\"flex flex-col leading-none\">\n <span class=\"text-48 font-light text-word-1\">\n {{ $n(selectedDay.maxTemp, 'integer') }}°\n </span>\n <span class=\"text-20 text-word-3\">\n {{ $n(selectedDay.minTemp, 'integer') }}°\n </span>\n </div>\n </div>\n <div class=\"flex flex-col gap-4 text-12 text-word-3\">\n <div\n v-if=\"selectedDay.precipitationProbabilityMax > 0\"\n class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:drop-line\" class=\"text-14\" />\n {{ selectedDay.precipitationProbabilityMax }}% ({{\n selectedDay.precipitationSum\n }}\n mm)\n </div>\n <div\n v-if=\"selectedDay.uvIndexMax > 0\"\n class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:sun-line\" class=\"text-14\" />\n UV {{ $n(selectedDay.uvIndexMax, 'integer') }}\n </div>\n <div class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:sun-foggy-line\" class=\"text-14\" />\n {{ $d(safeDate(selectedDay.sunrise), 'time') }}\n –\n {{ $d(safeDate(selectedDay.sunset), 'time') }}\n </div>\n </div>\n </div>\n\n <!-- Hourly forecast (filtered to selected day) -->\n <transition>\n <div\n v-if=\"filteredHourly.length > 0\"\n class=\"border-t border-surface-3\">\n <div\n class=\"flex overflow-x-auto gap-2 px-sm py-8 light-scrollbar\">\n <div\n v-for=\"hour in filteredHourly\"\n :key=\"hour.time\"\n class=\"flex flex-col items-center gap-4 min-w-48 px-4 py-6 rounded-xl text-11 text-word-3 shrink-0\">\n <span class=\"text-word-3\">{{\n Number.isNaN(safeDate(hour.time).getTime())\n ? hour.time\n : $d(safeDate(hour.time), 'time')\n }}</span>\n <VvIcon\n :name=\"wmoToIcon(hour.weatherCode)\"\n class=\"text-20 text-word-2\" />\n <span class=\"font-medium text-word-1\">\n {{ $n(hour.temperature, 'integer') }}°\n </span>\n <span\n v-if=\"hour.precipitationProbability > 0\"\n class=\"text-word-5 text-smaller\">\n {{ hour.precipitationProbability }}%\n </span>\n </div>\n </div>\n </div>\n </transition>\n\n <!-- Daily forecast (clickable, inside accordion) -->\n <transition>\n <VvAccordion\n v-if=\"data.daily?.length > 1\"\n v-model=\"dailyOpen\"\n modifiers=\"details no-padding\"\n :title=\"$t('weather.dailyForecast')\"\n class=\"border-t border-surface-3\">\n <button\n v-for=\"(day, index) in data.daily\"\n :key=\"day.date\"\n type=\"button\"\n class=\"flex items-center gap-sm px-sm py-8 text-12 w-full text-left transition-colors cursor-pointer border-t border-surface-3\"\n :class=\"\n index === selectedDayIndex\n ? 'bg-surface-2'\n : 'hover:bg-surface-1'\n \"\n @click=\"selectedDayIndex = index\">\n <span class=\"w-48 shrink-0 text-word-3 capitalize\">\n {{ formatDay(day.date, index, data.daily.length) }}\n </span>\n <VvIcon\n :name=\"wmoToIcon(day.weatherCode)\"\n class=\"text-18 text-word-2 shrink-0\" />\n <span\n v-if=\"day.precipitationProbabilityMax > 0\"\n class=\"text-word-5 text-11 w-32 shrink-0\">\n {{ day.precipitationProbabilityMax }}%\n </span>\n <span v-else class=\"w-32 shrink-0\" />\n <div class=\"ml-auto flex items-center gap-8 text-word-3\">\n <span class=\"text-word-1 font-semibold\">\n {{ $n(day.maxTemp, 'integer') }}°\n </span>\n <span>{{ $n(day.minTemp, 'integer') }}°</span>\n </div>\n </button>\n </VvAccordion>\n </transition>\n\n <!-- Air quality -->\n <div\n v-if=\"data.airQuality\"\n class=\"border-t border-surface-3 px-sm py-8 flex items-center gap-8 text-12\">\n <VvIcon name=\"ri:windy-line\" class=\"text-14 text-word-3\" />\n <span class=\"text-word-3\">{{ $t('weather.airQuality') }}</span>\n <span\n :class=\"[\n 'ml-auto px-8 py-2 text-11 font-semibold',\n aqiInfo(data.airQuality.aqi).class,\n ]\">\n {{ aqiInfo(data.airQuality.aqi).label }}\n ({{ data.airQuality.aqi }})\n </span>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, ref, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n import type { WeatherData } from 'models'\n import {\n aqiBand,\n wmoCategory,\n type AqiBandKey,\n type WmoCategory,\n } from 'utils'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const { t: $t, d: $d, n: $n } = useI18n({ useScope: 'global' })\n\n const toolPart = computed(() => {\n return props.part as { input?: WeatherData; output?: WeatherData }\n })\n\n const data = computed(\n () => toolPart.value.output ?? toolPart.value.input ?? null,\n )\n\n const selectedDayIndex = ref(0)\n\n const dailyOpen = ref(!data.value?.current)\n\n watch(selectedDayIndex, (index) => {\n if (index > 0) {\n dailyOpen.value = true\n }\n })\n\n const selectedDay = computed(\n () => data.value?.daily?.[selectedDayIndex.value],\n )\n\n /** Hourly entries filtered to the selected day's date */\n const filteredHourly = computed(() => {\n if (!data.value?.hourly?.length || !selectedDay.value) {\n return data.value?.hourly ?? []\n }\n const dayDate = selectedDay.value.date\n return data.value.hourly.filter((h) => h.time.startsWith(dayDate))\n })\n\n /**\n * Parses a date/time string in various formats the LLM might produce.\n * Tries ISO, space-separated, time-only, and common human-readable formats.\n */\n function safeDate(value: string): Date {\n // 1. Try native parsing (works for ISO 8601 and many standard formats)\n const direct = new Date(value)\n if (!Number.isNaN(direct.getTime())) {\n return direct\n }\n\n // 2. Replace space separator → T (\"2024-04-15 14:00\" → \"2024-04-15T14:00\")\n if (/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}/.test(value)) {\n const withT = new Date(value.replace(' ', 'T'))\n if (!Number.isNaN(withT.getTime())) {\n return withT\n }\n }\n\n // 3. Time-only (\"14:00\" or \"14:00:00\") → today at that hour\n const timeOnly = value.match(/^(\\d{1,2}):(\\d{2})(?::(\\d{2}))?$/)\n if (timeOnly) {\n const today = new Date()\n today.setHours(\n Number(timeOnly[1]),\n Number(timeOnly[2]),\n Number(timeOnly[3] ?? 0),\n 0,\n )\n return today\n }\n\n // 4. Date-only (\"2024-04-15\") → noon to avoid timezone edge\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) {\n const noon = new Date(value + 'T12:00:00')\n if (!Number.isNaN(noon.getTime())) {\n return noon\n }\n }\n\n // Last resort: return an obviously invalid sentinel so callers can handle it\n return new Date(NaN)\n }\n\n /** Iconify `wi:` icon per canonical WMO category. */\n const WMO_ICON: Record<WmoCategory, string> = {\n clear: 'wi:day-sunny',\n mainlyClear: 'wi:day-sunny-overcast',\n partlyCloudy: 'wi:day-cloudy',\n overcast: 'wi:cloudy',\n fog: 'wi:fog',\n drizzle: 'wi:sprinkle',\n freezingDrizzle: 'wi:sleet',\n rain: 'wi:rain',\n freezingRain: 'wi:rain-mix',\n snow: 'wi:snow',\n rainShowers: 'wi:showers',\n snowShowers: 'wi:snow-wind',\n thunderstorm: 'wi:thunderstorm',\n thunderstormHail: 'wi:storm-showers',\n unknown: 'wi:na',\n }\n\n /** Maps WMO weather code to an Iconify wi: icon name */\n function wmoToIcon(code: number): string {\n return WMO_ICON[wmoCategory(code)]\n }\n\n /**\n * Returns a formatted day label for daily forecast.\n * When daily has 1-2 entries, use the date string directly.\n * Otherwise, use index-based computation from today.\n */\n function formatDay(isoDate: string, index: number, total: number): string {\n const parsed = safeDate(isoDate + 'T12:00:00')\n if (!Number.isNaN(parsed.getTime())) {\n const today = new Date()\n today.setHours(12, 0, 0, 0)\n const diffDays = Math.round(\n (parsed.getTime() - today.getTime()) / 86_400_000,\n )\n if (diffDays === 0) {\n return $t('weather.today')\n }\n return $d(parsed, 'weekday-day')\n }\n if (index === 0 && total <= 7) {\n return $t('weather.today')\n }\n const fallback = new Date()\n fallback.setDate(fallback.getDate() + index)\n return $d(fallback, 'weekday-day')\n }\n\n const headerDate = computed(() => {\n if (selectedDay.value) {\n const parsed = safeDate(selectedDay.value.date + 'T12:00:00')\n if (!Number.isNaN(parsed.getTime())) {\n return formatDay(\n selectedDay.value.date,\n selectedDayIndex.value,\n data.value?.daily?.length ?? 1,\n )\n }\n }\n return formatDay(new Date().toISOString().slice(0, 10), 0, 1)\n })\n\n /** i18n label key + CSS class per canonical AQI band. */\n const AQI_PRESENTATION: Record<\n AqiBandKey,\n { labelKey: string; class: string }\n > = {\n good: {\n labelKey: 'weather.aqiGood',\n class: 'text-green-600 bg-green-50',\n },\n fair: {\n labelKey: 'weather.aqiFair',\n class: 'text-lime-600 bg-lime-50',\n },\n moderate: {\n labelKey: 'weather.aqiModerate',\n class: 'text-yellow-600 bg-yellow-50',\n },\n poor: {\n labelKey: 'weather.aqiPoor',\n class: 'text-orange-600 bg-orange-50',\n },\n veryPoor: {\n labelKey: 'weather.aqiVeryPoor',\n class: 'text-red-600 bg-red-50',\n },\n hazardous: {\n labelKey: 'weather.aqiHazardous',\n class: 'text-purple-700 bg-purple-50',\n },\n }\n\n /** Returns AQI label and CSS class for European AQI */\n function aqiInfo(aqi: number): { label: string; class: string } {\n const { labelKey, class: cssClass } = AQI_PRESENTATION[aqiBand(aqi).key]\n return { label: $t(labelKey), class: cssClass }\n }\n\n /** Formats wind direction degrees to compass label */\n function windDirectionLabel(deg: number): string {\n const dirs = ['N', 'NE', 'E', 'SE', 'S', 'SO', 'O', 'NO']\n return dirs[Math.round(deg / 45) % 8]\n }\n</script>\n\n<template>\n <div\n v-if=\"data\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden bg-surface\">\n <!-- Header -->\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8 min-h-40\">\n <VvIcon name=\"ri:temp-cold-line\" class=\"text-16\" />\n <strong class=\"font-bold truncate\">\n {{ data.locationName }}\n </strong>\n <span class=\"ml-auto shrink-0 capitalize\">\n {{ headerDate }}\n </span>\n </div>\n\n <!-- Current conditions (only when real-time current is available AND first day is selected) -->\n <div\n v-if=\"data.current && selectedDayIndex === 0\"\n class=\"px-sm py-md flex items-center gap-md flex-wrap\">\n <div class=\"flex items-center gap-8\">\n <VvIcon\n :name=\"wmoToIcon(data.current.weatherCode)\"\n class=\"text-48 text-word-2 shrink-0\" />\n <span class=\"text-48 font-light leading-none text-word-1\">\n {{ $n(data.current.temperature, 'integer') }}°\n </span>\n </div>\n <div class=\"flex flex-col gap-4 text-12 text-word-3\">\n <div class=\"flex items-center gap-6\">\n {{ $t('weather.feelsLike') }}\n {{ $n(data.current.feelsLike, 'integer') }}°\n </div>\n <div class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:water-percent-line\" class=\"text-14\" />\n {{ data.current.humidity }}%\n </div>\n <div class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:windy-line\" class=\"text-14\" />\n {{ $n(data.current.windSpeed, 'integer') }} km/h\n {{ windDirectionLabel(data.current.windDirection) }}\n </div>\n <div\n v-if=\"data.current.uvIndex > 0\"\n class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:sun-line\" class=\"text-14\" />\n UV {{ $n(data.current.uvIndex, 'integer') }}\n </div>\n </div>\n </div>\n\n <!-- Day summary (when no real-time current, or a non-today day is selected) -->\n <div\n v-else-if=\"selectedDay\"\n class=\"px-sm py-md flex items-center gap-md flex-wrap\">\n <div class=\"flex items-center gap-8\">\n <VvIcon\n :name=\"wmoToIcon(selectedDay.weatherCode)\"\n class=\"text-48 text-word-2 shrink-0\" />\n <div class=\"flex flex-col leading-none\">\n <span class=\"text-48 font-light text-word-1\">\n {{ $n(selectedDay.maxTemp, 'integer') }}°\n </span>\n <span class=\"text-20 text-word-3\">\n {{ $n(selectedDay.minTemp, 'integer') }}°\n </span>\n </div>\n </div>\n <div class=\"flex flex-col gap-4 text-12 text-word-3\">\n <div\n v-if=\"selectedDay.precipitationProbabilityMax > 0\"\n class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:drop-line\" class=\"text-14\" />\n {{ selectedDay.precipitationProbabilityMax }}% ({{\n selectedDay.precipitationSum\n }}\n mm)\n </div>\n <div\n v-if=\"selectedDay.uvIndexMax > 0\"\n class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:sun-line\" class=\"text-14\" />\n UV {{ $n(selectedDay.uvIndexMax, 'integer') }}\n </div>\n <div class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:sun-foggy-line\" class=\"text-14\" />\n {{ $d(safeDate(selectedDay.sunrise), 'time') }}\n –\n {{ $d(safeDate(selectedDay.sunset), 'time') }}\n </div>\n </div>\n </div>\n\n <!-- Hourly forecast (filtered to selected day) -->\n <transition>\n <div\n v-if=\"filteredHourly.length > 0\"\n class=\"border-t border-surface-3\">\n <div\n class=\"flex overflow-x-auto gap-2 px-sm py-8 light-scrollbar\">\n <div\n v-for=\"hour in filteredHourly\"\n :key=\"hour.time\"\n class=\"flex flex-col items-center gap-4 min-w-48 px-4 py-6 rounded-xl text-11 text-word-3 shrink-0\">\n <span class=\"text-word-3\">{{\n Number.isNaN(safeDate(hour.time).getTime())\n ? hour.time\n : $d(safeDate(hour.time), 'time')\n }}</span>\n <VvIcon\n :name=\"wmoToIcon(hour.weatherCode)\"\n class=\"text-20 text-word-2\" />\n <span class=\"font-medium text-word-1\">\n {{ $n(hour.temperature, 'integer') }}°\n </span>\n <span\n v-if=\"hour.precipitationProbability > 0\"\n class=\"text-word-5 text-smaller\">\n {{ hour.precipitationProbability }}%\n </span>\n </div>\n </div>\n </div>\n </transition>\n\n <!-- Daily forecast (clickable, inside accordion) -->\n <transition>\n <VvAccordion\n v-if=\"data.daily?.length > 1\"\n v-model=\"dailyOpen\"\n modifiers=\"details no-padding\"\n :title=\"$t('weather.dailyForecast')\"\n class=\"border-t border-surface-3\">\n <button\n v-for=\"(day, index) in data.daily\"\n :key=\"day.date\"\n type=\"button\"\n class=\"flex items-center gap-sm px-sm py-8 text-12 w-full text-left transition-colors cursor-pointer border-t border-surface-3\"\n :class=\"\n index === selectedDayIndex\n ? 'bg-surface-2'\n : 'hover:bg-surface-1'\n \"\n @click=\"selectedDayIndex = index\">\n <span class=\"w-48 shrink-0 text-word-3 capitalize\">\n {{ formatDay(day.date, index, data.daily.length) }}\n </span>\n <VvIcon\n :name=\"wmoToIcon(day.weatherCode)\"\n class=\"text-18 text-word-2 shrink-0\" />\n <span\n v-if=\"day.precipitationProbabilityMax > 0\"\n class=\"text-word-5 text-11 w-32 shrink-0\">\n {{ day.precipitationProbabilityMax }}%\n </span>\n <span v-else class=\"w-32 shrink-0\" />\n <div class=\"ml-auto flex items-center gap-8 text-word-3\">\n <span class=\"text-word-1 font-semibold\">\n {{ $n(day.maxTemp, 'integer') }}°\n </span>\n <span>{{ $n(day.minTemp, 'integer') }}°</span>\n </div>\n </button>\n </VvAccordion>\n </transition>\n\n <!-- Air quality -->\n <div\n v-if=\"data.airQuality\"\n class=\"border-t border-surface-3 px-sm py-8 flex items-center gap-8 text-12\">\n <VvIcon name=\"ri:windy-line\" class=\"text-14 text-word-3\" />\n <span class=\"text-word-3\">{{ $t('weather.airQuality') }}</span>\n <span\n :class=\"[\n 'ml-auto px-8 py-2 text-11 font-semibold',\n aqiInfo(data.airQuality.aqi).class,\n ]\">\n {{ aqiInfo(data.airQuality.aqi).label }}\n ({{ data.airQuality.aqi }})\n </span>\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PkToolShowWeather-Bzqalzh8.js","names":[],"sources":["../../../../packages/utils/src/weather.ts","../../../../packages/components/src/chat/PkToolShowWeather.vue","../../../../packages/components/src/chat/PkToolShowWeather.vue"],"sourcesContent":["/**\n * Framework-agnostic weather presentation primitives. They classify raw\n * open-meteo values into canonical categories; each consumer (web widget,\n * platform card renderer) maps a category to its own representation (an\n * Iconify name, an emoji, a CSS class, an i18n key). Keeping the classification\n * here means the WMO code bands and AQI thresholds live in exactly one place.\n */\n\n/** Canonical WMO weather-code category (resolution matches the web widget). */\nexport type WmoCategory =\n | 'clear'\n | 'mainlyClear'\n | 'partlyCloudy'\n | 'overcast'\n | 'fog'\n | 'drizzle'\n | 'freezingDrizzle'\n | 'rain'\n | 'freezingRain'\n | 'snow'\n | 'rainShowers'\n | 'snowShowers'\n | 'thunderstorm'\n | 'thunderstormHail'\n | 'unknown'\n\n/** Map a WMO weather interpretation code to a canonical category. */\nexport function wmoCategory(code: number | undefined): WmoCategory {\n if (code === undefined) {\n return 'unknown'\n }\n if (code === 0) {\n return 'clear'\n }\n if (code === 1) {\n return 'mainlyClear'\n }\n if (code === 2) {\n return 'partlyCloudy'\n }\n if (code === 3) {\n return 'overcast'\n }\n if (code === 45 || code === 48) {\n return 'fog'\n }\n if (code >= 51 && code <= 55) {\n return 'drizzle'\n }\n if (code === 56 || code === 57) {\n return 'freezingDrizzle'\n }\n if (code >= 61 && code <= 65) {\n return 'rain'\n }\n if (code === 66 || code === 67) {\n return 'freezingRain'\n }\n if (code >= 71 && code <= 77) {\n return 'snow'\n }\n if (code >= 80 && code <= 82) {\n return 'rainShowers'\n }\n if (code === 85 || code === 86) {\n return 'snowShowers'\n }\n if (code === 95) {\n return 'thunderstorm'\n }\n if (code === 96 || code === 99) {\n return 'thunderstormHail'\n }\n return 'unknown'\n}\n\n/** Emoji per category (used by the language-neutral platform card renderer). */\nconst WMO_EMOJI: Record<WmoCategory, string> = {\n clear: '☀️',\n mainlyClear: '⛅',\n partlyCloudy: '⛅',\n overcast: '⛅',\n fog: '🌫️',\n drizzle: '🌦️',\n freezingDrizzle: '🌦️',\n rain: '🌧️',\n freezingRain: '🌧️',\n snow: '❄️',\n rainShowers: '🌧️',\n snowShowers: '🌨️',\n thunderstorm: '⛈️',\n thunderstormHail: '⛈️',\n unknown: '🌡️',\n}\n\n/** WMO code → emoji (convenience for non-UI consumers). */\nexport function wmoEmoji(code: number | undefined): string {\n return WMO_EMOJI[wmoCategory(code)]\n}\n\n/** Canonical European-AQI band, ordered best → worst. */\nexport type AqiBandKey =\n 'good' | 'fair' | 'moderate' | 'poor' | 'veryPoor' | 'hazardous'\n\n/** Classify a European AQI value into a band (index + canonical key). */\nexport function aqiBand(aqi: number): { index: number; key: AqiBandKey } {\n if (aqi <= 20) {\n return { index: 0, key: 'good' }\n }\n if (aqi <= 40) {\n return { index: 1, key: 'fair' }\n }\n if (aqi <= 60) {\n return { index: 2, key: 'moderate' }\n }\n if (aqi <= 80) {\n return { index: 3, key: 'poor' }\n }\n if (aqi <= 100) {\n return { index: 4, key: 'veryPoor' }\n }\n return { index: 5, key: 'hazardous' }\n}\n\n/** Colored dot per AQI band index (used by the platform card renderer). */\nconst AQI_DOTS = ['🟢', '🟡', '🟠', '🔴', '🟣', '⚫']\n\n/** AQI value → colored dot (convenience for non-UI consumers). */\nexport function aqiDot(aqi: number): string {\n return AQI_DOTS[aqiBand(aqi).index]\n}\n","<script setup lang=\"ts\">\n import { computed, ref, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n import type { WeatherData } from 'models'\n import {\n aqiBand,\n wmoCategory,\n type AqiBandKey,\n type WmoCategory,\n } from 'utils'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const { t: $t, d: $d, n: $n } = useI18n({ useScope: 'global' })\n\n const toolPart = computed(() => {\n return props.part as { input?: WeatherData; output?: WeatherData }\n })\n\n const data = computed(\n () => toolPart.value.output ?? toolPart.value.input ?? null,\n )\n\n const selectedDayIndex = ref(0)\n\n const dailyOpen = ref(!data.value?.current)\n\n watch(selectedDayIndex, (index) => {\n if (index > 0) {\n dailyOpen.value = true\n }\n })\n\n const selectedDay = computed(\n () => data.value?.daily?.[selectedDayIndex.value],\n )\n\n /** Hourly entries filtered to the selected day's date */\n const filteredHourly = computed(() => {\n if (!data.value?.hourly?.length || !selectedDay.value) {\n return data.value?.hourly ?? []\n }\n const dayDate = selectedDay.value.date\n return data.value.hourly.filter((h) => h.time.startsWith(dayDate))\n })\n\n /**\n * Parses a date/time string in various formats the LLM might produce.\n * Tries ISO, space-separated, time-only, and common human-readable formats.\n */\n function safeDate(value: string): Date {\n // 1. Try native parsing (works for ISO 8601 and many standard formats)\n const direct = new Date(value)\n if (!Number.isNaN(direct.getTime())) {\n return direct\n }\n\n // 2. Replace space separator → T (\"2024-04-15 14:00\" → \"2024-04-15T14:00\")\n if (/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}/.test(value)) {\n const withT = new Date(value.replace(' ', 'T'))\n if (!Number.isNaN(withT.getTime())) {\n return withT\n }\n }\n\n // 3. Time-only (\"14:00\" or \"14:00:00\") → today at that hour\n const timeOnly = value.match(/^(\\d{1,2}):(\\d{2})(?::(\\d{2}))?$/)\n if (timeOnly) {\n const today = new Date()\n today.setHours(\n Number(timeOnly[1]),\n Number(timeOnly[2]),\n Number(timeOnly[3] ?? 0),\n 0,\n )\n return today\n }\n\n // 4. Date-only (\"2024-04-15\") → noon to avoid timezone edge\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) {\n const noon = new Date(value + 'T12:00:00')\n if (!Number.isNaN(noon.getTime())) {\n return noon\n }\n }\n\n // Last resort: return an obviously invalid sentinel so callers can handle it\n return new Date(NaN)\n }\n\n /** Iconify `wi:` icon per canonical WMO category. */\n const WMO_ICON: Record<WmoCategory, string> = {\n clear: 'wi:day-sunny',\n mainlyClear: 'wi:day-sunny-overcast',\n partlyCloudy: 'wi:day-cloudy',\n overcast: 'wi:cloudy',\n fog: 'wi:fog',\n drizzle: 'wi:sprinkle',\n freezingDrizzle: 'wi:sleet',\n rain: 'wi:rain',\n freezingRain: 'wi:rain-mix',\n snow: 'wi:snow',\n rainShowers: 'wi:showers',\n snowShowers: 'wi:snow-wind',\n thunderstorm: 'wi:thunderstorm',\n thunderstormHail: 'wi:storm-showers',\n unknown: 'wi:na',\n }\n\n /** Maps WMO weather code to an Iconify wi: icon name */\n function wmoToIcon(code: number): string {\n return WMO_ICON[wmoCategory(code)]\n }\n\n /**\n * Returns a formatted day label for daily forecast.\n * When daily has 1-2 entries, use the date string directly.\n * Otherwise, use index-based computation from today.\n */\n function formatDay(isoDate: string, index: number, total: number): string {\n const parsed = safeDate(isoDate + 'T12:00:00')\n if (!Number.isNaN(parsed.getTime())) {\n const today = new Date()\n today.setHours(12, 0, 0, 0)\n const diffDays = Math.round(\n (parsed.getTime() - today.getTime()) / 86_400_000,\n )\n if (diffDays === 0) {\n return $t('weather.today')\n }\n return $d(parsed, 'weekday-day')\n }\n if (index === 0 && total <= 7) {\n return $t('weather.today')\n }\n const fallback = new Date()\n fallback.setDate(fallback.getDate() + index)\n return $d(fallback, 'weekday-day')\n }\n\n const headerDate = computed(() => {\n if (selectedDay.value) {\n const parsed = safeDate(selectedDay.value.date + 'T12:00:00')\n if (!Number.isNaN(parsed.getTime())) {\n return formatDay(\n selectedDay.value.date,\n selectedDayIndex.value,\n data.value?.daily?.length ?? 1,\n )\n }\n }\n return formatDay(new Date().toISOString().slice(0, 10), 0, 1)\n })\n\n /** i18n label key + CSS class per canonical AQI band. */\n const AQI_PRESENTATION: Record<\n AqiBandKey,\n { labelKey: string; class: string }\n > = {\n good: {\n labelKey: 'weather.aqiGood',\n class: 'text-green-600 bg-green-50',\n },\n fair: {\n labelKey: 'weather.aqiFair',\n class: 'text-lime-600 bg-lime-50',\n },\n moderate: {\n labelKey: 'weather.aqiModerate',\n class: 'text-yellow-600 bg-yellow-50',\n },\n poor: {\n labelKey: 'weather.aqiPoor',\n class: 'text-orange-600 bg-orange-50',\n },\n veryPoor: {\n labelKey: 'weather.aqiVeryPoor',\n class: 'text-red-600 bg-red-50',\n },\n hazardous: {\n labelKey: 'weather.aqiHazardous',\n class: 'text-purple-700 bg-purple-50',\n },\n }\n\n /** Returns AQI label and CSS class for European AQI */\n function aqiInfo(aqi: number): { label: string; class: string } {\n const { labelKey, class: cssClass } = AQI_PRESENTATION[aqiBand(aqi).key]\n return { label: $t(labelKey), class: cssClass }\n }\n\n /** Formats wind direction degrees to compass label */\n function windDirectionLabel(deg: number): string {\n const dirs = ['N', 'NE', 'E', 'SE', 'S', 'SO', 'O', 'NO']\n return dirs[Math.round(deg / 45) % 8]\n }\n</script>\n\n<template>\n <div\n v-if=\"data\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden bg-surface\">\n <!-- Header -->\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8 min-h-40\">\n <VvIcon name=\"ri:temp-cold-line\" class=\"text-16\" />\n <strong class=\"font-bold truncate\">\n {{ data.locationName }}\n </strong>\n <span class=\"ml-auto shrink-0 capitalize\">\n {{ headerDate }}\n </span>\n </div>\n\n <!-- Current conditions (only when real-time current is available AND first day is selected) -->\n <div\n v-if=\"data.current && selectedDayIndex === 0\"\n class=\"px-sm py-md flex items-center gap-md flex-wrap\">\n <div class=\"flex items-center gap-8\">\n <VvIcon\n :name=\"wmoToIcon(data.current.weatherCode)\"\n class=\"text-48 text-word-2 shrink-0\" />\n <span class=\"text-48 font-light leading-none text-word-1\">\n {{ $n(data.current.temperature, 'integer') }}°\n </span>\n </div>\n <div class=\"flex flex-col gap-4 text-12 text-word-3\">\n <div class=\"flex items-center gap-6\">\n {{ $t('weather.feelsLike') }}\n {{ $n(data.current.feelsLike, 'integer') }}°\n </div>\n <div class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:water-percent-line\" class=\"text-14\" />\n {{ data.current.humidity }}%\n </div>\n <div class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:windy-line\" class=\"text-14\" />\n {{ $n(data.current.windSpeed, 'integer') }} km/h\n {{ windDirectionLabel(data.current.windDirection) }}\n </div>\n <div\n v-if=\"data.current.uvIndex > 0\"\n class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:sun-line\" class=\"text-14\" />\n UV {{ $n(data.current.uvIndex, 'integer') }}\n </div>\n </div>\n </div>\n\n <!-- Day summary (when no real-time current, or a non-today day is selected) -->\n <div\n v-else-if=\"selectedDay\"\n class=\"px-sm py-md flex items-center gap-md flex-wrap\">\n <div class=\"flex items-center gap-8\">\n <VvIcon\n :name=\"wmoToIcon(selectedDay.weatherCode)\"\n class=\"text-48 text-word-2 shrink-0\" />\n <div class=\"flex flex-col leading-none\">\n <span class=\"text-48 font-light text-word-1\">\n {{ $n(selectedDay.maxTemp, 'integer') }}°\n </span>\n <span class=\"text-20 text-word-3\">\n {{ $n(selectedDay.minTemp, 'integer') }}°\n </span>\n </div>\n </div>\n <div class=\"flex flex-col gap-4 text-12 text-word-3\">\n <div\n v-if=\"selectedDay.precipitationProbabilityMax > 0\"\n class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:drop-line\" class=\"text-14\" />\n {{ selectedDay.precipitationProbabilityMax }}% ({{\n selectedDay.precipitationSum\n }}\n mm)\n </div>\n <div\n v-if=\"selectedDay.uvIndexMax > 0\"\n class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:sun-line\" class=\"text-14\" />\n UV {{ $n(selectedDay.uvIndexMax, 'integer') }}\n </div>\n <div class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:sun-foggy-line\" class=\"text-14\" />\n {{ $d(safeDate(selectedDay.sunrise), 'time') }}\n –\n {{ $d(safeDate(selectedDay.sunset), 'time') }}\n </div>\n </div>\n </div>\n\n <!-- Hourly forecast (filtered to selected day) -->\n <transition>\n <div\n v-if=\"filteredHourly.length > 0\"\n class=\"border-t border-surface-3\">\n <div\n class=\"flex overflow-x-auto gap-2 px-sm py-8 light-scrollbar\">\n <div\n v-for=\"hour in filteredHourly\"\n :key=\"hour.time\"\n class=\"flex flex-col items-center gap-4 min-w-48 px-4 py-6 rounded-xl text-11 text-word-3 shrink-0\">\n <span class=\"text-word-3\">{{\n Number.isNaN(safeDate(hour.time).getTime())\n ? hour.time\n : $d(safeDate(hour.time), 'time')\n }}</span>\n <VvIcon\n :name=\"wmoToIcon(hour.weatherCode)\"\n class=\"text-20 text-word-2\" />\n <span class=\"font-medium text-word-1\">\n {{ $n(hour.temperature, 'integer') }}°\n </span>\n <span\n v-if=\"hour.precipitationProbability > 0\"\n class=\"text-word-5 text-smaller\">\n {{ hour.precipitationProbability }}%\n </span>\n </div>\n </div>\n </div>\n </transition>\n\n <!-- Daily forecast (clickable, inside accordion) -->\n <transition>\n <VvAccordion\n v-if=\"data.daily?.length > 1\"\n v-model=\"dailyOpen\"\n modifiers=\"details no-padding\"\n :title=\"$t('weather.dailyForecast')\"\n class=\"border-t border-surface-3\">\n <button\n v-for=\"(day, index) in data.daily\"\n :key=\"day.date\"\n type=\"button\"\n class=\"flex items-center gap-sm px-sm py-8 text-12 w-full text-left transition-colors cursor-pointer border-t border-surface-3\"\n :class=\"\n index === selectedDayIndex\n ? 'bg-surface-2'\n : 'hover:bg-surface-1'\n \"\n @click=\"selectedDayIndex = index\">\n <span class=\"w-48 shrink-0 text-word-3 capitalize\">\n {{ formatDay(day.date, index, data.daily.length) }}\n </span>\n <VvIcon\n :name=\"wmoToIcon(day.weatherCode)\"\n class=\"text-18 text-word-2 shrink-0\" />\n <span\n v-if=\"day.precipitationProbabilityMax > 0\"\n class=\"text-word-5 text-11 w-32 shrink-0\">\n {{ day.precipitationProbabilityMax }}%\n </span>\n <span v-else class=\"w-32 shrink-0\" />\n <div class=\"ml-auto flex items-center gap-8 text-word-3\">\n <span class=\"text-word-1 font-semibold\">\n {{ $n(day.maxTemp, 'integer') }}°\n </span>\n <span>{{ $n(day.minTemp, 'integer') }}°</span>\n </div>\n </button>\n </VvAccordion>\n </transition>\n\n <!-- Air quality -->\n <div\n v-if=\"data.airQuality\"\n class=\"border-t border-surface-3 px-sm py-8 flex items-center gap-8 text-12\">\n <VvIcon name=\"ri:windy-line\" class=\"text-14 text-word-3\" />\n <span class=\"text-word-3\">{{ $t('weather.airQuality') }}</span>\n <span\n :class=\"[\n 'ml-auto px-8 py-2 text-11 font-semibold',\n aqiInfo(data.airQuality.aqi).class,\n ]\">\n {{ aqiInfo(data.airQuality.aqi).label }}\n ({{ data.airQuality.aqi }})\n </span>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, ref, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n import type { WeatherData } from 'models'\n import {\n aqiBand,\n wmoCategory,\n type AqiBandKey,\n type WmoCategory,\n } from 'utils'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const { t: $t, d: $d, n: $n } = useI18n({ useScope: 'global' })\n\n const toolPart = computed(() => {\n return props.part as { input?: WeatherData; output?: WeatherData }\n })\n\n const data = computed(\n () => toolPart.value.output ?? toolPart.value.input ?? null,\n )\n\n const selectedDayIndex = ref(0)\n\n const dailyOpen = ref(!data.value?.current)\n\n watch(selectedDayIndex, (index) => {\n if (index > 0) {\n dailyOpen.value = true\n }\n })\n\n const selectedDay = computed(\n () => data.value?.daily?.[selectedDayIndex.value],\n )\n\n /** Hourly entries filtered to the selected day's date */\n const filteredHourly = computed(() => {\n if (!data.value?.hourly?.length || !selectedDay.value) {\n return data.value?.hourly ?? []\n }\n const dayDate = selectedDay.value.date\n return data.value.hourly.filter((h) => h.time.startsWith(dayDate))\n })\n\n /**\n * Parses a date/time string in various formats the LLM might produce.\n * Tries ISO, space-separated, time-only, and common human-readable formats.\n */\n function safeDate(value: string): Date {\n // 1. Try native parsing (works for ISO 8601 and many standard formats)\n const direct = new Date(value)\n if (!Number.isNaN(direct.getTime())) {\n return direct\n }\n\n // 2. Replace space separator → T (\"2024-04-15 14:00\" → \"2024-04-15T14:00\")\n if (/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}/.test(value)) {\n const withT = new Date(value.replace(' ', 'T'))\n if (!Number.isNaN(withT.getTime())) {\n return withT\n }\n }\n\n // 3. Time-only (\"14:00\" or \"14:00:00\") → today at that hour\n const timeOnly = value.match(/^(\\d{1,2}):(\\d{2})(?::(\\d{2}))?$/)\n if (timeOnly) {\n const today = new Date()\n today.setHours(\n Number(timeOnly[1]),\n Number(timeOnly[2]),\n Number(timeOnly[3] ?? 0),\n 0,\n )\n return today\n }\n\n // 4. Date-only (\"2024-04-15\") → noon to avoid timezone edge\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) {\n const noon = new Date(value + 'T12:00:00')\n if (!Number.isNaN(noon.getTime())) {\n return noon\n }\n }\n\n // Last resort: return an obviously invalid sentinel so callers can handle it\n return new Date(NaN)\n }\n\n /** Iconify `wi:` icon per canonical WMO category. */\n const WMO_ICON: Record<WmoCategory, string> = {\n clear: 'wi:day-sunny',\n mainlyClear: 'wi:day-sunny-overcast',\n partlyCloudy: 'wi:day-cloudy',\n overcast: 'wi:cloudy',\n fog: 'wi:fog',\n drizzle: 'wi:sprinkle',\n freezingDrizzle: 'wi:sleet',\n rain: 'wi:rain',\n freezingRain: 'wi:rain-mix',\n snow: 'wi:snow',\n rainShowers: 'wi:showers',\n snowShowers: 'wi:snow-wind',\n thunderstorm: 'wi:thunderstorm',\n thunderstormHail: 'wi:storm-showers',\n unknown: 'wi:na',\n }\n\n /** Maps WMO weather code to an Iconify wi: icon name */\n function wmoToIcon(code: number): string {\n return WMO_ICON[wmoCategory(code)]\n }\n\n /**\n * Returns a formatted day label for daily forecast.\n * When daily has 1-2 entries, use the date string directly.\n * Otherwise, use index-based computation from today.\n */\n function formatDay(isoDate: string, index: number, total: number): string {\n const parsed = safeDate(isoDate + 'T12:00:00')\n if (!Number.isNaN(parsed.getTime())) {\n const today = new Date()\n today.setHours(12, 0, 0, 0)\n const diffDays = Math.round(\n (parsed.getTime() - today.getTime()) / 86_400_000,\n )\n if (diffDays === 0) {\n return $t('weather.today')\n }\n return $d(parsed, 'weekday-day')\n }\n if (index === 0 && total <= 7) {\n return $t('weather.today')\n }\n const fallback = new Date()\n fallback.setDate(fallback.getDate() + index)\n return $d(fallback, 'weekday-day')\n }\n\n const headerDate = computed(() => {\n if (selectedDay.value) {\n const parsed = safeDate(selectedDay.value.date + 'T12:00:00')\n if (!Number.isNaN(parsed.getTime())) {\n return formatDay(\n selectedDay.value.date,\n selectedDayIndex.value,\n data.value?.daily?.length ?? 1,\n )\n }\n }\n return formatDay(new Date().toISOString().slice(0, 10), 0, 1)\n })\n\n /** i18n label key + CSS class per canonical AQI band. */\n const AQI_PRESENTATION: Record<\n AqiBandKey,\n { labelKey: string; class: string }\n > = {\n good: {\n labelKey: 'weather.aqiGood',\n class: 'text-green-600 bg-green-50',\n },\n fair: {\n labelKey: 'weather.aqiFair',\n class: 'text-lime-600 bg-lime-50',\n },\n moderate: {\n labelKey: 'weather.aqiModerate',\n class: 'text-yellow-600 bg-yellow-50',\n },\n poor: {\n labelKey: 'weather.aqiPoor',\n class: 'text-orange-600 bg-orange-50',\n },\n veryPoor: {\n labelKey: 'weather.aqiVeryPoor',\n class: 'text-red-600 bg-red-50',\n },\n hazardous: {\n labelKey: 'weather.aqiHazardous',\n class: 'text-purple-700 bg-purple-50',\n },\n }\n\n /** Returns AQI label and CSS class for European AQI */\n function aqiInfo(aqi: number): { label: string; class: string } {\n const { labelKey, class: cssClass } = AQI_PRESENTATION[aqiBand(aqi).key]\n return { label: $t(labelKey), class: cssClass }\n }\n\n /** Formats wind direction degrees to compass label */\n function windDirectionLabel(deg: number): string {\n const dirs = ['N', 'NE', 'E', 'SE', 'S', 'SO', 'O', 'NO']\n return dirs[Math.round(deg / 45) % 8]\n }\n</script>\n\n<template>\n <div\n v-if=\"data\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden bg-surface\">\n <!-- Header -->\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8 min-h-40\">\n <VvIcon name=\"ri:temp-cold-line\" class=\"text-16\" />\n <strong class=\"font-bold truncate\">\n {{ data.locationName }}\n </strong>\n <span class=\"ml-auto shrink-0 capitalize\">\n {{ headerDate }}\n </span>\n </div>\n\n <!-- Current conditions (only when real-time current is available AND first day is selected) -->\n <div\n v-if=\"data.current && selectedDayIndex === 0\"\n class=\"px-sm py-md flex items-center gap-md flex-wrap\">\n <div class=\"flex items-center gap-8\">\n <VvIcon\n :name=\"wmoToIcon(data.current.weatherCode)\"\n class=\"text-48 text-word-2 shrink-0\" />\n <span class=\"text-48 font-light leading-none text-word-1\">\n {{ $n(data.current.temperature, 'integer') }}°\n </span>\n </div>\n <div class=\"flex flex-col gap-4 text-12 text-word-3\">\n <div class=\"flex items-center gap-6\">\n {{ $t('weather.feelsLike') }}\n {{ $n(data.current.feelsLike, 'integer') }}°\n </div>\n <div class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:water-percent-line\" class=\"text-14\" />\n {{ data.current.humidity }}%\n </div>\n <div class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:windy-line\" class=\"text-14\" />\n {{ $n(data.current.windSpeed, 'integer') }} km/h\n {{ windDirectionLabel(data.current.windDirection) }}\n </div>\n <div\n v-if=\"data.current.uvIndex > 0\"\n class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:sun-line\" class=\"text-14\" />\n UV {{ $n(data.current.uvIndex, 'integer') }}\n </div>\n </div>\n </div>\n\n <!-- Day summary (when no real-time current, or a non-today day is selected) -->\n <div\n v-else-if=\"selectedDay\"\n class=\"px-sm py-md flex items-center gap-md flex-wrap\">\n <div class=\"flex items-center gap-8\">\n <VvIcon\n :name=\"wmoToIcon(selectedDay.weatherCode)\"\n class=\"text-48 text-word-2 shrink-0\" />\n <div class=\"flex flex-col leading-none\">\n <span class=\"text-48 font-light text-word-1\">\n {{ $n(selectedDay.maxTemp, 'integer') }}°\n </span>\n <span class=\"text-20 text-word-3\">\n {{ $n(selectedDay.minTemp, 'integer') }}°\n </span>\n </div>\n </div>\n <div class=\"flex flex-col gap-4 text-12 text-word-3\">\n <div\n v-if=\"selectedDay.precipitationProbabilityMax > 0\"\n class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:drop-line\" class=\"text-14\" />\n {{ selectedDay.precipitationProbabilityMax }}% ({{\n selectedDay.precipitationSum\n }}\n mm)\n </div>\n <div\n v-if=\"selectedDay.uvIndexMax > 0\"\n class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:sun-line\" class=\"text-14\" />\n UV {{ $n(selectedDay.uvIndexMax, 'integer') }}\n </div>\n <div class=\"flex items-center gap-6\">\n <VvIcon name=\"ri:sun-foggy-line\" class=\"text-14\" />\n {{ $d(safeDate(selectedDay.sunrise), 'time') }}\n –\n {{ $d(safeDate(selectedDay.sunset), 'time') }}\n </div>\n </div>\n </div>\n\n <!-- Hourly forecast (filtered to selected day) -->\n <transition>\n <div\n v-if=\"filteredHourly.length > 0\"\n class=\"border-t border-surface-3\">\n <div\n class=\"flex overflow-x-auto gap-2 px-sm py-8 light-scrollbar\">\n <div\n v-for=\"hour in filteredHourly\"\n :key=\"hour.time\"\n class=\"flex flex-col items-center gap-4 min-w-48 px-4 py-6 rounded-xl text-11 text-word-3 shrink-0\">\n <span class=\"text-word-3\">{{\n Number.isNaN(safeDate(hour.time).getTime())\n ? hour.time\n : $d(safeDate(hour.time), 'time')\n }}</span>\n <VvIcon\n :name=\"wmoToIcon(hour.weatherCode)\"\n class=\"text-20 text-word-2\" />\n <span class=\"font-medium text-word-1\">\n {{ $n(hour.temperature, 'integer') }}°\n </span>\n <span\n v-if=\"hour.precipitationProbability > 0\"\n class=\"text-word-5 text-smaller\">\n {{ hour.precipitationProbability }}%\n </span>\n </div>\n </div>\n </div>\n </transition>\n\n <!-- Daily forecast (clickable, inside accordion) -->\n <transition>\n <VvAccordion\n v-if=\"data.daily?.length > 1\"\n v-model=\"dailyOpen\"\n modifiers=\"details no-padding\"\n :title=\"$t('weather.dailyForecast')\"\n class=\"border-t border-surface-3\">\n <button\n v-for=\"(day, index) in data.daily\"\n :key=\"day.date\"\n type=\"button\"\n class=\"flex items-center gap-sm px-sm py-8 text-12 w-full text-left transition-colors cursor-pointer border-t border-surface-3\"\n :class=\"\n index === selectedDayIndex\n ? 'bg-surface-2'\n : 'hover:bg-surface-1'\n \"\n @click=\"selectedDayIndex = index\">\n <span class=\"w-48 shrink-0 text-word-3 capitalize\">\n {{ formatDay(day.date, index, data.daily.length) }}\n </span>\n <VvIcon\n :name=\"wmoToIcon(day.weatherCode)\"\n class=\"text-18 text-word-2 shrink-0\" />\n <span\n v-if=\"day.precipitationProbabilityMax > 0\"\n class=\"text-word-5 text-11 w-32 shrink-0\">\n {{ day.precipitationProbabilityMax }}%\n </span>\n <span v-else class=\"w-32 shrink-0\" />\n <div class=\"ml-auto flex items-center gap-8 text-word-3\">\n <span class=\"text-word-1 font-semibold\">\n {{ $n(day.maxTemp, 'integer') }}°\n </span>\n <span>{{ $n(day.minTemp, 'integer') }}°</span>\n </div>\n </button>\n </VvAccordion>\n </transition>\n\n <!-- Air quality -->\n <div\n v-if=\"data.airQuality\"\n class=\"border-t border-surface-3 px-sm py-8 flex items-center gap-8 text-12\">\n <VvIcon name=\"ri:windy-line\" class=\"text-14 text-word-3\" />\n <span class=\"text-word-3\">{{ $t('weather.airQuality') }}</span>\n <span\n :class=\"[\n 'ml-auto px-8 py-2 text-11 font-semibold',\n aqiInfo(data.airQuality.aqi).class,\n ]\">\n {{ aqiInfo(data.airQuality.aqi).label }}\n ({{ data.airQuality.aqi }})\n </span>\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { t as e } from "./rolldown-runtime-Dy4uBu1J.js";
|
|
|
2
2
|
import "./src-DT8FLE4_.js";
|
|
3
3
|
import { n as t } from "./url-validation-uLMZ5-AU.js";
|
|
4
4
|
import { t as n } from "./PkLazyImg-CDxX9xnq.js";
|
|
5
|
-
import { t as r } from "./PkUrl-
|
|
5
|
+
import { t as r } from "./PkUrl-B5CNTQj9.js";
|
|
6
6
|
import { VvIcon as i } from "@volverjs/ui-vue/components";
|
|
7
7
|
import { Fragment as a, computed as o, createBlock as s, createCommentVNode as c, createElementBlock as l, createElementVNode as u, createTextVNode as d, createVNode as f, defineComponent as p, openBlock as m, ref as h, renderList as g, toDisplayString as _, unref as v } from "vue";
|
|
8
8
|
//#region ../../packages/components/src/chat/PkToolShowWebPages.vue?vue&type=script&setup=true&lang.ts
|
|
@@ -76,4 +76,4 @@ var y = {
|
|
|
76
76
|
//#endregion
|
|
77
77
|
export { D as n, O as t };
|
|
78
78
|
|
|
79
|
-
//# sourceMappingURL=PkToolShowWebPages-
|
|
79
|
+
//# sourceMappingURL=PkToolShowWebPages-CosBYLrE.js.map
|
package/dist-vue/_chunks/{PkToolShowWebPages-Bzkkn9GV.js.map → PkToolShowWebPages-CosBYLrE.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PkToolShowWebPages-Bzkkn9GV.js","names":["$t"],"sources":["../../../../packages/components/src/chat/PkToolShowWebPages.vue","../../../../packages/components/src/chat/PkToolShowWebPages.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed, ref } from 'vue'\n import { isSameSite } from 'utils'\n import PkLazyImg from '../PkLazyImg.vue'\n import PkUrl from '../PkUrl.vue'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n pages: Array<{\n title: string\n url: string\n image?: string\n description?: string\n }>\n }\n }\n return part\n })\n\n // The model often passes the same URL several times (e.g. multiple KB\n // chunks from one page), so collapse duplicates, keeping the first (richest)\n // entry. Normalize by dropping the hash and any trailing slash.\n const normalizeUrl = (url: string) => {\n try {\n const u = new URL(url)\n u.hash = ''\n return u.toString().replace(/\\/$/, '')\n } catch {\n return url.trim().replace(/\\/$/, '')\n }\n }\n const uniquePages = computed(() => {\n const seen = new Set<string>()\n const result: NonNullable<typeof toolPart.value.input>['pages'] = []\n for (const page of toolPart.value.input?.pages || []) {\n const key = normalizeUrl(page.url)\n if (seen.has(key)) {\n continue\n }\n seen.add(key)\n result.push(page)\n }\n return result\n })\n\n const showMore = ref(false)\n const pages = computed(() => {\n if (showMore.value) {\n return uniquePages.value\n }\n return uniquePages.value.slice(0, 2)\n })\n const hasMore = computed(() => uniquePages.value.length > 2)\n</script>\n\n<template>\n <ul v-if=\"pages?.length\" class=\"u-pick-list w-full shrink-0\">\n <li\n v-for=\"(page, index) in pages\"\n :key=\"index\"\n class=\"u-pick-list__row\">\n <a\n :href=\"page.url\"\n :title=\"$t('action.open')\"\n :target=\"isSameSite(page.url) ? undefined : '_blank'\"\n :rel=\"isSameSite(page.url) ? undefined : 'noopener noreferrer'\"\n class=\"u-pick-list__entry u-pick-list__entry--roomy u-pick-list__entry--top\">\n <!-- og:images the model scraped are third-party urls: a dead one\n degrades to an icon instead of breaking the card layout -->\n <PkLazyImg\n v-if=\"page.image\"\n :src=\"page.image\"\n :alt=\"page.title\"\n fallback-icon=\"ri:image-off-line\"\n class=\"w-48 h-48 object-contain rounded-lg shrink-0 border border-surface-3 bg-surface\" />\n <div class=\"flex flex-col gap-4 min-w-0 flex-1\">\n <strong\n class=\"u-pick-list__label font-medium text-12 text-word-1\">\n {{ page.title }}\n </strong>\n <span\n class=\"text-10 text-word-4 truncate flex items-center gap-4\">\n <VvIcon name=\"ri:link\" class=\"shrink-0 text-12\" />\n <PkUrl :url=\"page.url\" />\n </span>\n <p\n v-if=\"page.description\"\n class=\"text-12 text-word-3 line-clamp-2\">\n {{ page.description }}\n </p>\n </div>\n </a>\n </li>\n <li v-if=\"hasMore\" class=\"u-pick-list__row\">\n <button\n class=\"u-pick-list__entry text-12 text-word-3 justify-center cursor-pointer\"\n @click=\"showMore = !showMore\">\n <VvIcon\n :name=\"\n showMore ? 'ri:arrow-up-s-line' : 'ri:arrow-down-s-line'\n \"\n class=\"text-16\" />\n {{\n showMore\n ? $t('action.showLess')\n : $t('action.showMore', {\n count: uniquePages.length - 2,\n })\n }}\n </button>\n </li>\n </ul>\n</template>\n","<script setup lang=\"ts\">\n import { computed, ref } from 'vue'\n import { isSameSite } from 'utils'\n import PkLazyImg from '../PkLazyImg.vue'\n import PkUrl from '../PkUrl.vue'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n pages: Array<{\n title: string\n url: string\n image?: string\n description?: string\n }>\n }\n }\n return part\n })\n\n // The model often passes the same URL several times (e.g. multiple KB\n // chunks from one page), so collapse duplicates, keeping the first (richest)\n // entry. Normalize by dropping the hash and any trailing slash.\n const normalizeUrl = (url: string) => {\n try {\n const u = new URL(url)\n u.hash = ''\n return u.toString().replace(/\\/$/, '')\n } catch {\n return url.trim().replace(/\\/$/, '')\n }\n }\n const uniquePages = computed(() => {\n const seen = new Set<string>()\n const result: NonNullable<typeof toolPart.value.input>['pages'] = []\n for (const page of toolPart.value.input?.pages || []) {\n const key = normalizeUrl(page.url)\n if (seen.has(key)) {\n continue\n }\n seen.add(key)\n result.push(page)\n }\n return result\n })\n\n const showMore = ref(false)\n const pages = computed(() => {\n if (showMore.value) {\n return uniquePages.value\n }\n return uniquePages.value.slice(0, 2)\n })\n const hasMore = computed(() => uniquePages.value.length > 2)\n</script>\n\n<template>\n <ul v-if=\"pages?.length\" class=\"u-pick-list w-full shrink-0\">\n <li\n v-for=\"(page, index) in pages\"\n :key=\"index\"\n class=\"u-pick-list__row\">\n <a\n :href=\"page.url\"\n :title=\"$t('action.open')\"\n :target=\"isSameSite(page.url) ? undefined : '_blank'\"\n :rel=\"isSameSite(page.url) ? undefined : 'noopener noreferrer'\"\n class=\"u-pick-list__entry u-pick-list__entry--roomy u-pick-list__entry--top\">\n <!-- og:images the model scraped are third-party urls: a dead one\n degrades to an icon instead of breaking the card layout -->\n <PkLazyImg\n v-if=\"page.image\"\n :src=\"page.image\"\n :alt=\"page.title\"\n fallback-icon=\"ri:image-off-line\"\n class=\"w-48 h-48 object-contain rounded-lg shrink-0 border border-surface-3 bg-surface\" />\n <div class=\"flex flex-col gap-4 min-w-0 flex-1\">\n <strong\n class=\"u-pick-list__label font-medium text-12 text-word-1\">\n {{ page.title }}\n </strong>\n <span\n class=\"text-10 text-word-4 truncate flex items-center gap-4\">\n <VvIcon name=\"ri:link\" class=\"shrink-0 text-12\" />\n <PkUrl :url=\"page.url\" />\n </span>\n <p\n v-if=\"page.description\"\n class=\"text-12 text-word-3 line-clamp-2\">\n {{ page.description }}\n </p>\n </div>\n </a>\n </li>\n <li v-if=\"hasMore\" class=\"u-pick-list__row\">\n <button\n class=\"u-pick-list__entry text-12 text-word-3 justify-center cursor-pointer\"\n @click=\"showMore = !showMore\">\n <VvIcon\n :name=\"\n showMore ? 'ri:arrow-up-s-line' : 'ri:arrow-down-s-line'\n \"\n class=\"text-16\" />\n {{\n showMore\n ? $t('action.showLess')\n : $t('action.showMore', {\n count: uniquePages.length - 2,\n })\n }}\n </button>\n </li>\n </ul>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;EAMI,IAAM,IAAQ,GAIR,IAAW,QACA,EAAM,IAWtB,GAKK,KAAgB,MAAgB;GAClC,IAAI;IACA,IAAM,IAAI,IAAI,IAAI,CAAG;IAErB,OADA,EAAE,OAAO,IACF,EAAE,SAAS,CAAC,CAAC,QAAQ,OAAO,EAAE;GACzC,QAAQ;IACJ,OAAO,EAAI,KAAK,CAAC,CAAC,QAAQ,OAAO,EAAE;GACvC;EACJ,GACM,IAAc,QAAe;GAC/B,IAAM,oBAAO,IAAI,IAAY,GACvB,IAA4D,CAAC;GACnE,KAAK,IAAM,KAAQ,EAAS,MAAM,OAAO,SAAS,CAAC,GAAG;IAClD,IAAM,IAAM,EAAa,EAAK,GAAG;IAC7B,EAAK,IAAI,CAAG,MAGhB,EAAK,IAAI,CAAG,GACZ,EAAO,KAAK,CAAI;GACpB;GACA,OAAO;EACX,CAAC,GAEK,IAAW,EAAI,EAAK,GACpB,IAAQ,QACN,EAAS,QACF,EAAY,QAEhB,EAAY,MAAM,MAAM,GAAG,CAAC,CACtC,GACK,IAAU,QAAe,EAAY,MAAM,SAAS,CAAC;;;GAIjD,OAAA,EAAA,OAAO,UAAjB,EAAA,GAAA,EAuDK,MAvDL,GAuDK,EAtDD,EAAA,EAAA,GAAA,EAmCK,GAAA,MAAA,EAlCuB,EAAA,QAAhB,GAAM,OADlB,EAAA,GAAA,EAmCK,MAAA;IAjCA,KAAK;IACN,OAAM;GACN,GAAA,CAAA,EA8BI,KAAA;IA7BC,MAAM,EAAK;IACX,OAAOA,EAAAA,GAAE,aAAA;IACT,QAAQ,EAAA,CAAA,CAAU,CAAC,EAAK,GAAG,IAAI,KAAA,IAAS;IACxC,KAAK,EAAA,CAAA,CAAU,CAAC,EAAK,GAAG,IAAI,KAAA,IAAS;IACtC,OAAM;GAII,GAAA,CAAA,EAAK,SADf,EAAA,GAAA,EAK8F,GAAA;;IAHzF,KAAK,EAAK;IACV,KAAK,EAAK;IACX,iBAAc;IACd,OAAM;GACV,GAAA,MAAA,GAAA,CAAA,OAAA,KAAA,CAAA,KAAA,EAAA,IAAA,EAAA,GAAA,EAeM,OAfN,GAeM;IAdF,EAGS,UAHT,GAGS,EADF,EAAK,KAAK,GAAA,CAAA;IAEjB,EAIO,QAJP,GAIO,CAFH,EAAkD,GAAA;KAA1C,MAAK;KAAU,OAAM;IAC7B,CAAA,GAAA,EAAyB,GAAA,EAAjB,KAAK,EAAK,IAAA,GAAA,MAAA,GAAA,CAAA,KAAA,CAAA,CAAA,CAAA;IAGZ,EAAK,eADf,EAAA,GAAA,EAII,KAJJ,GAII,EADG,EAAK,WAAW,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA;gBAKzB,GAAA,GAAA,IAAA,EAAA,SAAV,EAAA,GAAA,EAiBK,MAjBL,GAiBK,CAhBD,EAeS,UAAA;IAdL,OAAM;IACL,SAAK,AAAA,EAAA,QAAA,MAAE,EAAA,QAAQ,CAAI,EAAA;GACpB,GAAA,CAAA,EAIsB,GAAA;IAHjB,MAA+B,EAAA,QAAQ,uBAAA;IAGxC,OAAM;GAAY,GAAA,MAAA,GAAA,CAAA,MAAA,CAAA,GAAA,EAAA,MACtB,EACI,EAAA,QAAmCA,EAAAA,GAAE,iBAAA,IAA8CA,EAAAA,GAAE,mBAAA,EAA2D,OAAA,EAAA,MAAY,SAAM,EAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA"}
|
|
1
|
+
{"version":3,"file":"PkToolShowWebPages-CosBYLrE.js","names":["$t"],"sources":["../../../../packages/components/src/chat/PkToolShowWebPages.vue","../../../../packages/components/src/chat/PkToolShowWebPages.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed, ref } from 'vue'\n import { isSameSite } from 'utils'\n import PkLazyImg from '../PkLazyImg.vue'\n import PkUrl from '../PkUrl.vue'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n pages: Array<{\n title: string\n url: string\n image?: string\n description?: string\n }>\n }\n }\n return part\n })\n\n // The model often passes the same URL several times (e.g. multiple KB\n // chunks from one page), so collapse duplicates, keeping the first (richest)\n // entry. Normalize by dropping the hash and any trailing slash.\n const normalizeUrl = (url: string) => {\n try {\n const u = new URL(url)\n u.hash = ''\n return u.toString().replace(/\\/$/, '')\n } catch {\n return url.trim().replace(/\\/$/, '')\n }\n }\n const uniquePages = computed(() => {\n const seen = new Set<string>()\n const result: NonNullable<typeof toolPart.value.input>['pages'] = []\n for (const page of toolPart.value.input?.pages || []) {\n const key = normalizeUrl(page.url)\n if (seen.has(key)) {\n continue\n }\n seen.add(key)\n result.push(page)\n }\n return result\n })\n\n const showMore = ref(false)\n const pages = computed(() => {\n if (showMore.value) {\n return uniquePages.value\n }\n return uniquePages.value.slice(0, 2)\n })\n const hasMore = computed(() => uniquePages.value.length > 2)\n</script>\n\n<template>\n <ul v-if=\"pages?.length\" class=\"u-pick-list w-full shrink-0\">\n <li\n v-for=\"(page, index) in pages\"\n :key=\"index\"\n class=\"u-pick-list__row\">\n <a\n :href=\"page.url\"\n :title=\"$t('action.open')\"\n :target=\"isSameSite(page.url) ? undefined : '_blank'\"\n :rel=\"isSameSite(page.url) ? undefined : 'noopener noreferrer'\"\n class=\"u-pick-list__entry u-pick-list__entry--roomy u-pick-list__entry--top\">\n <!-- og:images the model scraped are third-party urls: a dead one\n degrades to an icon instead of breaking the card layout -->\n <PkLazyImg\n v-if=\"page.image\"\n :src=\"page.image\"\n :alt=\"page.title\"\n fallback-icon=\"ri:image-off-line\"\n class=\"w-48 h-48 object-contain rounded-lg shrink-0 border border-surface-3 bg-surface\" />\n <div class=\"flex flex-col gap-4 min-w-0 flex-1\">\n <strong\n class=\"u-pick-list__label font-medium text-12 text-word-1\">\n {{ page.title }}\n </strong>\n <span\n class=\"text-10 text-word-4 truncate flex items-center gap-4\">\n <VvIcon name=\"ri:link\" class=\"shrink-0 text-12\" />\n <PkUrl :url=\"page.url\" />\n </span>\n <p\n v-if=\"page.description\"\n class=\"text-12 text-word-3 line-clamp-2\">\n {{ page.description }}\n </p>\n </div>\n </a>\n </li>\n <li v-if=\"hasMore\" class=\"u-pick-list__row\">\n <button\n class=\"u-pick-list__entry text-12 text-word-3 justify-center cursor-pointer\"\n @click=\"showMore = !showMore\">\n <VvIcon\n :name=\"\n showMore ? 'ri:arrow-up-s-line' : 'ri:arrow-down-s-line'\n \"\n class=\"text-16\" />\n {{\n showMore\n ? $t('action.showLess')\n : $t('action.showMore', {\n count: uniquePages.length - 2,\n })\n }}\n </button>\n </li>\n </ul>\n</template>\n","<script setup lang=\"ts\">\n import { computed, ref } from 'vue'\n import { isSameSite } from 'utils'\n import PkLazyImg from '../PkLazyImg.vue'\n import PkUrl from '../PkUrl.vue'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n pages: Array<{\n title: string\n url: string\n image?: string\n description?: string\n }>\n }\n }\n return part\n })\n\n // The model often passes the same URL several times (e.g. multiple KB\n // chunks from one page), so collapse duplicates, keeping the first (richest)\n // entry. Normalize by dropping the hash and any trailing slash.\n const normalizeUrl = (url: string) => {\n try {\n const u = new URL(url)\n u.hash = ''\n return u.toString().replace(/\\/$/, '')\n } catch {\n return url.trim().replace(/\\/$/, '')\n }\n }\n const uniquePages = computed(() => {\n const seen = new Set<string>()\n const result: NonNullable<typeof toolPart.value.input>['pages'] = []\n for (const page of toolPart.value.input?.pages || []) {\n const key = normalizeUrl(page.url)\n if (seen.has(key)) {\n continue\n }\n seen.add(key)\n result.push(page)\n }\n return result\n })\n\n const showMore = ref(false)\n const pages = computed(() => {\n if (showMore.value) {\n return uniquePages.value\n }\n return uniquePages.value.slice(0, 2)\n })\n const hasMore = computed(() => uniquePages.value.length > 2)\n</script>\n\n<template>\n <ul v-if=\"pages?.length\" class=\"u-pick-list w-full shrink-0\">\n <li\n v-for=\"(page, index) in pages\"\n :key=\"index\"\n class=\"u-pick-list__row\">\n <a\n :href=\"page.url\"\n :title=\"$t('action.open')\"\n :target=\"isSameSite(page.url) ? undefined : '_blank'\"\n :rel=\"isSameSite(page.url) ? undefined : 'noopener noreferrer'\"\n class=\"u-pick-list__entry u-pick-list__entry--roomy u-pick-list__entry--top\">\n <!-- og:images the model scraped are third-party urls: a dead one\n degrades to an icon instead of breaking the card layout -->\n <PkLazyImg\n v-if=\"page.image\"\n :src=\"page.image\"\n :alt=\"page.title\"\n fallback-icon=\"ri:image-off-line\"\n class=\"w-48 h-48 object-contain rounded-lg shrink-0 border border-surface-3 bg-surface\" />\n <div class=\"flex flex-col gap-4 min-w-0 flex-1\">\n <strong\n class=\"u-pick-list__label font-medium text-12 text-word-1\">\n {{ page.title }}\n </strong>\n <span\n class=\"text-10 text-word-4 truncate flex items-center gap-4\">\n <VvIcon name=\"ri:link\" class=\"shrink-0 text-12\" />\n <PkUrl :url=\"page.url\" />\n </span>\n <p\n v-if=\"page.description\"\n class=\"text-12 text-word-3 line-clamp-2\">\n {{ page.description }}\n </p>\n </div>\n </a>\n </li>\n <li v-if=\"hasMore\" class=\"u-pick-list__row\">\n <button\n class=\"u-pick-list__entry text-12 text-word-3 justify-center cursor-pointer\"\n @click=\"showMore = !showMore\">\n <VvIcon\n :name=\"\n showMore ? 'ri:arrow-up-s-line' : 'ri:arrow-down-s-line'\n \"\n class=\"text-16\" />\n {{\n showMore\n ? $t('action.showLess')\n : $t('action.showMore', {\n count: uniquePages.length - 2,\n })\n }}\n </button>\n </li>\n </ul>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;EAMI,IAAM,IAAQ,GAIR,IAAW,QACA,EAAM,IAWtB,GAKK,KAAgB,MAAgB;GAClC,IAAI;IACA,IAAM,IAAI,IAAI,IAAI,CAAG;IAErB,OADA,EAAE,OAAO,IACF,EAAE,SAAS,CAAC,CAAC,QAAQ,OAAO,EAAE;GACzC,QAAQ;IACJ,OAAO,EAAI,KAAK,CAAC,CAAC,QAAQ,OAAO,EAAE;GACvC;EACJ,GACM,IAAc,QAAe;GAC/B,IAAM,oBAAO,IAAI,IAAY,GACvB,IAA4D,CAAC;GACnE,KAAK,IAAM,KAAQ,EAAS,MAAM,OAAO,SAAS,CAAC,GAAG;IAClD,IAAM,IAAM,EAAa,EAAK,GAAG;IAC7B,EAAK,IAAI,CAAG,MAGhB,EAAK,IAAI,CAAG,GACZ,EAAO,KAAK,CAAI;GACpB;GACA,OAAO;EACX,CAAC,GAEK,IAAW,EAAI,EAAK,GACpB,IAAQ,QACN,EAAS,QACF,EAAY,QAEhB,EAAY,MAAM,MAAM,GAAG,CAAC,CACtC,GACK,IAAU,QAAe,EAAY,MAAM,SAAS,CAAC;;;GAIjD,OAAA,EAAA,OAAO,UAAjB,EAAA,GAAA,EAuDK,MAvDL,GAuDK,EAtDD,EAAA,EAAA,GAAA,EAmCK,GAAA,MAAA,EAlCuB,EAAA,QAAhB,GAAM,OADlB,EAAA,GAAA,EAmCK,MAAA;IAjCA,KAAK;IACN,OAAM;GACN,GAAA,CAAA,EA8BI,KAAA;IA7BC,MAAM,EAAK;IACX,OAAOA,EAAAA,GAAE,aAAA;IACT,QAAQ,EAAA,CAAA,CAAU,CAAC,EAAK,GAAG,IAAI,KAAA,IAAS;IACxC,KAAK,EAAA,CAAA,CAAU,CAAC,EAAK,GAAG,IAAI,KAAA,IAAS;IACtC,OAAM;GAII,GAAA,CAAA,EAAK,SADf,EAAA,GAAA,EAK8F,GAAA;;IAHzF,KAAK,EAAK;IACV,KAAK,EAAK;IACX,iBAAc;IACd,OAAM;GACV,GAAA,MAAA,GAAA,CAAA,OAAA,KAAA,CAAA,KAAA,EAAA,IAAA,EAAA,GAAA,EAeM,OAfN,GAeM;IAdF,EAGS,UAHT,GAGS,EADF,EAAK,KAAK,GAAA,CAAA;IAEjB,EAIO,QAJP,GAIO,CAFH,EAAkD,GAAA;KAA1C,MAAK;KAAU,OAAM;IAC7B,CAAA,GAAA,EAAyB,GAAA,EAAjB,KAAK,EAAK,IAAA,GAAA,MAAA,GAAA,CAAA,KAAA,CAAA,CAAA,CAAA;IAGZ,EAAK,eADf,EAAA,GAAA,EAII,KAJJ,GAII,EADG,EAAK,WAAW,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA;gBAKzB,GAAA,GAAA,IAAA,EAAA,SAAV,EAAA,GAAA,EAiBK,MAjBL,GAiBK,CAhBD,EAeS,UAAA;IAdL,OAAM;IACL,SAAK,AAAA,EAAA,QAAA,MAAE,EAAA,QAAQ,CAAI,EAAA;GACpB,GAAA,CAAA,EAIsB,GAAA;IAHjB,MAA+B,EAAA,QAAQ,uBAAA;IAGxC,OAAM;GAAY,GAAA,MAAA,GAAA,CAAA,MAAA,CAAA,GAAA,EAAA,MACtB,EACI,EAAA,QAAmCA,EAAAA,GAAE,iBAAA,IAA8CA,EAAAA,GAAE,mBAAA,EAA2D,OAAA,EAAA,MAAY,SAAM,EAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,CAAA,KAAA,EAAA,IAAA,EAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as e } from "./PkStreamingMarkdown-
|
|
1
|
+
import { r as e } from "./PkStreamingMarkdown-D0IOaETI.js";
|
|
2
2
|
import { Fragment as t, computed as n, createBlock as r, createElementBlock as i, createElementVNode as a, defineComponent as o, normalizeClass as s, openBlock as c, renderList as l, resolveDynamicComponent as u, toDisplayString as d, withCtx as f } from "vue";
|
|
3
3
|
//#region ../../packages/components/src/PkUrl.vue?vue&type=script&setup=true&lang.ts
|
|
4
4
|
var p = {
|
|
@@ -80,4 +80,4 @@ var p = {
|
|
|
80
80
|
//#endregion
|
|
81
81
|
export { h as t };
|
|
82
82
|
|
|
83
|
-
//# sourceMappingURL=PkUrl-
|
|
83
|
+
//# sourceMappingURL=PkUrl-B5CNTQj9.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PkUrl-B5CNTQj9.js","names":[],"sources":["../../../../packages/components/src/PkUrl.vue","../../../../packages/components/src/PkUrl.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { useShortUrlResolver } from 'composables'\n\n interface Props {\n url: string\n maxLength?: number\n domainClass?: string\n target?: '_blank' | '_self' | '_parent' | '_top'\n rel?: string\n muted?: boolean\n }\n\n const props = withDefaults(defineProps<Props>(), {\n maxLength: 60,\n domainClass: undefined,\n target: '_blank',\n rel: 'noopener noreferrer',\n muted: false,\n })\n\n // Only the displayed URL text is resolved to its real target; the href is\n // kept as the short url so the redirect endpoint still handles tracking.\n const { resolve } = useShortUrlResolver()\n const resolved = resolve(() => props.url)\n const displayUrl = computed(() => resolved.value.url)\n const isResolving = computed(() => resolved.value.loading)\n\n const parsedUrl = computed(() => {\n try {\n const urlObj = new URL(displayUrl.value ?? props.url)\n let hostname = urlObj.hostname\n\n // Remove www. prefix\n if (hostname.startsWith('www.')) {\n hostname = hostname.substring(4)\n }\n\n // Get pathname and remove trailing slash\n let pathname = urlObj.pathname\n if (pathname === '/') {\n pathname = ''\n }\n\n // Split pathname into segments\n const segments = pathname\n .split('/')\n .filter((segment) => segment.length > 0)\n\n return {\n domain: hostname,\n segments,\n fullPath: hostname + pathname,\n }\n } catch {\n // If URL parsing fails, return the original URL\n const fallback = displayUrl.value ?? props.url\n return {\n domain: fallback,\n segments: [],\n fullPath: fallback,\n }\n }\n })\n\n const truncatedUrl = computed(() => {\n if (parsedUrl.value.fullPath.length <= props.maxLength) {\n return parsedUrl.value\n }\n\n // If too long, truncate segments from the beginning\n const domain = parsedUrl.value.domain\n const allSegments = parsedUrl.value.segments\n\n // Always show at least the last segment\n if (allSegments.length === 0) {\n return {\n domain,\n segments: [],\n fullPath: domain,\n }\n }\n\n const segments: string[] = []\n\n // Calculate from the end\n let currentLength = domain.length\n\n // Try to fit segments from the end\n for (let i = allSegments.length - 1; i >= 0; i--) {\n const segment = allSegments[i]\n\n // Always include at least the last segment\n if (segments.length === 0) {\n currentLength += segment.length + 1\n segments.unshift(segment)\n } else if (currentLength + segment.length + 1 <= props.maxLength) {\n currentLength += segment.length + 1\n segments.unshift(segment)\n } else {\n segments.unshift('...')\n break\n }\n }\n\n return {\n domain,\n segments,\n fullPath: domain + '/' + segments.join('/'),\n }\n })\n</script>\n\n<template>\n <Component\n :is=\"muted ? 'span' : 'a'\"\n class=\"pk-url\"\n :href=\"muted ? undefined : props.url\"\n :target=\"muted ? undefined : props.target\"\n :rel=\"muted ? undefined : props.rel\">\n <span v-if=\"isResolving\" class=\"pk-url__skeleton vv-skeleton\">\n <span class=\"vv-skeleton__item\" />\n </span>\n <template v-else>\n <span :class=\"['pk-url__domain', domainClass]\">{{\n truncatedUrl.domain\n }}</span>\n <template\n v-for=\"(segment, index) in truncatedUrl.segments\"\n :key=\"index\">\n <span class=\"pk-url__separator\">›</span>\n <span class=\"pk-url__segment\">{{ segment }}</span>\n </template>\n </template>\n </Component>\n</template>\n\n<style lang=\"scss\">\n @layer volver.components {\n .pk-url {\n display: inline-flex;\n align-items: center;\n gap: 0.5ch;\n }\n\n .pk-url__skeleton {\n display: inline-flex;\n width: 12ch;\n max-width: 100%;\n\n .vv-skeleton__item {\n width: 100%;\n height: 1em;\n border-radius: 0.25em;\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { useShortUrlResolver } from 'composables'\n\n interface Props {\n url: string\n maxLength?: number\n domainClass?: string\n target?: '_blank' | '_self' | '_parent' | '_top'\n rel?: string\n muted?: boolean\n }\n\n const props = withDefaults(defineProps<Props>(), {\n maxLength: 60,\n domainClass: undefined,\n target: '_blank',\n rel: 'noopener noreferrer',\n muted: false,\n })\n\n // Only the displayed URL text is resolved to its real target; the href is\n // kept as the short url so the redirect endpoint still handles tracking.\n const { resolve } = useShortUrlResolver()\n const resolved = resolve(() => props.url)\n const displayUrl = computed(() => resolved.value.url)\n const isResolving = computed(() => resolved.value.loading)\n\n const parsedUrl = computed(() => {\n try {\n const urlObj = new URL(displayUrl.value ?? props.url)\n let hostname = urlObj.hostname\n\n // Remove www. prefix\n if (hostname.startsWith('www.')) {\n hostname = hostname.substring(4)\n }\n\n // Get pathname and remove trailing slash\n let pathname = urlObj.pathname\n if (pathname === '/') {\n pathname = ''\n }\n\n // Split pathname into segments\n const segments = pathname\n .split('/')\n .filter((segment) => segment.length > 0)\n\n return {\n domain: hostname,\n segments,\n fullPath: hostname + pathname,\n }\n } catch {\n // If URL parsing fails, return the original URL\n const fallback = displayUrl.value ?? props.url\n return {\n domain: fallback,\n segments: [],\n fullPath: fallback,\n }\n }\n })\n\n const truncatedUrl = computed(() => {\n if (parsedUrl.value.fullPath.length <= props.maxLength) {\n return parsedUrl.value\n }\n\n // If too long, truncate segments from the beginning\n const domain = parsedUrl.value.domain\n const allSegments = parsedUrl.value.segments\n\n // Always show at least the last segment\n if (allSegments.length === 0) {\n return {\n domain,\n segments: [],\n fullPath: domain,\n }\n }\n\n const segments: string[] = []\n\n // Calculate from the end\n let currentLength = domain.length\n\n // Try to fit segments from the end\n for (let i = allSegments.length - 1; i >= 0; i--) {\n const segment = allSegments[i]\n\n // Always include at least the last segment\n if (segments.length === 0) {\n currentLength += segment.length + 1\n segments.unshift(segment)\n } else if (currentLength + segment.length + 1 <= props.maxLength) {\n currentLength += segment.length + 1\n segments.unshift(segment)\n } else {\n segments.unshift('...')\n break\n }\n }\n\n return {\n domain,\n segments,\n fullPath: domain + '/' + segments.join('/'),\n }\n })\n</script>\n\n<template>\n <Component\n :is=\"muted ? 'span' : 'a'\"\n class=\"pk-url\"\n :href=\"muted ? undefined : props.url\"\n :target=\"muted ? undefined : props.target\"\n :rel=\"muted ? undefined : props.rel\">\n <span v-if=\"isResolving\" class=\"pk-url__skeleton vv-skeleton\">\n <span class=\"vv-skeleton__item\" />\n </span>\n <template v-else>\n <span :class=\"['pk-url__domain', domainClass]\">{{\n truncatedUrl.domain\n }}</span>\n <template\n v-for=\"(segment, index) in truncatedUrl.segments\"\n :key=\"index\">\n <span class=\"pk-url__separator\">›</span>\n <span class=\"pk-url__segment\">{{ segment }}</span>\n </template>\n </template>\n </Component>\n</template>\n\n<style lang=\"scss\">\n @layer volver.components {\n .pk-url {\n display: inline-flex;\n align-items: center;\n gap: 0.5ch;\n }\n\n .pk-url__skeleton {\n display: inline-flex;\n width: 12ch;\n max-width: 100%;\n\n .vv-skeleton__item {\n width: 100%;\n height: 1em;\n border-radius: 0.25em;\n }\n }\n }\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAaI,IAAM,IAAQ,GAUR,EAAE,eAAY,EAAoB,GAClC,IAAW,QAAc,EAAM,GAAG,GAClC,IAAa,QAAe,EAAS,MAAM,GAAG,GAC9C,IAAc,QAAe,EAAS,MAAM,OAAO,GAEnD,IAAY,QAAe;GAC7B,IAAI;IACA,IAAM,IAAS,IAAI,IAAI,EAAW,SAAS,EAAM,GAAG,GAChD,IAAW,EAAO;IAGtB,AAAI,EAAS,WAAW,MAAM,MAC1B,IAAW,EAAS,UAAU,CAAC;IAInC,IAAI,IAAW,EAAO;IACtB,AAAI,MAAa,QACb,IAAW;IAIf,IAAM,IAAW,EACZ,MAAM,GAAG,CAAA,CACT,QAAQ,MAAY,EAAQ,SAAS,CAAC;IAE3C,OAAO;KACH,QAAQ;KACR;KACA,UAAU,IAAW;IACzB;GACJ,QAAQ;IAEJ,IAAM,IAAW,EAAW,SAAS,EAAM;IAC3C,OAAO;KACH,QAAQ;KACR,UAAU,CAAC;KACX,UAAU;IACd;GACJ;EACJ,CAAC,GAEK,IAAe,QAAe;GAChC,IAAI,EAAU,MAAM,SAAS,UAAU,EAAM,WACzC,OAAO,EAAU;GAIrB,IAAM,IAAS,EAAU,MAAM,QACzB,IAAc,EAAU,MAAM;GAGpC,IAAI,EAAY,WAAW,GACvB,OAAO;IACH;IACA,UAAU,CAAC;IACX,UAAU;GACd;GAGJ,IAAM,IAAqB,CAAC,GAGxB,IAAgB,EAAO;GAG3B,KAAK,IAAI,IAAI,EAAY,SAAS,GAAG,KAAK,GAAG,KAAK;IAC9C,IAAM,IAAU,EAAY;IAG5B,IAAI,EAAS,WAAW,GAEpB,AADA,KAAiB,EAAQ,SAAS,GAClC,EAAS,QAAQ,CAAO;SACrB,IAAI,IAAgB,EAAQ,SAAS,KAAK,EAAM,WAEnD,AADA,KAAiB,EAAQ,SAAS,GAClC,EAAS,QAAQ,CAAO;SACrB;KACH,EAAS,QAAQ,KAAK;KACtB;IACJ;GACJ;GAEA,OAAO;IACH;IACA;IACA,UAAU,IAAS,MAAM,EAAS,KAAK,GAAG;GAC9C;EACJ,CAAC;oBAID,EAAA,GAAA,EAoBY,EAnBH,EAAA,QAAK,SAAA,GAAA,GAAA;GACV,OAAM;GACL,MAAM,EAAA,QAAQ,KAAA,IAAY,EAAM;GAChC,QAAQ,EAAA,QAAQ,KAAA,IAAY,EAAM;GAClC,KAAK,EAAA,QAAQ,KAAA,IAAY,EAAM;;GAChC,SAAA,QAEO,CAFK,EAAA,SAAZ,EAAA,GAAA,EAEO,QAFP,GAEO,CAAA,GAAA,AAAA,EAAA,OAAA,CADH,EAAkC,QAAA,EAA5B,OAAM,oBAAmB,GAAA,MAAA,EAAA,CAAA,CAAA,CAAA,MAEnC,EAAA,GAAA,EAUW,GAAA,EAAA,KAAA,EAAA,GAAA,CATP,EAES,QAAA,EAFF,OAAK,EAAA,CAAA,kBAAqB,EAAA,WAAW,CAAA,EACxC,GAAA,EAAA,EAAA,MAAa,MAAM,GAAA,CAAA,IAEvB,EAAA,EAAA,GAAA,EAKW,GAAA,MAAA,EAJoB,EAAA,MAAa,WAAhC,GAAS,OACX,EAAA,GAAA,EAAA,GAAA,EAAA,KAAA,EAAK,GAAA,CACX,AAAA,EAAA,OAAA,EAAwC,QAAA,EAAlC,OAAM,oBAAmB,GAAC,KAAC,EAAA,GACjC,EAAkD,QAAlD,GAAkD,EAAjB,CAAO,GAAA,CAAA,CAAA,GAAA,EAAA"}
|
package/dist-vue/_chunks/{createChatbotApiClient-CJ_5_3IT.js → createChatbotApiClient-MkaPbGWB.js}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { C as e, S as t, _ as n, a as r, b as i, g as a, l as o, n as s, o as c, p as l, y as u } from "./schemas-DxbHVg3r.js";
|
|
2
2
|
import { i as d, t as ee } from "./Media-_HfFLHGD.js";
|
|
3
|
-
import {
|
|
3
|
+
import { A as f, O as te, a as p, c as m, f as h, l as g, n as ne, s as re, u as ie, y as ae } from "./Agent-De2gFNjR.js";
|
|
4
4
|
import "./src-DT8FLE4_.js";
|
|
5
5
|
import { r as _, t as oe } from "./url-validation-uLMZ5-AU.js";
|
|
6
6
|
import { Ability as se, buildMongoQueryMatcher as ce, createAliasResolver as le } from "@casl/ability";
|
|
@@ -78,7 +78,10 @@ n({
|
|
|
78
78
|
deviceContext: te.optional(),
|
|
79
79
|
externalContext: u(i(), t()).optional(),
|
|
80
80
|
smoothStream: c().optional()
|
|
81
|
-
})
|
|
81
|
+
}), n({
|
|
82
|
+
id: i().min(1),
|
|
83
|
+
messages: r(n({ role: i() }).loose()).min(1)
|
|
84
|
+
}).loose();
|
|
82
85
|
var O = /* @__PURE__ */ function(e) {
|
|
83
86
|
return e.SevereAbuse = "severe_abuse", e.HighRiskScore = "high_risk_score", e.RepeatedWarnings = "repeated_warnings", e;
|
|
84
87
|
}({});
|
|
@@ -572,4 +575,4 @@ function Be(e) {
|
|
|
572
575
|
//#endregion
|
|
573
576
|
export { X as n, k as r, Be as t };
|
|
574
577
|
|
|
575
|
-
//# sourceMappingURL=createChatbotApiClient-
|
|
578
|
+
//# sourceMappingURL=createChatbotApiClient-MkaPbGWB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createChatbotApiClient-MkaPbGWB.js","names":["c","l","d","f","s","n","e","t","i","r"],"sources":["../../../../packages/models/src/schema/ConversationAnalysis.ts","../../../../packages/models/src/schema/Chat.ts","../../../../node_modules/.pnpm/@ucast+core@2.0.0/node_modules/@ucast/core/dist/esm/index.mjs","../../../../node_modules/.pnpm/@ucast+mongo@3.0.0/node_modules/@ucast/mongo/dist/esm/index.mjs","../../../../packages/ability/src/types.ts","../../../../packages/ability/src/roles/User.ts","../../../../packages/ability/src/index.ts","../../../../packages/composable/src/chatbot/api/resolveShortUrls.ts","../../../../packages/composable/src/chatbot/api/createChatbotApiClient.ts"],"sourcesContent":["import * as z from 'zod'\n\nexport enum AbuseCategory {\n Harassment = 'harassment',\n HateSpeech = 'hate_speech',\n SexualContent = 'sexual_content',\n SelfHarm = 'self_harm',\n Violence = 'violence',\n PromptInjection = 'prompt_injection',\n DataExtraction = 'data_extraction',\n Spam = 'spam',\n OffTopicPersistent = 'off_topic_persistent',\n Impersonation = 'impersonation',\n}\n\nexport enum AbuseConfidence {\n Low = 'low',\n Medium = 'medium',\n High = 'high',\n}\n\nexport enum LlmIssueCategory {\n FalseSuccess = 'false_success',\n Hallucination = 'hallucination',\n OffBrand = 'off_brand',\n DataLeak = 'data_leak',\n InappropriateTone = 'inappropriate_tone',\n RefusalLoop = 'refusal_loop',\n Repetition = 'repetition',\n}\n\nexport enum ConversationAnalysisTrigger {\n SummaryCycle = 'summary_cycle',\n AgentRequest = 'agent_request',\n Manual = 'manual',\n}\n\nexport enum UserEngagement {\n High = 'high',\n Medium = 'medium',\n Low = 'low',\n Disengaged = 'disengaged',\n}\n\nexport enum UserTone {\n Polite = 'polite',\n Neutral = 'neutral',\n Impatient = 'impatient',\n Aggressive = 'aggressive',\n Abusive = 'abusive',\n}\n\nexport enum Sentiment {\n Positive = 'positive',\n Neutral = 'neutral',\n Negative = 'negative',\n Frustrated = 'frustrated',\n Excited = 'excited',\n}\n\nexport enum SentimentTrend {\n Improving = 'improving',\n Stable = 'stable',\n Degrading = 'degrading',\n}\n\nexport const ConversationAnalysisSchema = z.object({\n // --- Metadata (set programmatically, not by the LLM) ---\n analyzedAt: z.coerce.date().describe('When the analysis was generated.'),\n analysisTrigger: z\n .enum(ConversationAnalysisTrigger)\n .describe('What triggered this analysis run.'),\n\n // --- Sentiment & Tone ---\n sentiment: z\n .enum(Sentiment)\n .describe('Overall user sentiment in the conversation.'),\n sentimentTrend: z\n .enum(SentimentTrend)\n .describe('How the user sentiment evolved during the conversation.'),\n userTone: z\n .enum(UserTone)\n .describe('Predominant tone of the user messages.'),\n\n // --- Language ---\n language: z\n .string()\n .max(10)\n .describe(\n 'ISO 639-1 language code of the conversation (e.g. \"en\", \"it\").',\n ),\n\n // --- Topics ---\n topics: z\n .array(z.string().max(100))\n .max(10)\n .describe('Main topics discussed, as short lowercase labels.'),\n\n // --- User Abuse Detection ---\n userAbuseDetected: z\n .boolean()\n .describe(\n 'Whether user abuse was detected. If false, userAbuseCategories MUST be empty.',\n ),\n userAbuseCategories: z\n .array(z.enum(AbuseCategory))\n .default([])\n .describe(\n 'Abuse categories detected. Non-empty only if userAbuseDetected is true.',\n ),\n userAbuseConfidence: z\n .enum(AbuseConfidence)\n .optional()\n .describe(\n 'Confidence level of the abuse detection. Set only if userAbuseDetected is true.',\n ),\n userAbuseSummary: z\n .string()\n .max(500)\n .optional()\n .describe(\n 'Brief description of the abusive behavior detected. Always write in English. Set only if userAbuseDetected is true.',\n ),\n\n // --- LLM Quality Issues ---\n llmIssueDetected: z\n .boolean()\n .describe(\n 'Whether an LLM quality issue was detected. If false, llmIssueCategories MUST be empty.',\n ),\n llmIssueCategories: z\n .array(z.enum(LlmIssueCategory))\n .default([])\n .describe(\n 'LLM issue categories detected. Non-empty only if llmIssueDetected is true.',\n ),\n llmIssueSummary: z\n .string()\n .max(500)\n .optional()\n .describe(\n 'Brief description of the LLM quality issue detected. Always write in English. Set only if llmIssueDetected is true.',\n ),\n\n // --- Engagement ---\n userEngagement: z\n .enum(UserEngagement)\n .describe('Level of user engagement in the conversation.'),\n conversationGoalMet: z\n .boolean()\n .optional()\n .describe(\n 'Whether the user seems to have achieved what they came for. Leave undefined if unclear.',\n ),\n\n // --- Risk Score ---\n riskScore: z\n .number()\n .int()\n .min(0)\n .max(100)\n .describe(\n 'Overall risk score (0 = safe, 100 = critical). Combination of abuse severity, persistence and escalation.',\n ),\n})\n\nexport type ConversationAnalysis = z.infer<typeof ConversationAnalysisSchema>\n","import * as z from 'zod'\nimport { zodQs } from '../utils'\nimport type { UIMessage, LanguageModelUsage } from 'ai'\nimport { ConversationAnalysisSchema } from './ConversationAnalysis'\nimport {\n AgentBuiltInTool,\n AgentGatewayOptionsSchema,\n AgentReasoningSchema,\n AgentWebSearchSchema,\n AgentSearchMode,\n AgentRankingSchema,\n} from './Agent'\nimport { MIME_TYPE_REGEX } from './Media'\nimport type { PlatformContext } from './Platform'\n\nimport { DeviceContextSchema, type DeviceContext } from './DeviceContext'\n\nexport { DeviceContextSchema, type DeviceContext }\n\nconst TextPartSchema = z.object({\n type: z.literal('text'),\n text: z.string(),\n})\n\nconst FilePartSchema = z.object({\n type: z.literal('file'),\n mediaType: z.string().regex(MIME_TYPE_REGEX),\n url: z.url(),\n filename: z.string().optional(),\n providerMetadata: z\n .record(z.string(), z.record(z.string(), z.unknown()))\n .optional(),\n})\n\nconst MessagePartSchema = z.discriminatedUnion('type', [\n TextPartSchema,\n FilePartSchema,\n])\n\nexport const ChatRequestSchema = z.object({\n id: z.string(),\n messages: z.array(\n z.object({\n id: z.string().optional(),\n role: z.enum(['assistant', 'user']),\n content: z.string(),\n parts: z.array(MessagePartSchema),\n createdAt: z.string().optional(),\n }),\n ),\n model: z.string().optional(),\n temperature: z.number().optional(),\n prompt: z.string().optional(),\n maxOutputTokens: z.number().positive().optional(),\n presencePenalty: z.number().min(-2).max(2).optional(),\n frequencyPenalty: z.number().min(-2).max(2).optional(),\n searchMode: z.enum(AgentSearchMode).optional(),\n limit: z.number().optional(),\n ranking: AgentRankingSchema.optional(),\n reasoning: AgentReasoningSchema,\n webSearch: AgentWebSearchSchema.optional(),\n maxStepCount: z.number().int().min(1).max(40).optional(),\n disabledTools: z.array(z.enum(AgentBuiltInTool)).optional(),\n fallbackModels: z.array(z.string()).optional(),\n gatewayOptions: AgentGatewayOptionsSchema.partial().optional(),\n deviceContext: DeviceContextSchema.optional(),\n externalContext: z.record(z.string(), z.unknown()).optional(),\n smoothStream: z.boolean().optional(),\n})\n\nexport type ChatRequest = z.infer<typeof ChatRequestSchema>\n\n/**\n * What the chat route validates on the way in.\n *\n * Deliberately not `ChatRequestSchema`: a turn resumed after a client tool or\n * a tool approval posts the assistant message back, whose parts are tool\n * calls, and the part union above accepts text and files only. Pinning the\n * body to it would answer 400 to a legitimate resume. So this validates the\n * envelope the turn cannot run without and lets the rest through untouched\n * (`loose`), which is also why the overrides the client sends still reach the\n * service.\n *\n * The id is minted by the client and read back as a row key: without it the\n * lookup ran with `undefined` and the route answered 500 instead of 400\n * (found 2026-09-21).\n */\nexport const ChatRequestEnvelopeSchema = z\n .object({\n id: z.string().min(1),\n messages: z.array(z.object({ role: z.string() }).loose()).min(1),\n })\n .loose()\n\nexport enum BlockedReasonCode {\n SevereAbuse = 'severe_abuse',\n HighRiskScore = 'high_risk_score',\n RepeatedWarnings = 'repeated_warnings',\n}\n\nexport type ChatMetadata = {\n ipAddress: string\n /** HTTP `Origin` of the request, empty for a server-to-server caller. */\n origin: string\n userAgent: string\n /**\n * Non-default transport the conversation arrived through (for example\n * `openai-api`), so cost and usage reports can isolate it. Absent for the\n * web and widget chat.\n */\n transport?: string\n}\n\n/**\n * Channel a conversation arrived through, as the analytics slice it.\n *\n * Derived at read time and never stored: a platform conversation is identified\n * by `chats.metadata.platform` ({@link PlatformType}), every other non-web\n * surface by `chats.metadata.transport` ({@link ChatTransport}), and a chat\n * carrying neither marker is the web chat or the widget (the historical\n * default, which is why those rows have nothing to read). `reasoning_chats`\n * and `agent_endpoint_logs` have no metadata at all, so each of those tables\n * is a channel by itself.\n *\n * Not to be confused with {@link AgentChannel}, which says where an agent is\n * published (frontoffice, app, widget): this says where a conversation came\n * from.\n *\n * Only the platforms we actually run are listed. `PlatformType` declares five\n * more, and one of those appearing in the data is reported under its own raw\n * value rather than folded into a bucket, so a channel nobody expected shows\n * up in the dashboard instead of hiding inside `other`.\n */\nexport enum ChatChannel {\n /** Web chat and embeddable widget: no marker on the row. */\n Web = 'web',\n WhatsApp = 'whatsapp',\n Teams = 'teams',\n /** Spoken session opened by us, `transport = voice`. */\n Voice = 'voice',\n /** OpenAI-compatible REST surface, `transport = openai-api`. */\n Api = 'api',\n /** Every row of `reasoning_chats`: the reasoning endpoint. */\n Reasoning = 'reasoning',\n /** Every row of `agent_endpoint_logs`: the custom agent endpoints. */\n Endpoint = 'endpoint',\n}\n\nexport const ChatChannelSchema = z.enum(ChatChannel)\n\nexport type ChatMessageActions =\n 'show-info' | 'revise' | 'regenerate' | 'upvote' | 'downvote' | 'feedback'\n\nexport type Chat = z.infer<typeof ChatSchema>\nexport type ChatsQuerystring = z.infer<typeof ChatsQuerystringSchema>\n\nexport type UIChatMessageDeviceContext = DeviceContext\n\nexport type UIChatMessageMetadata = {\n /** Unix timestamp (ms) when the stream started */\n createdAt?: number\n /** Unix timestamp (ms) when the stream finished */\n completedAt?: number\n /** Canonical model ID used for the request (e.g. `google/gemini-3-flash`) */\n model?: string\n /** Total tokens consumed across all steps */\n totalTokens?: number\n /** Per-tool-call durations in ms, keyed by tool call ID */\n partTimings?: Record<string, number>\n /** Client device context sent with the request */\n deviceContext?: UIChatMessageDeviceContext\n /** Platform channel context (WhatsApp/Teams), the device-context equivalent for platform turns */\n platformContext?: PlatformContext\n /** External context provided by the host application and validated server-side */\n externalContext?: Record<string, unknown>\n /** Provider that ultimately served the request (e.g. `vertex`, `openai`) */\n resolvedProvider?: string\n /** Actual model ID as exposed by the resolved provider (e.g. `gemini-3-flash-preview`) */\n resolvedModelId?: string\n /** Market cost of the request in USD, as a numeric string */\n cost?: string\n /** Number of model-level routing attempts made by the gateway */\n modelAttemptCount?: number\n /** Total number of provider-level attempts (includes retries across providers) */\n totalProviderAttemptCount?: number\n /** Whether Zero Data Retention was active for this request */\n zeroDataRetention?: boolean\n /** Whether the provider was instructed not to use the prompt for model training */\n disallowPromptTraining?: boolean\n /** Vercel AI Gateway generation ID, useful for tracing in the Vercel dashboard */\n generationId?: string\n /** Tokens served from the provider's prompt cache (e.g. Gemini context caching) */\n cachedTokens?: number\n /** Provider traffic tier (e.g. `PROVISIONED_THROUGHPUT`, `ON_DEMAND`) */\n trafficType?: string\n /**\n * Transport the message travelled through ({@link ChatTransport}), when it\n * was not the web chat itself: `voice` marks a spoken exchange (the user\n * text is the call transcription, the assistant text was read aloud),\n * `openai-api` an API turn. Absent on plain web messages.\n */\n transport?: string\n}\n\nexport type UIChatMessage = UIMessage & {\n metadata?: UIChatMessageMetadata\n}\n\n/**\n * States in which a tool invocation part waits for nothing more.\n *\n * Two readers, one meaning: the backend leaves such a part alone instead of\n * forcing it to a terminal state (`completeUnresolvedToolInvocations`), and the\n * web client counts it as answered when deciding whether to resume a suspended\n * turn (`sendAutomaticallyWhen` in `useChatbotStore`). They used to keep a copy\n * each, with different membership.\n */\nexport const TOOL_TERMINAL_STATES: ReadonlySet<string> = new Set([\n 'output-available',\n 'output-error',\n 'output-denied',\n])\n\nexport const ChatSchema = z.object({\n id: z.string(),\n messages: z.array(z.unknown()) as unknown as z.ZodType<UIChatMessage[]>,\n title: z.string().nullable(),\n summary: z.string().nullable(),\n messageCountAtLastSummary: z.string().nullable(),\n createdAt: z.coerce.date(),\n updatedAt: z.coerce.date(),\n metadata: z.record(z.string(), z.unknown()),\n totalCostInUSD: z.string(),\n usage: z.unknown() as unknown as z.ZodType<LanguageModelUsage>,\n agentId: z.string().nullable(),\n userId: z.string(),\n organizationId: z.string(),\n deleted: z.boolean(),\n deletedAt: z.coerce.date().nullable(),\n deletedBy: z.string().nullable(),\n conversationAnalysis: ConversationAnalysisSchema.nullable().optional(),\n blocked: z.boolean(),\n blockedAt: z.coerce.date().nullable(),\n blockedReasonCode: z.enum(BlockedReasonCode).nullable(),\n blockedReason: z.string().nullable(),\n warningCount: z.number(),\n lastMessageAt: z.coerce.date(),\n})\n\nexport const ChatsQuerystringSchema = z.object({\n ...zodQs.pagination(),\n ...zodQs.sort(['updatedAt', 'createdAt', 'lastMessageAt']),\n ...zodQs.filters(['agentId', 'userId']),\n ...zodQs.range('updatedAt'),\n ...zodQs.range('lastMessageAt'),\n ...zodQs.ids(),\n startDate: z.string().optional(),\n endDate: z.string().optional(),\n})\n\nexport const ChatsPublicSchema = z.object({\n id: z.string(),\n agentId: z.string().optional(),\n organizationId: z.string(),\n summary: z.string().optional(),\n title: z.string().optional(),\n userId: z.string(),\n createdAt: z.coerce.date(),\n updatedAt: z.coerce.date(),\n lastMessageAt: z.coerce.date(),\n messages: z.array(z.unknown()),\n blocked: z.boolean(),\n})\n\nexport type ChatPublic = z.infer<typeof ChatsPublicSchema>\n","var e=class{constructor(e,t){this.operator=e,this.value=t,Object.defineProperty(this,`_notes`,{writable:!0})}get notes(){return this._notes}addNote(e){this._notes=this._notes||[],this._notes.push(e)}},t=class extends e{},n=class extends t{constructor(e,t){if(!Array.isArray(t))throw Error(`\"${e}\" operator expects to receive an array of conditions`);super(e,t)}};const r=`__itself__`;var i=class extends e{constructor(e,t,n){super(e,n),this.field=t}};const a=new t(`__null__`,null),o=Object.hasOwn||((e,t)=>Object.prototype.hasOwnProperty.call(e,t));function s(e,t){return t instanceof n&&t.operator===e}function c(e,t){let r;for(let i=0,a=t.length;i<a;i++){let a=t[i];if(a instanceof n){if(a.operator!==e){r&&r.push(a);continue}if(a.value.length===0)continue;r||(r=t.slice(0,i));let n=a.value;for(let e=0,t=n.length;e<t;e++)r.push(n[e])}else r&&r.push(a)}return r||t}function l(e,t){if(t.length===1)return t[0];if(t.length===0)return new n(e,t);let r=c(e,t);return r.length===1?r[0]:(r.length,new n(e,r))}const u=e=>e,d=()=>Object.create(null),f=Object.defineProperty(d(),`__@type@__`,{value:`ignore value`});function p(e,t,n=!1){if(!e||e&&e.constructor!==Object)return!1;for(let r in e)if(o(e,r)&&o(t,r)&&(!n||e[r]!==f))return!0;return!1}function m(e){let t=[];for(let n in e)o(e,n)&&e[n]!==f&&t.push(n);return t}function h(e,t){t!==a&&e.push(t)}const g=e=>l(`and`,e),_=e=>l(`or`,e);function v(e,t){let n=e[t];if(typeof n!=`function`)throw Error(`Unable to interpret \"${String(t)}\" condition. Did you forget to register interpreter for it?`);return n}function y(e){return e.operator}function b(e,t){let n=t,r=n&&n.getInterpreterName||y,i;switch(n?n.numberOfArguments:0){case 1:i=(t=>v(e,r(t,n))(t,a));break;case 3:i=((t,i,o)=>v(e,r(t,n))(t,i,o,a));break;default:i=((t,i)=>v(e,r(t,n))(t,i,a));break}let a={...n,interpret:i};return a.interpret}const x={compound(e,t,r){let i=(Array.isArray(t)?t:[t]).map(e=>r.parse(e));return new n(e.name,i)},field(e,t,n){return new i(e.name,n.field,t)},document(e,n){return new t(e.name,n)}};var S=class{constructor(e,t=d()){this.parse=this.parse.bind(this),this._options={operatorToConditionName:t.operatorToConditionName||u,defaultOperatorName:t.defaultOperatorName||`eq`,mergeFinalConditions:t.mergeFinalConditions||g},this._instructions=Object.keys(e).reduce((t,n)=>(t[n]={name:this._options.operatorToConditionName(n),...e[n]},t),{}),this._fieldInstructionContext={...t.fieldContext,field:``,query:{},parse:this.parse,hasOperators:e=>p(e,this._instructions,t.useIgnoreValue)},this._documentInstructionContext={...t.documentContext,parse:this.parse,query:{}},this._objectKeys=t.useIgnoreValue?m:Object.keys}setParse(e){this.parse=e,this._fieldInstructionContext.parse=e,this._documentInstructionContext.parse=e}parseField(e,t,n,r){let i=this._instructions[t];if(!i)throw Error(`Unsupported operator \"${t}\"`);if(i.type!==`field`)throw Error(`Unexpected ${i.type} operator \"${t}\" at field level`);return this._fieldInstructionContext.field=e,this._fieldInstructionContext.query=r,this.parseInstruction(i,n,this._fieldInstructionContext)}parseInstruction(e,t,n){return typeof e.validate==`function`&&e.validate(e,t),(e.parse||x[e.type])(e,t,n)}parseFieldOperators(e,t){let n=[],r=this._objectKeys(t);for(let i=0,a=r.length;i<a;i++){let a=r[i];if(!this._instructions[a])throw Error(`Field query for \"${e}\" may contain only operators or a plain object as a value`);h(n,this.parseField(e,a,t[a],t))}return n}parse(e){let t=[],n=this._objectKeys(e);this._documentInstructionContext.query=e;for(let r=0,i=n.length;r<i;r++){let i=n[r],a=e[i],o=this._instructions[i];if(o){if(o.type!==`document`&&o.type!==`compound`)throw Error(`Cannot use parsing instruction for operator \"${i}\" in \"document\" context as it is supposed to be used in \"${o.type}\" context`);h(t,this.parseInstruction(o,a,this._documentInstructionContext))}else this._fieldInstructionContext.hasOperators(a)?t.push(...this.parseFieldOperators(i,a)):h(t,this.parseField(i,this._options.defaultOperatorName,a,e))}return this._options.mergeFinalConditions(t)}};function C(e,t){return(n,...r)=>{let i=e(n,...r),a=t.bind(null,i);return Object.defineProperty(a,`ast`,{value:i}),a}}export{n as CompoundCondition,e as Condition,t as DocumentCondition,i as FieldCondition,r as ITSELF,a as NULL_CONDITION,S as ObjectQueryParser,g as buildAnd,_ as buildOr,b as createInterpreter,C as createTranslatorFactory,x as defaultInstructionParsers,p as hasOperators,u as identity,f as ignoreValue,s as isCompound,d as object,l as optimizedCompoundCondition};\n//# sourceMappingURL=index.mjs.map","import{CompoundCondition as e,FieldCondition as t,ITSELF as n,NULL_CONDITION as r,ObjectQueryParser as i,buildAnd as a,defaultInstructionParsers as o,optimizedCompoundCondition as s}from\"@ucast/core\";var c=Object.defineProperty,l=((e,t)=>{let n={};for(var r in e)c(n,r,{get:e[r],enumerable:!0});return t||c(n,Symbol.toStringTag,{value:`Module`}),n})({$all:()=>y,$and:()=>u,$elemMatch:()=>h,$eq:()=>E,$exists:()=>x,$gt:()=>C,$gte:()=>S,$in:()=>_,$lt:()=>w,$lte:()=>T,$mod:()=>b,$ne:()=>D,$nin:()=>v,$nor:()=>f,$not:()=>m,$options:()=>k,$or:()=>d,$regex:()=>O,$size:()=>g,$where:()=>A});const u={type:`compound`,validate:M,parse(e,t,n){let r=p(e,t,n);return s(e.name,r)}},d=u,f={type:`compound`,validate:M,parse(t,n,r){let i=p(t,n,r);return new e(t.name,i)}};function p(e,t,n){let r=Array(t.length);for(let i=0;i<t.length;i++){let a=t[i];F(e,a,i),r[i]=n.parse(a)}return r}const m={type:`field`,validate(e,t){if(!(t&&(t instanceof RegExp||t.constructor===Object)))throw Error(`\"${e.name}\" expects to receive either regular expression or object of field operators`)},parse(n,r,i){let a=r instanceof RegExp?new t(`regex`,i.field,r):i.parse(r,i);return new e(n.name,[a])}},h={type:`field`,validate(e,t){if(!t||t.constructor!==Object)throw Error(`\"${e.name}\" expects to receive an object with nested query or field level operators`)},parse(e,r,{parse:i,field:a,hasOperators:o}){let s=o(r)?i(r,{field:n}):i(r);return new t(e.name,a,s)}},g={type:`field`,validate:P(`number`)},_={type:`field`,validate:j},v=_,y=_,b={type:`field`,validate(e,t){if(!Array.isArray(t)||t.length!==2)throw Error(`\"${e.name}\" expects an array with 2 numeric elements`)}},x={type:`field`,validate:P(`boolean`)},S={type:`field`,validate:N},C=S,w=C,T=C,E={type:`field`},D=E,O={type:`field`,validate(e,t){if(!(t instanceof RegExp)&&typeof t!=`string`)throw Error(`\"${e.name}\" expects value to be a regular expression or a string that represents regular expression`)},parse(e,n,r){let i=typeof n==`string`?new RegExp(n,r.query.$options||``):n;return new t(e.name,r.field,i)}},k={type:`field`,parse:()=>r},A={type:`document`,validate:P(`function`)};function j(e,t){if(!Array.isArray(t))throw Error(`\"${e.name}\" expects value to be an array`)}function M(e,t){if(j(e,t),!t.length)throw Error(`\"${e.name}\" expects to have at least one element in array`)}function N(e,t){if(!(typeof t==`string`||typeof t==`number`||t instanceof Date))throw Error(`\"${e.name}\" expects value to be comparable (i.e., string, number or date)`)}function P(e){return(t,n)=>{if(typeof n!==e)throw Error(`\"${t.name}\" expects value to be a \"${e}\"`)}}function F(e,t,n){let r=t;if(!r||r.constructor!==Object)throw Error(`\"${e.name}\" expects item at index ${n} to be an object`)}var I=class extends i{constructor(e){super(e,{defaultOperatorName:`$eq`,operatorToConditionName:e=>e.slice(1)})}parse(e,t){return t&&t.field?a(this.parseFieldOperators(t.field,e)):super.parse(e)}};const L=l;export{y as $all,u as $and,h as $elemMatch,E as $eq,x as $exists,C as $gt,S as $gte,_ as $in,w as $lt,T as $lte,b as $mod,D as $ne,v as $nin,f as $nor,m as $not,k as $options,d as $or,O as $regex,g as $size,A as $where,I as MongoQueryParser,L as allParsingInstructions,o as defaultParsers};\n//# sourceMappingURL=index.mjs.map","import type { MongoQuery } from '@ucast/mongo2js'\n\n// Minimal structural shape of the better-auth session consumed here.\n// Declared locally to avoid a workspace dependency cycle with `auth`\n// (auth depends on `ability` for its access-control config).\n// The full `auth` Session is structurally assignable to this type.\nexport type Session = {\n session: {\n activeOrganizationId?: string | null\n organizationRole?: string | null\n }\n user: {\n id?: string\n role?: string | null\n }\n}\n\nexport enum Audience {\n Backoffice = 'backoffice',\n Frontoffice = 'frontoffice',\n System = 'system',\n Public = 'public',\n}\n\nexport enum Subject {\n All = 'all',\n Todo = 'todo',\n User = 'user',\n Chat = 'chat',\n Agent = 'agent',\n SubAgent = 'subAgent',\n Document = 'document',\n AgentDocument = 'agent_document',\n AgentAnalytic = 'agent_analytic',\n McpServer = 'mcp_server',\n Media = 'media',\n RevisedAnswer = 'revised_answer',\n Organization = 'organization',\n Member = 'member',\n Lead = 'lead',\n MessageFeedback = 'message_feedback',\n Backoffice = 'backoffice',\n Frontoffice = 'frontoffice',\n System = 'system',\n Invitation = 'invitation',\n Crawler = 'crawler',\n ReasoningChat = 'reasoning_chat',\n TimeTrackerChat = 'time_tracker_chat',\n OrganizationExternalAuth = 'organization_external_auth',\n AgentEndpoint = 'agent_endpoint',\n AgentEndpointLog = 'agent_endpoint_log',\n AgentApiTool = 'agent_api_tool',\n DocumentFolder = 'document_folder',\n Integration = 'integration',\n Notification = 'notification',\n PlatformConnection = 'platform_connection',\n}\n\n// action\nexport type Action =\n | 'create'\n | 'read'\n | 'update'\n | 'delete'\n | 'manage'\n | 'impersonate'\n | 'invite'\n | 'access'\n | 'clone'\n | 'ban'\n | 'unban'\n | 'change-role'\n | 'resend'\n | 'cancel'\n | 'execute'\n | 'refill'\n\nexport type Capability = {\n action: Action\n subject: Subject\n fields?: string[]\n condition?: MongoQuery\n inverted?: boolean\n}\n\nexport type CapabilitiesFactory = (\n currentSession?: Session | null,\n) => Capability[]\n","import { AgentStatus } from 'models'\nimport type { CapabilitiesFactory } from '../types'\nimport { Subject } from '../types'\n\nconst GuestCapabilities: CapabilitiesFactory = (currentSession) => {\n if (!currentSession) {\n return []\n }\n return [\n // chats\n {\n subject: Subject.Chat,\n action: 'create',\n },\n {\n subject: Subject.Chat,\n action: 'read',\n condition: {\n createdBy: {\n $eq: currentSession.user?.id,\n },\n },\n },\n {\n subject: Subject.Chat,\n action: 'update',\n },\n {\n subject: Subject.Chat,\n action: 'delete',\n },\n // agents\n {\n subject: Subject.Agent,\n action: 'read',\n condition: {\n status: {\n $eq: AgentStatus.Active,\n },\n },\n },\n // feedbacks\n {\n subject: Subject.MessageFeedback,\n action: 'create',\n },\n {\n subject: Subject.MessageFeedback,\n action: 'read',\n condition: {\n createdBy: {\n $eq: currentSession.user?.id,\n },\n },\n },\n ]\n}\nexport default GuestCapabilities\n","import type {\n MongoAbility,\n InferSubjects,\n ForcedSubject,\n FieldMatcher,\n} from '@casl/ability'\nimport type { MongoQuery } from '@ucast/mongo2js'\nimport type { Action, Capability, Subject } from './types'\nimport { type Session } from './types'\nimport { $or } from '@ucast/mongo2js'\nimport {\n AbilityBuilder,\n createMongoAbility,\n buildMongoQueryMatcher,\n Ability as PureAbility,\n createAliasResolver,\n subject as caslSubject,\n} from '@casl/ability'\nimport { organizationCapabilitiesByRole, userCapabilitiesByRole } from './roles'\nimport DefaultCapabilities from './roles/User'\nimport { createAccessControl } from 'better-auth/plugins'\nimport {\n adminAc,\n defaultStatements,\n memberAc,\n ownerAc,\n} from 'better-auth/plugins/organization/access'\n\nexport const OrganizationRoles = {\n admin: 'admin',\n owner: 'owner',\n member: 'member',\n user: 'user',\n} as const\n\nexport const UserRoles = {\n admin: 'admin',\n user: 'user',\n} as const\n\n// action alias\nconst resolveAction = createAliasResolver({\n modify: ['read', 'update', 'delete'],\n})\n\n// subject\nexport type AbilitySubject =\n | InferSubjects<'all' | Subject, true>\n | ForcedSubject<InferSubjects<'all' | Subject, true>>\ntype Ability = MongoAbility<[Action, AbilitySubject]>\n\n// matcher\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst conditionsMatcher = buildMongoQueryMatcher({ $or } as Record<string, any>)\nconst fieldMatcher: FieldMatcher = (fields) => (field) => fields.includes(field)\n\n// ability\nexport const ability = new PureAbility<[Action, AbilitySubject], MongoQuery>(\n DefaultCapabilities(),\n {\n conditionsMatcher,\n resolveAction,\n fieldMatcher,\n },\n)\n\nexport const isValidOrganizationRole = (\n role?: string | null,\n): role is keyof typeof OrganizationRoles => {\n if (!role) {\n return false\n }\n return role in OrganizationRoles\n}\n\nexport const isValidUserRole = (\n role?: string | null,\n): role is keyof typeof UserRoles => {\n if (!role) {\n return false\n }\n return role in UserRoles\n}\n\nexport const getOrganizationRoleCapabilities = (\n currentSession?: Session | null,\n): Capability[] => {\n const organizationRole = currentSession?.session?.organizationRole\n if (!isValidOrganizationRole(organizationRole)) {\n return DefaultCapabilities(currentSession)\n }\n const capabilities = organizationCapabilitiesByRole[organizationRole]\n if (typeof capabilities === 'function') {\n return capabilities(currentSession)\n }\n return capabilities\n}\n\nexport const getUserRoleCapabilities = (\n currentSession?: Session | null,\n): Capability[] => {\n const userRole = currentSession?.user?.role\n if (!isValidUserRole(userRole)) {\n return DefaultCapabilities(currentSession)\n }\n const capabilities = userCapabilitiesByRole[userRole]\n if (typeof capabilities === 'function') {\n return capabilities(currentSession)\n }\n return capabilities\n}\n\n/**\n * Builds a standalone ability instance for a session, without touching the\n * shared singleton. Use for per-call checks outside the HTTP request flow\n * (e.g. MCP tool handlers).\n */\nexport const buildAbilityForSession = (\n currentSession?: Session | null,\n): Ability => {\n const { can, build, cannot } = new AbilityBuilder<Ability>(\n createMongoAbility,\n )\n const organizationRoleCapabilities =\n getOrganizationRoleCapabilities(currentSession)\n const userRoleCapabilities = getUserRoleCapabilities(currentSession)\n const capabilities = [\n ...organizationRoleCapabilities,\n ...userRoleCapabilities,\n ]\n capabilities.forEach((capability) => {\n const { action, subject, fields, condition, inverted } = capability\n if (inverted) {\n cannot(action, subject, fields, condition)\n return\n }\n can(action, subject, fields, condition)\n })\n return build({\n conditionsMatcher,\n resolveAction,\n fieldMatcher,\n })\n}\n\nexport const updateAbilityFromSession = (currentSession?: Session | null) => {\n ability.update(buildAbilityForSession(currentSession).rules)\n}\n\nexport type PermissionMap = Partial<Record<Action, Subject>>\n\n/**\n * Evaluates a route-style permission map ({ action: Subject }) against an\n * ability instance. When `payload` is provided it is bound as subject\n * conditions, same as the HTTP route preHandler does with `request.body`.\n * Returns the first denied pair, or null when every check passes.\n * Single source of truth for both the HTTP preHandler and the Platform MCP\n * tool handlers.\n */\nexport const findDeniedPermission = (\n abilityInstance: Pick<Ability, 'can'>,\n permissions: PermissionMap,\n payload?: unknown,\n): { action: Action; subject: Subject } | null => {\n let action: Action\n for (action in permissions) {\n const actionSubject = permissions[action]\n if (!actionSubject) {\n continue\n }\n const target = payload\n ? caslSubject(\n actionSubject,\n payload as Record<PropertyKey, unknown>,\n )\n : actionSubject\n if (!abilityInstance.can(action, target)) {\n return { action, subject: actionSubject }\n }\n }\n return null\n}\n\nconst ac = createAccessControl(defaultStatements)\nconst adminRole = ac.newRole(adminAc.statements)\nconst ownerRole = ac.newRole(ownerAc.statements)\nconst memberRole = ac.newRole(memberAc.statements)\nconst userRole = ac.newRole(memberAc.statements)\n\nexport const betterAuthOrganizationSettings = {\n ac,\n roles: {\n owner: ownerRole,\n admin: adminRole,\n member: memberRole,\n user: userRole,\n },\n}\n\n/**\n * Whether a user is currently banned. A ban with no expiry is permanent, one\n * with an expiry in the future is still in force, one already elapsed is not.\n * Every admission path (API key, Platform MCP, voice callback) must apply the\n * same rule: a ban that holds in one path and not another is a hole.\n */\nexport const isUserBanned = (\n user:\n | { banned?: boolean | null; banExpires?: Date | null }\n | null\n | undefined,\n): boolean =>\n user?.banned === true &&\n (user.banExpires === null ||\n user.banExpires === undefined ||\n user.banExpires > new Date())\n\nexport * from './types'\nexport { subject } from '@casl/ability'\n","import { removeTrailingSlash } from 'utils'\n\nexport interface ResolveShortUrlsOptions {\n /** Extra headers to send (e.g. auth). */\n headers?: Record<string, string>\n /** Fetch credentials mode. Defaults to `'include'`. */\n credentials?: RequestCredentials\n}\n\n/**\n * Single implementation of the short-url batch resolve used across apps\n * (chatbot api client, frontend app root). Maps `/api/r/<hash>` short urls back\n * to their real target via `POST <backend>/api/r/resolve`.\n *\n * The redirect endpoint lives at `/api/r`, outside the JSON:API basePath, and\n * is unauthenticated. Returns an empty map (short urls left untouched) on any\n * failure so callers never have to handle errors.\n */\nexport async function resolveShortUrls(\n backendUrl: string,\n hashes: string[],\n options: ResolveShortUrlsOptions = {},\n): Promise<Record<string, string>> {\n try {\n const root = removeTrailingSlash(backendUrl)\n const response = await fetch(`${root}/api/r/resolve`, {\n method: 'POST',\n credentials: options.credentials ?? 'include',\n headers: {\n ...options.headers,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ hashes }),\n })\n if (!response.ok) {\n return {}\n }\n const data = (await response.json()) as {\n urls?: Record<string, string>\n }\n return data.urls ?? {}\n } catch {\n return {}\n }\n}\n","import { Audience } from 'ability'\nimport { ChatSchema, ChatsPublicSchema, VoiceSessionSchema } from 'models'\nimport type {\n AgentAccess,\n Chat,\n DeviceContext,\n MessageFeedback,\n AgentPublic,\n MediaSource,\n VoiceSession,\n} from 'models'\nimport { addInitialSlash, removeTrailingSlash } from 'utils'\nimport { resolveShortUrls as resolveShortUrlsRequest } from './resolveShortUrls'\n\n// The chats endpoints respond with the full shape (frontoffice) or the\n// trimmed public one — same union the backend declares. Parsing coerces the\n// date fields (plain JSON strings otherwise); on mismatch keep the raw\n// payload instead of failing.\nconst ConversationSchema = ChatSchema.or(ChatsPublicSchema)\nfunction parseConversation(raw: unknown): Chat {\n const result = ConversationSchema.safeParse(raw)\n return (result.success ? result.data : raw) as Chat\n}\n\n/**\n * What went wrong, in words, from the problem+json the backend answers with\n * (`{ type, title, status, message }`). Falling straight back to the status\n * produced \"API error: 409\" on screen, which tells the reader nothing and hides\n * a message that was already there and already explains the fix.\n */\nasync function readErrorMessage(response: Response): Promise<string> {\n const fallback = `${response.status} ${response.statusText}`.trim()\n try {\n const body = (await response.json()) as {\n message?: string\n title?: string\n }\n return body.message?.trim() || body.title?.trim() || fallback\n } catch {\n return fallback\n }\n}\n\nexport interface ChatbotApiClientOptions {\n baseUrl: string\n basePath?: string\n headers?: () => Record<string, string> | undefined\n credentials?: RequestCredentials\n}\n\nexport interface SubmitFeedbackPayload {\n messageId: string\n chatId: string\n agentId: string\n vote?: 'upvote' | 'downvote'\n userQuestion: string\n assistantMessage: string\n comment?: string\n}\n\nexport interface SubmitLeadPayload {\n agentId: string\n chatId: string\n [key: string]: unknown\n}\n\n/** A file from the user's \"My files\" KB, as listed for a chat. */\nexport interface ChatbotFile {\n documentId: string\n name: string | null\n mimeType: string | null\n indexStatus: string\n createdAt: string\n}\n\nexport interface ChatbotApiClient {\n getConversations(\n agentId: string,\n userId: string | undefined,\n ): Promise<Chat[]>\n getChat(agentId: string, chatId: string): Promise<Chat | null>\n updateChatTitle(\n agentId: string,\n chatId: string,\n title: string,\n ): Promise<Chat>\n deleteChat(agentId: string, chatId: string): Promise<void>\n getMessageFeedbacks(chatId: string): Promise<MessageFeedback[]>\n submitMessageFeedback(\n payload: SubmitFeedbackPayload,\n ): Promise<MessageFeedback>\n submitLead(payload: SubmitLeadPayload): Promise<void>\n getAgent(orgSlug: string, agentId: string): Promise<AgentPublic>\n getAgentAccess(orgSlug: string, agentId: string): Promise<AgentAccess>\n getMediaUrl(agentId: string, chatId: string, storedFileName: string): string\n appendAuthToken(url: string): string\n uploadMedia(\n agentId: string,\n chatId: string,\n file: File,\n ): Promise<MediaSource>\n getChatEndpoint(agentId: string, type?: 'chat' | 'reasoning'): string\n expandSourceContext(\n agentId: string,\n documentId: string,\n chunkIndex: number,\n windowSize?: number,\n ): Promise<{ content: string }>\n downloadSourceDocument(\n agentId: string,\n documentId: string,\n ): Promise<{ downloadUrl: string; filename: string; mimeType: string }>\n reverseGeocode(\n lat: number,\n lon: number,\n lang?: string,\n ): Promise<string | undefined>\n forwardGeocode(\n query: string,\n lang?: string,\n ): Promise<\n { latitude: number; longitude: number; displayName: string } | undefined\n >\n getOAuthAuthorizeUrl(\n agentId: string,\n serverName: string,\n ): Promise<{ mcpServerId: string; authorizeUrl: string }>\n getOAuthConnectionStatus(\n agentId: string,\n serverName: string,\n ): Promise<{ mcpServerId: string; connected: boolean }>\n resolveShortUrls(hashes: string[]): Promise<Record<string, string>>\n getChatFiles(chatId: string): Promise<ChatbotFile[]>\n getChatFileDownloadUrl(documentId: string, inline?: boolean): string\n getChatFilePreviewUrl(documentId: string): string\n deleteChatFile(documentId: string): Promise<void>\n createVoiceSession(\n agentId: string,\n chatId?: string,\n /**\n * Everything the call inherits from the page it starts on. Sent once,\n * because the spoken turns arrive from the voice provider and carry\n * none of it.\n */\n context?: {\n deviceContext?: DeviceContext\n externalContext?: Record<string, unknown>\n },\n ): Promise<VoiceSession>\n closeVoiceSession(agentId: string, sessionId: string): Promise<void>\n}\n\nexport function createChatbotApiClient(\n options: ChatbotApiClientOptions,\n): ChatbotApiClient {\n const basePath = options.basePath\n ? addInitialSlash(options.basePath)\n : `/api/v1/${Audience.Public}`\n\n const baseUrl = `${removeTrailingSlash(options.baseUrl)}${basePath}`\n\n // \"My files\" lives under the frontoffice audience, not the agent's base\n // (which may be public, backoffice, …) — derive it by swapping the trailing\n // audience segment of basePath for `frontoffice`.\n const frontofficeBase = `${removeTrailingSlash(options.baseUrl)}${basePath.replace(\n /\\/[^/]+$/,\n `/${Audience.Frontoffice}`,\n )}`\n\n async function request<T>(\n url: string,\n init?: RequestInit,\n responseType: 'json' | 'void' = 'json',\n ): Promise<T> {\n const response = await fetch(`${baseUrl}${url}`, {\n credentials: options.credentials ?? 'include',\n ...init,\n headers: {\n ...options.headers?.(),\n ...init?.headers,\n },\n })\n\n if (!response.ok) {\n throw new Error(await readErrorMessage(response))\n }\n\n if (responseType === 'void' || response.status === 204) {\n return undefined as T\n }\n\n return response.json() as Promise<T>\n }\n\n return {\n async getConversations(agentId, userId) {\n const userFilter = userId\n ? `&filter[userId]=${encodeURIComponent(userId)}`\n : ''\n const conversations = await request<unknown[]>(\n `/agents/${encodeURIComponent(agentId)}/chats?sort=-lastMessageAt&page[size]=100${userFilter}`,\n )\n return conversations.map(parseConversation)\n },\n\n async getChatFiles(chatId) {\n const response = await fetch(\n `${frontofficeBase}/me/documents?filter[chatId]=${encodeURIComponent(chatId)}&page[size]=100`,\n {\n credentials: options.credentials ?? 'include',\n headers: { ...options.headers?.() },\n },\n )\n if (!response.ok) {\n throw new Error(\n `API error: ${response.status} ${response.statusText}`,\n )\n }\n return (await response.json()) as ChatbotFile[]\n },\n\n getChatFileDownloadUrl(documentId, inline) {\n const suffix = inline ? '?inline=true' : ''\n // appendAuthToken carries a bearer in the query so <img>/<a>\n // subresources (which can't set an Authorization header) authorize\n // cross-origin in the embedded widget; no-op for cookie auth.\n return this.appendAuthToken(\n `${frontofficeBase}/me/documents/${encodeURIComponent(documentId)}/download${suffix}`,\n )\n },\n\n getChatFilePreviewUrl(documentId) {\n // Small resized preview blob for row thumbnails (see download\n // endpoint ?preview=true); auth token carried for cross-origin <img>.\n return this.appendAuthToken(\n `${frontofficeBase}/me/documents/${encodeURIComponent(documentId)}/download?preview=true`,\n )\n },\n\n async deleteChatFile(documentId) {\n const response = await fetch(\n `${frontofficeBase}/me/documents/${encodeURIComponent(documentId)}`,\n {\n method: 'DELETE',\n credentials: options.credentials ?? 'include',\n headers: { ...options.headers?.() },\n },\n )\n if (!response.ok) {\n throw new Error(\n `API error: ${response.status} ${response.statusText}`,\n )\n }\n },\n\n async getChat(agentId, chatId) {\n const result = await request<Chat | undefined>(\n `/agents/${encodeURIComponent(agentId)}/chats/${encodeURIComponent(chatId)}`,\n )\n return result ? parseConversation(result) : null\n },\n\n async updateChatTitle(agentId, chatId, title) {\n return parseConversation(\n await request<Chat>(\n `/agents/${encodeURIComponent(agentId)}/chats/${encodeURIComponent(chatId)}`,\n {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ title }),\n },\n ),\n )\n },\n\n async deleteChat(agentId, chatId) {\n await request<void>(\n `/agents/${encodeURIComponent(agentId)}/chats/${encodeURIComponent(chatId)}`,\n { method: 'DELETE' },\n 'void',\n )\n },\n\n async getMessageFeedbacks(chatId) {\n return request<MessageFeedback[]>(\n `/message-feedbacks?filter[chatId]=${encodeURIComponent(chatId)}&page[size]=200`,\n )\n },\n\n async submitMessageFeedback(payload) {\n return request<MessageFeedback>('/message-feedbacks', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n },\n\n async submitLead(payload) {\n await request<void>(\n '/leads',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n },\n 'void',\n )\n },\n\n async getAgent(orgSlug, agentId) {\n return request<AgentPublic>(\n `/organizations/${encodeURIComponent(orgSlug)}/agents/${encodeURIComponent(agentId)}`,\n )\n },\n\n async getAgentAccess(orgSlug, agentId) {\n return request<AgentAccess>(\n `/organizations/${encodeURIComponent(orgSlug)}/agents/${encodeURIComponent(agentId)}/access`,\n )\n },\n\n async uploadMedia(agentId, chatId, file) {\n const formData = new FormData()\n formData.append('file', file)\n const response = await fetch(\n `${baseUrl}/agents/${encodeURIComponent(agentId)}/chats/${encodeURIComponent(chatId)}/media/upload`,\n {\n method: 'POST',\n credentials: options.credentials ?? 'include',\n // Do NOT set Content-Type — browser sets multipart/form-data with boundary automatically\n headers: options.headers?.(),\n body: formData,\n },\n )\n if (!response.ok) {\n const text = await response.text().catch(() => '')\n let title = `Upload failed: ${response.status}`\n try {\n title =\n (JSON.parse(text) as { title?: string }).title ?? title\n } catch {\n // ignore parse errors\n }\n throw new Error(title)\n }\n return response.json() as Promise<MediaSource>\n },\n\n getChatEndpoint(agentId, type = 'chat') {\n const path = type === 'reasoning' ? 'reasoning-chat' : 'chat'\n return `${baseUrl}/agents/${encodeURIComponent(agentId)}/${path}`\n },\n\n appendAuthToken(url) {\n const bearer = options\n .headers?.()\n ?.[`Authorization`]?.slice('Bearer '.length)\n if (!bearer) {\n return url\n }\n const separator = url.includes('?') ? '&' : '?'\n return `${url}${separator}token=${encodeURIComponent(bearer)}`\n },\n\n getMediaUrl(agentId, chatId, storedFileName) {\n const base = `${baseUrl}/agents/${encodeURIComponent(agentId)}/chats/${encodeURIComponent(chatId)}/media/${encodeURIComponent(storedFileName)}/view`\n return this.appendAuthToken(base)\n },\n\n async expandSourceContext(\n agentId,\n documentId,\n chunkIndex,\n windowSize = 2,\n ) {\n return request<{ content: string }>(\n `/agents/${encodeURIComponent(agentId)}/sources/expand-context`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n documentId,\n chunkIndex,\n windowSize,\n }),\n },\n )\n },\n\n async downloadSourceDocument(agentId, documentId) {\n return request<{\n downloadUrl: string\n filename: string\n mimeType: string\n }>(\n `/agents/${encodeURIComponent(agentId)}/sources/documents/${encodeURIComponent(documentId)}/download`,\n )\n },\n\n async reverseGeocode(lat, lon, lang) {\n const params = new URLSearchParams({\n lat: String(lat),\n lon: String(lon),\n })\n if (lang) {\n params.set('lang', lang)\n }\n try {\n const data = await request<{ displayName?: string }>(\n `/geocoder/reverse?${params}`,\n )\n return data.displayName\n } catch {\n return undefined\n }\n },\n\n async forwardGeocode(query, lang) {\n const params = new URLSearchParams({ q: query })\n if (lang) {\n params.set('lang', lang)\n }\n try {\n return await request<{\n latitude: number\n longitude: number\n displayName: string\n }>(`/geocoder/forward?${params}`)\n } catch {\n return undefined\n }\n },\n\n async getOAuthAuthorizeUrl(agentId, serverName) {\n const params = new URLSearchParams({ serverName })\n return request<{ mcpServerId: string; authorizeUrl: string }>(\n `/agents/${encodeURIComponent(agentId)}/mcp-oauth/authorize?${params}`,\n )\n },\n\n async getOAuthConnectionStatus(agentId, serverName) {\n const params = new URLSearchParams({ serverName })\n return request<{ mcpServerId: string; connected: boolean }>(\n `/agents/${encodeURIComponent(agentId)}/mcp-oauth/status?${params}`,\n )\n },\n\n /**\n * Opens a voice session on the conversation currently on screen, so the\n * spoken turns land in the same thread the user can keep typing into.\n * The signed URL it returns is short-lived and per session: the provider\n * credential stays on the server.\n */\n async createVoiceSession(agentId, chatId, context) {\n return VoiceSessionSchema.parse(\n await request<unknown>(\n `/agents/${encodeURIComponent(agentId)}/voice/session`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n ...(chatId ? { chatId } : {}),\n // Sent once for the whole call: the spoken turns\n // come from the provider and carry nothing about\n // this browser nor about the page it runs on.\n ...(context?.deviceContext\n ? { deviceContext: context.deviceContext }\n : {}),\n ...(context?.externalContext\n ? { externalContext: context.externalContext }\n : {}),\n }),\n },\n ),\n )\n },\n\n /**\n * `keepalive` on purpose: this is the call that settles the minutes of a\n * session, and it is often made while the page is going away (hang up on\n * unload, tab closed). Without it the browser is free to cancel it.\n */\n async closeVoiceSession(agentId, sessionId) {\n await request<void>(\n `/agents/${encodeURIComponent(agentId)}/voice/session/${encodeURIComponent(sessionId)}`,\n { method: 'DELETE', keepalive: true },\n 'void',\n )\n },\n\n resolveShortUrls(hashes) {\n return resolveShortUrlsRequest(options.baseUrl, hashes, {\n headers: options.headers?.(),\n credentials: options.credentials,\n })\n },\n }\n}\n"],"x_google_ignoreList":[2,3],"mappings":";;;;;;;;;AAEA,IAAY,KAAL,yBAAA,GAAA;QACH,EAAA,aAAA,cACA,EAAA,aAAA,eACA,EAAA,gBAAA,kBACA,EAAA,WAAA,aACA,EAAA,WAAA,YACA,EAAA,kBAAA,oBACA,EAAA,iBAAA,mBACA,EAAA,OAAA,QACA,EAAA,qBAAA,wBACA,EAAA,gBAAA;AACJ,EAAA,CAAA,CAAA,GAEY,KAAL,yBAAA,GAAA;QACH,EAAA,MAAA,OACA,EAAA,SAAA,UACA,EAAA,OAAA;AACJ,EAAA,CAAA,CAAA,GAEY,KAAL,yBAAA,GAAA;QACH,EAAA,eAAA,iBACA,EAAA,gBAAA,iBACA,EAAA,WAAA,aACA,EAAA,WAAA,aACA,EAAA,oBAAA,sBACA,EAAA,cAAA,gBACA,EAAA,aAAA;AACJ,EAAA,CAAA,CAAA,GAEY,IAAL,yBAAA,GAAA;QACH,EAAA,eAAA,iBACA,EAAA,eAAA,iBACA,EAAA,SAAA;AACJ,EAAA,CAAA,CAAA,GAEY,IAAL,yBAAA,GAAA;QACH,EAAA,OAAA,QACA,EAAA,SAAA,UACA,EAAA,MAAA,OACA,EAAA,aAAA;AACJ,EAAA,CAAA,CAAA,GAEY,IAAL,yBAAA,GAAA;QACH,EAAA,SAAA,UACA,EAAA,UAAA,WACA,EAAA,YAAA,aACA,EAAA,aAAA,cACA,EAAA,UAAA;AACJ,EAAA,CAAA,CAAA,GAEY,IAAL,yBAAA,GAAA;QACH,EAAA,WAAA,YACA,EAAA,UAAA,WACA,EAAA,WAAA,YACA,EAAA,aAAA,cACA,EAAA,UAAA;AACJ,EAAA,CAAA,CAAA,GAEY,IAAL,yBAAA,GAAA;QACH,EAAA,YAAA,aACA,EAAA,SAAA,UACA,EAAA,YAAA;AACJ,EAAA,CAAA,CAAA,GAEa,IAA6B,EAAS;CAE/C,YAAY,EAAc,CAAC,CAAC,SAAS,kCAAkC;CACvE,iBAAiB,EACP,CAA2B,CAAC,CACjC,SAAS,mCAAmC;CAGjD,WAAW,EACD,CAAS,CAAC,CACf,SAAS,6CAA6C;CAC3D,gBAAgB,EACN,CAAc,CAAC,CACpB,SAAS,yDAAyD;CACvE,UAAU,EACA,CAAQ,CAAC,CACd,SAAS,wCAAwC;CAGtD,UAAU,EACE,CAAC,CACR,IAAI,EAAE,CAAC,CACP,SACG,oEACJ;CAGJ,QAAQ,EACG,EAAS,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAC1B,IAAI,EAAE,CAAC,CACP,SAAS,mDAAmD;CAGjE,mBAAmB,EACN,CAAC,CACT,SACG,+EACJ;CACJ,qBAAqB,EACV,EAAO,EAAa,CAAC,CAAC,CAC5B,QAAQ,CAAC,CAAC,CAAC,CACX,SACG,yEACJ;CACJ,qBAAqB,EACX,EAAe,CAAC,CACrB,SAAS,CAAC,CACV,SACG,iFACJ;CACJ,kBAAkB,EACN,CAAC,CACR,IAAI,GAAG,CAAC,CACR,SAAS,CAAC,CACV,SACG,qHACJ;CAGJ,kBAAkB,EACL,CAAC,CACT,SACG,wFACJ;CACJ,oBAAoB,EACT,EAAO,EAAgB,CAAC,CAAC,CAC/B,QAAQ,CAAC,CAAC,CAAC,CACX,SACG,4EACJ;CACJ,iBAAiB,EACL,CAAC,CACR,IAAI,GAAG,CAAC,CACR,SAAS,CAAC,CACV,SACG,qHACJ;CAGJ,gBAAgB,EACN,CAAc,CAAC,CACpB,SAAS,+CAA+C;CAC7D,qBAAqB,EACR,CAAC,CACT,SAAS,CAAC,CACV,SACG,yFACJ;CAGJ,WAAW,EACC,CAAC,CACR,IAAI,CAAC,CACL,IAAI,CAAC,CAAC,CACN,IAAI,GAAG,CAAC,CACR,SACG,2GACJ;AACR,CAAC,GCjJK,IAAiB,EAAS;CAC5B,MAAM,EAAU,MAAM;CACtB,MAAM,EAAS;AACnB,CAAC,GAEK,IAAiB,EAAS;CAC5B,MAAM,EAAU,MAAM;CACtB,WAAW,EAAS,CAAC,CAAC,MAAM,EAAe;CAC3C,KAAK,EAAM;CACX,UAAU,EAAS,CAAC,CAAC,SAAS;CAC9B,kBAAkB,EACN,EAAS,GAAG,EAAS,EAAS,GAAG,EAAU,CAAC,CAAC,CAAC,CACrD,SAAS;AAClB,CAAC,GAEK,IAAoB,EAAqB,QAAQ,CACnD,GACA,CACJ,CAAC;AAEgC,EAAS;CACtC,IAAI,EAAS;CACb,UAAU,EACN,EAAS;EACL,IAAI,EAAS,CAAC,CAAC,SAAS;EACxB,MAAM,EAAO,CAAC,aAAa,MAAM,CAAC;EAClC,SAAS,EAAS;EAClB,OAAO,EAAQ,CAAiB;EAChC,WAAW,EAAS,CAAC,CAAC,SAAS;CACnC,CAAC,CACL;CACA,OAAO,EAAS,CAAC,CAAC,SAAS;CAC3B,aAAa,EAAS,CAAC,CAAC,SAAS;CACjC,QAAQ,EAAS,CAAC,CAAC,SAAS;CAC5B,iBAAiB,EAAS,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;CAChD,iBAAiB,EAAS,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;CACpD,kBAAkB,EAAS,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;CACrD,YAAY,EAAO,CAAe,CAAC,CAAC,SAAS;CAC7C,OAAO,EAAS,CAAC,CAAC,SAAS;CAC3B,SAAS,GAAmB,SAAS;CACrC,WAAW;CACX,WAAW,EAAqB,SAAS;CACzC,cAAc,EAAS,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,SAAS;CACvD,eAAe,EAAQ,EAAO,EAAgB,CAAC,CAAC,CAAC,SAAS;CAC1D,gBAAgB,EAAQ,EAAS,CAAC,CAAC,CAAC,SAAS;CAC7C,gBAAgB,EAA0B,QAAQ,CAAC,CAAC,SAAS;CAC7D,eAAe,GAAoB,SAAS;CAC5C,iBAAiB,EAAS,EAAS,GAAG,EAAU,CAAC,CAAC,CAAC,SAAS;CAC5D,cAAc,EAAU,CAAC,CAAC,SAAS;AACvC,CAAC,GAmBwC,EAC7B;CACJ,IAAI,EAAS,CAAC,CAAC,IAAI,CAAC;CACpB,UAAU,EAAQ,EAAS,EAAE,MAAM,EAAS,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACnE,CAAC,CAAC,CACD,MAAM;AAEX,IAAY,IAAL,yBAAA,GAAA;QACH,EAAA,cAAA,gBACA,EAAA,gBAAA,mBACA,EAAA,mBAAA;AACJ,EAAA,CAAA,CAAA;AAkDiC,EAAO,gBAfjC,SAAA,GAAA;QAEH,EAAA,MAAA,OACA,EAAA,WAAA,YACA,EAAA,QAAA,SAEA,EAAA,QAAA,SAEA,EAAA,MAAA,OAEA,EAAA,YAAA,aAEA,EAAA,WAAA;AACJ,EAAA,CAAA,CAEwC,CAAW;AAqEnD,IAAa,oBAA4C,IAAI,IAAI;CAC7D;CACA;CACA;AACJ,CAAC,GAEY,IAAa,EAAS;CAC/B,IAAI,EAAS;CACb,UAAU,EAAQ,EAAU,CAAC;CAC7B,OAAO,EAAS,CAAC,CAAC,SAAS;CAC3B,SAAS,EAAS,CAAC,CAAC,SAAS;CAC7B,2BAA2B,EAAS,CAAC,CAAC,SAAS;CAC/C,WAAW,EAAc;CACzB,WAAW,EAAc;CACzB,UAAU,EAAS,EAAS,GAAG,EAAU,CAAC;CAC1C,gBAAgB,EAAS;CACzB,OAAO,EAAU;CACjB,SAAS,EAAS,CAAC,CAAC,SAAS;CAC7B,QAAQ,EAAS;CACjB,gBAAgB,EAAS;CACzB,SAAS,EAAU;CACnB,WAAW,EAAc,CAAC,CAAC,SAAS;CACpC,WAAW,EAAS,CAAC,CAAC,SAAS;CAC/B,sBAAsB,EAA2B,SAAS,CAAC,CAAC,SAAS;CACrE,SAAS,EAAU;CACnB,WAAW,EAAc,CAAC,CAAC,SAAS;CACpC,mBAAmB,EAAO,CAAiB,CAAC,CAAC,SAAS;CACtD,eAAe,EAAS,CAAC,CAAC,SAAS;CACnC,cAAc,EAAS;CACvB,eAAe,EAAc;AACjC,CAAC;AAEqC,EAAS;CAC3C,GAAG,EAAM,WAAW;CACpB,GAAG,EAAM,KAAK;EAAC;EAAa;EAAa;CAAe,CAAC;CACzD,GAAG,EAAM,QAAQ,CAAC,WAAW,QAAQ,CAAC;CACtC,GAAG,EAAM,MAAM,WAAW;CAC1B,GAAG,EAAM,MAAM,eAAe;CAC9B,GAAG,EAAM,IAAI;CACb,WAAW,EAAS,CAAC,CAAC,SAAS;CAC/B,SAAS,EAAS,CAAC,CAAC,SAAS;AACjC,CAAC;AAED,IAAa,IAAoB,EAAS;CACtC,IAAI,EAAS;CACb,SAAS,EAAS,CAAC,CAAC,SAAS;CAC7B,gBAAgB,EAAS;CACzB,SAAS,EAAS,CAAC,CAAC,SAAS;CAC7B,OAAO,EAAS,CAAC,CAAC,SAAS;CAC3B,QAAQ,EAAS;CACjB,WAAW,EAAc;CACzB,WAAW,EAAc;CACzB,eAAe,EAAc;CAC7B,UAAU,EAAQ,EAAU,CAAC;CAC7B,SAAS,EAAU;AACvB,CAAC,GChRG,IAAE,MAAK;CAAC,YAAY,GAAE,GAAE;EAAC,KAAK,WAAS,GAAE,KAAK,QAAM,GAAE,OAAO,eAAe,MAAK,UAAS,EAAC,UAAS,CAAC,EAAC,CAAC;CAAC;CAAC,IAAI,QAAO;EAAC,OAAO,KAAK;CAAM;CAAC,QAAQ,GAAE;EAAC,KAAK,SAAO,KAAK,UAAQ,CAAC,GAAE,KAAK,OAAO,KAAK,CAAC;CAAC;AAAC,GAAE,IAAE,cAAc,EAAC,CAAC,GAAE,IAAE,cAAc,EAAC;CAAC,YAAY,GAAE,GAAE;EAAC,IAAG,CAAC,MAAM,QAAQ,CAAC,GAAE,MAAM,MAAM,IAAI,EAAE,qDAAqD;EAAE,MAAM,GAAE,CAAC;CAAC;AAAC,GAAQ,IAAE,cAAiB,IAAE,cAAc,EAAC;CAAC,YAAY,GAAE,GAAE,GAAE;EAAC,MAAM,GAAE,CAAC,GAAE,KAAK,QAAM;CAAC;AAAC,GAAQ,IAAE,IAAI,EAAE,YAAW,IAAI;AAAI,OAAO;AAAiH,SAASA,GAAE,GAAE,GAAE;CAAC,IAAI;CAAE,KAAI,IAAI,IAAE,GAAE,IAAE,EAAE,QAAO,IAAE,GAAE,KAAI;EAAC,IAAI,IAAE,EAAE;EAAG,IAAG,aAAa,GAAE;GAAC,IAAG,EAAE,aAAW,GAAE;IAAC,KAAG,EAAE,KAAK,CAAC;IAAE;GAAQ;GAAC,IAAG,EAAE,MAAM,WAAS,GAAE;GAAS,AAAI,MAAE,EAAE,MAAM,GAAE,CAAC;GAAG,IAAI,IAAE,EAAE;GAAM,KAAI,IAAI,IAAE,GAAE,IAAE,EAAE,QAAO,IAAE,GAAE,KAAI,EAAE,KAAK,EAAE,EAAE;EAAC,OAAM,KAAG,EAAE,KAAK,CAAC;CAAC;CAAC,OAAO,KAAG;AAAC;AAAC,SAASC,GAAE,GAAE,GAAE;CAAC,IAAG,EAAE,WAAS,GAAE,OAAO,EAAE;CAAG,IAAG,EAAE,WAAS,GAAE,OAAO,IAAI,EAAE,GAAE,CAAC;CAAE,IAAI,IAAED,GAAE,GAAE,CAAC;CAAE,OAAO,EAAE,WAAS,IAAE,EAAE,MAAI,EAAE,QAAO,IAAI,EAAE,GAAE,CAAC;AAAE;AAA0C,OAAO,eAA7B,OAAO,OAAO,IAAI,GAA8B,cAAa,EAAC,OAAM,eAAc,CAAC;;;ACA54B,IAAI,IAAE,OAAO;EAAmB,GAAE,MAAI;CAAC,IAAI,IAAE,CAAC;CAAE,KAAI,IAAI,KAAK,GAAE,EAAE,GAAE,GAAE;EAAC,KAAI,EAAE;EAAG,YAAW,CAAC;CAAC,CAAC;CAAE,OAAO,KAAG,EAAE,GAAE,OAAO,aAAY,EAAC,OAAM,SAAQ,CAAC,GAAE;AAAC,EAAA,CAAG;CAAC,YAAS;CAAE,YAAS;CAAE,kBAAe;CAAE,WAAQ;CAAE,eAAY;CAAE,WAAQ;CAAE,YAAS;CAAE,WAAQ;CAAE,WAAQ;CAAE,YAAS;CAAE,YAAS;CAAE,WAAQ;CAAE,YAAS;CAAE,YAAS;CAAE,YAAS;CAAE,gBAAa;CAAE,WAAQ;CAAE,cAAW;CAAE,aAAU;CAAE,cAAW;AAAC,CAAC;AAAE,IAAM,IAAE;CAAC,MAAK;CAAW,UAAS;CAAE,MAAM,GAAE,GAAE,GAAE;EAAC,IAAI,IAAE,EAAE,GAAE,GAAE,CAAC;EAAE,OAAOI,GAAE,EAAE,MAAK,CAAC;CAAC;AAAC,GAAE,IAAE,GAAE,KAAE;CAAC,MAAK;CAAW,UAAS;CAAE,MAAM,GAAE,GAAE,GAAE;EAAC,IAAI,IAAE,EAAE,GAAEC,GAAE,CAAC;EAAE,OAAO,IAAIC,EAAE,EAAE,MAAK,CAAC;CAAC;AAAC;AAAE,SAAS,EAAE,GAAE,GAAE,GAAE;CAAC,IAAI,IAAE,MAAM,EAAE,MAAM;CAAE,KAAI,IAAI,IAAE,GAAE,IAAE,EAAE,QAAO,KAAI;EAAC,IAAI,IAAE,EAAE;EAAG,GAAE,GAAE,GAAE,CAAC,GAAE,EAAE,KAAG,EAAE,MAAM,CAAC;CAAC;CAAC,OAAO;AAAC;AAAC,IAAM,KAAE;CAAC,MAAK;CAAQ,SAAS,GAAE,GAAE;EAAC,IAAG,EAAE,MAAI,aAAa,UAAQ,EAAE,gBAAc,UAAS,MAAM,MAAM,IAAI,EAAE,KAAK,4EAA4E;CAAC;CAAE,MAAM,GAAE,GAAE,GAAE;EAAC,IAAI,IAAE,aAAa,SAAO,IAAIC,EAAE,SAAQC,EAAE,OAAM,CAAC,IAAEA,EAAE,MAAM,GAAEA,CAAC;EAAE,OAAO,IAAIF,EAAED,EAAE,MAAK,CAAC,CAAC,CAAC;CAAC;AAAC,GAAE,KAAE;CAAC,MAAK;CAAQ,SAAS,GAAE,GAAE;EAAC,IAAG,CAAC,KAAG,EAAE,gBAAc,QAAO,MAAM,MAAM,IAAI,EAAE,KAAK,0EAA0E;CAAC;CAAE,MAAM,GAAE,GAAE,EAAC,OAAMG,GAAE,OAAM,GAAE,cAAa,KAAG;EAAC,IAAI,IAAE,EAAEC,CAAC,IAAED,EAAEC,GAAE,EAAC,OAAMJ,EAAC,CAAC,IAAEG,EAAEC,CAAC;EAAE,OAAO,IAAIF,EAAE,EAAE,MAAK,GAAE,CAAC;CAAC;AAAC,GAAE,KAAE;CAAC,MAAK;CAAQ,UAAS,EAAE,QAAQ;AAAC,GAAE,IAAE;CAAC,MAAK;CAAQ,UAAS;AAAC,GAAE,KAAE,GAAE,KAAE,GAAE,KAAE;CAAC,MAAK;CAAQ,SAAS,GAAE,GAAE;EAAC,IAAG,CAAC,MAAM,QAAQ,CAAC,KAAG,EAAE,WAAS,GAAE,MAAM,MAAM,IAAI,EAAE,KAAK,2CAA2C;CAAC;AAAC,GAAE,KAAE;CAAC,MAAK;CAAQ,UAAS,EAAE,SAAS;AAAC,GAAE,IAAE;CAAC,MAAK;CAAQ,UAAS;AAAC,GAAE,IAAE,GAAE,KAAE,GAAE,KAAE,GAAE,IAAE,EAAC,MAAK,QAAO,GAAE,KAAE,GAAE,KAAE;CAAC,MAAK;CAAQ,SAAS,GAAE,GAAE;EAAC,IAAG,EAAE,aAAa,WAAS,OAAO,KAAG,UAAS,MAAM,MAAM,IAAI,EAAE,KAAK,0FAA0F;CAAC;CAAE,MAAM,GAAE,GAAE,GAAE;EAAC,IAAIC,IAAE,OAAO,KAAG,WAAS,IAAI,OAAO,GAAE,EAAE,MAAM,YAAU,EAAE,IAAE;EAAE,OAAO,IAAID,EAAE,EAAE,MAAK,EAAE,OAAMC,CAAC;CAAC;AAAC,GAAE,KAAE;CAAC,MAAK;CAAQ,aAAUC;AAAC,GAAE,KAAE;CAAC,MAAK;CAAW,UAAS,EAAE,UAAU;AAAC;AAAE,SAAS,EAAE,GAAE,GAAE;CAAC,IAAG,CAAC,MAAM,QAAQ,CAAC,GAAE,MAAM,MAAM,IAAI,EAAE,KAAK,+BAA+B;AAAC;AAAC,SAAS,EAAE,GAAE,GAAE;CAAC,IAAG,EAAE,GAAE,CAAC,GAAE,CAAC,EAAE,QAAO,MAAM,MAAM,IAAI,EAAE,KAAK,gDAAgD;AAAC;AAAC,SAAS,EAAE,GAAE,GAAE;CAAC,IAAG,EAAE,OAAO,KAAG,YAAU,OAAO,KAAG,YAAU,aAAa,OAAM,MAAM,MAAM,IAAI,EAAE,KAAK,gEAAgE;AAAC;AAAC,SAAS,EAAE,GAAE;CAAC,QAAO,GAAE,MAAI;EAAC,IAAG,OAAO,MAAI,GAAE,MAAM,MAAM,IAAI,EAAE,KAAK,2BAA2B,EAAE,EAAE;CAAC;AAAC;AAAC,SAAS,GAAE,GAAE,GAAE,GAAE;CAAC,IAAI,IAAE;CAAE,IAAG,CAAC,KAAG,EAAE,gBAAc,QAAO,MAAM,MAAM,IAAI,EAAE,KAAK,0BAA0B,EAAE,iBAAiB;AAAC;;;ACiBnpF,IAAY,IAAL,yBAAA,GAAA;QACH,EAAA,aAAA,cACA,EAAA,cAAA,eACA,EAAA,SAAA,UACA,EAAA,SAAA;AACJ,EAAA,CAAA,CAAA,GAEY,IAAL,yBAAA,GAAA;QACH,EAAA,MAAA,OACA,EAAA,OAAA,QACA,EAAA,OAAA,QACA,EAAA,OAAA,QACA,EAAA,QAAA,SACA,EAAA,WAAA,YACA,EAAA,WAAA,YACA,EAAA,gBAAA,kBACA,EAAA,gBAAA,kBACA,EAAA,YAAA,cACA,EAAA,QAAA,SACA,EAAA,gBAAA,kBACA,EAAA,eAAA,gBACA,EAAA,SAAA,UACA,EAAA,OAAA,QACA,EAAA,kBAAA,oBACA,EAAA,aAAA,cACA,EAAA,cAAA,eACA,EAAA,SAAA,UACA,EAAA,aAAA,cACA,EAAA,UAAA,WACA,EAAA,gBAAA,kBACA,EAAA,kBAAA,qBACA,EAAA,2BAAA,8BACA,EAAA,gBAAA,kBACA,EAAA,mBAAA,sBACA,EAAA,eAAA,kBACA,EAAA,iBAAA,mBACA,EAAA,cAAA,eACA,EAAA,eAAA,gBACA,EAAA,qBAAA;AACJ,EAAA,CAAA,CAAA,GCpDM,MAA0C,MACvC,IAGE;CAEH;EACI,SAAS,EAAQ;EACjB,QAAQ;CACZ;CACA;EACI,SAAS,EAAQ;EACjB,QAAQ;EACR,WAAW,EACP,WAAW,EACP,KAAK,EAAe,MAAM,GAC9B,EACJ;CACJ;CACA;EACI,SAAS,EAAQ;EACjB,QAAQ;CACZ;CACA;EACI,SAAS,EAAQ;EACjB,QAAQ;CACZ;CAEA;EACI,SAAS,EAAQ;EACjB,QAAQ;EACR,WAAW,EACP,QAAQ,EACJ,KAAK,GAAY,OACrB,EACJ;CACJ;CAEA;EACI,SAAS,EAAQ;EACjB,QAAQ;CACZ;CACA;EACI,SAAS,EAAQ;EACjB,QAAQ;EACR,WAAW,EACP,WAAW,EACP,KAAK,EAAe,MAAM,GAC9B,EACJ;CACJ;AACJ,IAjDW,CAAC,GCmCV,KAAgB,GAAoB,EACtC,QAAQ;CAAC;CAAQ;CAAU;AAAQ,EACvC,CAAC,GAUK,KAAoB,GAAuB,EAAE,KAAA,EAAI,CAAwB;AAIxD,IAAI,GACvB,GAAoB,GACpB;CACI;CACA;CACA,eAR4B,OAAY,MAAU,EAAO,SAAS,CAAK;AAS3E,CACJ;AAuHA,IAAM,IAAK,GAAoB,EAAiB;AAC9B,EAAG,QAAQ,GAAQ,UAAU,GAC7B,EAAG,QAAQ,GAAQ,UAAU,GAC5B,EAAG,QAAQ,EAAS,UAAU,GAChC,EAAG,QAAQ,EAAS,UAAU;;;ACzK/C,eAAsB,GAClB,GACA,GACA,IAAmC,CAAC,GACL;CAC/B,IAAI;EACA,IAAM,IAAO,EAAoB,CAAU,GACrC,IAAW,MAAM,MAAM,GAAG,EAAK,iBAAiB;GAClD,QAAQ;GACR,aAAa,EAAQ,eAAe;GACpC,SAAS;IACL,GAAG,EAAQ;IACX,gBAAgB;GACpB;GACA,MAAM,KAAK,UAAU,EAAE,UAAO,CAAC;EACnC,CAAC;EAOD,OANK,EAAS,MAMP,MAHa,EAAS,KAAK,EAAA,CAGtB,QAAQ,CAAC,IALV,CAAC;CAMhB,QAAQ;EACJ,OAAO,CAAC;CACZ;AACJ;;;AC1BA,IAAM,KAAqB,EAAW,GAAG,CAAiB;AAC1D,SAAS,EAAkB,GAAoB;CAC3C,IAAM,IAAS,GAAmB,UAAU,CAAG;CAC/C,OAAQ,EAAO,UAAU,EAAO,OAAO;AAC3C;AAQA,eAAe,GAAiB,GAAqC;CACjE,IAAM,IAAW,GAAG,EAAS,OAAO,GAAG,EAAS,aAAa,KAAK;CAClE,IAAI;EACA,IAAM,IAAQ,MAAM,EAAS,KAAK;EAIlC,OAAO,EAAK,SAAS,KAAK,KAAK,EAAK,OAAO,KAAK,KAAK;CACzD,QAAQ;EACJ,OAAO;CACX;AACJ;AA+GA,SAAgB,GACZ,GACgB;CAChB,IAAM,IAAW,EAAQ,WACnB,GAAgB,EAAQ,QAAQ,IAChC,WAAW,EAAS,UAEpB,IAAU,GAAG,EAAoB,EAAQ,OAAO,IAAI,KAKpD,IAAkB,GAAG,EAAoB,EAAQ,OAAO,IAAI,EAAS,QACvE,YACA,IAAI,EAAS,aACjB;CAEA,eAAe,EACX,GACA,GACA,IAAgC,QACtB;EACV,IAAM,IAAW,MAAM,MAAM,GAAG,IAAU,KAAO;GAC7C,aAAa,EAAQ,eAAe;GACpC,GAAG;GACH,SAAS;IACL,GAAG,EAAQ,UAAU;IACrB,GAAG,GAAM;GACb;EACJ,CAAC;EAED,IAAI,CAAC,EAAS,IACV,MAAU,MAAM,MAAM,GAAiB,CAAQ,CAAC;EAGhD,UAAiB,UAAU,EAAS,WAAW,KAInD,OAAO,EAAS,KAAK;CACzB;CAEA,OAAO;EACH,MAAM,iBAAiB,GAAS,GAAQ;GACpC,IAAM,IAAa,IACb,mBAAmB,mBAAmB,CAAM,MAC5C;GAIN,QAAO,MAHqB,EACxB,WAAW,mBAAmB,CAAO,EAAE,2CAA2C,GACtF,EAAA,CACqB,IAAI,CAAiB;EAC9C;EAEA,MAAM,aAAa,GAAQ;GACvB,IAAM,IAAW,MAAM,MACnB,GAAG,EAAgB,+BAA+B,mBAAmB,CAAM,EAAE,kBAC7E;IACI,aAAa,EAAQ,eAAe;IACpC,SAAS,EAAE,GAAG,EAAQ,UAAU,EAAE;GACtC,CACJ;GACA,IAAI,CAAC,EAAS,IACV,MAAU,MACN,cAAc,EAAS,OAAO,GAAG,EAAS,YAC9C;GAEJ,OAAQ,MAAM,EAAS,KAAK;EAChC;EAEA,uBAAuB,GAAY,GAAQ;GACvC,IAAM,IAAS,IAAS,iBAAiB;GAIzC,OAAO,KAAK,gBACR,GAAG,EAAgB,gBAAgB,mBAAmB,CAAU,EAAE,WAAW,GACjF;EACJ;EAEA,sBAAsB,GAAY;GAG9B,OAAO,KAAK,gBACR,GAAG,EAAgB,gBAAgB,mBAAmB,CAAU,EAAE,uBACtE;EACJ;EAEA,MAAM,eAAe,GAAY;GAC7B,IAAM,IAAW,MAAM,MACnB,GAAG,EAAgB,gBAAgB,mBAAmB,CAAU,KAChE;IACI,QAAQ;IACR,aAAa,EAAQ,eAAe;IACpC,SAAS,EAAE,GAAG,EAAQ,UAAU,EAAE;GACtC,CACJ;GACA,IAAI,CAAC,EAAS,IACV,MAAU,MACN,cAAc,EAAS,OAAO,GAAG,EAAS,YAC9C;EAER;EAEA,MAAM,QAAQ,GAAS,GAAQ;GAC3B,IAAM,IAAS,MAAM,EACjB,WAAW,mBAAmB,CAAO,EAAE,SAAS,mBAAmB,CAAM,GAC7E;GACA,OAAO,IAAS,EAAkB,CAAM,IAAI;EAChD;EAEA,MAAM,gBAAgB,GAAS,GAAQ,GAAO;GAC1C,OAAO,EACH,MAAM,EACF,WAAW,mBAAmB,CAAO,EAAE,SAAS,mBAAmB,CAAM,KACzE;IACI,QAAQ;IACR,SAAS,EAAE,gBAAgB,mBAAmB;IAC9C,MAAM,KAAK,UAAU,EAAE,SAAM,CAAC;GAClC,CACJ,CACJ;EACJ;EAEA,MAAM,WAAW,GAAS,GAAQ;GAC9B,MAAM,EACF,WAAW,mBAAmB,CAAO,EAAE,SAAS,mBAAmB,CAAM,KACzE,EAAE,QAAQ,SAAS,GACnB,MACJ;EACJ;EAEA,MAAM,oBAAoB,GAAQ;GAC9B,OAAO,EACH,qCAAqC,mBAAmB,CAAM,EAAE,gBACpE;EACJ;EAEA,MAAM,sBAAsB,GAAS;GACjC,OAAO,EAAyB,sBAAsB;IAClD,QAAQ;IACR,SAAS,EAAE,gBAAgB,mBAAmB;IAC9C,MAAM,KAAK,UAAU,CAAO;GAChC,CAAC;EACL;EAEA,MAAM,WAAW,GAAS;GACtB,MAAM,EACF,UACA;IACI,QAAQ;IACR,SAAS,EAAE,gBAAgB,mBAAmB;IAC9C,MAAM,KAAK,UAAU,CAAO;GAChC,GACA,MACJ;EACJ;EAEA,MAAM,SAAS,GAAS,GAAS;GAC7B,OAAO,EACH,kBAAkB,mBAAmB,CAAO,EAAE,UAAU,mBAAmB,CAAO,GACtF;EACJ;EAEA,MAAM,eAAe,GAAS,GAAS;GACnC,OAAO,EACH,kBAAkB,mBAAmB,CAAO,EAAE,UAAU,mBAAmB,CAAO,EAAE,QACxF;EACJ;EAEA,MAAM,YAAY,GAAS,GAAQ,GAAM;GACrC,IAAM,IAAW,IAAI,SAAS;GAC9B,EAAS,OAAO,QAAQ,CAAI;GAC5B,IAAM,IAAW,MAAM,MACnB,GAAG,EAAQ,UAAU,mBAAmB,CAAO,EAAE,SAAS,mBAAmB,CAAM,EAAE,gBACrF;IACI,QAAQ;IACR,aAAa,EAAQ,eAAe;IAEpC,SAAS,EAAQ,UAAU;IAC3B,MAAM;GACV,CACJ;GACA,IAAI,CAAC,EAAS,IAAI;IACd,IAAM,IAAO,MAAM,EAAS,KAAK,CAAC,CAAC,YAAY,EAAE,GAC7C,IAAQ,kBAAkB,EAAS;IACvC,IAAI;KACA,IACK,KAAK,MAAM,CAAI,CAAC,CAAwB,SAAS;IAC1D,QAAQ,CAER;IACA,MAAU,MAAM,CAAK;GACzB;GACA,OAAO,EAAS,KAAK;EACzB;EAEA,gBAAgB,GAAS,IAAO,QAAQ;GAEpC,OAAO,GAAG,EAAQ,UAAU,mBAAmB,CAAO,EAAE,GAD3C,MAAS,cAAc,mBAAmB;EAE3D;EAEA,gBAAgB,GAAK;GACjB,IAAM,IAAS,EACV,UAAU,CAAC,EACT,eAAkB,MAAM,CAAgB;GAK/C,OAJK,IAIE,GAAG,IADQ,EAAI,SAAS,GAAG,IAAI,MAAM,IAClB,QAAQ,mBAAmB,CAAM,MAHhD;EAIf;EAEA,YAAY,GAAS,GAAQ,GAAgB;GACzC,IAAM,IAAO,GAAG,EAAQ,UAAU,mBAAmB,CAAO,EAAE,SAAS,mBAAmB,CAAM,EAAE,SAAS,mBAAmB,CAAc,EAAE;GAC9I,OAAO,KAAK,gBAAgB,CAAI;EACpC;EAEA,MAAM,oBACF,GACA,GACA,GACA,IAAa,GACf;GACE,OAAO,EACH,WAAW,mBAAmB,CAAO,EAAE,0BACvC;IACI,QAAQ;IACR,SAAS,EAAE,gBAAgB,mBAAmB;IAC9C,MAAM,KAAK,UAAU;KACjB;KACA;KACA;IACJ,CAAC;GACL,CACJ;EACJ;EAEA,MAAM,uBAAuB,GAAS,GAAY;GAC9C,OAAO,EAKH,WAAW,mBAAmB,CAAO,EAAE,qBAAqB,mBAAmB,CAAU,EAAE,UAC/F;EACJ;EAEA,MAAM,eAAe,GAAK,GAAK,GAAM;GACjC,IAAM,IAAS,IAAI,gBAAgB;IAC/B,KAAK,OAAO,CAAG;IACf,KAAK,OAAO,CAAG;GACnB,CAAC;GACD,AAAI,KACA,EAAO,IAAI,QAAQ,CAAI;GAE3B,IAAI;IAIA,QAAO,MAHY,EACf,qBAAqB,GACzB,EAAA,CACY;GAChB,QAAQ;IACJ;GACJ;EACJ;EAEA,MAAM,eAAe,GAAO,GAAM;GAC9B,IAAM,IAAS,IAAI,gBAAgB,EAAE,GAAG,EAAM,CAAC;GAC/C,AAAI,KACA,EAAO,IAAI,QAAQ,CAAI;GAE3B,IAAI;IACA,OAAO,MAAM,EAIV,qBAAqB,GAAQ;GACpC,QAAQ;IACJ;GACJ;EACJ;EAEA,MAAM,qBAAqB,GAAS,GAAY;GAC5C,IAAM,IAAS,IAAI,gBAAgB,EAAE,cAAW,CAAC;GACjD,OAAO,EACH,WAAW,mBAAmB,CAAO,EAAE,uBAAuB,GAClE;EACJ;EAEA,MAAM,yBAAyB,GAAS,GAAY;GAChD,IAAM,IAAS,IAAI,gBAAgB,EAAE,cAAW,CAAC;GACjD,OAAO,EACH,WAAW,mBAAmB,CAAO,EAAE,oBAAoB,GAC/D;EACJ;EAQA,MAAM,mBAAmB,GAAS,GAAQ,GAAS;GAC/C,OAAO,GAAmB,MACtB,MAAM,EACF,WAAW,mBAAmB,CAAO,EAAE,iBACvC;IACI,QAAQ;IACR,SAAS,EAAE,gBAAgB,mBAAmB;IAC9C,MAAM,KAAK,UAAU;KACjB,GAAI,IAAS,EAAE,UAAO,IAAI,CAAC;KAI3B,GAAI,GAAS,gBACP,EAAE,eAAe,EAAQ,cAAc,IACvC,CAAC;KACP,GAAI,GAAS,kBACP,EAAE,iBAAiB,EAAQ,gBAAgB,IAC3C,CAAC;IACX,CAAC;GACL,CACJ,CACJ;EACJ;EAOA,MAAM,kBAAkB,GAAS,GAAW;GACxC,MAAM,EACF,WAAW,mBAAmB,CAAO,EAAE,iBAAiB,mBAAmB,CAAS,KACpF;IAAE,QAAQ;IAAU,WAAW;GAAK,GACpC,MACJ;EACJ;EAEA,iBAAiB,GAAQ;GACrB,OAAO,GAAwB,EAAQ,SAAS,GAAQ;IACpD,SAAS,EAAQ,UAAU;IAC3B,aAAa,EAAQ;GACzB,CAAC;EACL;CACJ;AACJ"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { E as e, S as t, T as n, _ as r, a as i, b as a, c as o, f as s, g as c, h as l, i as u, l as d, m as f, n as p, o as m, p as h, r as g, x as _, y as ee } from "./schemas-DxbHVg3r.js";
|
|
2
|
-
import { E as te } from "./Agent-
|
|
3
|
-
import { r as ne, t as re } from "./createChatbotApiClient-
|
|
2
|
+
import { E as te } from "./Agent-De2gFNjR.js";
|
|
3
|
+
import { r as ne, t as re } from "./createChatbotApiClient-MkaPbGWB.js";
|
|
4
4
|
import { t as ie } from "./src-DT8FLE4_.js";
|
|
5
5
|
import { n as ae } from "./message-RohfrdWS.js";
|
|
6
6
|
import { t as oe } from "./useSafeLocalStorage-Ce3S1Ayn.js";
|
|
@@ -2832,6 +2832,9 @@ I({
|
|
|
2832
2832
|
prefix: "call",
|
|
2833
2833
|
size: 24
|
|
2834
2834
|
}), new TextEncoder(), I({
|
|
2835
|
+
prefix: "call",
|
|
2836
|
+
size: 24
|
|
2837
|
+
}), I({
|
|
2835
2838
|
prefix: "aiobj",
|
|
2836
2839
|
size: 24
|
|
2837
2840
|
});
|
|
@@ -4137,4 +4140,4 @@ function gi(e) {
|
|
|
4137
4140
|
//#endregion
|
|
4138
4141
|
export { L as a, Fr as i, gi as n, ci as r, li as t };
|
|
4139
4142
|
|
|
4140
|
-
//# sourceMappingURL=useChatbotStore-
|
|
4143
|
+
//# sourceMappingURL=useChatbotStore-BzfqjiYz.js.map
|