@8wave/ai-elements 0.115.0-beta.23 → 0.115.0-beta.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/dist/_chunks/{PkStreamingMarkdown-BKxA6Ntl.js → PkStreamingMarkdown-B7SRIqnV.js} +2 -2
  2. package/dist/_chunks/{PkStreamingMarkdown-BKxA6Ntl.js.map → PkStreamingMarkdown-B7SRIqnV.js.map} +1 -1
  3. package/dist/_chunks/{PkToolRequestOAuthConnection-CgQePKKb.js → PkToolRequestOAuthConnection-CbZn1f14.js} +31 -25
  4. package/dist/_chunks/PkToolRequestOAuthConnection-CbZn1f14.js.map +1 -0
  5. package/dist/_chunks/{PkToolShowArtifact-CHxeuKEU.js → PkToolShowArtifact-CRQySuGC.js} +2 -2
  6. package/dist/_chunks/{PkToolShowArtifact-CHxeuKEU.js.map → PkToolShowArtifact-CRQySuGC.js.map} +1 -1
  7. package/dist/_chunks/{PkToolShowCalendarEvent-D0jVbqWt.js → PkToolShowCalendarEvent-Cj7yRj-0.js} +2 -2
  8. package/dist/_chunks/{PkToolShowCalendarEvent-D0jVbqWt.js.map → PkToolShowCalendarEvent-Cj7yRj-0.js.map} +1 -1
  9. package/dist/_chunks/{PkToolShowContactForm-DqVLVwqJ.js → PkToolShowContactForm-DGmzPa3d.js} +2 -2
  10. package/dist/_chunks/{PkToolShowContactForm-DqVLVwqJ.js.map → PkToolShowContactForm-DGmzPa3d.js.map} +1 -1
  11. package/dist/_chunks/{PkToolShowForm-YJQPYfEe.js → PkToolShowForm-76LQdZHH.js} +2 -2
  12. package/dist/_chunks/{PkToolShowForm-YJQPYfEe.js.map → PkToolShowForm-76LQdZHH.js.map} +1 -1
  13. package/dist/_chunks/{PkToolShowImageGallery-1mq-_cnp.js → PkToolShowImageGallery-BmpcrdIL.js} +2 -2
  14. package/dist/_chunks/{PkToolShowImageGallery-1mq-_cnp.js.map → PkToolShowImageGallery-BmpcrdIL.js.map} +1 -1
  15. package/dist/_chunks/{PkToolShowSources-ClqmBUMB.js → PkToolShowSources-13IBQve7.js} +3 -3
  16. package/dist/_chunks/{PkToolShowSources-ClqmBUMB.js.map → PkToolShowSources-13IBQve7.js.map} +1 -1
  17. package/dist/_chunks/{PkToolShowWebPages-BgXlRdmH.js → PkToolShowWebPages-CCSRAlz5.js} +2 -2
  18. package/dist/_chunks/{PkToolShowWebPages-BgXlRdmH.js.map → PkToolShowWebPages-CCSRAlz5.js.map} +1 -1
  19. package/dist/_chunks/{markdown-BAq2EAVh.js → markdown-tS_2A0k9.js} +5 -2
  20. package/dist/_chunks/{markdown-BAq2EAVh.js.map → markdown-tS_2A0k9.js.map} +1 -1
  21. package/dist/_chunks/{url-validation-uLMZ5-AU.js → url-validation-9DstIfq2.js} +9 -2
  22. package/dist/_chunks/{url-validation-uLMZ5-AU.js.map → url-validation-9DstIfq2.js.map} +1 -1
  23. package/dist/ai-elements.es.js +23 -13
  24. package/dist/ai-elements.es.js.map +1 -1
  25. package/dist-vue/PkChatbot.js +1 -1
  26. package/dist-vue/PkChatbotEmptyState.js +1 -1
  27. package/dist-vue/PkChatbotInput.js +1 -1
  28. package/dist-vue/PkChatbotMessages.js +1 -1
  29. package/dist-vue/PkChatbotSteps.js +1 -1
  30. package/dist-vue/PkChatbotViewChat.js +1 -1
  31. package/dist-vue/PkChatbotViewConversations.js +1 -1
  32. package/dist-vue/PkChatbotViewFiles.js +1 -1
  33. package/dist-vue/PkChatbotViewProfile.js +1 -1
  34. package/dist-vue/_chunks/{Document-CRiJBpnk.js → Document-BmfGStvM.js} +5 -2
  35. package/dist-vue/_chunks/{Document-CRiJBpnk.js.map → Document-BmfGStvM.js.map} +1 -1
  36. package/dist-vue/_chunks/{PkChatbot-_7hJo-g0.js → PkChatbot-DKqKEsUn.js} +7 -7
  37. package/dist-vue/_chunks/{PkChatbot-_7hJo-g0.js.map → PkChatbot-DKqKEsUn.js.map} +1 -1
  38. package/dist-vue/_chunks/{PkChatbotEmptyState-Dicjr_Fv.js → PkChatbotEmptyState-BPPP0-0U.js} +2 -2
  39. package/dist-vue/_chunks/{PkChatbotEmptyState-Dicjr_Fv.js.map → PkChatbotEmptyState-BPPP0-0U.js.map} +1 -1
  40. package/dist-vue/_chunks/{PkChatbotInput-DcLmOqA1.js → PkChatbotInput-BHcxLnWU.js} +2 -2
  41. package/dist-vue/_chunks/{PkChatbotInput-DcLmOqA1.js.map → PkChatbotInput-BHcxLnWU.js.map} +1 -1
  42. package/dist-vue/_chunks/{PkChatbotMessages-ClPdP7sw.js → PkChatbotMessages-CaHFzdIC.js} +16 -16
  43. package/dist-vue/_chunks/{PkChatbotMessages-ClPdP7sw.js.map → PkChatbotMessages-CaHFzdIC.js.map} +1 -1
  44. package/dist-vue/_chunks/{PkChatbotSteps-CPPjwTJN.js → PkChatbotSteps-CXiFF3Z-.js} +2 -2
  45. package/dist-vue/_chunks/{PkChatbotSteps-CPPjwTJN.js.map → PkChatbotSteps-CXiFF3Z-.js.map} +1 -1
  46. package/dist-vue/_chunks/{PkChatbotViewChat-BBYfIQBR.js → PkChatbotViewChat-D5HtjK3u.js} +8 -6
  47. package/dist-vue/_chunks/{PkChatbotViewChat-BBYfIQBR.js.map → PkChatbotViewChat-D5HtjK3u.js.map} +1 -1
  48. package/dist-vue/_chunks/{PkChatbotViewConversations-DvmRjVND.js → PkChatbotViewConversations-C5O-IocA.js} +2 -2
  49. package/dist-vue/_chunks/{PkChatbotViewConversations-DvmRjVND.js.map → PkChatbotViewConversations-C5O-IocA.js.map} +1 -1
  50. package/dist-vue/_chunks/{PkChatbotViewFiles-D7KcAEiB.js → PkChatbotViewFiles-W8DDmtTi.js} +3 -3
  51. package/dist-vue/_chunks/{PkChatbotViewFiles-D7KcAEiB.js.map → PkChatbotViewFiles-W8DDmtTi.js.map} +1 -1
  52. package/dist-vue/_chunks/{PkChatbotViewProfile-C1eLHU7x.js → PkChatbotViewProfile--upofqcF.js} +2 -2
  53. package/dist-vue/_chunks/{PkChatbotViewProfile-C1eLHU7x.js.map → PkChatbotViewProfile--upofqcF.js.map} +1 -1
  54. package/dist-vue/_chunks/{PkStreamingMarkdown-DYy79C1P.js → PkStreamingMarkdown-it3X7T75.js} +2 -2
  55. package/dist-vue/_chunks/{PkStreamingMarkdown-DYy79C1P.js.map → PkStreamingMarkdown-it3X7T75.js.map} +1 -1
  56. package/dist-vue/_chunks/PkToolRequestOAuthConnection-BiaSF6R_.js +124 -0
  57. package/dist-vue/_chunks/PkToolRequestOAuthConnection-BiaSF6R_.js.map +1 -0
  58. package/dist-vue/_chunks/{PkToolShowArtifact-DUOnFdfa.js → PkToolShowArtifact-BFyFYjHI.js} +2 -2
  59. package/dist-vue/_chunks/{PkToolShowArtifact-DUOnFdfa.js.map → PkToolShowArtifact-BFyFYjHI.js.map} +1 -1
  60. package/dist-vue/_chunks/{PkToolShowCalendarEvent-BsBdsbV0.js → PkToolShowCalendarEvent-yttlTHiX.js} +2 -2
  61. package/dist-vue/_chunks/{PkToolShowCalendarEvent-BsBdsbV0.js.map → PkToolShowCalendarEvent-yttlTHiX.js.map} +1 -1
  62. package/dist-vue/_chunks/{PkToolShowContactForm-1TFKvG_s.js → PkToolShowContactForm-YpaC_31s.js} +2 -2
  63. package/dist-vue/_chunks/{PkToolShowContactForm-1TFKvG_s.js.map → PkToolShowContactForm-YpaC_31s.js.map} +1 -1
  64. package/dist-vue/_chunks/{PkToolShowDiagram-Co3GRItt.js → PkToolShowDiagram-Bdxjd0BJ.js} +2 -2
  65. package/dist-vue/_chunks/{PkToolShowDiagram-Co3GRItt.js.map → PkToolShowDiagram-Bdxjd0BJ.js.map} +1 -1
  66. package/dist-vue/_chunks/{PkToolShowEmail-BDsBoETQ.js → PkToolShowEmail-CNkFP7qC.js} +2 -2
  67. package/dist-vue/_chunks/{PkToolShowEmail-BDsBoETQ.js.map → PkToolShowEmail-CNkFP7qC.js.map} +1 -1
  68. package/dist-vue/_chunks/{PkToolShowForm-DwFKxMJd.js → PkToolShowForm-FKJNKXPq.js} +2 -2
  69. package/dist-vue/_chunks/{PkToolShowForm-DwFKxMJd.js.map → PkToolShowForm-FKJNKXPq.js.map} +1 -1
  70. package/dist-vue/_chunks/{PkToolShowImageGallery-DudQzBx4.js → PkToolShowImageGallery-DmhZLnBk.js} +2 -2
  71. package/dist-vue/_chunks/{PkToolShowImageGallery-DudQzBx4.js.map → PkToolShowImageGallery-DmhZLnBk.js.map} +1 -1
  72. package/dist-vue/_chunks/{PkToolShowMessage-Dau3agUy.js → PkToolShowMessage-C9xFAi1s.js} +2 -2
  73. package/dist-vue/_chunks/{PkToolShowMessage-Dau3agUy.js.map → PkToolShowMessage-C9xFAi1s.js.map} +1 -1
  74. package/dist-vue/_chunks/{PkToolShowProductList-CsupMsuy.js → PkToolShowProductList-k1ckf1Ko.js} +2 -2
  75. package/dist-vue/_chunks/{PkToolShowProductList-CsupMsuy.js.map → PkToolShowProductList-k1ckf1Ko.js.map} +1 -1
  76. package/dist-vue/_chunks/{PkToolShowSources-CIccPA8Z.js → PkToolShowSources-DE0RO8z9.js} +4 -4
  77. package/dist-vue/_chunks/{PkToolShowSources-CIccPA8Z.js.map → PkToolShowSources-DE0RO8z9.js.map} +1 -1
  78. package/dist-vue/_chunks/{PkToolShowWebPages-D4E3Xzg1.js → PkToolShowWebPages-v-6DGCNM.js} +3 -3
  79. package/dist-vue/_chunks/{PkToolShowWebPages-D4E3Xzg1.js.map → PkToolShowWebPages-v-6DGCNM.js.map} +1 -1
  80. package/dist-vue/_chunks/{PkUrl-Cu3qKl4G.js → PkUrl-C5UXwNxy.js} +2 -2
  81. package/dist-vue/_chunks/{PkUrl-Cu3qKl4G.js.map → PkUrl-C5UXwNxy.js.map} +1 -1
  82. package/dist-vue/_chunks/{createChatbotApiClient-BJz36z7v.js → createChatbotApiClient-L7wpQUUA.js} +2 -2
  83. package/dist-vue/_chunks/{createChatbotApiClient-BJz36z7v.js.map → createChatbotApiClient-L7wpQUUA.js.map} +1 -1
  84. package/dist-vue/_chunks/mcpOAuthReport-DG84H11Y.js +9 -0
  85. package/dist-vue/_chunks/mcpOAuthReport-DG84H11Y.js.map +1 -0
  86. package/dist-vue/_chunks/{url-validation-uLMZ5-AU.js → url-validation-9DstIfq2.js} +9 -2
  87. package/dist-vue/_chunks/{url-validation-uLMZ5-AU.js.map → url-validation-9DstIfq2.js.map} +1 -1
  88. package/dist-vue/_chunks/{useChatbotStore-D3Q1ZgQg.js → useChatbotStore-Ctr5gDIr.js} +2 -2
  89. package/dist-vue/_chunks/{useChatbotStore-D3Q1ZgQg.js.map → useChatbotStore-Ctr5gDIr.js.map} +1 -1
  90. package/dist-vue/api.js +1 -1
  91. package/dist-vue/composables.js +10 -2
  92. package/dist-vue/composables.js.map +1 -1
  93. package/dist-vue/index.js +2973 -2972
  94. package/dist-vue/index.js.map +1 -1
  95. package/dist-vue/packages/auth/src/social-redirect-plugin.d.ts +13 -1
  96. package/dist-vue/packages/components/src/chat/PkToolRequestOAuthConnection.d.ts +5 -0
  97. package/dist-vue/packages/components/src/chat/index.d.ts +1 -0
  98. package/dist-vue/packages/components/src/chat/mcpOAuthReport.d.ts +11 -0
  99. package/dist-vue/packages/models/src/schema/Document.d.ts +1 -0
  100. package/dist-vue/packages/models/src/schema/McpServer.d.ts +0 -3
  101. package/dist-vue/packages/models/src/schema/Organization.d.ts +23 -6
  102. package/package.json +1 -1
  103. package/dist/_chunks/PkToolRequestOAuthConnection-CgQePKKb.js.map +0 -1
  104. package/dist-vue/_chunks/PkToolRequestOAuthConnection-a2LegFoE.js +0 -122
  105. package/dist-vue/_chunks/PkToolRequestOAuthConnection-a2LegFoE.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import { C as e, L as t, O as n, Tt as r, _ as i, b as a, bt as o, d as s, g as c, h as l, it as u, m as d, pt as f, v as p, x as m, xt as h, z as g } from "./vue.runtime.esm-bundler-CIT_Sbqw.js";
2
2
  import "./src-BQHP1-Xs.js";
3
- import { n as _ } from "./url-validation-uLMZ5-AU.js";
3
+ import { n as _ } from "./url-validation-9DstIfq2.js";
4
4
  import { t as v } from "./index.es-C2U5wcOx.js";
5
5
  import { t as y } from "./PkLazyImg-CNrySgjY.js";
6
6
  import { t as b } from "./PkUrl-BPbjZJ1A.js";
@@ -75,4 +75,4 @@ var x = {
75
75
  //#endregion
76
76
  export { O as default };
77
77
 
78
- //# sourceMappingURL=PkToolShowWebPages-BgXlRdmH.js.map
78
+ //# sourceMappingURL=PkToolShowWebPages-CCSRAlz5.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PkToolShowWebPages-BgXlRdmH.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;IACjC,AAAI,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-CCSRAlz5.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;IACjC,AAAI,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"}
@@ -183,7 +183,10 @@ var O = o({
183
183
  I.File, I.Url, I.PlainText, o({
184
184
  document: L,
185
185
  returnedToRoot: u()
186
- }), o({ count: s().int() }), o({ agentId: e() }), o({
186
+ }), o({
187
+ count: s().int(),
188
+ retentionDays: s().int().min(0)
189
+ }), o({ agentId: e() }), o({
187
190
  purged: s().int(),
188
191
  remaining: s().int()
189
192
  }), o({
@@ -330,4 +333,4 @@ var R = (e) => {
330
333
  //#endregion
331
334
  export { B as a, z as i, H as n, R as r, U as t };
332
335
 
333
- //# sourceMappingURL=markdown-BAq2EAVh.js.map
336
+ //# sourceMappingURL=markdown-tS_2A0k9.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"markdown-BAq2EAVh.js","names":[],"sources":["../../../../packages/models/src/schema/constants.ts","../../../../packages/models/src/schema/Header.ts","../../../../packages/models/src/schema/Document.ts","../../../../packages/utils/src/markdown.ts"],"sourcesContent":["/**\n * The models an agent of this platform may be pointed at.\n *\n * The gateway listing DESCRIBES what exists, this list PERMITS. They are two\n * different questions, and conflating them broke production once: on\n * 2026-07-23 two models entered the catalog before the installed\n * `@ai-sdk/gateway` knew them, and their tool calls failed under the generic\n * handling. Exposing every model the day the listing shows it would reproduce\n * that by construction.\n *\n * Adding one is a line here, after the checklist in\n * `docs/agents/llm-integration.md`: it must be `type: language` in the\n * listing, produce text and carry the `tool-use` tag. Everything else about\n * it, the commercial name, the price, the context window, the two privacy\n * flags, comes from the listing and is never written down twice.\n *\n * A test checks every id against a saved copy of the listing, which is what\n * replaces the by-hand verification that missed a model on 2026-09-18.\n */\nexport const GATEWAY_MODELS = [\n // OpenAI\n 'openai/gpt-5-nano',\n 'openai/gpt-5-mini',\n 'openai/gpt-5.1-thinking',\n 'openai/gpt-5.2',\n 'openai/gpt-5.4-nano',\n 'openai/gpt-5.4-mini',\n 'openai/gpt-5.4',\n 'openai/gpt-5.4-pro',\n 'openai/gpt-5.5',\n 'openai/gpt-5.5-pro',\n 'openai/gpt-5.6-luna',\n 'openai/gpt-5.6-terra',\n 'openai/gpt-5.6-sol',\n 'openai/gpt-5.6-luna-fast',\n 'openai/gpt-5.6-terra-fast',\n 'openai/gpt-5.6-sol-fast',\n 'openai/gpt-6-astra',\n 'openai/gpt-6-astra-fast',\n 'openai/gpt-6-sol',\n 'openai/gpt-6-sol-fast',\n 'openai/gpt-6-luna',\n 'openai/gpt-6-luna-fast',\n 'openai/gpt-6.1-sol',\n 'openai/gpt-6.1-sol-fast',\n // Google Gemini\n 'google/gemini-2.5-flash-lite',\n 'google/gemini-2.5-flash',\n 'google/gemini-2.5-pro',\n 'google/gemini-3-flash',\n 'google/gemini-3.1-pro-preview',\n 'google/gemini-3.1-flash-lite',\n 'google/gemini-3.5-flash',\n 'google/gemini-3.5-flash-lite',\n 'google/gemini-3.6-flash',\n 'google/gemini-3.7-flash',\n 'google/gemini-3.8-flash',\n // Anthropic Claude\n 'anthropic/claude-haiku-4.5',\n 'anthropic/claude-sonnet-4.6',\n 'anthropic/claude-sonnet-5',\n 'anthropic/claude-sonnet-5.5',\n 'anthropic/claude-opus-4.6',\n 'anthropic/claude-opus-4.7',\n 'anthropic/claude-opus-4.8',\n 'anthropic/claude-opus-5',\n 'anthropic/claude-opus-5-fast',\n 'anthropic/claude-opus-5.5',\n 'anthropic/claude-opus-5.5-fast',\n 'anthropic/claude-fable-5',\n 'anthropic/claude-fable-5.1',\n // Deepseek\n 'deepseek/deepseek-v3.2',\n 'deepseek/deepseek-v4-flash-0731',\n 'deepseek/deepseek-v4.1-flash',\n 'deepseek/deepseek-v4-pro-0813',\n // Alibaba\n 'alibaba/qwen3.6-plus',\n 'alibaba/qwen3.7-max',\n 'alibaba/qwen3.7-plus',\n 'alibaba/qwen3.7-flash',\n 'alibaba/qwen3.8-flash',\n 'alibaba/qwen3.8-max',\n 'alibaba/qwen3.8-27b',\n 'alibaba/qwen3.8-max-0902',\n 'alibaba/qwen3.8-omni-flash',\n 'alibaba/qwen3.8-max-prime',\n // SpaceXAI\n 'spacexai/grok-4.3',\n 'spacexai/grok-4.6',\n 'spacexai/grok-4.7',\n // z.ai\n 'zai/glm-5.2',\n 'zai/glm-5.2-fast',\n 'zai/glm-5.3',\n 'zai/glm-5.3-flash',\n 'zai/glm-5.3-fast',\n 'zai/glm-5.3-flashx',\n // Meta\n 'meta/muse-spark-1.1',\n 'meta/muse-spark-1.2',\n 'meta/muse-spark-1.3',\n // Moonshot AI\n 'moonshotai/kimi-k3',\n 'moonshotai/kimi-k3-fast',\n // Mistral\n 'mistral/ministral-14b',\n 'mistral/mistral-small',\n 'mistral/mistral-medium-3.5',\n 'mistral/mistral-large-3',\n // Xiaomi\n 'xiaomi/mimo-v2.6-flash',\n 'xiaomi/mimo-v2.6-pro',\n 'xiaomi/mimo-v2.6-pro-ultraspeed',\n] as const satisfies readonly string[]\n\n/**\n * A model id: an entry of {@link GATEWAY_MODELS}, or a `byok/` id served by an\n * organization's own endpoint. A plain string on purpose, because the second\n * half cannot be enumerated.\n */\nexport type ModelId = string\n\n/**\n * Prices are stored per token, the unit the gateway listing publishes, and\n * shown per million, the unit every price page uses. One copy, so the page,\n * its dialogs and the picker never disagree on the factor.\n */\nexport const PER_MILLION_TOKENS = 1_000_000\n\n/**\n * The models the platform falls back to when an organization has expressed no\n * preference. The only model ids written in the code besides the curated list.\n */\nexport const PLATFORM_MODEL_DEFAULTS = {\n /** New agents, and the runtime fallback of an agent with no model. */\n agentModel: 'openai/gpt-5.6-terra',\n /** Question reformulation, JSON to schema, memory reconciliation. */\n utilityModel: 'google/gemini-3-flash',\n} as const\n\n/**\n * Models used to vectorize text, never to answer. Kept apart from\n * {@link GATEWAY_MODELS} so an embedding id cannot reach the chat plumbing,\n * and out of the catalog for the same reason: they are not selectable.\n */\nexport enum EmbeddingModel {\n textEmbedding3Small = 'openai/text-embedding-3-small',\n textEmbedding3Large = 'openai/text-embedding-3-large',\n geminiEmbedding2 = 'google/gemini-embedding-2',\n}\n\nexport const EMBED_MODEL = EmbeddingModel.geminiEmbedding2\n\n/**\n * Model that answers typed questions (yes/no, choice, score) with calibrated\n * probabilities instead of text, through the gateway's `experimental_evaluate`\n * (TypeSafe Jev). Out of the catalog like the embeddings: it decides for the\n * platform, it never answers the user. Its gateway listing reports no ZDR,\n * yet a ZDR request is served, routed to TypeSafe alone (measured\n * 2026-09-28, scripts/spikeJevEvaluation.ts).\n */\nexport const EVALUATION_MODEL = 'typesafe-ai/jev'\n\n/**\n * Supported languages for documents and revised answers\n */\nexport enum SupportedLanguage {\n it = 'it',\n en = 'en',\n es = 'es',\n fr = 'fr',\n de = 'de',\n}\n\n/**\n * Language display names (i18n keys)\n */\nexport const LANGUAGE_NAMES: Record<SupportedLanguage, string> = {\n [SupportedLanguage.it]: 'language.italian',\n [SupportedLanguage.en]: 'language.english',\n [SupportedLanguage.es]: 'language.spanish',\n [SupportedLanguage.fr]: 'language.french',\n [SupportedLanguage.de]: 'language.german',\n}\n\n/**\n * Content extraction strategies for URL scraping\n */\nexport enum ExtractionStrategy {\n /** Use Mozilla Readability for content extraction (fast, free, no API calls) */\n READABILITY = 'readability',\n /** Use AI-based extraction (better for complex layouts, requires API calls) */\n AI = 'ai',\n}\n\n/**\n * Browser engine options for URL scraping\n */\nexport enum BrowserEngine {\n /** Use simple HTTP fetch (fast, lightweight, no JavaScript support) */\n FETCH = 'fetch',\n /** Use Puppeteer with headless Chrome (full browser, JavaScript support) */\n PUPPETEER = 'puppeteer',\n /** Delegate browser rendering to an external pdf-image-generator service */\n REMOTE = 'remote',\n}\n\n/**\n * Which report family has to account for a credit charge.\n *\n * The hourly reconciliation trusts `cost_reports` (the gateway's own billing,\n * copied in house) as the source of truth for what an organization spent. A\n * charge whose supplier is not the gateway has no counterpart there, so it must\n * be told apart or the reconciliation forgives it: that is what happened to the\n * voice minutes until 2026-08-31.\n *\n * Declared here, written on the ledger row at charge time, never inferred from\n * `source` downstream: the next non-gateway supplier must be a compile-time\n * decision, not a string nobody remembered to add to a list.\n */\nexport enum BillingSource {\n /** Billed by the AI gateway, so it lands in `cost_reports`. */\n GATEWAY = 'gateway',\n /** Billed by another supplier (voice minutes, OCR): the ledger is the only record. */\n INTERNAL = 'internal',\n}\n\n/**\n * Kinds of row on the credit ledger.\n *\n * It used to be a free string with exactly one value ever written, `debit`.\n * Adding a second one is not free: the hourly reconciliation sums debits to\n * rebuild the real-time estimate, and the analytics endpoint sums the ledger to\n * chart spend, so a new type that nobody filters out is a number silently\n * doubled.\n */\nexport enum CreditTransactionType {\n /** A charge for something consumed, written in real time. */\n DEBIT = 'debit',\n /** The hourly settlement against the gateway report: the audit trail of a balance move. */\n RECONCILIATION = 'reconciliation',\n}\n\n/**\n * Prefix that marks a model served by the organization's own OpenAI compatible\n * endpoint rather than by the gateway.\n *\n * It is not a gateway brand, which is the point: every switch on the provider\n * (reasoning options, the Google thought signature repair, the per-provider\n * timeouts, the native web search tools) falls into its default branch without\n * any of them having to learn about BYOK.\n */\nexport const BYOK_MODEL_PREFIX = 'byok/'\n\nexport const isByokModel = (id?: string | null): boolean =>\n Boolean(id?.startsWith(BYOK_MODEL_PREFIX))\n\n/**\n * The id as the endpoint wants it, with the prefix removed. The remainder may\n * itself contain slashes (`byok/meta-llama/Llama-3.3-70B`), so this cuts the\n * prefix and does not split.\n */\nexport const byokModelId = (id: string): string =>\n id.startsWith(BYOK_MODEL_PREFIX) ? id.slice(BYOK_MODEL_PREFIX.length) : id\n","import * as z from 'zod'\nimport { decodeOnly } from '../utils'\n\nexport const HeaderSchema = z.object({\n key: z.string().optional(),\n value: z.string().optional(),\n})\n\nexport const HeadesSchema = decodeOnly(\n z.array(HeaderSchema),\n z.array(z.object({ key: z.string(), value: z.string() })),\n (headers) =>\n headers?.filter(\n (header) => header.key?.trim() && header.value?.trim(),\n ) as Array<{ key: string; value: string }>,\n)\n\nexport type Header = z.infer<typeof HeaderSchema>\nexport type Headers = z.infer<typeof HeadesSchema>\n\n/** Upper bound of a secret value, so a form cannot store an arbitrarily large blob. */\nexport const MAX_SECRET_VALUE_LENGTH = 4096\n\n/**\n * A header that carries a credential, as the API returns it: its name, and\n * whether a value is stored. The headers of API tools and MCP servers carry\n * the keys of the services they call (`Authorization`, `X-Api-Key`), so the\n * value never leaves the backend, the contract of the headers of the\n * organization's model provider.\n */\nexport const SecretHeaderSchema = z.object({\n key: z.string(),\n hasValue: z.boolean(),\n})\n\n/**\n * Secret headers as a save sends them. On an update an empty value keeps the\n * one stored under the same name, while the URL keeps its origin; a name left\n * out is removed. A row without a name is an empty row of the form, and\n * dropped. Two names that differ only in case are one HTTP header, so they\n * are refused: a kept value would match the first and the request send the\n * last.\n */\nexport const SecretHeaderListSchema = decodeOnly(\n z.array(\n z.object({\n key: z.string().optional(),\n value: z.string().max(MAX_SECRET_VALUE_LENGTH).optional(),\n }),\n ),\n z\n .array(z.object({ key: z.string(), value: z.string().optional() }))\n .refine(\n (headers) =>\n new Set(headers.map(({ key }) => key.toLowerCase())).size ===\n headers.length,\n { params: { i18n: 'validation.duplicateHeader' } },\n ),\n (headers) =>\n headers\n .filter((header) => header.key?.trim())\n .map(({ key, value }) => ({ key: key!.trim(), value })),\n)\n\nexport type SecretHeader = z.infer<typeof SecretHeaderSchema>\nexport type SecretHeaderDto = z.infer<typeof SecretHeaderListSchema>[number]\n/**\n * A secret header as stored (`agent_api_tools.headers`, `mcp_server.headers`),\n * with `value` encrypted by `encryptSecret`; rows saved before 0.115.0 hold it\n * in clear until their next save. Backend only: it never reaches a response.\n */\nexport type StoredSecretHeader = { key: string; value: string }\n","import * as z from 'zod'\nimport { zodQs, decodeOnly } from '../utils'\nimport {\n SupportedLanguage,\n ExtractionStrategy,\n BrowserEngine,\n} from './constants'\nimport { MediaSchema } from './Media'\nimport { HeadesSchema } from './Header'\n\n/**\n * Processing status for document indexing and embedding generation\n */\nexport enum IndexStatus {\n Pending = 'pending',\n Processing = 'processing',\n Success = 'success',\n Failed = 'failed',\n}\n\n// ===== Document Source Types =====\n\n/**\n * Conversion options for document processing\n * Used when creating or reprocessing documents\n */\nexport const ConversionOptionsSchema = z.object({\n extractionStrategy: z.enum(ExtractionStrategy).optional(),\n browserEngine: z\n .enum(BrowserEngine)\n .optional()\n .default(BrowserEngine.FETCH),\n headers: HeadesSchema.nullish(),\n aiDescriptionModel: z.string().optional(),\n aiDescriptionPrompt: z.string().max(5000).optional(),\n language: z.string().optional(),\n forceOcr: z.boolean().default(false),\n pages: z\n .string()\n .max(100)\n .regex(/^\\d+(\\s*-\\s*\\d+)?(\\s*,\\s*\\d+(\\s*-\\s*\\d+)?)*$/)\n .optional(),\n})\n\nexport type ConversionOptions = z.infer<typeof ConversionOptionsSchema>\n\n// ===== Document Source (metadata.source) =====\n\n/**\n * Who keeps a document's content up to date.\n *\n * `web` is a page the platform re-reads on its own; the others are cloud\n * document sources. Distinct from `documents.source_provider`, which carries\n * only the providers that OWN their documents (the cloud ones) and is null for\n * everything else: a web page discovered by a source stays editable.\n */\nexport enum DocumentSourceProvider {\n Web = 'web',\n SharePoint = 'sharepoint',\n GoogleDrive = 'google-drive',\n}\n\n/**\n * Outcome of the last pass over a document's source.\n *\n * `unchanged` is the one that pays for the whole mechanism: the source was read\n * and produced the same text, so no chunk was rewritten and no embedding was\n * charged. `shrunk` is a refusal, not a failure: the page answered but with far\n * less content than before, so the good version was kept.\n */\nexport enum DocumentRefreshResult {\n Updated = 'updated',\n Unchanged = 'unchanged',\n Failed = 'failed',\n Shrunk = 'shrunk',\n Gone = 'gone',\n}\n\n/**\n * How often a document re-reads its source on its own.\n *\n * `null` is the fourth value and the default: manual, which is what every\n * document is today and what every type other than `url` can ever be.\n */\nexport enum DocumentRefreshInterval {\n Daily = 'daily',\n Weekly = 'weekly',\n Monthly = 'monthly',\n}\n\n/**\n * The Postgres interval each trigger advances by.\n *\n * One table, read by the two places that move a deadline: the service, when\n * somebody sets or changes the trigger, and the timer, when a due document has\n * been queued. Written as literals rather than composed at the call site\n * because they end up inside SQL.\n */\nexport const REFRESH_INTERVAL_SQL: Record<DocumentRefreshInterval, string> = {\n [DocumentRefreshInterval.Daily]: '1 day',\n [DocumentRefreshInterval.Weekly]: '7 days',\n [DocumentRefreshInterval.Monthly]: '1 month',\n}\n\n/**\n * Hours after which a document left `processing` is treated as abandoned.\n *\n * A killed worker leaves that status behind, and nothing else moves it: the row\n * would drop out of the refresh timer's selection for good, because the timer\n * only claims documents that are `success` or `failed`. Past this window the\n * timer takes it anyway, and a manual refresh stops being refused.\n *\n * Generous on purpose: a scrape is bounded by the Functions host timeout, so\n * anything still `processing` after six hours is not running.\n */\nexport const STALE_PROCESSING_HOURS = 6\n\nexport const DocumentLastRefreshSchema = z.object({\n at: z.string(),\n result: z.enum(DocumentRefreshResult),\n httpStatus: z.number().optional(),\n error: z.string().optional(),\n /** Reset by the first good outcome; the notification threshold reads it. */\n consecutiveFailures: z.number().optional(),\n /**\n * Words before and after, written by the shrink guard. They are kept rather\n * than only compared because the guard's thresholds are a starting point:\n * after a month of real pages one can tell whether they cut too much.\n */\n previousWordCount: z.number().optional(),\n newWordCount: z.number().optional(),\n})\n\nexport type DocumentLastRefresh = z.infer<typeof DocumentLastRefreshSchema>\n\n/** Fields every source branch shares, whatever keeps the document up to date. */\nconst commonSourceFields = {\n /**\n * Hash of the text that actually reaches the chunks, so an unchanged source\n * costs no chunking and no embedding. Written by the processor on every\n * pass, which is what lets a document imported before this existed start\n * comparing from its second pass on.\n */\n contentHash: z.string().optional(),\n lastRefresh: DocumentLastRefreshSchema.optional(),\n}\n\nconst WebDocumentSourceSchema = z.object({\n provider: z.literal(DocumentSourceProvider.Web),\n url: z.string(),\n // Written by a successful conversion, and only then: at insert time the\n // page has not been read yet, so a value here would attest a scrape that\n // never happened.\n lastScrapedAt: z.string().optional(),\n /**\n * Hash of the deterministic text handed to the extraction step, before the\n * model. With `extractionStrategy: 'ai'` the model's output differs on every\n * call, so comparing the final markdown would always say \"changed\" and\n * every interval would pay conversion, chunking and embedding. This is what\n * the AI path compares, and it decides whether to call the model at all.\n */\n extractionInputHash: z.string().optional(),\n /**\n * Where the last successful pass actually landed after redirects.\n *\n * The shrink guard compares this with the new final URL, and not with `url`\n * on purpose: plenty of sites always redirect (a locale prefix, a trailing\n * slash, http to https), so comparing against the stored URL would refuse\n * every update of those pages forever. What says a page is gone is its\n * destination changing from the one it has been landing on.\n */\n finalUrl: z.string().optional(),\n /**\n * The web source that discovered this page. It says who found it, not who\n * governs it: the page stays editable like any other. Editing the text by\n * hand takes it off, and the page stops belonging to the source.\n */\n sourceId: z.uuid().optional(),\n /**\n * The last run of that source that found the page listed.\n *\n * Not the last successful read of the page, which is `lastScrapedAt`:\n * this is the marker the removal option reads, named like the cloud\n * field because the same reconciliation reads both. A page without one is\n * never removed.\n */\n lastSyncedAt: z.string().optional(),\n /**\n * The `<lastmod>` the sitemap declared the last time the source read it.\n * A change that is newer than `lastScrapedAt` queues an early refresh.\n */\n lastmod: z.string().optional(),\n ...commonSourceFields,\n})\n\n/** Coordinates a cloud adapter needs to find the item again, plus its content fingerprint. */\nconst cloudSourceFields = {\n /** The `document_sync_sources` row that owns this document. */\n sourceId: z.uuid(),\n remoteId: z.string(),\n webUrl: z.string(),\n path: z.string(),\n /**\n * The provider's own content fingerprint, compared for equality only and\n * never interpreted. It is what lets a sync skip the download entirely.\n */\n fingerprint: z.string(),\n /** Marks the document as seen by a run: the reconciliation after a resync reads it. */\n lastSyncedAt: z.string(),\n /** When the provider says the item last changed. Shown, never compared: the fingerprint decides. */\n lastModified: z.string().optional(),\n /**\n * A newly downloaded blob waiting to be converted. It sits here instead of\n * replacing `metadata.media` so that a conversion failure cannot destroy the\n * version that works: the processor promotes it only on success.\n */\n candidate: z\n .object({\n media: MediaSchema,\n fingerprint: z.string(),\n name: z.string(),\n webUrl: z.string(),\n path: z.string(),\n lastModified: z.string().optional(),\n })\n .optional(),\n ...commonSourceFields,\n}\n\nconst SharePointDocumentSourceSchema = z.object({\n provider: z.literal(DocumentSourceProvider.SharePoint),\n ...cloudSourceFields,\n})\n\nconst GoogleDriveDocumentSourceSchema = z.object({\n provider: z.literal(DocumentSourceProvider.GoogleDrive),\n ...cloudSourceFields,\n})\n\n/**\n * `metadata.source`, discriminated on `provider`.\n *\n * One object cannot hold both shapes: a web page has a URL and a scrape date, a\n * cloud file has remote coordinates and a fingerprint, and making every field\n * optional to fit both is the same as having no schema. Rows written before the\n * discriminator existed carry no `provider`, so they are normalized to the web\n * branch before routing: that is the only shape that could have been written.\n *\n * The normalization runs on parse, and responses are serialized by the\n * parse-based compiler (see `apps/backend/src/utils/responseSerializer.ts`), so\n * a legacy row still comes out of the API intact.\n */\nexport const DocumentSourceSchema = z.preprocess(\n (value) => {\n if (\n value &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n !('provider' in value)\n ) {\n return { provider: DocumentSourceProvider.Web, ...value }\n }\n return value\n },\n z.discriminatedUnion('provider', [\n WebDocumentSourceSchema,\n SharePointDocumentSourceSchema,\n GoogleDriveDocumentSourceSchema,\n ]),\n)\n\nexport type DocumentSource = z.infer<typeof DocumentSourceSchema>\nexport type WebDocumentSource = z.infer<typeof WebDocumentSourceSchema>\n\n/**\n * The page URL of a document's source, when its source is a web page.\n *\n * One place to narrow the union, so the views that show \"where this came from\"\n * do not each grow their own check, and a cloud-synced document returns nothing\n * here instead of a broken link: its address is `webUrl` on the remote item,\n * which is a different thing to show and to say.\n */\nexport function documentSourceUrl(source?: DocumentSource): string | undefined {\n return source && 'url' in source ? source.url : undefined\n}\n\n// ===== Processing queue contract =====\n\n/**\n * Why a document is being processed again. Absent means the ingestion of a new\n * document, which is the only case whose natural key is the document id alone.\n */\nexport type DocumentProcessingKind = 'refresh' | 'reprocess' | 'reindex'\n\n/**\n * The `document-processing` queue message.\n *\n * Lives here because two processes read it: the backend publishes it and the\n * Azure Function consumes it. It used to be declared in each, and the copy in\n * the function app was already a field behind.\n */\nexport interface DocumentProcessingJob {\n documentId: string\n conversionOptions?: ConversionOptions\n /**\n * Set by every caller that processes a document which already exists. It\n * shapes the message id (see `publishProcessingJob`) and, for `refresh`,\n * turns on the refresh mode of the processor.\n */\n kind?: DocumentProcessingKind\n /**\n * Only a scheduled refresh enforces the shrink guard. A person who clicked\n * \"refresh now\" is looking at the result and may well be refreshing a page\n * that really did get shorter, so the guard would only stand in their way.\n */\n guarded?: boolean\n /**\n * The web source whose sitemap asked for this early refresh. Nobody is\n * watching it either, so it enforces the shrink guard; and it is void if\n * the page no longer belongs to that source, which is what editing its text\n * by hand does. Not `guarded`, which also voids a page without a trigger:\n * a source reads its pages whether they have one or not.\n */\n sourceId?: string\n}\n\n/**\n * Metadata structure for document.metadata column\n * Consolidates all metadata from converters and source info\n */\nexport const DocumentMetadataSchema = z\n .object({\n // === Source Info (URL and synced documents) ===\n source: DocumentSourceSchema.optional(),\n\n // === Media Info (File documents only) ===\n media: MediaSchema.optional(),\n\n // === Common Fields (all document types) ===\n title: z.string().optional(),\n author: z.string().optional(),\n description: z.string().optional(),\n summary: z.string().optional(),\n keywords: z.array(z.string()).optional(),\n\n // === PDF Specific ===\n subject: z.string().optional(),\n creator: z.string().optional(), // Original application\n producer: z.string().optional(), // PDF generator software\n creationDate: z.string().optional(),\n modificationDate: z.string().optional(),\n pageCount: decodeOnly(\n z.union([z.number(), z.array(z.unknown())]),\n z.number(),\n (val) => (Array.isArray(val) ? val.length : val),\n ).optional(),\n encrypted: z.boolean().optional(),\n\n // === DOCX Specific ===\n characterCount: z.number().optional(),\n lineCount: z.number().optional(),\n\n // === URL Specific ===\n siteName: z.string().optional(),\n canonicalUrl: z.url().optional(),\n imageUrl: z.url().optional(),\n favicon: z.url().optional(),\n type: z.string().optional(), // og:type (article, website, etc.)\n locale: z.string().optional(),\n tags: z.array(z.string()).optional(),\n publishedTime: z.string().optional(),\n modifiedTime: z.string().optional(),\n\n // === Metrics (all document types) ===\n wordCount: z.number().optional(),\n paragraphCount: z.number().optional(),\n readingTime: z.number().optional(), // in minutes\n\n // === OCR (PDF documents) ===\n ocrUsed: z.boolean().optional(),\n ocrProvider: z.string().optional(),\n ocrModel: z.string().optional(),\n ocrPages: z.string().optional(),\n ocrCost: z.number().optional(),\n ocrError: z.string().optional(),\n\n // === RAG / Duplicates / Sync Info ===\n chunksCount: z.number().optional(),\n redundantChunksCount: z.number().optional(),\n hasRedundantChunks: z.boolean().optional(),\n qdrantSynced: z.boolean().optional(),\n\n // === Conversion Options (for reprocessing) ===\n conversionOptions: ConversionOptionsSchema.optional(),\n })\n .loose() // Allow additional custom fields\n\nexport type DocumentMetadata = z.infer<typeof DocumentMetadataSchema>\n\n/**\n * Document type enum\n *\n * - 'file': Document created from uploaded file (PDF, DOCX)\n * - 'url': Document created from web scraping\n * - 'revised-answer': Document created from revised AI answer\n * - 'plain-text': Document created from plain text input\n */\nexport enum DocumentType {\n File = 'file',\n Url = 'url',\n RevisedAnswer = 'revised-answer',\n PlainText = 'plain-text',\n}\n\n// ===== Schemas =====\n\n/**\n * Full document schema from database\n * Extended with computed field chunksCount\n */\nconst BaseDocumentSchema = z.object({\n id: z.string(),\n externalId: z.string().nullable(),\n name: z.string(),\n content: z.string(),\n type: z.string(),\n language: z.string(),\n metadata: z.record(z.string(), z.unknown()),\n indexStatus: z.string(),\n processedAt: z.coerce.date().nullable(),\n createdAt: z.coerce.date(),\n createdBy: z.string(),\n updatedAt: z.coerce.date(),\n updatedBy: z.string(),\n deleted: z.boolean(),\n deletedAt: z.coerce.date().nullable(),\n deletedBy: z.string().nullable(),\n organizationId: z.string(),\n priority: z.number().int().min(1).max(5).default(3),\n /** The automatic refresh trigger; null is manual, and only `url` can have one. */\n refreshInterval: z.enum(DocumentRefreshInterval).nullable().optional(),\n /**\n * When the trigger next comes due. Null with an interval set means paused:\n * the source answered that the page is gone for good.\n */\n nextRefreshAt: z.coerce.date().nullable().optional(),\n /**\n * Which sync source owns this document, when one does.\n *\n * Null is the ordinary case. A non-null value means a job keeps the\n * document up to date, which is what makes it read only: editing it, moving\n * it or deleting it by hand would be undone at the next run, silently.\n * Written only by providers that own their documents, never by a crawl that\n * merely discovered a page.\n */\n sourceProvider: z.enum(DocumentSourceProvider).nullable().optional(),\n})\n\nexport const DocumentSchema = BaseDocumentSchema.extend({\n type: z.enum(DocumentType),\n indexStatus: z.enum(IndexStatus),\n metadata: DocumentMetadataSchema,\n // Add computed field for chunks count (populated by service layer)\n chunksCount: z.number().optional(),\n // Computed fields for redundancy tracking\n redundantChunksCount: z.number().optional(),\n hasRedundantChunks: z.boolean().optional(),\n // Qdrant sync status\n qdrantSynced: z.boolean().optional(),\n // Agent IDs associated with this document (populated in single-item reads)\n agentIds: z.array(z.string()).optional(),\n // Folder ID for this document within an agent context (populated in agent-scoped reads)\n folderId: z.string().nullable().optional(),\n // Full folder path string e.g. \"Parent / Child\" (populated in list reads when agentId is set)\n folderPath: z.string().nullable().optional(),\n /** Who sent the document to the trash, by name (populated in trash reads). */\n deletedByName: z.string().nullable().optional(),\n})\n\n/**\n * The document types the trash holds: the ones a person adds to a knowledge\n * base by hand. A revised answer lives and dies with its own page, so it is\n * never listed, restored or emptied from here.\n */\nexport const DOCUMENT_TRASH_TYPES = [\n DocumentType.File,\n DocumentType.Url,\n DocumentType.PlainText,\n] as const\n\n/**\n * Why a restore was refused (docs/specs/document-trash.md, Decision 3), sent\n * as `additionalData.reason` of a `conflict` problem. The third case of the\n * decision, a folder that no longer exists, is not a refusal: the document\n * goes back to the root and the answer says so.\n */\nexport enum DocumentRestoreRefusal {\n /** Every agent the document belonged to has been deleted. */\n AgentGone = 'agent-gone',\n /**\n * A live document of the same source holds its remote identity; its id\n * travels as `additionalData.documentId`.\n */\n IdentityTaken = 'identity-taken',\n}\n\nexport const DocumentRestoreResultSchema = z.object({\n document: DocumentSchema,\n /** Its folder was gone, so it went back to the root of its agent. */\n returnedToRoot: z.boolean(),\n})\n\nexport const DocumentTrashSummarySchema = z.object({\n /** Documents in the trash of the agent, the ones it can restore. */\n count: z.number().int(),\n})\n\nexport const DocumentEmptyTrashDtoSchema = z.object({\n agentId: z.uuid(),\n})\n\nexport const DocumentEmptyTrashResultSchema = z.object({\n purged: z.number().int(),\n /** Still in the trash: one call empties a batch, the caller asks again. */\n remaining: z.number().int(),\n})\n\n/**\n * Query parameters for listing documents with pagination, sorting, and filters\n */\nexport const DocumentQuerystringSchema = z.object({\n ...zodQs.pagination(),\n ...zodQs.sort(['id', 'updatedAt', 'createdAt', 'name', 'deletedAt']),\n ...zodQs.filters(['type', 'language', 'agentId', 'indexStatus']),\n // 'true' lists the trash instead of the knowledge base: a flat list, by\n // agent, of what that agent can restore. Every other read keeps ignoring\n // deleted documents.\n 'filter[deleted]': z.enum(['true', 'false']).optional(),\n ...zodQs.fullText(),\n ...zodQs.ids(),\n 'filter[similarity]': z.string().optional(),\n // UUID = documents in that folder; 'null' = documents at root (no folder); absent = all documents\n 'filter[folderId]': z.string().optional(),\n 'filter[hasRedundantChunks]': z.string().optional(),\n // One of the intervals, 'null' for the documents left on manual, 'auto' for\n // any of the three. Same convention as `filter[folderId]`, and handled\n // outside `getFilters` for the same reason: `inArray` cannot say IS NULL.\n 'filter[refreshInterval]': z.string().optional(),\n // A provider, 'null' for the documents nobody syncs, 'any' for the ones a\n // source owns whoever it is. Same convention and the same reason as above.\n 'filter[sourceProvider]': z.string().optional(),\n})\n\n/**\n * Document creation schema for POST /documents endpoint\n *\n * Supports three types:\n * - 'file': Requires media object with uploaded file info\n * - 'url': Requires url string for web scraping\n * - 'revised-answer': Requires content (created from revisedAnswer service)\n */\nexport const DocumentCreateDtoSchema = z\n .object({\n type: z.enum(DocumentType).default(DocumentType.File),\n name: z.string().min(1).max(255).optional(),\n language: z.enum(SupportedLanguage).optional(),\n organizationId: z.string(),\n agentIds: z.array(z.string()).min(1, 'At least one agent is required'),\n folderId: z.uuid().nullable().optional(),\n media: MediaSchema.optional(),\n url: z.url().optional(),\n content: z.string().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n extractionStrategy: z.enum(ExtractionStrategy).optional(),\n browserEngine: z.enum(BrowserEngine).optional(),\n headers: HeadesSchema.nullish().default([]),\n aiDescriptionModel: z.string().optional(),\n aiDescriptionPrompt: z.string().max(5000).optional(),\n forceOcr: z.boolean().default(false),\n pages: z\n .string()\n .max(100)\n .regex(/^\\d+(\\s*-\\s*\\d+)?(\\s*,\\s*\\d+(\\s*-\\s*\\d+)?)*$/)\n .optional(),\n priority: z.number().int().min(1).max(5).default(3).optional(),\n refreshInterval: z.enum(DocumentRefreshInterval).nullable().optional(),\n /**\n * The web source this page is imported for: the pages ticked in the\n * crawler dialog when it also creates a source. They land in the\n * source's folder as pages the source discovered, so its removal\n * option and its early refresh apply to them from the first run.\n */\n syncSourceId: z.uuid().optional(),\n })\n .superRefine((data, ctx) => {\n if (data.syncSourceId && data.type !== DocumentType.Url) {\n ctx.addIssue({\n code: 'custom',\n params: {\n i18n: 'errors.syncSourceUrlOnly',\n },\n path: ['syncSourceId'],\n })\n }\n if (data.type === DocumentType.File && !data.media) {\n ctx.addIssue({\n code: 'custom',\n params: {\n i18n: 'errors.required',\n },\n path: ['media'],\n })\n return\n }\n if (data.type === DocumentType.Url && !data.url) {\n ctx.addIssue({\n code: 'custom',\n params: {\n i18n: 'errors.required',\n },\n path: ['url'],\n })\n }\n // The database has the same CHECK, but a 400 saying which field is\n // wrong beats a constraint violation surfacing as a 500.\n if (data.refreshInterval && data.type !== DocumentType.Url) {\n ctx.addIssue({\n code: 'custom',\n params: {\n i18n: 'errors.refreshIntervalUrlOnly',\n },\n path: ['refreshInterval'],\n })\n }\n if (\n data.type === DocumentType.PlainText &&\n !(data.name || data.language)\n ) {\n if (!data.name) {\n ctx.addIssue({\n code: 'custom',\n params: {\n i18n: 'errors.required',\n },\n path: ['name'],\n })\n }\n if (!data.language) {\n ctx.addIssue({\n code: 'custom',\n params: {\n i18n: 'errors.required',\n },\n path: ['language'],\n })\n }\n }\n })\n\n/**\n * Document update schema for PUT /documents/:id endpoint\n *\n * All fields are optional, but at least one must be provided\n */\nexport const DocumentUpdateDtoSchema = z.object({\n id: z.string(),\n organizationId: z.string(),\n content: z.string().optional(),\n name: z.string().min(1).max(255).optional(),\n language: z.enum(SupportedLanguage).optional(),\n priority: z.number().int().min(1).max(5).optional(),\n agentIds: z.array(z.string()).min(1).optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n refreshInterval: z.enum(DocumentRefreshInterval).nullable().optional(),\n})\n\n/** Body of `PATCH /documents/:id/refresh-interval`, twin of the priority route. */\nexport const DocumentRefreshIntervalDtoSchema = z.object({\n refreshInterval: z.enum(DocumentRefreshInterval).nullable(),\n})\n\n/** Body of `POST /documents/bulk-refresh-interval`. */\nexport const DocumentBulkRefreshIntervalDtoSchema = z.object({\n ids: z.array(z.uuid()).min(1).max(100),\n refreshInterval: z.enum(DocumentRefreshInterval).nullable(),\n})\n\n/** Body of `POST /documents/bulk-refresh`, twin of `bulk-reprocess`. */\nexport const DocumentBulkRefreshDtoSchema = z.object({\n ids: z.array(z.uuid()).min(1).max(100),\n})\n\n// ===== Type Exports =====\n\nexport type Document = z.infer<typeof DocumentSchema>\nexport type DocumentQuerystring = z.infer<typeof DocumentQuerystringSchema>\nexport type DocumentCreateDto = z.infer<typeof DocumentCreateDtoSchema>\nexport type DocumentUpdateDto = z.infer<typeof DocumentUpdateDtoSchema>\nexport type DocumentRefreshIntervalDto = z.infer<\n typeof DocumentRefreshIntervalDtoSchema\n>\nexport type DocumentBulkRefreshIntervalDto = z.infer<\n typeof DocumentBulkRefreshIntervalDtoSchema\n>\nexport type DocumentBulkRefreshDto = z.infer<\n typeof DocumentBulkRefreshDtoSchema\n>\nexport type DocumentRestoreResult = z.infer<typeof DocumentRestoreResultSchema>\nexport type DocumentTrashSummary = z.infer<typeof DocumentTrashSummarySchema>\nexport type DocumentEmptyTrashDto = z.infer<typeof DocumentEmptyTrashDtoSchema>\nexport type DocumentEmptyTrashResult = z.infer<\n typeof DocumentEmptyTrashResultSchema\n>\n\n// ===== Helper Functions =====\n\nexport const getStatusColor = (status: IndexStatus) => {\n switch (status) {\n case IndexStatus.Success:\n return 'success'\n case IndexStatus.Failed:\n return 'danger'\n case IndexStatus.Processing:\n return 'warning'\n default:\n return 'info'\n }\n}\n\nexport const getStatusIcon = (status: IndexStatus) => {\n switch (status) {\n case IndexStatus.Success:\n return 'ri:check-line'\n case IndexStatus.Failed:\n return 'ri:error-warning-line'\n case IndexStatus.Processing:\n return 'ri:hourglass-line'\n default:\n return 'ri:time-line'\n }\n}\n\nexport const getTypeIcon = (type: DocumentType) => {\n switch (type) {\n case DocumentType.File:\n return 'ri:file-line'\n case DocumentType.Url:\n return 'ri:link'\n case DocumentType.RevisedAnswer:\n return 'ri:feedback-line'\n default:\n return 'ri:input-method-line'\n }\n}\n\nexport const getFileIcon = (extension: string) => {\n const ext = (\n extension.startsWith('.') ? extension.slice(1) : extension\n ).toLowerCase()\n switch (ext) {\n case 'pdf':\n return 'ri:file-pdf-2-line'\n case 'doc':\n case 'docx':\n return 'ri:file-word-line'\n case 'xls':\n case 'xlsx':\n return 'ri:file-excel-line'\n case 'ppt':\n case 'pptx':\n return 'ri:file-ppt-line'\n case 'txt':\n return 'ri:file-text-line'\n case 'mp3':\n case 'wav':\n case 'ogg':\n return 'ri:file-music-line'\n case 'mp4':\n case 'avi':\n case 'mkv':\n return 'ri:file-video-line'\n case 'jpg':\n case 'jpeg':\n case 'png':\n case 'gif':\n case 'bmp':\n case 'svg':\n return 'ri:file-image-line'\n case 'zip':\n case 'rar':\n case '7z':\n return 'ri:file-zip-line'\n default:\n return 'ri:file-line'\n }\n}\n\n/** Whether a MIME type is an image. */\nexport const isImageMime = (mimeType?: string | null): boolean =>\n (mimeType ?? '').startsWith('image/')\n\n/** Whether a file MIME type can be previewed inline in the browser (image or\n * PDF) instead of being forced as a download. Shared by every file-list surface\n * so the preview/download decision stays consistent. */\nexport const isInlineViewable = (mimeType?: string | null): boolean =>\n isImageMime(mimeType) || mimeType === 'application/pdf'\n\n/** File-type identity for list rows and previews: icon, accent color\n * (CSS value driving glyph and tile tint) and a short human kind label. */\nexport interface FileKind {\n icon: string\n accent: string\n label: string\n}\n\n/** File-type identity derived from a MIME type. Accents match the chat\n * attachment cards (PkChatbotFilePreview) so files read the same everywhere. */\nexport const fileKindForMime = (mimeType?: string | null): FileKind => {\n const mime = mimeType ?? ''\n if (isImageMime(mime)) {\n return { icon: 'ri:image-line', accent: '#ec4899', label: 'Image' }\n }\n if (mime === 'application/pdf') {\n return { icon: 'ri:file-pdf-2-line', accent: '#e2483d', label: 'PDF' }\n }\n if (mime === 'application/msword' || mime.includes('wordprocessingml')) {\n return { icon: 'ri:file-word-line', accent: '#2b7de9', label: 'Word' }\n }\n if (mime === 'application/vnd.ms-excel' || mime.includes('spreadsheetml')) {\n return {\n icon: 'ri:file-excel-line',\n accent: '#1f9d57',\n label: 'Spreadsheet',\n }\n }\n if (\n mime === 'application/vnd.ms-powerpoint' ||\n mime.includes('presentationml')\n ) {\n return {\n icon: 'ri:file-ppt-line',\n accent: '#d98324',\n label: 'Presentation',\n }\n }\n if (mime.startsWith('audio/')) {\n return { icon: 'ri:file-music-line', accent: '#8b5cf6', label: 'Audio' }\n }\n if (mime.startsWith('video/')) {\n return { icon: 'ri:file-video-line', accent: '#6366f1', label: 'Video' }\n }\n if (\n mime === 'application/zip' ||\n mime === 'application/x-rar-compressed' ||\n mime === 'application/x-7z-compressed'\n ) {\n return { icon: 'ri:file-zip-line', accent: '#c08a1e', label: 'Archive' }\n }\n if (mime.startsWith('text/')) {\n return { icon: 'ri:file-text-line', accent: '#64748b', label: 'Text' }\n }\n return { icon: 'ri:file-line', accent: '#64748b', label: 'File' }\n}\n\n/** Icon for a file-list row, derived from its MIME type. */\nexport const fileIconForMime = (mimeType?: string | null): string =>\n fileKindForMime(mimeType).icon\n","export const stripMarkdown = (text?: string | null) => {\n if (!text) {\n return undefined\n }\n return text\n .replace(/!\\[.*?\\]\\(.*?\\)/g, '') // images\n .replace(/\\[([^\\]]+)\\]\\(.*?\\)/g, '$1') // links\n .replace(/`{1,3}[^`]*`{1,3}/g, '') // inline code / code blocks\n .replace(/#{1,6}\\s/g, '') // headings\n .replace(/(\\*{1,3}|_{1,3})(.*?)\\1/g, '$2') // bold / italic\n .replace(/~~(.*?)~~/g, '$1') // strikethrough\n .replace(/^\\s*[-*+>]\\s+/gm, '') // lists and blockquotes\n .replace(/\\n+/g, ' ') // newlines\n .trim()\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"markdown-tS_2A0k9.js","names":[],"sources":["../../../../packages/models/src/schema/constants.ts","../../../../packages/models/src/schema/Header.ts","../../../../packages/models/src/schema/Document.ts","../../../../packages/utils/src/markdown.ts"],"sourcesContent":["/**\n * The models an agent of this platform may be pointed at.\n *\n * The gateway listing DESCRIBES what exists, this list PERMITS. They are two\n * different questions, and conflating them broke production once: on\n * 2026-07-23 two models entered the catalog before the installed\n * `@ai-sdk/gateway` knew them, and their tool calls failed under the generic\n * handling. Exposing every model the day the listing shows it would reproduce\n * that by construction.\n *\n * Adding one is a line here, after the checklist in\n * `docs/agents/llm-integration.md`: it must be `type: language` in the\n * listing, produce text and carry the `tool-use` tag. Everything else about\n * it, the commercial name, the price, the context window, the two privacy\n * flags, comes from the listing and is never written down twice.\n *\n * A test checks every id against a saved copy of the listing, which is what\n * replaces the by-hand verification that missed a model on 2026-09-18.\n */\nexport const GATEWAY_MODELS = [\n // OpenAI\n 'openai/gpt-5-nano',\n 'openai/gpt-5-mini',\n 'openai/gpt-5.1-thinking',\n 'openai/gpt-5.2',\n 'openai/gpt-5.4-nano',\n 'openai/gpt-5.4-mini',\n 'openai/gpt-5.4',\n 'openai/gpt-5.4-pro',\n 'openai/gpt-5.5',\n 'openai/gpt-5.5-pro',\n 'openai/gpt-5.6-luna',\n 'openai/gpt-5.6-terra',\n 'openai/gpt-5.6-sol',\n 'openai/gpt-5.6-luna-fast',\n 'openai/gpt-5.6-terra-fast',\n 'openai/gpt-5.6-sol-fast',\n 'openai/gpt-6-astra',\n 'openai/gpt-6-astra-fast',\n 'openai/gpt-6-sol',\n 'openai/gpt-6-sol-fast',\n 'openai/gpt-6-luna',\n 'openai/gpt-6-luna-fast',\n 'openai/gpt-6.1-sol',\n 'openai/gpt-6.1-sol-fast',\n // Google Gemini\n 'google/gemini-2.5-flash-lite',\n 'google/gemini-2.5-flash',\n 'google/gemini-2.5-pro',\n 'google/gemini-3-flash',\n 'google/gemini-3.1-pro-preview',\n 'google/gemini-3.1-flash-lite',\n 'google/gemini-3.5-flash',\n 'google/gemini-3.5-flash-lite',\n 'google/gemini-3.6-flash',\n 'google/gemini-3.7-flash',\n 'google/gemini-3.8-flash',\n // Anthropic Claude\n 'anthropic/claude-haiku-4.5',\n 'anthropic/claude-sonnet-4.6',\n 'anthropic/claude-sonnet-5',\n 'anthropic/claude-sonnet-5.5',\n 'anthropic/claude-opus-4.6',\n 'anthropic/claude-opus-4.7',\n 'anthropic/claude-opus-4.8',\n 'anthropic/claude-opus-5',\n 'anthropic/claude-opus-5-fast',\n 'anthropic/claude-opus-5.5',\n 'anthropic/claude-opus-5.5-fast',\n 'anthropic/claude-fable-5',\n 'anthropic/claude-fable-5.1',\n // Deepseek\n 'deepseek/deepseek-v3.2',\n 'deepseek/deepseek-v4-flash-0731',\n 'deepseek/deepseek-v4.1-flash',\n 'deepseek/deepseek-v4-pro-0813',\n // Alibaba\n 'alibaba/qwen3.6-plus',\n 'alibaba/qwen3.7-max',\n 'alibaba/qwen3.7-plus',\n 'alibaba/qwen3.7-flash',\n 'alibaba/qwen3.8-flash',\n 'alibaba/qwen3.8-max',\n 'alibaba/qwen3.8-27b',\n 'alibaba/qwen3.8-max-0902',\n 'alibaba/qwen3.8-omni-flash',\n 'alibaba/qwen3.8-max-prime',\n // SpaceXAI\n 'spacexai/grok-4.3',\n 'spacexai/grok-4.6',\n 'spacexai/grok-4.7',\n // z.ai\n 'zai/glm-5.2',\n 'zai/glm-5.2-fast',\n 'zai/glm-5.3',\n 'zai/glm-5.3-flash',\n 'zai/glm-5.3-fast',\n 'zai/glm-5.3-flashx',\n // Meta\n 'meta/muse-spark-1.1',\n 'meta/muse-spark-1.2',\n 'meta/muse-spark-1.3',\n // Moonshot AI\n 'moonshotai/kimi-k3',\n 'moonshotai/kimi-k3-fast',\n // Mistral\n 'mistral/ministral-14b',\n 'mistral/mistral-small',\n 'mistral/mistral-medium-3.5',\n 'mistral/mistral-large-3',\n // Xiaomi\n 'xiaomi/mimo-v2.6-flash',\n 'xiaomi/mimo-v2.6-pro',\n 'xiaomi/mimo-v2.6-pro-ultraspeed',\n] as const satisfies readonly string[]\n\n/**\n * A model id: an entry of {@link GATEWAY_MODELS}, or a `byok/` id served by an\n * organization's own endpoint. A plain string on purpose, because the second\n * half cannot be enumerated.\n */\nexport type ModelId = string\n\n/**\n * Prices are stored per token, the unit the gateway listing publishes, and\n * shown per million, the unit every price page uses. One copy, so the page,\n * its dialogs and the picker never disagree on the factor.\n */\nexport const PER_MILLION_TOKENS = 1_000_000\n\n/**\n * The models the platform falls back to when an organization has expressed no\n * preference. The only model ids written in the code besides the curated list.\n */\nexport const PLATFORM_MODEL_DEFAULTS = {\n /** New agents, and the runtime fallback of an agent with no model. */\n agentModel: 'openai/gpt-5.6-terra',\n /** Question reformulation, JSON to schema, memory reconciliation. */\n utilityModel: 'google/gemini-3-flash',\n} as const\n\n/**\n * Models used to vectorize text, never to answer. Kept apart from\n * {@link GATEWAY_MODELS} so an embedding id cannot reach the chat plumbing,\n * and out of the catalog for the same reason: they are not selectable.\n */\nexport enum EmbeddingModel {\n textEmbedding3Small = 'openai/text-embedding-3-small',\n textEmbedding3Large = 'openai/text-embedding-3-large',\n geminiEmbedding2 = 'google/gemini-embedding-2',\n}\n\nexport const EMBED_MODEL = EmbeddingModel.geminiEmbedding2\n\n/**\n * Model that answers typed questions (yes/no, choice, score) with calibrated\n * probabilities instead of text, through the gateway's `experimental_evaluate`\n * (TypeSafe Jev). Out of the catalog like the embeddings: it decides for the\n * platform, it never answers the user. Its gateway listing reports no ZDR,\n * yet a ZDR request is served, routed to TypeSafe alone (measured\n * 2026-09-28, scripts/spikeJevEvaluation.ts).\n */\nexport const EVALUATION_MODEL = 'typesafe-ai/jev'\n\n/**\n * Supported languages for documents and revised answers\n */\nexport enum SupportedLanguage {\n it = 'it',\n en = 'en',\n es = 'es',\n fr = 'fr',\n de = 'de',\n}\n\n/**\n * Language display names (i18n keys)\n */\nexport const LANGUAGE_NAMES: Record<SupportedLanguage, string> = {\n [SupportedLanguage.it]: 'language.italian',\n [SupportedLanguage.en]: 'language.english',\n [SupportedLanguage.es]: 'language.spanish',\n [SupportedLanguage.fr]: 'language.french',\n [SupportedLanguage.de]: 'language.german',\n}\n\n/**\n * Content extraction strategies for URL scraping\n */\nexport enum ExtractionStrategy {\n /** Use Mozilla Readability for content extraction (fast, free, no API calls) */\n READABILITY = 'readability',\n /** Use AI-based extraction (better for complex layouts, requires API calls) */\n AI = 'ai',\n}\n\n/**\n * Browser engine options for URL scraping\n */\nexport enum BrowserEngine {\n /** Use simple HTTP fetch (fast, lightweight, no JavaScript support) */\n FETCH = 'fetch',\n /** Use Puppeteer with headless Chrome (full browser, JavaScript support) */\n PUPPETEER = 'puppeteer',\n /** Delegate browser rendering to an external pdf-image-generator service */\n REMOTE = 'remote',\n}\n\n/**\n * Which report family has to account for a credit charge.\n *\n * The hourly reconciliation trusts `cost_reports` (the gateway's own billing,\n * copied in house) as the source of truth for what an organization spent. A\n * charge whose supplier is not the gateway has no counterpart there, so it must\n * be told apart or the reconciliation forgives it: that is what happened to the\n * voice minutes until 2026-08-31.\n *\n * Declared here, written on the ledger row at charge time, never inferred from\n * `source` downstream: the next non-gateway supplier must be a compile-time\n * decision, not a string nobody remembered to add to a list.\n */\nexport enum BillingSource {\n /** Billed by the AI gateway, so it lands in `cost_reports`. */\n GATEWAY = 'gateway',\n /** Billed by another supplier (voice minutes, OCR): the ledger is the only record. */\n INTERNAL = 'internal',\n}\n\n/**\n * Kinds of row on the credit ledger.\n *\n * It used to be a free string with exactly one value ever written, `debit`.\n * Adding a second one is not free: the hourly reconciliation sums debits to\n * rebuild the real-time estimate, and the analytics endpoint sums the ledger to\n * chart spend, so a new type that nobody filters out is a number silently\n * doubled.\n */\nexport enum CreditTransactionType {\n /** A charge for something consumed, written in real time. */\n DEBIT = 'debit',\n /** The hourly settlement against the gateway report: the audit trail of a balance move. */\n RECONCILIATION = 'reconciliation',\n}\n\n/**\n * Prefix that marks a model served by the organization's own OpenAI compatible\n * endpoint rather than by the gateway.\n *\n * It is not a gateway brand, which is the point: every switch on the provider\n * (reasoning options, the Google thought signature repair, the per-provider\n * timeouts, the native web search tools) falls into its default branch without\n * any of them having to learn about BYOK.\n */\nexport const BYOK_MODEL_PREFIX = 'byok/'\n\nexport const isByokModel = (id?: string | null): boolean =>\n Boolean(id?.startsWith(BYOK_MODEL_PREFIX))\n\n/**\n * The id as the endpoint wants it, with the prefix removed. The remainder may\n * itself contain slashes (`byok/meta-llama/Llama-3.3-70B`), so this cuts the\n * prefix and does not split.\n */\nexport const byokModelId = (id: string): string =>\n id.startsWith(BYOK_MODEL_PREFIX) ? id.slice(BYOK_MODEL_PREFIX.length) : id\n","import * as z from 'zod'\nimport { decodeOnly } from '../utils'\n\nexport const HeaderSchema = z.object({\n key: z.string().optional(),\n value: z.string().optional(),\n})\n\nexport const HeadesSchema = decodeOnly(\n z.array(HeaderSchema),\n z.array(z.object({ key: z.string(), value: z.string() })),\n (headers) =>\n headers?.filter(\n (header) => header.key?.trim() && header.value?.trim(),\n ) as Array<{ key: string; value: string }>,\n)\n\nexport type Header = z.infer<typeof HeaderSchema>\nexport type Headers = z.infer<typeof HeadesSchema>\n\n/** Upper bound of a secret value, so a form cannot store an arbitrarily large blob. */\nexport const MAX_SECRET_VALUE_LENGTH = 4096\n\n/**\n * A header that carries a credential, as the API returns it: its name, and\n * whether a value is stored. The headers of API tools and MCP servers carry\n * the keys of the services they call (`Authorization`, `X-Api-Key`), so the\n * value never leaves the backend, the contract of the headers of the\n * organization's model provider.\n */\nexport const SecretHeaderSchema = z.object({\n key: z.string(),\n hasValue: z.boolean(),\n})\n\n/**\n * Secret headers as a save sends them. On an update an empty value keeps the\n * one stored under the same name, while the URL keeps its origin; a name left\n * out is removed. A row without a name is an empty row of the form, and\n * dropped. Two names that differ only in case are one HTTP header, so they\n * are refused: a kept value would match the first and the request send the\n * last.\n */\nexport const SecretHeaderListSchema = decodeOnly(\n z.array(\n z.object({\n key: z.string().optional(),\n value: z.string().max(MAX_SECRET_VALUE_LENGTH).optional(),\n }),\n ),\n z\n .array(z.object({ key: z.string(), value: z.string().optional() }))\n .refine(\n (headers) =>\n new Set(headers.map(({ key }) => key.toLowerCase())).size ===\n headers.length,\n { params: { i18n: 'validation.duplicateHeader' } },\n ),\n (headers) =>\n headers\n .filter((header) => header.key?.trim())\n .map(({ key, value }) => ({ key: key!.trim(), value })),\n)\n\nexport type SecretHeader = z.infer<typeof SecretHeaderSchema>\nexport type SecretHeaderDto = z.infer<typeof SecretHeaderListSchema>[number]\n/**\n * A secret header as stored (`agent_api_tools.headers`, `mcp_server.headers`),\n * with `value` encrypted by `encryptSecret`; rows saved before 0.115.0 hold it\n * in clear until their next save. Backend only: it never reaches a response.\n */\nexport type StoredSecretHeader = { key: string; value: string }\n","import * as z from 'zod'\nimport { zodQs, decodeOnly } from '../utils'\nimport {\n SupportedLanguage,\n ExtractionStrategy,\n BrowserEngine,\n} from './constants'\nimport { MediaSchema } from './Media'\nimport { HeadesSchema } from './Header'\n\n/**\n * Processing status for document indexing and embedding generation\n */\nexport enum IndexStatus {\n Pending = 'pending',\n Processing = 'processing',\n Success = 'success',\n Failed = 'failed',\n}\n\n// ===== Document Source Types =====\n\n/**\n * Conversion options for document processing\n * Used when creating or reprocessing documents\n */\nexport const ConversionOptionsSchema = z.object({\n extractionStrategy: z.enum(ExtractionStrategy).optional(),\n browserEngine: z\n .enum(BrowserEngine)\n .optional()\n .default(BrowserEngine.FETCH),\n headers: HeadesSchema.nullish(),\n aiDescriptionModel: z.string().optional(),\n aiDescriptionPrompt: z.string().max(5000).optional(),\n language: z.string().optional(),\n forceOcr: z.boolean().default(false),\n pages: z\n .string()\n .max(100)\n .regex(/^\\d+(\\s*-\\s*\\d+)?(\\s*,\\s*\\d+(\\s*-\\s*\\d+)?)*$/)\n .optional(),\n})\n\nexport type ConversionOptions = z.infer<typeof ConversionOptionsSchema>\n\n// ===== Document Source (metadata.source) =====\n\n/**\n * Who keeps a document's content up to date.\n *\n * `web` is a page the platform re-reads on its own; the others are cloud\n * document sources. Distinct from `documents.source_provider`, which carries\n * only the providers that OWN their documents (the cloud ones) and is null for\n * everything else: a web page discovered by a source stays editable.\n */\nexport enum DocumentSourceProvider {\n Web = 'web',\n SharePoint = 'sharepoint',\n GoogleDrive = 'google-drive',\n}\n\n/**\n * Outcome of the last pass over a document's source.\n *\n * `unchanged` is the one that pays for the whole mechanism: the source was read\n * and produced the same text, so no chunk was rewritten and no embedding was\n * charged. `shrunk` is a refusal, not a failure: the page answered but with far\n * less content than before, so the good version was kept.\n */\nexport enum DocumentRefreshResult {\n Updated = 'updated',\n Unchanged = 'unchanged',\n Failed = 'failed',\n Shrunk = 'shrunk',\n Gone = 'gone',\n}\n\n/**\n * How often a document re-reads its source on its own.\n *\n * `null` is the fourth value and the default: manual, which is what every\n * document is today and what every type other than `url` can ever be.\n */\nexport enum DocumentRefreshInterval {\n Daily = 'daily',\n Weekly = 'weekly',\n Monthly = 'monthly',\n}\n\n/**\n * The Postgres interval each trigger advances by.\n *\n * One table, read by the two places that move a deadline: the service, when\n * somebody sets or changes the trigger, and the timer, when a due document has\n * been queued. Written as literals rather than composed at the call site\n * because they end up inside SQL.\n */\nexport const REFRESH_INTERVAL_SQL: Record<DocumentRefreshInterval, string> = {\n [DocumentRefreshInterval.Daily]: '1 day',\n [DocumentRefreshInterval.Weekly]: '7 days',\n [DocumentRefreshInterval.Monthly]: '1 month',\n}\n\n/**\n * Hours after which a document left `processing` is treated as abandoned.\n *\n * A killed worker leaves that status behind, and nothing else moves it: the row\n * would drop out of the refresh timer's selection for good, because the timer\n * only claims documents that are `success` or `failed`. Past this window the\n * timer takes it anyway, and a manual refresh stops being refused.\n *\n * Generous on purpose: a scrape is bounded by the Functions host timeout, so\n * anything still `processing` after six hours is not running.\n */\nexport const STALE_PROCESSING_HOURS = 6\n\nexport const DocumentLastRefreshSchema = z.object({\n at: z.string(),\n result: z.enum(DocumentRefreshResult),\n httpStatus: z.number().optional(),\n error: z.string().optional(),\n /** Reset by the first good outcome; the notification threshold reads it. */\n consecutiveFailures: z.number().optional(),\n /**\n * Words before and after, written by the shrink guard. They are kept rather\n * than only compared because the guard's thresholds are a starting point:\n * after a month of real pages one can tell whether they cut too much.\n */\n previousWordCount: z.number().optional(),\n newWordCount: z.number().optional(),\n})\n\nexport type DocumentLastRefresh = z.infer<typeof DocumentLastRefreshSchema>\n\n/** Fields every source branch shares, whatever keeps the document up to date. */\nconst commonSourceFields = {\n /**\n * Hash of the text that actually reaches the chunks, so an unchanged source\n * costs no chunking and no embedding. Written by the processor on every\n * pass, which is what lets a document imported before this existed start\n * comparing from its second pass on.\n */\n contentHash: z.string().optional(),\n lastRefresh: DocumentLastRefreshSchema.optional(),\n}\n\nconst WebDocumentSourceSchema = z.object({\n provider: z.literal(DocumentSourceProvider.Web),\n url: z.string(),\n // Written by a successful conversion, and only then: at insert time the\n // page has not been read yet, so a value here would attest a scrape that\n // never happened.\n lastScrapedAt: z.string().optional(),\n /**\n * Hash of the deterministic text handed to the extraction step, before the\n * model. With `extractionStrategy: 'ai'` the model's output differs on every\n * call, so comparing the final markdown would always say \"changed\" and\n * every interval would pay conversion, chunking and embedding. This is what\n * the AI path compares, and it decides whether to call the model at all.\n */\n extractionInputHash: z.string().optional(),\n /**\n * Where the last successful pass actually landed after redirects.\n *\n * The shrink guard compares this with the new final URL, and not with `url`\n * on purpose: plenty of sites always redirect (a locale prefix, a trailing\n * slash, http to https), so comparing against the stored URL would refuse\n * every update of those pages forever. What says a page is gone is its\n * destination changing from the one it has been landing on.\n */\n finalUrl: z.string().optional(),\n /**\n * The web source that discovered this page. It says who found it, not who\n * governs it: the page stays editable like any other. Editing the text by\n * hand takes it off, and the page stops belonging to the source.\n */\n sourceId: z.uuid().optional(),\n /**\n * The last run of that source that found the page listed.\n *\n * Not the last successful read of the page, which is `lastScrapedAt`:\n * this is the marker the removal option reads, named like the cloud\n * field because the same reconciliation reads both. A page without one is\n * never removed.\n */\n lastSyncedAt: z.string().optional(),\n /**\n * The `<lastmod>` the sitemap declared the last time the source read it.\n * A change that is newer than `lastScrapedAt` queues an early refresh.\n */\n lastmod: z.string().optional(),\n ...commonSourceFields,\n})\n\n/** Coordinates a cloud adapter needs to find the item again, plus its content fingerprint. */\nconst cloudSourceFields = {\n /** The `document_sync_sources` row that owns this document. */\n sourceId: z.uuid(),\n remoteId: z.string(),\n webUrl: z.string(),\n path: z.string(),\n /**\n * The provider's own content fingerprint, compared for equality only and\n * never interpreted. It is what lets a sync skip the download entirely.\n */\n fingerprint: z.string(),\n /** Marks the document as seen by a run: the reconciliation after a resync reads it. */\n lastSyncedAt: z.string(),\n /** When the provider says the item last changed. Shown, never compared: the fingerprint decides. */\n lastModified: z.string().optional(),\n /**\n * A newly downloaded blob waiting to be converted. It sits here instead of\n * replacing `metadata.media` so that a conversion failure cannot destroy the\n * version that works: the processor promotes it only on success.\n */\n candidate: z\n .object({\n media: MediaSchema,\n fingerprint: z.string(),\n name: z.string(),\n webUrl: z.string(),\n path: z.string(),\n lastModified: z.string().optional(),\n })\n .optional(),\n ...commonSourceFields,\n}\n\nconst SharePointDocumentSourceSchema = z.object({\n provider: z.literal(DocumentSourceProvider.SharePoint),\n ...cloudSourceFields,\n})\n\nconst GoogleDriveDocumentSourceSchema = z.object({\n provider: z.literal(DocumentSourceProvider.GoogleDrive),\n ...cloudSourceFields,\n})\n\n/**\n * `metadata.source`, discriminated on `provider`.\n *\n * One object cannot hold both shapes: a web page has a URL and a scrape date, a\n * cloud file has remote coordinates and a fingerprint, and making every field\n * optional to fit both is the same as having no schema. Rows written before the\n * discriminator existed carry no `provider`, so they are normalized to the web\n * branch before routing: that is the only shape that could have been written.\n *\n * The normalization runs on parse, and responses are serialized by the\n * parse-based compiler (see `apps/backend/src/utils/responseSerializer.ts`), so\n * a legacy row still comes out of the API intact.\n */\nexport const DocumentSourceSchema = z.preprocess(\n (value) => {\n if (\n value &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n !('provider' in value)\n ) {\n return { provider: DocumentSourceProvider.Web, ...value }\n }\n return value\n },\n z.discriminatedUnion('provider', [\n WebDocumentSourceSchema,\n SharePointDocumentSourceSchema,\n GoogleDriveDocumentSourceSchema,\n ]),\n)\n\nexport type DocumentSource = z.infer<typeof DocumentSourceSchema>\nexport type WebDocumentSource = z.infer<typeof WebDocumentSourceSchema>\n\n/**\n * The page URL of a document's source, when its source is a web page.\n *\n * One place to narrow the union, so the views that show \"where this came from\"\n * do not each grow their own check, and a cloud-synced document returns nothing\n * here instead of a broken link: its address is `webUrl` on the remote item,\n * which is a different thing to show and to say.\n */\nexport function documentSourceUrl(source?: DocumentSource): string | undefined {\n return source && 'url' in source ? source.url : undefined\n}\n\n// ===== Processing queue contract =====\n\n/**\n * Why a document is being processed again. Absent means the ingestion of a new\n * document, which is the only case whose natural key is the document id alone.\n */\nexport type DocumentProcessingKind = 'refresh' | 'reprocess' | 'reindex'\n\n/**\n * The `document-processing` queue message.\n *\n * Lives here because two processes read it: the backend publishes it and the\n * Azure Function consumes it. It used to be declared in each, and the copy in\n * the function app was already a field behind.\n */\nexport interface DocumentProcessingJob {\n documentId: string\n conversionOptions?: ConversionOptions\n /**\n * Set by every caller that processes a document which already exists. It\n * shapes the message id (see `publishProcessingJob`) and, for `refresh`,\n * turns on the refresh mode of the processor.\n */\n kind?: DocumentProcessingKind\n /**\n * Only a scheduled refresh enforces the shrink guard. A person who clicked\n * \"refresh now\" is looking at the result and may well be refreshing a page\n * that really did get shorter, so the guard would only stand in their way.\n */\n guarded?: boolean\n /**\n * The web source whose sitemap asked for this early refresh. Nobody is\n * watching it either, so it enforces the shrink guard; and it is void if\n * the page no longer belongs to that source, which is what editing its text\n * by hand does. Not `guarded`, which also voids a page without a trigger:\n * a source reads its pages whether they have one or not.\n */\n sourceId?: string\n}\n\n/**\n * Metadata structure for document.metadata column\n * Consolidates all metadata from converters and source info\n */\nexport const DocumentMetadataSchema = z\n .object({\n // === Source Info (URL and synced documents) ===\n source: DocumentSourceSchema.optional(),\n\n // === Media Info (File documents only) ===\n media: MediaSchema.optional(),\n\n // === Common Fields (all document types) ===\n title: z.string().optional(),\n author: z.string().optional(),\n description: z.string().optional(),\n summary: z.string().optional(),\n keywords: z.array(z.string()).optional(),\n\n // === PDF Specific ===\n subject: z.string().optional(),\n creator: z.string().optional(), // Original application\n producer: z.string().optional(), // PDF generator software\n creationDate: z.string().optional(),\n modificationDate: z.string().optional(),\n pageCount: decodeOnly(\n z.union([z.number(), z.array(z.unknown())]),\n z.number(),\n (val) => (Array.isArray(val) ? val.length : val),\n ).optional(),\n encrypted: z.boolean().optional(),\n\n // === DOCX Specific ===\n characterCount: z.number().optional(),\n lineCount: z.number().optional(),\n\n // === URL Specific ===\n siteName: z.string().optional(),\n canonicalUrl: z.url().optional(),\n imageUrl: z.url().optional(),\n favicon: z.url().optional(),\n type: z.string().optional(), // og:type (article, website, etc.)\n locale: z.string().optional(),\n tags: z.array(z.string()).optional(),\n publishedTime: z.string().optional(),\n modifiedTime: z.string().optional(),\n\n // === Metrics (all document types) ===\n wordCount: z.number().optional(),\n paragraphCount: z.number().optional(),\n readingTime: z.number().optional(), // in minutes\n\n // === OCR (PDF documents) ===\n ocrUsed: z.boolean().optional(),\n ocrProvider: z.string().optional(),\n ocrModel: z.string().optional(),\n ocrPages: z.string().optional(),\n ocrCost: z.number().optional(),\n ocrError: z.string().optional(),\n\n // === RAG / Duplicates / Sync Info ===\n chunksCount: z.number().optional(),\n redundantChunksCount: z.number().optional(),\n hasRedundantChunks: z.boolean().optional(),\n qdrantSynced: z.boolean().optional(),\n\n // === Conversion Options (for reprocessing) ===\n conversionOptions: ConversionOptionsSchema.optional(),\n })\n .loose() // Allow additional custom fields\n\nexport type DocumentMetadata = z.infer<typeof DocumentMetadataSchema>\n\n/**\n * Document type enum\n *\n * - 'file': Document created from uploaded file (PDF, DOCX)\n * - 'url': Document created from web scraping\n * - 'revised-answer': Document created from revised AI answer\n * - 'plain-text': Document created from plain text input\n */\nexport enum DocumentType {\n File = 'file',\n Url = 'url',\n RevisedAnswer = 'revised-answer',\n PlainText = 'plain-text',\n}\n\n// ===== Schemas =====\n\n/**\n * Full document schema from database\n * Extended with computed field chunksCount\n */\nconst BaseDocumentSchema = z.object({\n id: z.string(),\n externalId: z.string().nullable(),\n name: z.string(),\n content: z.string(),\n type: z.string(),\n language: z.string(),\n metadata: z.record(z.string(), z.unknown()),\n indexStatus: z.string(),\n processedAt: z.coerce.date().nullable(),\n createdAt: z.coerce.date(),\n createdBy: z.string(),\n updatedAt: z.coerce.date(),\n updatedBy: z.string(),\n deleted: z.boolean(),\n deletedAt: z.coerce.date().nullable(),\n deletedBy: z.string().nullable(),\n organizationId: z.string(),\n priority: z.number().int().min(1).max(5).default(3),\n /** The automatic refresh trigger; null is manual, and only `url` can have one. */\n refreshInterval: z.enum(DocumentRefreshInterval).nullable().optional(),\n /**\n * When the trigger next comes due. Null with an interval set means paused:\n * the source answered that the page is gone for good.\n */\n nextRefreshAt: z.coerce.date().nullable().optional(),\n /**\n * Which sync source owns this document, when one does.\n *\n * Null is the ordinary case. A non-null value means a job keeps the\n * document up to date, which is what makes it read only: editing it, moving\n * it or deleting it by hand would be undone at the next run, silently.\n * Written only by providers that own their documents, never by a crawl that\n * merely discovered a page.\n */\n sourceProvider: z.enum(DocumentSourceProvider).nullable().optional(),\n})\n\nexport const DocumentSchema = BaseDocumentSchema.extend({\n type: z.enum(DocumentType),\n indexStatus: z.enum(IndexStatus),\n metadata: DocumentMetadataSchema,\n // Add computed field for chunks count (populated by service layer)\n chunksCount: z.number().optional(),\n // Computed fields for redundancy tracking\n redundantChunksCount: z.number().optional(),\n hasRedundantChunks: z.boolean().optional(),\n // Qdrant sync status\n qdrantSynced: z.boolean().optional(),\n // Agent IDs associated with this document (populated in single-item reads)\n agentIds: z.array(z.string()).optional(),\n // Folder ID for this document within an agent context (populated in agent-scoped reads)\n folderId: z.string().nullable().optional(),\n // Full folder path string e.g. \"Parent / Child\" (populated in list reads when agentId is set)\n folderPath: z.string().nullable().optional(),\n /** Who sent the document to the trash, by name (populated in trash reads). */\n deletedByName: z.string().nullable().optional(),\n})\n\n/**\n * The document types the trash holds: the ones a person adds to a knowledge\n * base by hand. A revised answer lives and dies with its own page, so it is\n * never listed, restored or emptied from here.\n */\nexport const DOCUMENT_TRASH_TYPES = [\n DocumentType.File,\n DocumentType.Url,\n DocumentType.PlainText,\n] as const\n\n/**\n * Why a restore was refused (docs/specs/document-trash.md, Decision 3), sent\n * as `additionalData.reason` of a `conflict` problem. The third case of the\n * decision, a folder that no longer exists, is not a refusal: the document\n * goes back to the root and the answer says so.\n */\nexport enum DocumentRestoreRefusal {\n /** Every agent the document belonged to has been deleted. */\n AgentGone = 'agent-gone',\n /**\n * A live document of the same source holds its remote identity; its id\n * travels as `additionalData.documentId`.\n */\n IdentityTaken = 'identity-taken',\n}\n\nexport const DocumentRestoreResultSchema = z.object({\n document: DocumentSchema,\n /** Its folder was gone, so it went back to the root of its agent. */\n returnedToRoot: z.boolean(),\n})\n\nexport const DocumentTrashSummarySchema = z.object({\n /** Documents in the trash of the agent, the ones it can restore. */\n count: z.number().int(),\n /**\n * Days a document stays in the trash before it is destroyed for good,\n * `0` when nothing destroys it (`trashRetentionDaysOf`).\n */\n retentionDays: z.number().int().min(0),\n})\n\nexport const DocumentEmptyTrashDtoSchema = z.object({\n agentId: z.uuid(),\n})\n\nexport const DocumentEmptyTrashResultSchema = z.object({\n purged: z.number().int(),\n /** Still in the trash: one call empties a batch, the caller asks again. */\n remaining: z.number().int(),\n})\n\n/**\n * Query parameters for listing documents with pagination, sorting, and filters\n */\nexport const DocumentQuerystringSchema = z.object({\n ...zodQs.pagination(),\n ...zodQs.sort(['id', 'updatedAt', 'createdAt', 'name', 'deletedAt']),\n ...zodQs.filters(['type', 'language', 'agentId', 'indexStatus']),\n // 'true' lists the trash instead of the knowledge base: a flat list, by\n // agent, of what that agent can restore. Every other read keeps ignoring\n // deleted documents.\n 'filter[deleted]': z.enum(['true', 'false']).optional(),\n ...zodQs.fullText(),\n ...zodQs.ids(),\n 'filter[similarity]': z.string().optional(),\n // UUID = documents in that folder; 'null' = documents at root (no folder); absent = all documents\n 'filter[folderId]': z.string().optional(),\n 'filter[hasRedundantChunks]': z.string().optional(),\n // One of the intervals, 'null' for the documents left on manual, 'auto' for\n // any of the three. Same convention as `filter[folderId]`, and handled\n // outside `getFilters` for the same reason: `inArray` cannot say IS NULL.\n 'filter[refreshInterval]': z.string().optional(),\n // A provider, 'null' for the documents nobody syncs, 'any' for the ones a\n // source owns whoever it is. Same convention and the same reason as above.\n 'filter[sourceProvider]': z.string().optional(),\n})\n\n/**\n * Document creation schema for POST /documents endpoint\n *\n * Supports three types:\n * - 'file': Requires media object with uploaded file info\n * - 'url': Requires url string for web scraping\n * - 'revised-answer': Requires content (created from revisedAnswer service)\n */\nexport const DocumentCreateDtoSchema = z\n .object({\n type: z.enum(DocumentType).default(DocumentType.File),\n name: z.string().min(1).max(255).optional(),\n language: z.enum(SupportedLanguage).optional(),\n organizationId: z.string(),\n agentIds: z.array(z.string()).min(1, 'At least one agent is required'),\n folderId: z.uuid().nullable().optional(),\n media: MediaSchema.optional(),\n url: z.url().optional(),\n content: z.string().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n extractionStrategy: z.enum(ExtractionStrategy).optional(),\n browserEngine: z.enum(BrowserEngine).optional(),\n headers: HeadesSchema.nullish().default([]),\n aiDescriptionModel: z.string().optional(),\n aiDescriptionPrompt: z.string().max(5000).optional(),\n forceOcr: z.boolean().default(false),\n pages: z\n .string()\n .max(100)\n .regex(/^\\d+(\\s*-\\s*\\d+)?(\\s*,\\s*\\d+(\\s*-\\s*\\d+)?)*$/)\n .optional(),\n priority: z.number().int().min(1).max(5).default(3).optional(),\n refreshInterval: z.enum(DocumentRefreshInterval).nullable().optional(),\n /**\n * The web source this page is imported for: the pages ticked in the\n * crawler dialog when it also creates a source. They land in the\n * source's folder as pages the source discovered, so its removal\n * option and its early refresh apply to them from the first run.\n */\n syncSourceId: z.uuid().optional(),\n })\n .superRefine((data, ctx) => {\n if (data.syncSourceId && data.type !== DocumentType.Url) {\n ctx.addIssue({\n code: 'custom',\n params: {\n i18n: 'errors.syncSourceUrlOnly',\n },\n path: ['syncSourceId'],\n })\n }\n if (data.type === DocumentType.File && !data.media) {\n ctx.addIssue({\n code: 'custom',\n params: {\n i18n: 'errors.required',\n },\n path: ['media'],\n })\n return\n }\n if (data.type === DocumentType.Url && !data.url) {\n ctx.addIssue({\n code: 'custom',\n params: {\n i18n: 'errors.required',\n },\n path: ['url'],\n })\n }\n // The database has the same CHECK, but a 400 saying which field is\n // wrong beats a constraint violation surfacing as a 500.\n if (data.refreshInterval && data.type !== DocumentType.Url) {\n ctx.addIssue({\n code: 'custom',\n params: {\n i18n: 'errors.refreshIntervalUrlOnly',\n },\n path: ['refreshInterval'],\n })\n }\n if (\n data.type === DocumentType.PlainText &&\n !(data.name || data.language)\n ) {\n if (!data.name) {\n ctx.addIssue({\n code: 'custom',\n params: {\n i18n: 'errors.required',\n },\n path: ['name'],\n })\n }\n if (!data.language) {\n ctx.addIssue({\n code: 'custom',\n params: {\n i18n: 'errors.required',\n },\n path: ['language'],\n })\n }\n }\n })\n\n/**\n * Document update schema for PUT /documents/:id endpoint\n *\n * All fields are optional, but at least one must be provided\n */\nexport const DocumentUpdateDtoSchema = z.object({\n id: z.string(),\n organizationId: z.string(),\n content: z.string().optional(),\n name: z.string().min(1).max(255).optional(),\n language: z.enum(SupportedLanguage).optional(),\n priority: z.number().int().min(1).max(5).optional(),\n agentIds: z.array(z.string()).min(1).optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n refreshInterval: z.enum(DocumentRefreshInterval).nullable().optional(),\n})\n\n/** Body of `PATCH /documents/:id/refresh-interval`, twin of the priority route. */\nexport const DocumentRefreshIntervalDtoSchema = z.object({\n refreshInterval: z.enum(DocumentRefreshInterval).nullable(),\n})\n\n/** Body of `POST /documents/bulk-refresh-interval`. */\nexport const DocumentBulkRefreshIntervalDtoSchema = z.object({\n ids: z.array(z.uuid()).min(1).max(100),\n refreshInterval: z.enum(DocumentRefreshInterval).nullable(),\n})\n\n/** Body of `POST /documents/bulk-refresh`, twin of `bulk-reprocess`. */\nexport const DocumentBulkRefreshDtoSchema = z.object({\n ids: z.array(z.uuid()).min(1).max(100),\n})\n\n// ===== Type Exports =====\n\nexport type Document = z.infer<typeof DocumentSchema>\nexport type DocumentQuerystring = z.infer<typeof DocumentQuerystringSchema>\nexport type DocumentCreateDto = z.infer<typeof DocumentCreateDtoSchema>\nexport type DocumentUpdateDto = z.infer<typeof DocumentUpdateDtoSchema>\nexport type DocumentRefreshIntervalDto = z.infer<\n typeof DocumentRefreshIntervalDtoSchema\n>\nexport type DocumentBulkRefreshIntervalDto = z.infer<\n typeof DocumentBulkRefreshIntervalDtoSchema\n>\nexport type DocumentBulkRefreshDto = z.infer<\n typeof DocumentBulkRefreshDtoSchema\n>\nexport type DocumentRestoreResult = z.infer<typeof DocumentRestoreResultSchema>\nexport type DocumentTrashSummary = z.infer<typeof DocumentTrashSummarySchema>\nexport type DocumentEmptyTrashDto = z.infer<typeof DocumentEmptyTrashDtoSchema>\nexport type DocumentEmptyTrashResult = z.infer<\n typeof DocumentEmptyTrashResultSchema\n>\n\n// ===== Helper Functions =====\n\nexport const getStatusColor = (status: IndexStatus) => {\n switch (status) {\n case IndexStatus.Success:\n return 'success'\n case IndexStatus.Failed:\n return 'danger'\n case IndexStatus.Processing:\n return 'warning'\n default:\n return 'info'\n }\n}\n\nexport const getStatusIcon = (status: IndexStatus) => {\n switch (status) {\n case IndexStatus.Success:\n return 'ri:check-line'\n case IndexStatus.Failed:\n return 'ri:error-warning-line'\n case IndexStatus.Processing:\n return 'ri:hourglass-line'\n default:\n return 'ri:time-line'\n }\n}\n\nexport const getTypeIcon = (type: DocumentType) => {\n switch (type) {\n case DocumentType.File:\n return 'ri:file-line'\n case DocumentType.Url:\n return 'ri:link'\n case DocumentType.RevisedAnswer:\n return 'ri:feedback-line'\n default:\n return 'ri:input-method-line'\n }\n}\n\nexport const getFileIcon = (extension: string) => {\n const ext = (\n extension.startsWith('.') ? extension.slice(1) : extension\n ).toLowerCase()\n switch (ext) {\n case 'pdf':\n return 'ri:file-pdf-2-line'\n case 'doc':\n case 'docx':\n return 'ri:file-word-line'\n case 'xls':\n case 'xlsx':\n return 'ri:file-excel-line'\n case 'ppt':\n case 'pptx':\n return 'ri:file-ppt-line'\n case 'txt':\n return 'ri:file-text-line'\n case 'mp3':\n case 'wav':\n case 'ogg':\n return 'ri:file-music-line'\n case 'mp4':\n case 'avi':\n case 'mkv':\n return 'ri:file-video-line'\n case 'jpg':\n case 'jpeg':\n case 'png':\n case 'gif':\n case 'bmp':\n case 'svg':\n return 'ri:file-image-line'\n case 'zip':\n case 'rar':\n case '7z':\n return 'ri:file-zip-line'\n default:\n return 'ri:file-line'\n }\n}\n\n/** Whether a MIME type is an image. */\nexport const isImageMime = (mimeType?: string | null): boolean =>\n (mimeType ?? '').startsWith('image/')\n\n/** Whether a file MIME type can be previewed inline in the browser (image or\n * PDF) instead of being forced as a download. Shared by every file-list surface\n * so the preview/download decision stays consistent. */\nexport const isInlineViewable = (mimeType?: string | null): boolean =>\n isImageMime(mimeType) || mimeType === 'application/pdf'\n\n/** File-type identity for list rows and previews: icon, accent color\n * (CSS value driving glyph and tile tint) and a short human kind label. */\nexport interface FileKind {\n icon: string\n accent: string\n label: string\n}\n\n/** File-type identity derived from a MIME type. Accents match the chat\n * attachment cards (PkChatbotFilePreview) so files read the same everywhere. */\nexport const fileKindForMime = (mimeType?: string | null): FileKind => {\n const mime = mimeType ?? ''\n if (isImageMime(mime)) {\n return { icon: 'ri:image-line', accent: '#ec4899', label: 'Image' }\n }\n if (mime === 'application/pdf') {\n return { icon: 'ri:file-pdf-2-line', accent: '#e2483d', label: 'PDF' }\n }\n if (mime === 'application/msword' || mime.includes('wordprocessingml')) {\n return { icon: 'ri:file-word-line', accent: '#2b7de9', label: 'Word' }\n }\n if (mime === 'application/vnd.ms-excel' || mime.includes('spreadsheetml')) {\n return {\n icon: 'ri:file-excel-line',\n accent: '#1f9d57',\n label: 'Spreadsheet',\n }\n }\n if (\n mime === 'application/vnd.ms-powerpoint' ||\n mime.includes('presentationml')\n ) {\n return {\n icon: 'ri:file-ppt-line',\n accent: '#d98324',\n label: 'Presentation',\n }\n }\n if (mime.startsWith('audio/')) {\n return { icon: 'ri:file-music-line', accent: '#8b5cf6', label: 'Audio' }\n }\n if (mime.startsWith('video/')) {\n return { icon: 'ri:file-video-line', accent: '#6366f1', label: 'Video' }\n }\n if (\n mime === 'application/zip' ||\n mime === 'application/x-rar-compressed' ||\n mime === 'application/x-7z-compressed'\n ) {\n return { icon: 'ri:file-zip-line', accent: '#c08a1e', label: 'Archive' }\n }\n if (mime.startsWith('text/')) {\n return { icon: 'ri:file-text-line', accent: '#64748b', label: 'Text' }\n }\n return { icon: 'ri:file-line', accent: '#64748b', label: 'File' }\n}\n\n/** Icon for a file-list row, derived from its MIME type. */\nexport const fileIconForMime = (mimeType?: string | null): string =>\n fileKindForMime(mimeType).icon\n","export const stripMarkdown = (text?: string | null) => {\n if (!text) {\n return undefined\n }\n return text\n .replace(/!\\[.*?\\]\\(.*?\\)/g, '') // images\n .replace(/\\[([^\\]]+)\\]\\(.*?\\)/g, '$1') // links\n .replace(/`{1,3}[^`]*`{1,3}/g, '') // inline code / code blocks\n .replace(/#{1,6}\\s/g, '') // headings\n .replace(/(\\*{1,3}|_{1,3})(.*?)\\1/g, '$2') // bold / italic\n .replace(/~~(.*?)~~/g, '$1') // strikethrough\n .replace(/^\\s*[-*+>]\\s+/gm, '') // lists and blockquotes\n .replace(/\\n+/g, ' ') // newlines\n .trim()\n}\n"],"mappings":";;CAwJ2B,iBANpB,SAAA,GAAA;QACH,EAAA,sBAAA,iCACA,EAAA,sBAAA,iCACA,EAAA,mBAAA;AACJ,EAAA,CAAA,CAAA,CAE2B,EAAA,CAAe;AAe1C,IAAY,IAAL,yBAAA,GAAA;QACH,EAAA,KAAA,MACA,EAAA,KAAA,MACA,EAAA,KAAA,MACA,EAAA,KAAA,MACA,EAAA,KAAA;AACJ,EAAA,CAAA,CAAA;AAMK,EAAkB,IAClB,EAAkB,IAClB,EAAkB,IAClB,EAAkB,IAClB,EAAkB;AAMvB,IAAY,IAAL,yBAAA,GAAA;QAEH,EAAA,cAAA,eAEA,EAAA,KAAA;AACJ,EAAA,CAAA,CAAA,GAKY,IAAL,yBAAA,GAAA;QAEH,EAAA,QAAA,SAEA,EAAA,YAAA,aAEA,EAAA,SAAA;AACJ,EAAA,CAAA,CAAA,GC3Ma,IAAe,EAAS;CACjC,KAAK,EAAS,CAAC,CAAC,SAAS;CACzB,OAAO,EAAS,CAAC,CAAC,SAAS;AAC/B,CAAC,GAEY,IAAe,EACxB,EAAQ,CAAY,GACpB,EAAQ,EAAS;CAAE,KAAK,EAAS;CAAG,OAAO,EAAS;AAAE,CAAC,CAAC,IACvD,MACG,GAAS,QACJ,MAAW,EAAO,KAAK,KAAK,KAAK,EAAO,OAAO,KAAK,CACzD,CACR;AAekC,EAAS;CACvC,KAAK,EAAS;CACd,UAAU,EAAU;AACxB,CAAC,GAUqC,EAClC,EACI,EAAS;CACL,KAAK,EAAS,CAAC,CAAC,SAAS;CACzB,OAAO,EAAS,CAAC,CAAC,IAAI,IAAuB,CAAC,CAAC,SAAS;AAC5D,CAAC,CACL,GACA,EACW,EAAS;CAAE,KAAK,EAAS;CAAG,OAAO,EAAS,CAAC,CAAC,SAAS;AAAE,CAAC,CAAC,CAAC,CAClE,QACI,MACG,IAAI,IAAI,EAAQ,KAAK,EAAE,aAAU,EAAI,YAAY,CAAC,CAAC,CAAC,CAAC,SACrD,EAAQ,QACZ,EAAE,QAAQ,EAAE,MAAM,6BAA6B,EAAE,CACrD,IACH,MACG,EACK,QAAQ,MAAW,EAAO,KAAK,KAAK,CAAC,CAAC,CACtC,KAAK,EAAE,QAAK,gBAAa;CAAE,KAAK,EAAK,KAAK;CAAG;AAAM,EAAE,CAClE;;;ACjDA,IAAY,IAAL,yBAAA,GAAA;QACH,EAAA,UAAA,WACA,EAAA,aAAA,cACA,EAAA,UAAA,WACA,EAAA,SAAA;AACJ,EAAA,CAAA,CAAA,GAQa,IAA0B,EAAS;CAC5C,oBAAoB,EAAO,CAAkB,CAAC,CAAC,SAAS;CACxD,eAAe,EACL,CAAa,CAAC,CACnB,SAAS,CAAC,CACV,QAAQ,EAAc,KAAK;CAChC,SAAS,EAAa,QAAQ;CAC9B,oBAAoB,EAAS,CAAC,CAAC,SAAS;CACxC,qBAAqB,EAAS,CAAC,CAAC,IAAI,GAAI,CAAC,CAAC,SAAS;CACnD,UAAU,EAAS,CAAC,CAAC,SAAS;CAC9B,UAAU,EAAU,CAAC,CAAC,QAAQ,EAAK;CACnC,OAAO,EACK,CAAC,CACR,IAAI,GAAG,CAAC,CACR,MAAM,8CAA8C,CAAC,CACrD,SAAS;AAClB,CAAC,GAcW,IAAL,yBAAA,GAAA;QACH,EAAA,MAAA,OACA,EAAA,aAAA,cACA,EAAA,cAAA;AACJ,EAAA,CAAA,CAAA,GAUY,IAAL,yBAAA,GAAA;QACH,EAAA,UAAA,WACA,EAAA,YAAA,aACA,EAAA,SAAA,UACA,EAAA,SAAA,UACA,EAAA,OAAA;AACJ,EAAA,CAAA,CAAA,GAQY,IAAL,yBAAA,GAAA;QACH,EAAA,QAAA,SACA,EAAA,SAAA,UACA,EAAA,UAAA;AACJ,EAAA,CAAA,CAAA;AAWK,EAAwB,OACxB,EAAwB,QACxB,EAAwB;AAgB7B,IAAa,IAA4B,EAAS;CAC9C,IAAI,EAAS;CACb,QAAQ,EAAO,CAAqB;CACpC,YAAY,EAAS,CAAC,CAAC,SAAS;CAChC,OAAO,EAAS,CAAC,CAAC,SAAS;CAE3B,qBAAqB,EAAS,CAAC,CAAC,SAAS;CAMzC,mBAAmB,EAAS,CAAC,CAAC,SAAS;CACvC,cAAc,EAAS,CAAC,CAAC,SAAS;AACtC,CAAC,GAKK,IAAqB;CAOvB,aAAa,EAAS,CAAC,CAAC,SAAS;CACjC,aAAa,EAA0B,SAAS;AACpD,GAEM,IAA0B,EAAS;CACrC,UAAU,EAAU,EAAuB,GAAG;CAC9C,KAAK,EAAS;CAId,eAAe,EAAS,CAAC,CAAC,SAAS;CAQnC,qBAAqB,EAAS,CAAC,CAAC,SAAS;CAUzC,UAAU,EAAS,CAAC,CAAC,SAAS;CAM9B,UAAU,EAAO,CAAC,CAAC,SAAS;CAS5B,cAAc,EAAS,CAAC,CAAC,SAAS;CAKlC,SAAS,EAAS,CAAC,CAAC,SAAS;CAC7B,GAAG;AACP,CAAC,GAGK,IAAoB;CAEtB,UAAU,EAAO;CACjB,UAAU,EAAS;CACnB,QAAQ,EAAS;CACjB,MAAM,EAAS;CAKf,aAAa,EAAS;CAEtB,cAAc,EAAS;CAEvB,cAAc,EAAS,CAAC,CAAC,SAAS;CAMlC,WAAW,EACC;EACJ,OAAO;EACP,aAAa,EAAS;EACtB,MAAM,EAAS;EACf,QAAQ,EAAS;EACjB,MAAM,EAAS;EACf,cAAc,EAAS,CAAC,CAAC,SAAS;CACtC,CAAC,CAAC,CACD,SAAS;CACd,GAAG;AACP,GAEM,IAAiC,EAAS;CAC5C,UAAU,EAAU,EAAuB,UAAU;CACrD,GAAG;AACP,CAAC,GAEK,IAAkC,EAAS;CAC7C,UAAU,EAAU,EAAuB,WAAW;CACtD,GAAG;AACP,CAAC,GAeY,IAAuB,GAC/B,MAEO,KACA,OAAO,KAAU,YACjB,CAAC,MAAM,QAAQ,CAAK,KACpB,EAAE,cAAc,KAET;CAAE,UAAU,EAAuB;CAAK,GAAG;AAAM,IAErD,GAEX,EAAqB,YAAY;CAC7B;CACA;CACA;AACJ,CAAC,CACL,GA6Da,IAAyB,EAC1B;CAEJ,QAAQ,EAAqB,SAAS;CAGtC,OAAO,EAAY,SAAS;CAG5B,OAAO,EAAS,CAAC,CAAC,SAAS;CAC3B,QAAQ,EAAS,CAAC,CAAC,SAAS;CAC5B,aAAa,EAAS,CAAC,CAAC,SAAS;CACjC,SAAS,EAAS,CAAC,CAAC,SAAS;CAC7B,UAAU,EAAQ,EAAS,CAAC,CAAC,CAAC,SAAS;CAGvC,SAAS,EAAS,CAAC,CAAC,SAAS;CAC7B,SAAS,EAAS,CAAC,CAAC,SAAS;CAC7B,UAAU,EAAS,CAAC,CAAC,SAAS;CAC9B,cAAc,EAAS,CAAC,CAAC,SAAS;CAClC,kBAAkB,EAAS,CAAC,CAAC,SAAS;CACtC,WAAW,EACP,EAAQ,CAAC,EAAS,GAAG,EAAQ,EAAU,CAAC,CAAC,CAAC,GAC1C,EAAS,IACR,MAAS,MAAM,QAAQ,CAAG,IAAI,EAAI,SAAS,CAChD,CAAC,CAAC,SAAS;CACX,WAAW,EAAU,CAAC,CAAC,SAAS;CAGhC,gBAAgB,EAAS,CAAC,CAAC,SAAS;CACpC,WAAW,EAAS,CAAC,CAAC,SAAS;CAG/B,UAAU,EAAS,CAAC,CAAC,SAAS;CAC9B,cAAc,EAAM,CAAC,CAAC,SAAS;CAC/B,UAAU,EAAM,CAAC,CAAC,SAAS;CAC3B,SAAS,EAAM,CAAC,CAAC,SAAS;CAC1B,MAAM,EAAS,CAAC,CAAC,SAAS;CAC1B,QAAQ,EAAS,CAAC,CAAC,SAAS;CAC5B,MAAM,EAAQ,EAAS,CAAC,CAAC,CAAC,SAAS;CACnC,eAAe,EAAS,CAAC,CAAC,SAAS;CACnC,cAAc,EAAS,CAAC,CAAC,SAAS;CAGlC,WAAW,EAAS,CAAC,CAAC,SAAS;CAC/B,gBAAgB,EAAS,CAAC,CAAC,SAAS;CACpC,aAAa,EAAS,CAAC,CAAC,SAAS;CAGjC,SAAS,EAAU,CAAC,CAAC,SAAS;CAC9B,aAAa,EAAS,CAAC,CAAC,SAAS;CACjC,UAAU,EAAS,CAAC,CAAC,SAAS;CAC9B,UAAU,EAAS,CAAC,CAAC,SAAS;CAC9B,SAAS,EAAS,CAAC,CAAC,SAAS;CAC7B,UAAU,EAAS,CAAC,CAAC,SAAS;CAG9B,aAAa,EAAS,CAAC,CAAC,SAAS;CACjC,sBAAsB,EAAS,CAAC,CAAC,SAAS;CAC1C,oBAAoB,EAAU,CAAC,CAAC,SAAS;CACzC,cAAc,EAAU,CAAC,CAAC,SAAS;CAGnC,mBAAmB,EAAwB,SAAS;AACxD,CAAC,CAAC,CACD,MAAM,GAYC,IAAL,yBAAA,GAAA;QACH,EAAA,OAAA,QACA,EAAA,MAAA,OACA,EAAA,gBAAA,kBACA,EAAA,YAAA;AACJ,EAAA,CAAA,CAAA,GA8Ca,IAtCc,EAAS;CAChC,IAAI,EAAS;CACb,YAAY,EAAS,CAAC,CAAC,SAAS;CAChC,MAAM,EAAS;CACf,SAAS,EAAS;CAClB,MAAM,EAAS;CACf,UAAU,EAAS;CACnB,UAAU,EAAS,EAAS,GAAG,EAAU,CAAC;CAC1C,aAAa,EAAS;CACtB,aAAa,EAAc,CAAC,CAAC,SAAS;CACtC,WAAW,EAAc;CACzB,WAAW,EAAS;CACpB,WAAW,EAAc;CACzB,WAAW,EAAS;CACpB,SAAS,EAAU;CACnB,WAAW,EAAc,CAAC,CAAC,SAAS;CACpC,WAAW,EAAS,CAAC,CAAC,SAAS;CAC/B,gBAAgB,EAAS;CACzB,UAAU,EAAS,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;CAElD,iBAAiB,EAAO,CAAuB,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;CAKrE,eAAe,EAAc,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;CAUnD,gBAAgB,EAAO,CAAsB,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;AACvE,CAE8B,CAAA,CAAmB,OAAO;CACpD,MAAM,EAAO,CAAY;CACzB,aAAa,EAAO,CAAW;CAC/B,UAAU;CAEV,aAAa,EAAS,CAAC,CAAC,SAAS;CAEjC,sBAAsB,EAAS,CAAC,CAAC,SAAS;CAC1C,oBAAoB,EAAU,CAAC,CAAC,SAAS;CAEzC,cAAc,EAAU,CAAC,CAAC,SAAS;CAEnC,UAAU,EAAQ,EAAS,CAAC,CAAC,CAAC,SAAS;CAEvC,UAAU,EAAS,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;CAEzC,YAAY,EAAS,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;CAE3C,eAAe,EAAS,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;AAClD,CAAC;AAQG,EAAa,MACb,EAAa,KACb,EAAa,WAmB0B,EAAS;CAChD,UAAU;CAEV,gBAAgB,EAAU;AAC9B,CAAC,GAEyC,EAAS;CAE/C,OAAO,EAAS,CAAC,CAAC,IAAI;CAKtB,eAAe,EAAS,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;AACzC,CAAC,GAE0C,EAAS,EAChD,SAAS,EAAO,EACpB,CAAC,GAE6C,EAAS;CACnD,QAAQ,EAAS,CAAC,CAAC,IAAI;CAEvB,WAAW,EAAS,CAAC,CAAC,IAAI;AAC9B,CAAC,GAKwC,EAAS;CAC9C,GAAG,EAAM,WAAW;CACpB,GAAG,EAAM,KAAK;EAAC;EAAM;EAAa;EAAa;EAAQ;CAAW,CAAC;CACnE,GAAG,EAAM,QAAQ;EAAC;EAAQ;EAAY;EAAW;CAAa,CAAC;CAI/D,mBAAmB,EAAO,CAAC,QAAQ,OAAO,CAAC,CAAC,CAAC,SAAS;CACtD,GAAG,EAAM,SAAS;CAClB,GAAG,EAAM,IAAI;CACb,sBAAsB,EAAS,CAAC,CAAC,SAAS;CAE1C,oBAAoB,EAAS,CAAC,CAAC,SAAS;CACxC,8BAA8B,EAAS,CAAC,CAAC,SAAS;CAIlD,2BAA2B,EAAS,CAAC,CAAC,SAAS;CAG/C,0BAA0B,EAAS,CAAC,CAAC,SAAS;AAClD,CAAC,GAUsC,EAC3B;CACJ,MAAM,EAAO,CAAY,CAAC,CAAC,QAAQ,EAAa,IAAI;CACpD,MAAM,EAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,SAAS;CAC1C,UAAU,EAAO,CAAiB,CAAC,CAAC,SAAS;CAC7C,gBAAgB,EAAS;CACzB,UAAU,EAAQ,EAAS,CAAC,CAAC,CAAC,IAAI,GAAG,gCAAgC;CACrE,UAAU,EAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;CACvC,OAAO,EAAY,SAAS;CAC5B,KAAK,EAAM,CAAC,CAAC,SAAS;CACtB,SAAS,EAAS,CAAC,CAAC,SAAS;CAC7B,UAAU,EAAS,EAAS,GAAG,EAAU,CAAC,CAAC,CAAC,SAAS;CACrD,oBAAoB,EAAO,CAAkB,CAAC,CAAC,SAAS;CACxD,eAAe,EAAO,CAAa,CAAC,CAAC,SAAS;CAC9C,SAAS,EAAa,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC;CAC1C,oBAAoB,EAAS,CAAC,CAAC,SAAS;CACxC,qBAAqB,EAAS,CAAC,CAAC,IAAI,GAAI,CAAC,CAAC,SAAS;CACnD,UAAU,EAAU,CAAC,CAAC,QAAQ,EAAK;CACnC,OAAO,EACK,CAAC,CACR,IAAI,GAAG,CAAC,CACR,MAAM,8CAA8C,CAAC,CACrD,SAAS;CACd,UAAU,EAAS,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;CAC7D,iBAAiB,EAAO,CAAuB,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;CAOrE,cAAc,EAAO,CAAC,CAAC,SAAS;AACpC,CAAC,CAAC,CACD,aAAa,GAAM,MAAQ;CAUxB,IATI,EAAK,gBAAgB,EAAK,SAAS,EAAa,OAChD,EAAI,SAAS;EACT,MAAM;EACN,QAAQ,EACJ,MAAM,2BACV;EACA,MAAM,CAAC,cAAc;CACzB,CAAC,GAED,EAAK,SAAS,EAAa,QAAQ,CAAC,EAAK,OAAO;EAChD,EAAI,SAAS;GACT,MAAM;GACN,QAAQ,EACJ,MAAM,kBACV;GACA,MAAM,CAAC,OAAO;EAClB,CAAC;EACD;CACJ;CAqBA,AApBI,EAAK,SAAS,EAAa,OAAO,CAAC,EAAK,OACxC,EAAI,SAAS;EACT,MAAM;EACN,QAAQ,EACJ,MAAM,kBACV;EACA,MAAM,CAAC,KAAK;CAChB,CAAC,GAID,EAAK,mBAAmB,EAAK,SAAS,EAAa,OACnD,EAAI,SAAS;EACT,MAAM;EACN,QAAQ,EACJ,MAAM,gCACV;EACA,MAAM,CAAC,iBAAiB;CAC5B,CAAC,GAGD,EAAK,SAAS,EAAa,aAC3B,EAAE,EAAK,QAAQ,EAAK,cAEf,EAAK,QACN,EAAI,SAAS;EACT,MAAM;EACN,QAAQ,EACJ,MAAM,kBACV;EACA,MAAM,CAAC,MAAM;CACjB,CAAC,GAEA,EAAK,YACN,EAAI,SAAS;EACT,MAAM;EACN,QAAQ,EACJ,MAAM,kBACV;EACA,MAAM,CAAC,UAAU;CACrB,CAAC;AAGb,CAAC,GAOkC,EAAS;CAC5C,IAAI,EAAS;CACb,gBAAgB,EAAS;CACzB,SAAS,EAAS,CAAC,CAAC,SAAS;CAC7B,MAAM,EAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,SAAS;CAC1C,UAAU,EAAO,CAAiB,CAAC,CAAC,SAAS;CAC7C,UAAU,EAAS,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;CAClD,UAAU,EAAQ,EAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;CAC9C,UAAU,EAAS,EAAS,GAAG,EAAU,CAAC,CAAC,CAAC,SAAS;CACrD,iBAAiB,EAAO,CAAuB,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;AACzE,CAAC,GAG+C,EAAS,EACrD,iBAAiB,EAAO,CAAuB,CAAC,CAAC,SAAS,EAC9D,CAAC,GAGmD,EAAS;CACzD,KAAK,EAAQ,EAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG;CACrC,iBAAiB,EAAO,CAAuB,CAAC,CAAC,SAAS;AAC9D,CAAC,GAG2C,EAAS,EACjD,KAAK,EAAQ,EAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,EACzC,CAAC;AAoDD,IAAa,KAAe,MAAuB;CAC/C,QAAQ,GAAR;EACI,KAAK,EAAa,MACd,OAAO;EACX,KAAK,EAAa,KACd,OAAO;EACX,KAAK,EAAa,eACd,OAAO;EACX,SACI,OAAO;CACf;AACJ,GA6Ca,KAAe,OACvB,KAAY,GAAA,CAAI,WAAW,QAAQ,GAK3B,KAAoB,MAC7B,EAAY,CAAQ,KAAK,MAAa,mBAY7B,KAAmB,MAAuC;CACnE,IAAM,IAAO,KAAY;CA2CzB,OA1CI,EAAY,CAAI,IACT;EAAE,MAAM;EAAiB,QAAQ;EAAW,OAAO;CAAQ,IAElE,MAAS,oBACF;EAAE,MAAM;EAAsB,QAAQ;EAAW,OAAO;CAAM,IAErE,MAAS,wBAAwB,EAAK,SAAS,kBAAkB,IAC1D;EAAE,MAAM;EAAqB,QAAQ;EAAW,OAAO;CAAO,IAErE,MAAS,8BAA8B,EAAK,SAAS,eAAe,IAC7D;EACH,MAAM;EACN,QAAQ;EACR,OAAO;CACX,IAGA,MAAS,mCACT,EAAK,SAAS,gBAAgB,IAEvB;EACH,MAAM;EACN,QAAQ;EACR,OAAO;CACX,IAEA,EAAK,WAAW,QAAQ,IACjB;EAAE,MAAM;EAAsB,QAAQ;EAAW,OAAO;CAAQ,IAEvE,EAAK,WAAW,QAAQ,IACjB;EAAE,MAAM;EAAsB,QAAQ;EAAW,OAAO;CAAQ,IAGvE,MAAS,qBACT,MAAS,kCACT,MAAS,gCAEF;EAAE,MAAM;EAAoB,QAAQ;EAAW,OAAO;CAAU,IAEvE,EAAK,WAAW,OAAO,IAChB;EAAE,MAAM;EAAqB,QAAQ;EAAW,OAAO;CAAO,IAElE;EAAE,MAAM;EAAgB,QAAQ;EAAW,OAAO;CAAO;AACpE,GAGa,KAAmB,MAC5B,EAAgB,CAAQ,CAAC,CAAC,MCv2BjB,KAAiB,MAAyB;CACnD,IAAK,GAGL,OAAO,EACF,QAAQ,oBAAoB,EAAE,CAAC,CAC/B,QAAQ,wBAAwB,IAAI,CAAC,CACrC,QAAQ,sBAAsB,EAAE,CAAC,CACjC,QAAQ,aAAa,EAAE,CAAC,CACxB,QAAQ,4BAA4B,IAAI,CAAC,CACzC,QAAQ,cAAc,IAAI,CAAC,CAC3B,QAAQ,mBAAmB,EAAE,CAAC,CAC9B,QAAQ,QAAQ,GAAG,CAAC,CACpB,KAAK;AACd"}
@@ -18,7 +18,14 @@ function r(e) {
18
18
  function i(e) {
19
19
  return n(e) ? e.slice(0, -1) : e;
20
20
  }
21
+ function a(e) {
22
+ if (e) try {
23
+ return new URL(e).origin;
24
+ } catch {
25
+ return;
26
+ }
27
+ }
21
28
  //#endregion
22
- export { r as n, i as r, t };
29
+ export { a as i, r as n, i as r, t };
23
30
 
24
- //# sourceMappingURL=url-validation-uLMZ5-AU.js.map
31
+ //# sourceMappingURL=url-validation-9DstIfq2.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"url-validation-uLMZ5-AU.js","names":[],"sources":["../../../../packages/utils/src/url-validation.ts"],"sourcesContent":["/**\n * Check if URL points to an HTML page based on extension and content-type\n * @param url - The URL to check\n * @param contentType - Optional content-type header from response\n * @returns true if URL appears to be HTML, false otherwise\n */\nexport function isHtmlUrl(url: string, contentType?: string): boolean {\n // Check content-type if available\n if (contentType) {\n return contentType.includes('text/html')\n }\n\n // Check URL extension\n let urlObj: URL\n try {\n urlObj = new URL(url)\n } catch {\n return false\n }\n const pathname = urlObj.pathname.toLowerCase()\n\n // Exclude common non-HTML extensions\n const nonHtmlExtensions = [\n '.pdf',\n '.doc',\n '.docx',\n '.xls',\n '.xlsx',\n '.ppt',\n '.pptx',\n '.zip',\n '.rar',\n '.tar',\n '.gz',\n '.jpg',\n '.jpeg',\n '.png',\n '.gif',\n '.svg',\n '.webp',\n '.mp4',\n '.avi',\n '.mov',\n '.mp3',\n '.wav',\n '.css',\n '.js',\n '.json',\n '.xml',\n '.txt',\n ]\n\n return !nonHtmlExtensions.some((ext) => pathname.endsWith(ext))\n}\n\n/**\n * Checks if a URL has an initial slash\n * @param url - The URL string to check\n * @returns true if URL has an initial slash, false otherwise\n */\nexport function hasInitialSlash(url: string): boolean {\n return url.startsWith('/')\n}\n\n/**\n * Adds an initial slash to a URL if it doesn't already have one\n * @param url - The URL string to modify\n * @returns The URL string with an initial slash\n */\nexport function addInitialSlash(url: string): string {\n return hasInitialSlash(url) ? url : `/${url}`\n}\n\n/**\n * Checks if a URL has a trailing slash\n * @param url - The URL string to check\n * @returns true if URL has a trailing slash, false otherwise\n */\nexport function hasTrailingSlash(url: string): boolean {\n return url.endsWith('/')\n}\n\n/**\n * Checks whether a URL belongs to the same site as the current page.\n * Relative URLs and malformed URLs are treated as same-site.\n * Comparison is based on hostname only, so http and https variants of\n * the same domain are considered the same site.\n * @param url - The URL to check\n * @returns true if the URL is same-site or relative/malformed, false otherwise\n */\nexport function isSameSite(url: string): boolean {\n try {\n const target = new URL(url, window.location.origin)\n return target.hostname === window.location.hostname\n } catch {\n return true\n }\n}\n\n/**\n * Removes the trailing slash from a URL if it exists\n * @param url - The URL string to modify\n * @returns The URL string without a trailing slash\n */\nexport function removeTrailingSlash(url: string): string {\n return hasTrailingSlash(url) ? url.slice(0, -1) : url\n}\n\n/**\n * The origin a URL points to (scheme, host and port), or `undefined` when it\n * does not parse. An API tool's secret parameters are sent only to the origin\n * they were typed for: backend and panel compare with this.\n */\nexport function urlOrigin(url: string | undefined): string | undefined {\n if (!url) {\n return undefined\n }\n try {\n return new URL(url).origin\n } catch {\n return undefined\n }\n}\n"],"mappings":";AA4DA,SAAgB,EAAgB,GAAsB;CAClD,OAAO,EAAI,WAAW,GAAG;AAC7B;AAOA,SAAgB,EAAgB,GAAqB;CACjD,OAAO,EAAgB,CAAG,IAAI,IAAM,IAAI;AAC5C;AAOA,SAAgB,EAAiB,GAAsB;CACnD,OAAO,EAAI,SAAS,GAAG;AAC3B;AAUA,SAAgB,EAAW,GAAsB;CAC7C,IAAI;EAEA,OAAO,IADY,IAAI,GAAK,OAAO,SAAS,MACrC,CAAA,CAAO,aAAa,OAAO,SAAS;CAC/C,QAAQ;EACJ,OAAO;CACX;AACJ;AAOA,SAAgB,EAAoB,GAAqB;CACrD,OAAO,EAAiB,CAAG,IAAI,EAAI,MAAM,GAAG,EAAE,IAAI;AACtD"}
1
+ {"version":3,"file":"url-validation-9DstIfq2.js","names":[],"sources":["../../../../packages/utils/src/url-validation.ts"],"sourcesContent":["/**\n * Check if URL points to an HTML page based on extension and content-type\n * @param url - The URL to check\n * @param contentType - Optional content-type header from response\n * @returns true if URL appears to be HTML, false otherwise\n */\nexport function isHtmlUrl(url: string, contentType?: string): boolean {\n // Check content-type if available\n if (contentType) {\n return contentType.includes('text/html')\n }\n\n // Check URL extension\n let urlObj: URL\n try {\n urlObj = new URL(url)\n } catch {\n return false\n }\n const pathname = urlObj.pathname.toLowerCase()\n\n // Exclude common non-HTML extensions\n const nonHtmlExtensions = [\n '.pdf',\n '.doc',\n '.docx',\n '.xls',\n '.xlsx',\n '.ppt',\n '.pptx',\n '.zip',\n '.rar',\n '.tar',\n '.gz',\n '.jpg',\n '.jpeg',\n '.png',\n '.gif',\n '.svg',\n '.webp',\n '.mp4',\n '.avi',\n '.mov',\n '.mp3',\n '.wav',\n '.css',\n '.js',\n '.json',\n '.xml',\n '.txt',\n ]\n\n return !nonHtmlExtensions.some((ext) => pathname.endsWith(ext))\n}\n\n/**\n * Checks if a URL has an initial slash\n * @param url - The URL string to check\n * @returns true if URL has an initial slash, false otherwise\n */\nexport function hasInitialSlash(url: string): boolean {\n return url.startsWith('/')\n}\n\n/**\n * Adds an initial slash to a URL if it doesn't already have one\n * @param url - The URL string to modify\n * @returns The URL string with an initial slash\n */\nexport function addInitialSlash(url: string): string {\n return hasInitialSlash(url) ? url : `/${url}`\n}\n\n/**\n * Checks if a URL has a trailing slash\n * @param url - The URL string to check\n * @returns true if URL has a trailing slash, false otherwise\n */\nexport function hasTrailingSlash(url: string): boolean {\n return url.endsWith('/')\n}\n\n/**\n * Checks whether a URL belongs to the same site as the current page.\n * Relative URLs and malformed URLs are treated as same-site.\n * Comparison is based on hostname only, so http and https variants of\n * the same domain are considered the same site.\n * @param url - The URL to check\n * @returns true if the URL is same-site or relative/malformed, false otherwise\n */\nexport function isSameSite(url: string): boolean {\n try {\n const target = new URL(url, window.location.origin)\n return target.hostname === window.location.hostname\n } catch {\n return true\n }\n}\n\n/**\n * Removes the trailing slash from a URL if it exists\n * @param url - The URL string to modify\n * @returns The URL string without a trailing slash\n */\nexport function removeTrailingSlash(url: string): string {\n return hasTrailingSlash(url) ? url.slice(0, -1) : url\n}\n\n/**\n * The origin a URL points to (scheme, host and port), or `undefined` when it\n * does not parse. An API tool's secret parameters are sent only to the origin\n * they were typed for: backend and panel compare with this.\n */\nexport function urlOrigin(url: string | undefined): string | undefined {\n if (!url) {\n return undefined\n }\n try {\n return new URL(url).origin\n } catch {\n return undefined\n }\n}\n"],"mappings":";AA4DA,SAAgB,EAAgB,GAAsB;CAClD,OAAO,EAAI,WAAW,GAAG;AAC7B;AAOA,SAAgB,EAAgB,GAAqB;CACjD,OAAO,EAAgB,CAAG,IAAI,IAAM,IAAI;AAC5C;AAOA,SAAgB,EAAiB,GAAsB;CACnD,OAAO,EAAI,SAAS,GAAG;AAC3B;AAUA,SAAgB,EAAW,GAAsB;CAC7C,IAAI;EAEA,OAAO,IADY,IAAI,GAAK,OAAO,SAAS,MACrC,CAAA,CAAO,aAAa,OAAO,SAAS;CAC/C,QAAQ;EACJ,OAAO;CACX;AACJ;AAOA,SAAgB,EAAoB,GAAqB;CACrD,OAAO,EAAiB,CAAG,IAAI,EAAI,MAAM,GAAG,EAAE,IAAI;AACtD;AAOA,SAAgB,EAAU,GAA6C;CACnE,IAAK,GAGL,IAAI;EACA,OAAO,IAAI,IAAI,CAAG,CAAC,CAAC;CACxB,QAAQ;EACJ;CACJ;AACJ"}
@@ -3,12 +3,12 @@ import { S as e, T as t, a as n, b as r, c as i, d as a, f as o, g as s, h as c,
3
3
  import { $ as S, B as ee, C, Ct as te, D as w, E as T, F as ne, G as E, H as re, I as ie, J as ae, K as oe, L as D, M as O, N as se, O as k, P as A, R as j, S as M, St as N, T as ce, Tt as P, X as F, Z as le, _ as I, _t as ue, b as L, bt as R, c as de, ct as z, d as B, dt as fe, et as pe, g as V, gt as me, h as H, ht as he, it as U, j as ge, k as _e, l as ve, lt as ye, m as W, n as be, nt as xe, ot as Se, pt as G, q as Ce, r as we, rt as Te, st as Ee, t as K, u as De, ut as Oe, v as q, vt as ke, w as Ae, wt as je, x as J, xt as Y, y as Me, yt as X, z as Ne } from "./_chunks/vue.runtime.esm-bundler-CIT_Sbqw.js";
4
4
  import { n as Pe, r as Fe, t as Ie } from "./_chunks/vue-i18n-BdMHu4Kd.js";
5
5
  import { i as Le, n as Re, r as ze } from "./_chunks/iconify-CN8mivJ9.js";
6
- import { C as Be, D as Ve, E as He, O as Ue, S as We, T as Ge, _ as Ke, a as qe, b as Je, d as Ye, f as Xe, g as Ze, h as Qe, i as $e, k as et, l as tt, m as nt, n as rt, o as it, p as at, r as ot, t as st, u as ct, v as lt, w as ut, x as dt, y as ft } from "./_chunks/PkStreamingMarkdown-BKxA6Ntl.js";
6
+ import { C as Be, D as Ve, E as He, O as Ue, S as We, T as Ge, _ as Ke, a as qe, b as Je, d as Ye, f as Xe, g as Ze, h as Qe, i as $e, k as et, l as tt, m as nt, n as rt, o as it, p as at, r as ot, t as st, u as ct, v as lt, w as ut, x as dt, y as ft } from "./_chunks/PkStreamingMarkdown-B7SRIqnV.js";
7
7
  import { a as pt, d as mt, f as ht, h as gt, i as _t, l as vt, n as yt, o as bt, p as xt, r as St, s as Ct, t as wt, u as Tt } from "./_chunks/Agent-DK76k05_.js";
8
- import { a as Et, i as Dt, n as Ot, t as kt } from "./_chunks/markdown-BAq2EAVh.js";
8
+ import { a as Et, i as Dt, n as Ot, t as kt } from "./_chunks/markdown-tS_2A0k9.js";
9
9
  import { t as At } from "./_chunks/src-BQHP1-Xs.js";
10
10
  import { t as jt } from "./_chunks/text-DbSEK8si.js";
11
- import { r as Mt, t as Nt } from "./_chunks/url-validation-uLMZ5-AU.js";
11
+ import { r as Mt, t as Nt } from "./_chunks/url-validation-9DstIfq2.js";
12
12
  import { a as Pt, m as Ft, p as It, s as Lt } from "./_chunks/dist-QdjZA6MJ.js";
13
13
  import { a as Rt, d as zt, f as Bt, i as Vt, l as Ht, m as Ut, r as Wt, t as Gt, u as Kt } from "./_chunks/index.es-C2U5wcOx.js";
14
14
  import { n as qt, r as Jt, t as Yt } from "./_chunks/index.es-CvfaFCuJ.js";
@@ -897,6 +897,8 @@ var Pn = {
897
897
  documentTrash: {
898
898
  columnDeletedAt: "Eliminato il",
899
899
  columnDeletedBy: "Eliminato da",
900
+ columnPurgedIn: "Eliminazione tra",
901
+ daysLeft: "Alla prossima pulizia | {count} giorno | {count} giorni",
900
902
  empty: "Il cestino è vuoto.",
901
903
  emptyConsequence: "I file originali e i testi estratti vengono distrutti: non sarà più possibile ripristinarli né scaricarli. Un documento condiviso con altri agenti sparisce anche dal loro cestino.",
902
904
  emptyQuestion: "Il documento nel cestino viene eliminato definitivamente. | I {count} documenti nel cestino vengono eliminati definitivamente.",
@@ -904,6 +906,7 @@ var Pn = {
904
906
  emptyTitle: "Svuotare il cestino?",
905
907
  emptyTrash: "Svuota cestino",
906
908
  intro: "L'agente non cerca più nei documenti del cestino. Puoi ripristinarli o eliminarli definitivamente.",
909
+ introRetention: "Ogni documento resta qui {count} giorno, poi viene eliminato definitivamente. | Ogni documento resta qui {count} giorni, poi viene eliminato definitivamente.",
907
910
  openLiveDocument: "Apri il documento che lo sostituisce",
908
911
  purge: "Elimina definitivamente",
909
912
  purgeConsequence: "Il file originale e il testo estratto vengono distrutti: non sarà più possibile ripristinarlo né scaricarlo.",
@@ -1030,6 +1033,7 @@ var Pn = {
1030
1033
  defaultDays: "Predefinito: {count} giorno. | Predefinito: {count} giorni.",
1031
1034
  defaultDisabled: "Predefinito: disattivato.",
1032
1035
  legend: "Conservazione dei dati (GDPR)",
1036
+ trashLabel: "Svuotamento del cestino",
1033
1037
  unitDays: "giorni"
1034
1038
  },
1035
1039
  help: {
@@ -2275,6 +2279,8 @@ var Pn = {
2275
2279
  documentTrash: {
2276
2280
  columnDeletedAt: "Deleted on",
2277
2281
  columnDeletedBy: "Deleted by",
2282
+ columnPurgedIn: "Deleted for good in",
2283
+ daysLeft: "At the next cleanup | {count} day | {count} days",
2278
2284
  empty: "The trash is empty.",
2279
2285
  emptyConsequence: "The original files and the extracted text are destroyed: they can no longer be restored or downloaded. A document shared with other agents leaves their trash too.",
2280
2286
  emptyQuestion: "The document in the trash is deleted permanently. | The {count} documents in the trash are deleted permanently.",
@@ -2282,6 +2288,7 @@ var Pn = {
2282
2288
  emptyTitle: "Empty the trash?",
2283
2289
  emptyTrash: "Empty trash",
2284
2290
  intro: "The agent no longer searches the documents in the trash. You can restore them or delete them permanently.",
2291
+ introRetention: "Each document stays here for {count} day, then it is deleted for good. | Each document stays here for {count} days, then it is deleted for good.",
2285
2292
  openLiveDocument: "Open the document in its place",
2286
2293
  purge: "Delete permanently",
2287
2294
  purgeConsequence: "The original file and the extracted text are destroyed: it can no longer be restored or downloaded.",
@@ -2408,6 +2415,7 @@ var Pn = {
2408
2415
  defaultDays: "Default: {count} day. | Default: {count} days.",
2409
2416
  defaultDisabled: "Default: disabled.",
2410
2417
  legend: "Data retention (GDPR)",
2418
+ trashLabel: "Trash emptying",
2411
2419
  unitDays: "days"
2412
2420
  },
2413
2421
  help: {
@@ -11445,25 +11453,25 @@ var Hp = ["datetime"], Up = 6e4, Wp = /* @__PURE__ */ C({
11445
11453
  //#region ../../packages/components/src/chat/toolComponentMap.ts
11446
11454
  k();
11447
11455
  var Gp = {
11448
- requestOAuthConnection: M(() => import("./_chunks/PkToolRequestOAuthConnection-CgQePKKb.js")),
11449
- showArtifact: M(() => import("./_chunks/PkToolShowArtifact-CHxeuKEU.js")),
11450
- showCalendarEvent: M(() => import("./_chunks/PkToolShowCalendarEvent-D0jVbqWt.js")),
11456
+ requestOAuthConnection: M(() => import("./_chunks/PkToolRequestOAuthConnection-CbZn1f14.js")),
11457
+ showArtifact: M(() => import("./_chunks/PkToolShowArtifact-CRQySuGC.js")),
11458
+ showCalendarEvent: M(() => import("./_chunks/PkToolShowCalendarEvent-Cj7yRj-0.js")),
11451
11459
  showComparison: M(() => import("./_chunks/PkToolShowComparison-8d6fAhRp.js")),
11452
- showContactForm: M(() => import("./_chunks/PkToolShowContactForm-DqVLVwqJ.js")),
11460
+ showContactForm: M(() => import("./_chunks/PkToolShowContactForm-DGmzPa3d.js")),
11453
11461
  showDiagram: M(() => import("./_chunks/PkToolShowDiagram-CWsqmvB2.js")),
11454
11462
  showEmail: M(() => import("./_chunks/PkToolShowEmail-CTgtiwbx.js")),
11455
- showImageGallery: M(() => import("./_chunks/PkToolShowImageGallery-1mq-_cnp.js")),
11463
+ showImageGallery: M(() => import("./_chunks/PkToolShowImageGallery-BmpcrdIL.js")),
11456
11464
  showLocation: M(() => import("./_chunks/PkToolShowLocation-D72rWN1o.js")),
11457
11465
  showMessage: M(() => import("./_chunks/PkToolShowMessage-Dy6LJKyD.js")),
11458
- showForm: M(() => import("./_chunks/PkToolShowForm-YJQPYfEe.js")),
11459
- showMultipleChoice: M(() => import("./_chunks/PkToolShowForm-YJQPYfEe.js")),
11466
+ showForm: M(() => import("./_chunks/PkToolShowForm-76LQdZHH.js")),
11467
+ showMultipleChoice: M(() => import("./_chunks/PkToolShowForm-76LQdZHH.js")),
11460
11468
  showProductList: M(() => import("./_chunks/PkToolShowProductList-BpCZ1x86.js")),
11461
11469
  showQrCode: M(() => import("./_chunks/PkToolShowQrCode-BF7J2tXo.js")),
11462
- showSources: M(() => import("./_chunks/PkToolShowSources-ClqmBUMB.js")),
11470
+ showSources: M(() => import("./_chunks/PkToolShowSources-13IBQve7.js")),
11463
11471
  showSuggestedReply: M(() => import("./_chunks/PkToolShowSuggestedReply-Dl4x_nEJ.js")),
11464
11472
  showVideo: M(() => import("./_chunks/PkToolShowVideo-p6Y9j3-B.js")),
11465
11473
  showWeather: M(() => import("./_chunks/PkToolShowWeather-B9QOh9HH.js")),
11466
- showWebPages: M(() => import("./_chunks/PkToolShowWebPages-BgXlRdmH.js"))
11474
+ showWebPages: M(() => import("./_chunks/PkToolShowWebPages-CCSRAlz5.js"))
11467
11475
  };
11468
11476
  k(), Y();
11469
11477
  var Kp = {
@@ -13492,7 +13500,7 @@ var rg = { class: "pk-chatbot-view-chat__input-stage" }, ig = {
13492
13500
  },
13493
13501
  emits: ["show-info", "revise"],
13494
13502
  setup(e, { emit: t }) {
13495
- let n = M(() => import("./_chunks/PkToolShowForm-YJQPYfEe.js")), r = M(() => import("./_chunks/PkToolShowContactForm-DqVLVwqJ.js")), i = M(() => import("./_chunks/PkToolShowSuggestedReply-Dl4x_nEJ.js")), a = M(() => import("./_chunks/PkToolShowSources-ClqmBUMB.js")), o = M(() => import("./_chunks/PkToolRequestGeolocation-OF1PWhMw.js")), s = M(() => import("./_chunks/PkToolRequestOAuthConnection-CgQePKKb.js")), c = M(() => import("./_chunks/PkToolShowLocation-D72rWN1o.js")), l = M(() => import("./_chunks/PkToolShowDiagram-CWsqmvB2.js")), u = e, d = t, f = Ju(u.agentId), { agentInterface: p, agentFileUpload: m, agentVoice: h, actions: g, revisedAnswers: _, messages: v, chat: y, messageFeedbacks: b, feedbackDialogMessage: x, isFeedbackSubmitting: ee, isFeedbackSubmitted: C, feedbackSubmitError: te, isLeadSubmitted: w, isLoadingSubmitLead: T, submitLeadError: ne, input: E, inputMessagePlaceholder: re, isConversationBlocked: ie, baseUrl: oe, pendingAttachments: O, isAttachmentLimitReached: se, fileLimitError: k, apiClient: j, isDark: ce } = Nn(f), { handleSubmit: le, stopGeneration: ue, regenerate: L, onUpvote: de, onDownvote: B, onFeedback: fe, onFeedbackSubmit: pe, onLeadSubmit: me, startNewChat: he, addToolOutput: U, addToolApprovalResponse: ge, handleFileSelect: _e, clearFileLimitError: ve, refreshMessages: ye, appendMessage: be } = f, { t: xe } = Fe({ useScope: "global" }), Se = W(() => {
13503
+ let n = M(() => import("./_chunks/PkToolShowForm-76LQdZHH.js")), r = M(() => import("./_chunks/PkToolShowContactForm-DGmzPa3d.js")), i = M(() => import("./_chunks/PkToolShowSuggestedReply-Dl4x_nEJ.js")), a = M(() => import("./_chunks/PkToolShowSources-13IBQve7.js")), o = M(() => import("./_chunks/PkToolRequestGeolocation-OF1PWhMw.js")), s = M(() => import("./_chunks/PkToolRequestOAuthConnection-CbZn1f14.js")), c = M(() => import("./_chunks/PkToolShowLocation-D72rWN1o.js")), l = M(() => import("./_chunks/PkToolShowDiagram-CWsqmvB2.js")), u = e, d = t, f = Ju(u.agentId), { agentInterface: p, agentFileUpload: m, agentVoice: h, actions: g, revisedAnswers: _, messages: v, chat: y, messageFeedbacks: b, feedbackDialogMessage: x, isFeedbackSubmitting: ee, isFeedbackSubmitted: C, feedbackSubmitError: te, isLeadSubmitted: w, isLoadingSubmitLead: T, submitLeadError: ne, input: E, inputMessagePlaceholder: re, isConversationBlocked: ie, baseUrl: oe, pendingAttachments: O, isAttachmentLimitReached: se, fileLimitError: k, apiClient: j, isDark: ce } = Nn(f), { handleSubmit: le, stopGeneration: ue, regenerate: L, onUpvote: de, onDownvote: B, onFeedback: fe, onFeedbackSubmit: pe, onLeadSubmit: me, startNewChat: he, addToolOutput: U, addToolApprovalResponse: ge, handleFileSelect: _e, clearFileLimitError: ve, refreshMessages: ye, appendMessage: be } = f, { t: xe } = Fe({ useScope: "global" }), Se = W(() => {
13496
13504
  let e = k.value;
13497
13505
  if (e) return e.reason === "per-chat" ? xe("message.fileLimitPerChat", { max: e.max }) : xe("message.fileLimitPerMessage", { max: e.max });
13498
13506
  }), Ce = qt(() => p.value?.dismissableNotice), we = W(() => v.value.some((e) => e.role === "user")), Te = W(() => u.modifier === "fullscreen" && !we.value), Ee = od(p, () => u.userName), De = ae("chatViewEl"), Oe = async (e) => (await j.value.expandSourceContext(u.agentId, e.documentId, e.chunkIndex)).content, ke = async (e) => {
@@ -13732,11 +13740,13 @@ var rg = { class: "pk-chatbot-view-chat__input-stage" }, ig = {
13732
13740
  }, 1024)]),
13733
13741
  "tool-requestOAuthConnection": S(({ part: e }) => [J(R(s), {
13734
13742
  part: e,
13743
+ "backend-url": R(oe),
13735
13744
  "resolve-connection": (e) => R(j).getOAuthAuthorizeUrl(u.agentId, e),
13736
13745
  "check-connection": (e) => R(j).getOAuthConnectionStatus(u.agentId, e),
13737
13746
  onConnected: (t) => dt(e, t)
13738
13747
  }, null, 8, [
13739
13748
  "part",
13749
+ "backend-url",
13740
13750
  "resolve-connection",
13741
13751
  "check-connection",
13742
13752
  "onConnected"