@8wave/ai-elements 0.68.0 → 0.69.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/_chunks/{PkStreamingMarkdown-D3MJ5dfu.js → PkStreamingMarkdown-C0BpOvli.js} +2 -2
  2. package/dist/_chunks/{PkStreamingMarkdown-D3MJ5dfu.js.map → PkStreamingMarkdown-C0BpOvli.js.map} +1 -1
  3. package/dist/_chunks/{PkToolShowArtifact-BFe_MhNr.js → PkToolShowArtifact-DzNIkKvZ.js} +3 -3
  4. package/dist/_chunks/{PkToolShowArtifact-BFe_MhNr.js.map → PkToolShowArtifact-DzNIkKvZ.js.map} +1 -1
  5. package/dist/_chunks/{PkToolShowLocation-DN57lKN1.js → PkToolShowLocation-BsBiA4jV.js} +2 -2
  6. package/dist/_chunks/{PkToolShowLocation-DN57lKN1.js.map → PkToolShowLocation-BsBiA4jV.js.map} +1 -1
  7. package/dist/_chunks/src-BRYn66N3.js.map +1 -1
  8. package/dist/_chunks/{vue-leaflet.es-7LObg4WN.js → vue-leaflet.es-BT-uRmMx.js} +5 -5
  9. package/dist/_chunks/{vue-leaflet.es-7LObg4WN.js.map → vue-leaflet.es-BT-uRmMx.js.map} +1 -1
  10. package/dist/ai-elements.es.js +293 -299
  11. package/dist/ai-elements.es.js.map +1 -1
  12. package/dist-vue/PkChatbot.js +1 -1
  13. package/dist-vue/PkChatbotMessages.js +1 -1
  14. package/dist-vue/PkChatbotViewChat.js +1 -1
  15. package/dist-vue/PkChatbotViewConversations.js +1 -1
  16. package/dist-vue/PkChatbotViewProfile.js +1 -1
  17. package/dist-vue/_chunks/{PkChatbot-C_ASB2zq.js → PkChatbot-Cy7p5UI_.js} +5 -5
  18. package/dist-vue/_chunks/{PkChatbot-C_ASB2zq.js.map → PkChatbot-Cy7p5UI_.js.map} +1 -1
  19. package/dist-vue/_chunks/{PkChatbotMessages-CQdxH86L.js → PkChatbotMessages-C7-ZtU0-.js} +11 -11
  20. package/dist-vue/_chunks/{PkChatbotMessages-CQdxH86L.js.map → PkChatbotMessages-C7-ZtU0-.js.map} +1 -1
  21. package/dist-vue/_chunks/{PkChatbotViewChat-DHOeNxnR.js → PkChatbotViewChat-EWotdJkz.js} +3 -3
  22. package/dist-vue/_chunks/{PkChatbotViewChat-DHOeNxnR.js.map → PkChatbotViewChat-EWotdJkz.js.map} +1 -1
  23. package/dist-vue/_chunks/{PkChatbotViewConversations-DFv_8-8K.js → PkChatbotViewConversations-Ct0TbDrg.js} +2 -2
  24. package/dist-vue/_chunks/{PkChatbotViewConversations-DFv_8-8K.js.map → PkChatbotViewConversations-Ct0TbDrg.js.map} +1 -1
  25. package/dist-vue/_chunks/{PkChatbotViewProfile-BUj0YnIi.js → PkChatbotViewProfile-BhdCxVSX.js} +2 -2
  26. package/dist-vue/_chunks/{PkChatbotViewProfile-BUj0YnIi.js.map → PkChatbotViewProfile-BhdCxVSX.js.map} +1 -1
  27. package/dist-vue/_chunks/{PkToolShowArtifact-DIw-_JPA.js → PkToolShowArtifact-pTS7wzhw.js} +2 -2
  28. package/dist-vue/_chunks/{PkToolShowArtifact-DIw-_JPA.js.map → PkToolShowArtifact-pTS7wzhw.js.map} +1 -1
  29. package/dist-vue/_chunks/{PkToolShowCalendarEvent-ZZM8p7wu.js → PkToolShowCalendarEvent-DQ--fzwb.js} +2 -2
  30. package/dist-vue/_chunks/{PkToolShowCalendarEvent-ZZM8p7wu.js.map → PkToolShowCalendarEvent-DQ--fzwb.js.map} +1 -1
  31. package/dist-vue/_chunks/{PkToolShowComparison-7akNsf1w.js → PkToolShowComparison-CzRUrjbP.js} +2 -2
  32. package/dist-vue/_chunks/{PkToolShowComparison-7akNsf1w.js.map → PkToolShowComparison-CzRUrjbP.js.map} +1 -1
  33. package/dist-vue/_chunks/{PkToolShowEmail-CpiAbmr0.js → PkToolShowEmail-htn0ivwY.js} +2 -2
  34. package/dist-vue/_chunks/{PkToolShowEmail-CpiAbmr0.js.map → PkToolShowEmail-htn0ivwY.js.map} +1 -1
  35. package/dist-vue/_chunks/{PkToolShowImageGallery-jY7iYqTv.js → PkToolShowImageGallery-CpU183SC.js} +2 -2
  36. package/dist-vue/_chunks/{PkToolShowImageGallery-jY7iYqTv.js.map → PkToolShowImageGallery-CpU183SC.js.map} +1 -1
  37. package/dist-vue/_chunks/{PkToolShowLocation-BeOkj0Q2.js → PkToolShowLocation-DSZvW68g.js} +2 -2
  38. package/dist-vue/_chunks/{PkToolShowLocation-BeOkj0Q2.js.map → PkToolShowLocation-DSZvW68g.js.map} +1 -1
  39. package/dist-vue/_chunks/{PkToolShowMessage-AS8VNcYP.js → PkToolShowMessage-DtGDm3pq.js} +2 -2
  40. package/dist-vue/_chunks/{PkToolShowMessage-AS8VNcYP.js.map → PkToolShowMessage-DtGDm3pq.js.map} +1 -1
  41. package/dist-vue/_chunks/{PkToolShowProductList-FEq8sFxW.js → PkToolShowProductList-BlkUdbtV.js} +2 -2
  42. package/dist-vue/_chunks/{PkToolShowProductList-FEq8sFxW.js.map → PkToolShowProductList-BlkUdbtV.js.map} +1 -1
  43. package/dist-vue/_chunks/{PkToolShowQrCode-DAt8tBHK.js → PkToolShowQrCode-BUyhM_MN.js} +2 -2
  44. package/dist-vue/_chunks/{PkToolShowQrCode-DAt8tBHK.js.map → PkToolShowQrCode-BUyhM_MN.js.map} +1 -1
  45. package/dist-vue/_chunks/{PkToolShowWebPages-jA5eZRdi.js → PkToolShowWebPages-BQp9A4vb.js} +2 -2
  46. package/dist-vue/_chunks/{PkToolShowWebPages-jA5eZRdi.js.map → PkToolShowWebPages-BQp9A4vb.js.map} +1 -1
  47. package/dist-vue/_chunks/{dist-C-yeiSHm.js → dist-BHuX2VvC.js} +2 -2
  48. package/dist-vue/_chunks/{dist-C-yeiSHm.js.map → dist-BHuX2VvC.js.map} +1 -1
  49. package/dist-vue/_chunks/{dist-D2-23M8l.js → dist-BWXfA4NS.js} +4 -4
  50. package/dist-vue/_chunks/{dist-D2-23M8l.js.map → dist-BWXfA4NS.js.map} +1 -1
  51. package/dist-vue/_chunks/{dist-DJ_vDk0q.js → dist-CAXUIcdd.js} +3 -3
  52. package/dist-vue/_chunks/{dist-DJ_vDk0q.js.map → dist-CAXUIcdd.js.map} +1 -1
  53. package/dist-vue/_chunks/{dist-C38fHUMa.js → dist-D-VT7gvP.js} +2 -2
  54. package/dist-vue/_chunks/{dist-C38fHUMa.js.map → dist-D-VT7gvP.js.map} +1 -1
  55. package/dist-vue/_chunks/{dist-BrsWoii-.js → dist-DEe8jwtO.js} +2 -2
  56. package/dist-vue/_chunks/{dist-BrsWoii-.js.map → dist-DEe8jwtO.js.map} +1 -1
  57. package/dist-vue/_chunks/{dist-BmqFgHbN.js → dist-DV82RztV.js} +2 -2
  58. package/dist-vue/_chunks/{dist-BmqFgHbN.js.map → dist-DV82RztV.js.map} +1 -1
  59. package/dist-vue/_chunks/{dist-ByzpJpuj.js → dist-DVM_p-M1.js} +3 -3
  60. package/dist-vue/_chunks/{dist-ByzpJpuj.js.map → dist-DVM_p-M1.js.map} +1 -1
  61. package/dist-vue/_chunks/{dist-D3coexrW.js → dist-DfEAZDKB.js} +2 -2
  62. package/dist-vue/_chunks/{dist-D3coexrW.js.map → dist-DfEAZDKB.js.map} +1 -1
  63. package/dist-vue/_chunks/{dist-veLX58Me.js → dist-QbFF3eM_.js} +2 -2
  64. package/dist-vue/_chunks/{dist-veLX58Me.js.map → dist-QbFF3eM_.js.map} +1 -1
  65. package/dist-vue/_chunks/{dist-B65AhbTK.js → dist-bUGhZmKp.js} +3 -3
  66. package/dist-vue/_chunks/{dist-B65AhbTK.js.map → dist-bUGhZmKp.js.map} +1 -1
  67. package/dist-vue/_chunks/{dist-DmKzgdbO.js → dist-jVwgEJDw.js} +2 -2
  68. package/dist-vue/_chunks/{dist-DmKzgdbO.js.map → dist-jVwgEJDw.js.map} +1 -1
  69. package/dist-vue/_chunks/src-DjRNH9vV.js.map +1 -1
  70. package/dist-vue/_chunks/{useChatbotStore-B9BUWM4O.js → useChatbotStore-ys9uGP5v.js} +4 -10
  71. package/dist-vue/_chunks/{useChatbotStore-B9BUWM4O.js.map → useChatbotStore-ys9uGP5v.js.map} +1 -1
  72. package/dist-vue/composables.js +1 -1
  73. package/dist-vue/index.js +32 -32
  74. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PkChatbotViewChat-DHOeNxnR.js","names":["$t","$n","$t"],"sources":["../../../../packages/models/src/schema/Header.ts","../../../../packages/models/src/schema/Document.ts","../../../../packages/components/src/chat/PkToolShowMultipleChoice.vue","../../../../packages/components/src/chat/PkToolShowMultipleChoice.vue","../../../../packages/components/src/composables/useLocalizedString.ts","../../../../packages/components/src/chat/PkToolShowContactForm.vue","../../../../packages/components/src/chat/PkToolShowContactForm.vue","../../../../packages/components/src/chat/PkToolShowSuggestedReply.vue","../../../../packages/components/src/chat/PkToolShowSuggestedReply.vue","../../../../packages/components/src/chat/PkChunkPreview.vue","../../../../packages/components/src/chat/PkChunkPreview.vue","../../../../packages/components/src/chat/PkDocumentHeader.vue","../../../../packages/components/src/chat/PkDocumentHeader.vue","../../../../packages/components/src/chat/PkToolShowSources.vue","../../../../packages/components/src/chat/PkToolShowSources.vue","../../../../packages/components/src/chat/PkToolRequestGeolocation.vue","../../../../packages/components/src/chat/PkToolRequestGeolocation.vue","../../../../packages/components/src/chat/PkChatbotViewChat.vue","../../../../packages/components/src/chat/PkChatbotViewChat.vue"],"sourcesContent":["import * as z from 'zod'\n\nexport const HeaderSchema = z.object({\n key: z.string().optional(),\n value: z.string().optional(),\n})\n\nexport const HeadesSchema = z.array(HeaderSchema).transform((headers) => {\n return 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","import * as z from 'zod'\nimport { zodQs } 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.enum(BrowserEngine).optional(),\n headers: HeadesSchema.nullish(),\n})\n\nexport type ConversionOptions = z.infer<typeof ConversionOptionsSchema>\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 documents only) ===\n source: z\n .object({\n url: z.string(),\n lastScrapedAt: z.string(),\n })\n .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: z\n .union([z.number(), z.array(z.unknown())])\n .transform((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 // === 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})\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})\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']),\n ...zodQs.filters(['type', 'language', 'agentId', 'indexStatus']),\n ...zodQs.fullText(),\n ...zodQs.ids(),\n 'filter[similarity]': 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 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 })\n .superRefine((data, ctx) => {\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 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 agentIds: z.array(z.string()).min(1).optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\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>\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","<script setup lang=\"ts\">\n import { computed } from 'vue'\n\n type LegacyOption = { id: string; label: string; value: string }\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const emit = defineEmits<{\n select: [option: string]\n }>()\n\n const toolPart = computed(() => {\n return JSON.parse(JSON.stringify(props.part)) as {\n state?: string\n toolCallId?: string\n input?: {\n question: string\n options: string[] | LegacyOption[]\n }\n output?: string | LegacyOption\n }\n })\n\n /** Normalize options to string[] (supports legacy { label } objects) */\n const normalizedOptions = computed(() => {\n return (toolPart.value?.input?.options ?? []).map((o) =>\n typeof o === 'string' ? o : o.label,\n )\n })\n\n /** Normalize output to string (supports legacy { label } objects) */\n const normalizedOutput = computed(() => {\n const out = toolPart.value?.output\n if (!out) {\n return undefined\n }\n return typeof out === 'string' ? out : out.label\n })\n\n const toolState = computed(() => {\n return toolPart.value?.state || 'unknown'\n })\n\n const isInteractive = computed(() => {\n return toolState.value === 'input-available'\n })\n</script>\n\n<template>\n <div\n v-if=\"normalizedOptions.length\"\n :key=\"toolState\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-10 font-bold bg-surface-1 text-12 border-b border-surface-3 text-word-3\">\n {{ toolPart.input?.question }}\n </div>\n <div class=\"px-sm py-10\">\n <VvButtonGroup\n :key=\"normalizedOptions.length\"\n modifiers=\"vertical\"\n class=\"w-full\">\n <VvButton\n v-for=\"(option, index) in normalizedOptions\"\n :key=\"index\"\n modifiers=\"action-multiline\"\n class=\"whitespace-normal w-full\"\n :class=\"{\n pressed: option === normalizedOutput,\n }\"\n :disabled=\"!isInteractive\"\n :label=\"option\"\n @click.stop=\"emit('select', option)\" />\n </VvButtonGroup>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed } from 'vue'\n\n type LegacyOption = { id: string; label: string; value: string }\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const emit = defineEmits<{\n select: [option: string]\n }>()\n\n const toolPart = computed(() => {\n return JSON.parse(JSON.stringify(props.part)) as {\n state?: string\n toolCallId?: string\n input?: {\n question: string\n options: string[] | LegacyOption[]\n }\n output?: string | LegacyOption\n }\n })\n\n /** Normalize options to string[] (supports legacy { label } objects) */\n const normalizedOptions = computed(() => {\n return (toolPart.value?.input?.options ?? []).map((o) =>\n typeof o === 'string' ? o : o.label,\n )\n })\n\n /** Normalize output to string (supports legacy { label } objects) */\n const normalizedOutput = computed(() => {\n const out = toolPart.value?.output\n if (!out) {\n return undefined\n }\n return typeof out === 'string' ? out : out.label\n })\n\n const toolState = computed(() => {\n return toolPart.value?.state || 'unknown'\n })\n\n const isInteractive = computed(() => {\n return toolState.value === 'input-available'\n })\n</script>\n\n<template>\n <div\n v-if=\"normalizedOptions.length\"\n :key=\"toolState\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-10 font-bold bg-surface-1 text-12 border-b border-surface-3 text-word-3\">\n {{ toolPart.input?.question }}\n </div>\n <div class=\"px-sm py-10\">\n <VvButtonGroup\n :key=\"normalizedOptions.length\"\n modifiers=\"vertical\"\n class=\"w-full\">\n <VvButton\n v-for=\"(option, index) in normalizedOptions\"\n :key=\"index\"\n modifiers=\"action-multiline\"\n class=\"whitespace-normal w-full\"\n :class=\"{\n pressed: option === normalizedOutput,\n }\"\n :disabled=\"!isInteractive\"\n :label=\"option\"\n @click.stop=\"emit('select', option)\" />\n </VvButtonGroup>\n </div>\n </div>\n</template>\n","import { computed, toValue, type ComputedRef, type MaybeRefOrGetter } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport type { LocalizedString } from 'models'\n\nexport function useLocalizedString(\n value: MaybeRefOrGetter<LocalizedString | undefined>,\n fallbackKey: string,\n): ComputedRef<string>\nexport function useLocalizedString(\n value: MaybeRefOrGetter<LocalizedString | undefined>,\n): ComputedRef<string | undefined>\nexport function useLocalizedString(\n value: MaybeRefOrGetter<LocalizedString | undefined>,\n fallbackKey?: string,\n): ComputedRef<string | undefined> {\n const { locale, t, te } = useI18n({ useScope: 'global' })\n\n return computed(() => {\n const val = toValue(value)\n const fb =\n fallbackKey !== undefined && te(fallbackKey)\n ? t(fallbackKey)\n : undefined\n\n if (!val) {\n return fb\n }\n\n return val[locale.value] || fb\n })\n}\n","<script setup lang=\"ts\">\n import { computed, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { useForm } from '@volverjs/form-vue'\n import * as z from 'zod'\n import { useLocalStorage } from '@vueuse/core'\n import type { LocalizedString } from 'models'\n import { useLocalizedString } from '../composables/useLocalizedString'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const props = defineProps<{\n part: unknown\n submitted?: boolean\n loading?: boolean\n error?: string\n readonly?: boolean\n privacyPolicyNotice?: LocalizedString\n }>()\n\n const toolPart = computed(() => {\n const part = props.part as {\n type: string\n toolCallId: string\n input?: {\n name: string\n email: string\n phone?: string\n conversationContext?: Record<string, unknown>\n }\n }\n return part\n })\n\n const input = computed(() => toolPart.value.input)\n\n const localSubmitted = useLocalStorage<boolean>(\n computed(\n () =>\n `${toolPart.value.toolCallId}-${toolPart.value.type}-submitted`,\n ),\n false,\n )\n\n const LeadFormSchema = z.object({\n name: z.string().min(1).max(255).default(''),\n email: z.email().max(255).default(''),\n phone: z\n .string()\n .max(50)\n .regex(/^[+0-9\\s\\-.()]*$/, $t('validation.invalidPhoneNumber'))\n .optional(),\n })\n\n const emit = defineEmits<{\n submit: [data: Record<string, unknown>]\n }>()\n\n const { VvForm, VvFormField, formData } = useForm(LeadFormSchema, {\n lazyLoad: true,\n })\n\n // Pre-populate form with input values\n watch(\n input,\n (newInput) => {\n formData.value = {\n name: newInput?.name || '',\n email: newInput?.email || '',\n phone: newInput?.phone || '',\n }\n },\n { immediate: true },\n )\n\n watch(\n () => props.submitted,\n (submitted) => {\n if (submitted) {\n localSubmitted.value = true\n }\n },\n { immediate: true },\n )\n\n const isSubmitted = computed(() => {\n return props.submitted || localSubmitted.value\n })\n\n const submitLead = async (data: Record<string, unknown>): Promise<void> => {\n emit('submit', { ...data, metadata: input.value?.conversationContext })\n }\n\n const privacyNotice = useLocalizedString(\n () => props.privacyPolicyNotice,\n 'message.defaultPrivacyPolicyNotice',\n )\n</script>\n\n<template>\n <div class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8 min-h-40\">\n <VvIcon name=\"ri:send-plane-2-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{ $t('label.contactUs') }}</strong>\n </div>\n\n <Transition mode=\"out-in\">\n <div v-if=\"!isSubmitted\" class=\"p-sm\">\n <VvForm v-model=\"formData\" :readonly @submit=\"submitLead\">\n <VvFormField\n name=\"name\"\n type=\"text\"\n :label=\"$t('label.name')\"\n :placeholder=\"$t('placeholder.name')\"\n icon=\"ri:user-line\"\n modifiers=\"compact no-label\"\n class=\"mb-md\" />\n <VvFormField\n name=\"email\"\n type=\"email\"\n :label=\"$t('label.email')\"\n :placeholder=\"$t('placeholder.email')\"\n icon=\"ri:mail-line\"\n modifiers=\"compact no-label\"\n class=\"mb-md\" />\n <VvFormField\n name=\"phone\"\n type=\"tel\"\n :label=\"$t('label.phone')\"\n :placeholder=\"$t('placeholder.phone')\"\n icon=\"ri:phone-line\"\n class=\"mb-md\"\n modifiers=\"compact no-label\" />\n\n <div class=\"flex justify-between items-center gap-16 mt-xs\">\n <div\n class=\"text-smaller text-word-3 flex items-center gap-8\">\n <VvIcon\n name=\"ri:shield-check-line\"\n class=\"text-16 shrink-0\" />\n <PkStreamingMarkdown\n :markdown=\"privacyNotice\"\n class=\"wysiwyg\" />\n </div>\n <VvButton\n type=\"submit\"\n modifiers=\"primary\"\n :loading\n :disabled=\"loading || readonly\"\n icon-position=\"right\"\n class=\"shrink-0\"\n :label=\"$t('action.submit')\" />\n </div>\n </VvForm>\n </div>\n <div v-else class=\"p-sm\">\n <div class=\"flex items-center gap-sm\">\n <VvIcon\n name=\"ri:mail-check-line\"\n class=\"text-24 text-success\" />\n <div>\n <strong class=\"font-semibold block text-success\">\n {{ $t('message.leadSubmittedTitle') }}\n </strong>\n <p class=\"text-word-3\">\n {{ $t('message.leadSubmittedMessage') }}\n </p>\n </div>\n </div>\n </div>\n </Transition>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { useForm } from '@volverjs/form-vue'\n import * as z from 'zod'\n import { useLocalStorage } from '@vueuse/core'\n import type { LocalizedString } from 'models'\n import { useLocalizedString } from '../composables/useLocalizedString'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const props = defineProps<{\n part: unknown\n submitted?: boolean\n loading?: boolean\n error?: string\n readonly?: boolean\n privacyPolicyNotice?: LocalizedString\n }>()\n\n const toolPart = computed(() => {\n const part = props.part as {\n type: string\n toolCallId: string\n input?: {\n name: string\n email: string\n phone?: string\n conversationContext?: Record<string, unknown>\n }\n }\n return part\n })\n\n const input = computed(() => toolPart.value.input)\n\n const localSubmitted = useLocalStorage<boolean>(\n computed(\n () =>\n `${toolPart.value.toolCallId}-${toolPart.value.type}-submitted`,\n ),\n false,\n )\n\n const LeadFormSchema = z.object({\n name: z.string().min(1).max(255).default(''),\n email: z.email().max(255).default(''),\n phone: z\n .string()\n .max(50)\n .regex(/^[+0-9\\s\\-.()]*$/, $t('validation.invalidPhoneNumber'))\n .optional(),\n })\n\n const emit = defineEmits<{\n submit: [data: Record<string, unknown>]\n }>()\n\n const { VvForm, VvFormField, formData } = useForm(LeadFormSchema, {\n lazyLoad: true,\n })\n\n // Pre-populate form with input values\n watch(\n input,\n (newInput) => {\n formData.value = {\n name: newInput?.name || '',\n email: newInput?.email || '',\n phone: newInput?.phone || '',\n }\n },\n { immediate: true },\n )\n\n watch(\n () => props.submitted,\n (submitted) => {\n if (submitted) {\n localSubmitted.value = true\n }\n },\n { immediate: true },\n )\n\n const isSubmitted = computed(() => {\n return props.submitted || localSubmitted.value\n })\n\n const submitLead = async (data: Record<string, unknown>): Promise<void> => {\n emit('submit', { ...data, metadata: input.value?.conversationContext })\n }\n\n const privacyNotice = useLocalizedString(\n () => props.privacyPolicyNotice,\n 'message.defaultPrivacyPolicyNotice',\n )\n</script>\n\n<template>\n <div class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8 min-h-40\">\n <VvIcon name=\"ri:send-plane-2-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{ $t('label.contactUs') }}</strong>\n </div>\n\n <Transition mode=\"out-in\">\n <div v-if=\"!isSubmitted\" class=\"p-sm\">\n <VvForm v-model=\"formData\" :readonly @submit=\"submitLead\">\n <VvFormField\n name=\"name\"\n type=\"text\"\n :label=\"$t('label.name')\"\n :placeholder=\"$t('placeholder.name')\"\n icon=\"ri:user-line\"\n modifiers=\"compact no-label\"\n class=\"mb-md\" />\n <VvFormField\n name=\"email\"\n type=\"email\"\n :label=\"$t('label.email')\"\n :placeholder=\"$t('placeholder.email')\"\n icon=\"ri:mail-line\"\n modifiers=\"compact no-label\"\n class=\"mb-md\" />\n <VvFormField\n name=\"phone\"\n type=\"tel\"\n :label=\"$t('label.phone')\"\n :placeholder=\"$t('placeholder.phone')\"\n icon=\"ri:phone-line\"\n class=\"mb-md\"\n modifiers=\"compact no-label\" />\n\n <div class=\"flex justify-between items-center gap-16 mt-xs\">\n <div\n class=\"text-smaller text-word-3 flex items-center gap-8\">\n <VvIcon\n name=\"ri:shield-check-line\"\n class=\"text-16 shrink-0\" />\n <PkStreamingMarkdown\n :markdown=\"privacyNotice\"\n class=\"wysiwyg\" />\n </div>\n <VvButton\n type=\"submit\"\n modifiers=\"primary\"\n :loading\n :disabled=\"loading || readonly\"\n icon-position=\"right\"\n class=\"shrink-0\"\n :label=\"$t('action.submit')\" />\n </div>\n </VvForm>\n </div>\n <div v-else class=\"p-sm\">\n <div class=\"flex items-center gap-sm\">\n <VvIcon\n name=\"ri:mail-check-line\"\n class=\"text-24 text-success\" />\n <div>\n <strong class=\"font-semibold block text-success\">\n {{ $t('message.leadSubmittedTitle') }}\n </strong>\n <p class=\"text-word-3\">\n {{ $t('message.leadSubmittedMessage') }}\n </p>\n </div>\n </div>\n </div>\n </Transition>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, ref } from 'vue'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const emit = defineEmits<{\n select: [value: string]\n }>()\n\n const toolPart = computed(() => {\n return JSON.parse(JSON.stringify(props.part)) as {\n state?: string\n toolCallId?: string\n input?: {\n label: string\n prompt?: string\n }\n output?: string\n }\n })\n\n const clicked = ref(false)\n\n const isInteractive = computed(() => {\n return toolPart.value?.state === 'input-available' && !clicked.value\n })\n\n function handleClick() {\n if (!isInteractive.value) {\n return\n }\n clicked.value = true\n const value =\n toolPart.value?.input?.prompt ?? toolPart.value?.input?.label\n if (value) {\n emit('select', value)\n }\n }\n</script>\n\n<template>\n <div v-if=\"toolPart.input?.label\" class=\"pk-tool-suggested-reply\">\n <button\n type=\"button\"\n class=\"pk-tool-suggested-reply__link\"\n :class=\"{ 'is-clicked': clicked, 'is-disabled': !isInteractive }\"\n :disabled=\"!isInteractive\"\n @click.stop=\"handleClick\">\n <VvIcon\n name=\"ri:corner-down-right-line\"\n class=\"pk-tool-suggested-reply__icon\" />\n <span>{{ toolPart.input.label }}</span>\n </button>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-tool-suggested-reply {\n display: flex;\n align-items: center;\n\n &__link {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n background: none;\n border: none;\n padding: 0;\n font: inherit;\n font-size: 0.875em;\n text-decoration: underline;\n text-underline-offset: 2px;\n cursor: pointer;\n transition: opacity 0.15s ease;\n color: var(--color-word-3);\n transition: var(--transition-colors);\n\n &:hover:not(:disabled) {\n color: var(--color-word);\n }\n\n &.is-disabled {\n cursor: default;\n pointer-events: none;\n color: var(--color-word-5);\n }\n\n &.is-clicked {\n color: var(--color-word-5);\n text-decoration: none;\n }\n }\n\n &__icon {\n width: 1em;\n height: 1em;\n flex-shrink: 0;\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, ref } from 'vue'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const emit = defineEmits<{\n select: [value: string]\n }>()\n\n const toolPart = computed(() => {\n return JSON.parse(JSON.stringify(props.part)) as {\n state?: string\n toolCallId?: string\n input?: {\n label: string\n prompt?: string\n }\n output?: string\n }\n })\n\n const clicked = ref(false)\n\n const isInteractive = computed(() => {\n return toolPart.value?.state === 'input-available' && !clicked.value\n })\n\n function handleClick() {\n if (!isInteractive.value) {\n return\n }\n clicked.value = true\n const value =\n toolPart.value?.input?.prompt ?? toolPart.value?.input?.label\n if (value) {\n emit('select', value)\n }\n }\n</script>\n\n<template>\n <div v-if=\"toolPart.input?.label\" class=\"pk-tool-suggested-reply\">\n <button\n type=\"button\"\n class=\"pk-tool-suggested-reply__link\"\n :class=\"{ 'is-clicked': clicked, 'is-disabled': !isInteractive }\"\n :disabled=\"!isInteractive\"\n @click.stop=\"handleClick\">\n <VvIcon\n name=\"ri:corner-down-right-line\"\n class=\"pk-tool-suggested-reply__icon\" />\n <span>{{ toolPart.input.label }}</span>\n </button>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-tool-suggested-reply {\n display: flex;\n align-items: center;\n\n &__link {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n background: none;\n border: none;\n padding: 0;\n font: inherit;\n font-size: 0.875em;\n text-decoration: underline;\n text-underline-offset: 2px;\n cursor: pointer;\n transition: opacity 0.15s ease;\n color: var(--color-word-3);\n transition: var(--transition-colors);\n\n &:hover:not(:disabled) {\n color: var(--color-word);\n }\n\n &.is-disabled {\n cursor: default;\n pointer-events: none;\n color: var(--color-word-5);\n }\n\n &.is-clicked {\n color: var(--color-word-5);\n text-decoration: none;\n }\n }\n\n &__icon {\n width: 1em;\n height: 1em;\n flex-shrink: 0;\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { stripMarkdown } from 'utils'\n\n const props = defineProps<{\n content: string\n similarity?: number\n maxSimilarity?: number\n expanded: boolean\n }>()\n\n const similarityPercent = computed(() => {\n if (props.similarity == null) {\n return null\n }\n const max =\n props.maxSimilarity && props.maxSimilarity > 0\n ? props.maxSimilarity\n : 1\n return Math.round((props.similarity / max) * 100)\n })\n</script>\n\n<template>\n <VvIcon name=\"ri:text-snippet\" class=\"shrink-0 text-12 text-word-4\" />\n <span class=\"text-10 text-word-2 truncate flex-1\" :title=\"content\">\n {{ stripMarkdown(content) }}\n </span>\n <span v-if=\"similarityPercent != null\" class=\"text-10 text-word-4 shrink-0\">\n {{ similarityPercent }}%\n </span>\n <VvIcon\n :name=\"expanded ? 'ri:arrow-up-s-line' : 'ri:arrow-down-s-line'\"\n class=\"text-14 text-word-4 shrink-0\" />\n</template>\n","<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { stripMarkdown } from 'utils'\n\n const props = defineProps<{\n content: string\n similarity?: number\n maxSimilarity?: number\n expanded: boolean\n }>()\n\n const similarityPercent = computed(() => {\n if (props.similarity == null) {\n return null\n }\n const max =\n props.maxSimilarity && props.maxSimilarity > 0\n ? props.maxSimilarity\n : 1\n return Math.round((props.similarity / max) * 100)\n })\n</script>\n\n<template>\n <VvIcon name=\"ri:text-snippet\" class=\"shrink-0 text-12 text-word-4\" />\n <span class=\"text-10 text-word-2 truncate flex-1\" :title=\"content\">\n {{ stripMarkdown(content) }}\n </span>\n <span v-if=\"similarityPercent != null\" class=\"text-10 text-word-4 shrink-0\">\n {{ similarityPercent }}%\n </span>\n <VvIcon\n :name=\"expanded ? 'ri:arrow-up-s-line' : 'ri:arrow-down-s-line'\"\n class=\"text-14 text-word-4 shrink-0\" />\n</template>\n","<script setup lang=\"ts\">\n import type { DocumentType } from 'models'\n import { getTypeIcon } from 'models'\n import PkUrl from '../PkUrl.vue'\n\n defineProps<{\n type: string\n name: string\n url?: string\n filename?: string\n }>()\n</script>\n\n<template>\n <VvIcon\n :name=\"getTypeIcon(type as DocumentType)\"\n class=\"shrink-0 text-14 text-word-3\" />\n <div class=\"flex flex-col gap-2 min-w-0 flex-1\">\n <strong class=\"font-bold text-12 text-word-1 truncate block\">\n {{ name }}\n </strong>\n <span v-if=\"filename\" class=\"text-10 text-word-4 truncate\">\n {{ filename }}\n </span>\n <span\n v-if=\"url\"\n class=\"text-10 text-word-4 truncate flex items-center gap-4\">\n <VvIcon name=\"ri:link\" class=\"shrink-0 text-10\" />\n <PkUrl :url=\"url\" />\n </span>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import type { DocumentType } from 'models'\n import { getTypeIcon } from 'models'\n import PkUrl from '../PkUrl.vue'\n\n defineProps<{\n type: string\n name: string\n url?: string\n filename?: string\n }>()\n</script>\n\n<template>\n <VvIcon\n :name=\"getTypeIcon(type as DocumentType)\"\n class=\"shrink-0 text-14 text-word-3\" />\n <div class=\"flex flex-col gap-2 min-w-0 flex-1\">\n <strong class=\"font-bold text-12 text-word-1 truncate block\">\n {{ name }}\n </strong>\n <span v-if=\"filename\" class=\"text-10 text-word-4 truncate\">\n {{ filename }}\n </span>\n <span\n v-if=\"url\"\n class=\"text-10 text-word-4 truncate flex items-center gap-4\">\n <VvIcon name=\"ri:link\" class=\"shrink-0 text-10\" />\n <PkUrl :url=\"url\" />\n </span>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, ref, reactive } from 'vue'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n import PkChunkPreview from './PkChunkPreview.vue'\n import PkDocumentHeader from './PkDocumentHeader.vue'\n\n interface SourceItem {\n chunkId: string\n documentId: string\n documentName: string\n documentType: string\n language: string\n content: string\n chunkIndex?: number | null\n similarity?: number\n sourceUrl?: string\n sourceFilename?: string\n sourceDescription?: string\n sourceImageUrl?: string\n }\n\n const props = defineProps<{\n part: unknown\n onExpandContext?: (payload: {\n documentId: string\n chunkIndex: number\n }) => Promise<string>\n onDownload?: (documentId: string) => void\n }>()\n\n const toolPart = computed(() => {\n return props.part as {\n input?: {\n sources: SourceItem[]\n }\n }\n })\n\n const sources = computed(() => toolPart.value.input?.sources || [])\n\n const groupedSources = computed(() => {\n const groups = new Map<\n string,\n { document: SourceItem; chunks: SourceItem[] }\n >()\n for (const source of sources.value) {\n const existing = groups.get(source.documentId)\n if (existing) {\n existing.chunks.push(source)\n } else {\n groups.set(source.documentId, {\n document: source,\n chunks: [source],\n })\n }\n }\n return [...groups.values()]\n })\n\n const maxSimilarity = computed(() => {\n return Math.max(...sources.value.map((s) => s.similarity ?? 0), 0)\n })\n\n const expandedDocuments = reactive(new Set<string>())\n const expandedChunks = reactive(new Set<string>())\n const contextData = reactive(new Map<string, string>())\n const loadingContext = reactive(new Set<string>())\n\n const toggleDocument = (documentId: string) => {\n if (expandedDocuments.has(documentId)) {\n expandedDocuments.delete(documentId)\n } else {\n expandedDocuments.add(documentId)\n }\n }\n\n const toggleChunk = (chunkId: string) => {\n if (expandedChunks.has(chunkId)) {\n expandedChunks.delete(chunkId)\n } else {\n expandedChunks.add(chunkId)\n }\n }\n\n const handleExpandContext = async (source: SourceItem) => {\n if (source.chunkIndex == null || !props.onExpandContext) {\n return\n }\n loadingContext.add(source.chunkId)\n try {\n const content = await props.onExpandContext({\n documentId: source.documentId,\n chunkIndex: source.chunkIndex,\n })\n contextData.set(source.chunkId, content)\n } finally {\n loadingContext.delete(source.chunkId)\n }\n }\n\n const clearContext = (chunkId: string) => {\n contextData.delete(chunkId)\n }\n\n const showMore = ref(false)\n const visibleGroups = computed(() => {\n if (showMore.value) {\n return groupedSources.value\n }\n return groupedSources.value.slice(0, 3)\n })\n const hasMore = computed(() => groupedSources.value.length > 3)\n</script>\n\n<template>\n <div v-if=\"sources.length\" class=\"flex flex-col gap-xs w-full\">\n <div class=\"flex items-center gap-4 text-12 text-word-3 font-semibold\">\n <VvIcon name=\"ri:article-line\" class=\"text-14\" />\n {{ $t('label.sources') }}\n <span class=\"text-word-4 font-normal\">\n ({{ groupedSources.length }})\n </span>\n </div>\n\n <ul class=\"flex flex-col gap-xs\">\n <li\n v-for=\"group in visibleGroups\"\n :key=\"group.document.documentId\"\n class=\"border border-surface-3 rounded-lg overflow-hidden\">\n <!-- Document header -->\n <button\n class=\"flex items-center gap-8 p-8 w-full text-left hover:bg-surface-1 transition-colors cursor-pointer\"\n @click=\"toggleDocument(group.document.documentId)\">\n <PkDocumentHeader\n :type=\"group.document.documentType\"\n :name=\"group.document.documentName\"\n :url=\"group.document.sourceUrl\"\n :filename=\"group.document.sourceFilename\" />\n <div class=\"flex items-center gap-4 shrink-0\">\n <span\n v-if=\"group.chunks.length > 1\"\n class=\"text-10 text-word-4 bg-surface-2 rounded px-4 py-2\">\n {{ group.chunks.length }}\n </span>\n <span\n class=\"text-10 text-word-4 bg-surface-2 rounded px-4 py-2 uppercase\">\n {{ group.document.language }}\n </span>\n <VvIcon\n :name=\"\n expandedDocuments.has(group.document.documentId)\n ? 'ri:arrow-up-s-line'\n : 'ri:arrow-down-s-line'\n \"\n class=\"text-16 text-word-3\" />\n </div>\n </button>\n\n <!-- Expanded content -->\n <div\n v-if=\"expandedDocuments.has(group.document.documentId)\"\n class=\"border-t border-surface-3\">\n <PkStreamingMarkdown\n v-if=\"group.document.sourceDescription\"\n :markdown=\"group.document.sourceDescription\"\n class=\"px-8 py-4 text-10 text-word-3 bg-surface-1 border-b border-surface-3\" />\n\n <!-- Chunk excerpts -->\n <div\n v-for=\"chunk in group.chunks\"\n :key=\"chunk.chunkId\"\n class=\"border-b border-surface-3 last:border-b-0\">\n <button\n class=\"flex items-center gap-8 px-8 py-6 w-full text-left hover:bg-surface-1 transition-colors cursor-pointer\"\n @click=\"toggleChunk(chunk.chunkId)\">\n <PkChunkPreview\n :content=\"chunk.content\"\n :similarity=\"chunk.similarity\"\n :max-similarity=\"maxSimilarity\"\n :expanded=\"expandedChunks.has(chunk.chunkId)\" />\n </button>\n\n <!-- Expanded chunk content -->\n <div\n v-if=\"expandedChunks.has(chunk.chunkId)\"\n class=\"bg-surface-1 border-t border-surface-3\">\n <div class=\"p-8 text-10 text-word-3\">\n <transition mode=\"out-in\">\n <!-- Context expansion -->\n <PkStreamingMarkdown\n v-if=\"contextData.has(chunk.chunkId)\"\n :markdown=\"\n contextData.get(chunk.chunkId)!\n \"\n class=\"wysiwyg\" />\n\n <!-- Chunk content -->\n <PkStreamingMarkdown\n v-else\n :markdown=\"chunk.content\"\n class=\"wysiwyg\" />\n </transition>\n </div>\n\n <!-- Actions bar -->\n <div\n class=\"flex items-center gap-8 px-8 py-6 border-t border-surface-3 bg-surface\">\n <!-- Expand / collapse context -->\n <button\n v-if=\"\n onExpandContext &&\n chunk.chunkIndex != null &&\n !contextData.has(chunk.chunkId)\n \"\n class=\"text-10 text-word-3 hover:text-word flex items-center gap-4 cursor-pointer\"\n :disabled=\"\n loadingContext.has(chunk.chunkId)\n \"\n @click=\"handleExpandContext(chunk)\">\n <VvIcon\n :name=\"\n loadingContext.has(chunk.chunkId)\n ? 'line-md:loading-loop'\n : 'ri:expand-up-down-line'\n \"\n class=\"text-12\" />\n {{ $t('label.expandContext') }}\n </button>\n <button\n v-else-if=\"contextData.has(chunk.chunkId)\"\n class=\"text-10 text-word-3 hover:text-word-1 flex items-center gap-4 cursor-pointer\"\n @click=\"clearContext(chunk.chunkId)\">\n <VvIcon\n name=\"ri:collapse-vertical-line\"\n class=\"text-12\" />\n {{ $t('label.collapseContext') }}\n </button>\n\n <!-- Open source URL -->\n <a\n v-if=\"chunk.sourceUrl\"\n :href=\"chunk.sourceUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"text-10 text-word-3 hover:text-word-1 flex items-center gap-4 ml-auto\">\n <VvIcon\n name=\"ri:external-link-line\"\n class=\"text-12\" />\n {{ $t('label.openSource') }}\n </a>\n\n <!-- Download file -->\n <button\n v-if=\"\n onDownload &&\n chunk.documentType === 'file'\n \"\n class=\"text-10 text-word-3 hover:text-word-1 flex items-center gap-4 cursor-pointer\"\n :class=\"{\n 'ml-auto': !chunk.sourceUrl,\n }\"\n @click=\"onDownload(chunk.documentId)\">\n <VvIcon\n name=\"ri:download-line\"\n class=\"text-12\" />\n {{ $t('label.downloadFile') }}\n </button>\n </div>\n </div>\n </div>\n </div>\n </li>\n </ul>\n\n <!-- Show more -->\n <button\n v-if=\"hasMore\"\n class=\"text-12 text-word-3 cursor-pointer hover:underline flex items-center gap-4 mx-auto\"\n @click=\"showMore = !showMore\">\n <VvIcon\n :name=\"showMore ? 'ri:arrow-up-s-line' : 'ri:arrow-down-s-line'\"\n class=\"text-16\" />\n {{\n showMore\n ? $t('action.showLess')\n : $t('action.showMore', {\n count: groupedSources.length - 3,\n })\n }}\n </button>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, ref, reactive } from 'vue'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n import PkChunkPreview from './PkChunkPreview.vue'\n import PkDocumentHeader from './PkDocumentHeader.vue'\n\n interface SourceItem {\n chunkId: string\n documentId: string\n documentName: string\n documentType: string\n language: string\n content: string\n chunkIndex?: number | null\n similarity?: number\n sourceUrl?: string\n sourceFilename?: string\n sourceDescription?: string\n sourceImageUrl?: string\n }\n\n const props = defineProps<{\n part: unknown\n onExpandContext?: (payload: {\n documentId: string\n chunkIndex: number\n }) => Promise<string>\n onDownload?: (documentId: string) => void\n }>()\n\n const toolPart = computed(() => {\n return props.part as {\n input?: {\n sources: SourceItem[]\n }\n }\n })\n\n const sources = computed(() => toolPart.value.input?.sources || [])\n\n const groupedSources = computed(() => {\n const groups = new Map<\n string,\n { document: SourceItem; chunks: SourceItem[] }\n >()\n for (const source of sources.value) {\n const existing = groups.get(source.documentId)\n if (existing) {\n existing.chunks.push(source)\n } else {\n groups.set(source.documentId, {\n document: source,\n chunks: [source],\n })\n }\n }\n return [...groups.values()]\n })\n\n const maxSimilarity = computed(() => {\n return Math.max(...sources.value.map((s) => s.similarity ?? 0), 0)\n })\n\n const expandedDocuments = reactive(new Set<string>())\n const expandedChunks = reactive(new Set<string>())\n const contextData = reactive(new Map<string, string>())\n const loadingContext = reactive(new Set<string>())\n\n const toggleDocument = (documentId: string) => {\n if (expandedDocuments.has(documentId)) {\n expandedDocuments.delete(documentId)\n } else {\n expandedDocuments.add(documentId)\n }\n }\n\n const toggleChunk = (chunkId: string) => {\n if (expandedChunks.has(chunkId)) {\n expandedChunks.delete(chunkId)\n } else {\n expandedChunks.add(chunkId)\n }\n }\n\n const handleExpandContext = async (source: SourceItem) => {\n if (source.chunkIndex == null || !props.onExpandContext) {\n return\n }\n loadingContext.add(source.chunkId)\n try {\n const content = await props.onExpandContext({\n documentId: source.documentId,\n chunkIndex: source.chunkIndex,\n })\n contextData.set(source.chunkId, content)\n } finally {\n loadingContext.delete(source.chunkId)\n }\n }\n\n const clearContext = (chunkId: string) => {\n contextData.delete(chunkId)\n }\n\n const showMore = ref(false)\n const visibleGroups = computed(() => {\n if (showMore.value) {\n return groupedSources.value\n }\n return groupedSources.value.slice(0, 3)\n })\n const hasMore = computed(() => groupedSources.value.length > 3)\n</script>\n\n<template>\n <div v-if=\"sources.length\" class=\"flex flex-col gap-xs w-full\">\n <div class=\"flex items-center gap-4 text-12 text-word-3 font-semibold\">\n <VvIcon name=\"ri:article-line\" class=\"text-14\" />\n {{ $t('label.sources') }}\n <span class=\"text-word-4 font-normal\">\n ({{ groupedSources.length }})\n </span>\n </div>\n\n <ul class=\"flex flex-col gap-xs\">\n <li\n v-for=\"group in visibleGroups\"\n :key=\"group.document.documentId\"\n class=\"border border-surface-3 rounded-lg overflow-hidden\">\n <!-- Document header -->\n <button\n class=\"flex items-center gap-8 p-8 w-full text-left hover:bg-surface-1 transition-colors cursor-pointer\"\n @click=\"toggleDocument(group.document.documentId)\">\n <PkDocumentHeader\n :type=\"group.document.documentType\"\n :name=\"group.document.documentName\"\n :url=\"group.document.sourceUrl\"\n :filename=\"group.document.sourceFilename\" />\n <div class=\"flex items-center gap-4 shrink-0\">\n <span\n v-if=\"group.chunks.length > 1\"\n class=\"text-10 text-word-4 bg-surface-2 rounded px-4 py-2\">\n {{ group.chunks.length }}\n </span>\n <span\n class=\"text-10 text-word-4 bg-surface-2 rounded px-4 py-2 uppercase\">\n {{ group.document.language }}\n </span>\n <VvIcon\n :name=\"\n expandedDocuments.has(group.document.documentId)\n ? 'ri:arrow-up-s-line'\n : 'ri:arrow-down-s-line'\n \"\n class=\"text-16 text-word-3\" />\n </div>\n </button>\n\n <!-- Expanded content -->\n <div\n v-if=\"expandedDocuments.has(group.document.documentId)\"\n class=\"border-t border-surface-3\">\n <PkStreamingMarkdown\n v-if=\"group.document.sourceDescription\"\n :markdown=\"group.document.sourceDescription\"\n class=\"px-8 py-4 text-10 text-word-3 bg-surface-1 border-b border-surface-3\" />\n\n <!-- Chunk excerpts -->\n <div\n v-for=\"chunk in group.chunks\"\n :key=\"chunk.chunkId\"\n class=\"border-b border-surface-3 last:border-b-0\">\n <button\n class=\"flex items-center gap-8 px-8 py-6 w-full text-left hover:bg-surface-1 transition-colors cursor-pointer\"\n @click=\"toggleChunk(chunk.chunkId)\">\n <PkChunkPreview\n :content=\"chunk.content\"\n :similarity=\"chunk.similarity\"\n :max-similarity=\"maxSimilarity\"\n :expanded=\"expandedChunks.has(chunk.chunkId)\" />\n </button>\n\n <!-- Expanded chunk content -->\n <div\n v-if=\"expandedChunks.has(chunk.chunkId)\"\n class=\"bg-surface-1 border-t border-surface-3\">\n <div class=\"p-8 text-10 text-word-3\">\n <transition mode=\"out-in\">\n <!-- Context expansion -->\n <PkStreamingMarkdown\n v-if=\"contextData.has(chunk.chunkId)\"\n :markdown=\"\n contextData.get(chunk.chunkId)!\n \"\n class=\"wysiwyg\" />\n\n <!-- Chunk content -->\n <PkStreamingMarkdown\n v-else\n :markdown=\"chunk.content\"\n class=\"wysiwyg\" />\n </transition>\n </div>\n\n <!-- Actions bar -->\n <div\n class=\"flex items-center gap-8 px-8 py-6 border-t border-surface-3 bg-surface\">\n <!-- Expand / collapse context -->\n <button\n v-if=\"\n onExpandContext &&\n chunk.chunkIndex != null &&\n !contextData.has(chunk.chunkId)\n \"\n class=\"text-10 text-word-3 hover:text-word flex items-center gap-4 cursor-pointer\"\n :disabled=\"\n loadingContext.has(chunk.chunkId)\n \"\n @click=\"handleExpandContext(chunk)\">\n <VvIcon\n :name=\"\n loadingContext.has(chunk.chunkId)\n ? 'line-md:loading-loop'\n : 'ri:expand-up-down-line'\n \"\n class=\"text-12\" />\n {{ $t('label.expandContext') }}\n </button>\n <button\n v-else-if=\"contextData.has(chunk.chunkId)\"\n class=\"text-10 text-word-3 hover:text-word-1 flex items-center gap-4 cursor-pointer\"\n @click=\"clearContext(chunk.chunkId)\">\n <VvIcon\n name=\"ri:collapse-vertical-line\"\n class=\"text-12\" />\n {{ $t('label.collapseContext') }}\n </button>\n\n <!-- Open source URL -->\n <a\n v-if=\"chunk.sourceUrl\"\n :href=\"chunk.sourceUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"text-10 text-word-3 hover:text-word-1 flex items-center gap-4 ml-auto\">\n <VvIcon\n name=\"ri:external-link-line\"\n class=\"text-12\" />\n {{ $t('label.openSource') }}\n </a>\n\n <!-- Download file -->\n <button\n v-if=\"\n onDownload &&\n chunk.documentType === 'file'\n \"\n class=\"text-10 text-word-3 hover:text-word-1 flex items-center gap-4 cursor-pointer\"\n :class=\"{\n 'ml-auto': !chunk.sourceUrl,\n }\"\n @click=\"onDownload(chunk.documentId)\">\n <VvIcon\n name=\"ri:download-line\"\n class=\"text-12\" />\n {{ $t('label.downloadFile') }}\n </button>\n </div>\n </div>\n </div>\n </div>\n </li>\n </ul>\n\n <!-- Show more -->\n <button\n v-if=\"hasMore\"\n class=\"text-12 text-word-3 cursor-pointer hover:underline flex items-center gap-4 mx-auto\"\n @click=\"showMore = !showMore\">\n <VvIcon\n :name=\"showMore ? 'ri:arrow-up-s-line' : 'ri:arrow-down-s-line'\"\n class=\"text-16\" />\n {{\n showMore\n ? $t('action.showLess')\n : $t('action.showMore', {\n count: groupedSources.length - 3,\n })\n }}\n </button>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, onMounted } from 'vue'\n import { useI18n } from 'vue-i18n'\n\n import type { ReverseGeocodeFn } from 'utils/src/device-context'\n\n type GeolocationOutput =\n | {\n latitude: number\n longitude: number\n accuracy?: number\n city?: string\n }\n | { error: 'permission_denied' | 'position_unavailable' | 'timeout' }\n\n const props = defineProps<{\n part: unknown\n reverseGeocode?: ReverseGeocodeFn\n }>()\n\n const emit = defineEmits<{\n result: [output: GeolocationOutput]\n }>()\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const toolPart = computed(() => {\n return props.part as {\n state?: string\n input?: { reason?: string }\n output?: GeolocationOutput\n }\n })\n\n const state = computed(() => toolPart.value.state ?? 'unknown')\n\n const isOutputAvailable = computed(() => state.value === 'output-available')\n\n const successOutput = computed(() => {\n const out = toolPart.value.output\n if (!out || 'error' in out) {\n return undefined\n }\n return out\n })\n\n const errorOutput = computed(() => {\n const out = toolPart.value.output\n if (!out || !('error' in out)) {\n return undefined\n }\n return out\n })\n\n /** Maps GeolocationPositionError.code to a typed string */\n function mapGeolocationError(\n code: number,\n ): 'permission_denied' | 'position_unavailable' | 'timeout' {\n if (code === 1) {\n return 'permission_denied'\n }\n if (code === 3) {\n return 'timeout'\n }\n return 'position_unavailable'\n }\n\n onMounted(() => {\n if (state.value !== 'input-available') {\n return\n }\n\n if (!navigator.geolocation) {\n emit('result', { error: 'position_unavailable' })\n return\n }\n\n navigator.geolocation.getCurrentPosition(\n async (position) => {\n const { latitude, longitude, accuracy } = position.coords\n const city = props.reverseGeocode\n ? await props\n .reverseGeocode(latitude, longitude)\n .catch(() => undefined)\n : undefined\n emit('result', { latitude, longitude, accuracy, city })\n },\n (error) => {\n emit('result', { error: mapGeolocationError(error.code) })\n },\n { timeout: 15000 },\n )\n })\n</script>\n\n<template>\n <div\n class=\"flex items-center gap-6 text-12 text-word-3 border border-surface-3 rounded-xl px-sm py-10\">\n <!-- Loading state -->\n <template v-if=\"!isOutputAvailable\">\n <VvIcon name=\"line-md:loading-loop\" class=\"text-16\" />\n <span>{{ $t('messagePart.requestGeolocation') }}</span>\n </template>\n\n <!-- Success state -->\n <template v-else-if=\"successOutput\">\n <VvIcon name=\"ri:map-pin-line\" class=\"text-16\" />\n <span>\n {{\n $n(successOutput.latitude, {\n style: 'decimal',\n minimumFractionDigits: 5,\n maximumFractionDigits: 5,\n })\n }},\n {{\n $n(successOutput.longitude, {\n style: 'decimal',\n minimumFractionDigits: 5,\n maximumFractionDigits: 5,\n })\n }}\n <template v-if=\"successOutput.accuracy !== undefined\">\n (±{{\n $n(successOutput.accuracy, {\n style: 'unit',\n unit: 'meter',\n })\n }})\n </template>\n </span>\n </template>\n\n <!-- Error state -->\n <template v-else-if=\"errorOutput\">\n <span class=\"i-vv-alert-circle text-16 shrink-0 text-danger\" />\n <span>\n {{\n errorOutput.error === 'permission_denied'\n ? $t('message.geolocationPermissionDenied')\n : $t('message.geolocationUnavailable')\n }}\n </span>\n </template>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, onMounted } from 'vue'\n import { useI18n } from 'vue-i18n'\n\n import type { ReverseGeocodeFn } from 'utils/src/device-context'\n\n type GeolocationOutput =\n | {\n latitude: number\n longitude: number\n accuracy?: number\n city?: string\n }\n | { error: 'permission_denied' | 'position_unavailable' | 'timeout' }\n\n const props = defineProps<{\n part: unknown\n reverseGeocode?: ReverseGeocodeFn\n }>()\n\n const emit = defineEmits<{\n result: [output: GeolocationOutput]\n }>()\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const toolPart = computed(() => {\n return props.part as {\n state?: string\n input?: { reason?: string }\n output?: GeolocationOutput\n }\n })\n\n const state = computed(() => toolPart.value.state ?? 'unknown')\n\n const isOutputAvailable = computed(() => state.value === 'output-available')\n\n const successOutput = computed(() => {\n const out = toolPart.value.output\n if (!out || 'error' in out) {\n return undefined\n }\n return out\n })\n\n const errorOutput = computed(() => {\n const out = toolPart.value.output\n if (!out || !('error' in out)) {\n return undefined\n }\n return out\n })\n\n /** Maps GeolocationPositionError.code to a typed string */\n function mapGeolocationError(\n code: number,\n ): 'permission_denied' | 'position_unavailable' | 'timeout' {\n if (code === 1) {\n return 'permission_denied'\n }\n if (code === 3) {\n return 'timeout'\n }\n return 'position_unavailable'\n }\n\n onMounted(() => {\n if (state.value !== 'input-available') {\n return\n }\n\n if (!navigator.geolocation) {\n emit('result', { error: 'position_unavailable' })\n return\n }\n\n navigator.geolocation.getCurrentPosition(\n async (position) => {\n const { latitude, longitude, accuracy } = position.coords\n const city = props.reverseGeocode\n ? await props\n .reverseGeocode(latitude, longitude)\n .catch(() => undefined)\n : undefined\n emit('result', { latitude, longitude, accuracy, city })\n },\n (error) => {\n emit('result', { error: mapGeolocationError(error.code) })\n },\n { timeout: 15000 },\n )\n })\n</script>\n\n<template>\n <div\n class=\"flex items-center gap-6 text-12 text-word-3 border border-surface-3 rounded-xl px-sm py-10\">\n <!-- Loading state -->\n <template v-if=\"!isOutputAvailable\">\n <VvIcon name=\"line-md:loading-loop\" class=\"text-16\" />\n <span>{{ $t('messagePart.requestGeolocation') }}</span>\n </template>\n\n <!-- Success state -->\n <template v-else-if=\"successOutput\">\n <VvIcon name=\"ri:map-pin-line\" class=\"text-16\" />\n <span>\n {{\n $n(successOutput.latitude, {\n style: 'decimal',\n minimumFractionDigits: 5,\n maximumFractionDigits: 5,\n })\n }},\n {{\n $n(successOutput.longitude, {\n style: 'decimal',\n minimumFractionDigits: 5,\n maximumFractionDigits: 5,\n })\n }}\n <template v-if=\"successOutput.accuracy !== undefined\">\n (±{{\n $n(successOutput.accuracy, {\n style: 'unit',\n unit: 'meter',\n })\n }})\n </template>\n </span>\n </template>\n\n <!-- Error state -->\n <template v-else-if=\"errorOutput\">\n <span class=\"i-vv-alert-circle text-16 shrink-0 text-danger\" />\n <span>\n {{\n errorOutput.error === 'permission_denied'\n ? $t('message.geolocationPermissionDenied')\n : $t('message.geolocationUnavailable')\n }}\n </span>\n </template>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, useTemplateRef } from 'vue'\n import { useDropZone } from '@vueuse/core'\n import { storeToRefs } from 'pinia'\n import PkChatbotMessages from './PkChatbotMessages.vue'\n import PkChatbotInput from './PkChatbotInput.vue'\n import PkToolShowMultipleChoice from './PkToolShowMultipleChoice.vue'\n import PkToolShowContactForm from './PkToolShowContactForm.vue'\n import PkToolShowSuggestedReply from './PkToolShowSuggestedReply.vue'\n import PkToolShowSources from './PkToolShowSources.vue'\n import PkToolRequestGeolocation from './PkToolRequestGeolocation.vue'\n import { useLocalizedString } from '../composables/useLocalizedString'\n import { useChatbotStore } from 'composables'\n import type { UIChatMessage } from 'models'\n\n const props = defineProps<{ agentId: string }>()\n\n const emit = defineEmits<{\n 'show-info': [message: UIChatMessage]\n revise: [message: UIChatMessage]\n }>()\n\n const store = useChatbotStore(props.agentId)\n\n const {\n name,\n agentInterface,\n agentFileUpload,\n actions,\n revisedAnswers,\n messages,\n chat,\n messageFeedbacks,\n feedbackDialogMessage,\n isFeedbackSubmitting,\n isFeedbackSubmitted,\n feedbackSubmitError,\n isLeadSubmitted,\n isLoadingSubmitLead,\n submitLeadError,\n input,\n inputMessagePlaceholder,\n isConversationBlocked,\n baseUrl,\n pendingAttachments,\n apiClient,\n } = storeToRefs(store)\n\n const {\n handleSubmit: storeHandleSubmit,\n stopGeneration,\n regenerate,\n onUpvote,\n onDownvote,\n onFeedback,\n onFeedbackSubmit,\n onLeadSubmit,\n startNewChat,\n addToolOutput,\n handleFileSelect,\n } = store\n\n const dismissableNotice = useLocalizedString(\n () => agentInterface.value?.dismissableNotice,\n )\n\n const chatViewEl = useTemplateRef<HTMLDivElement>('chatViewEl')\n\n const handleExpandSourceContext = async (payload: {\n documentId: string\n chunkIndex: number\n }) => {\n const result = await apiClient.value.expandSourceContext(\n props.agentId,\n payload.documentId,\n payload.chunkIndex,\n )\n return result.content\n }\n\n const handleDownloadSource = async (documentId: string) => {\n const result = await apiClient.value.downloadSourceDocument(\n props.agentId,\n documentId,\n )\n window.open(result.downloadUrl, '_blank')\n }\n\n const handleFileDrop = (files: File[] | null) => {\n if (!agentFileUpload.value?.enabled || !files) {\n return\n }\n for (const file of files) {\n handleFileSelect(file)\n }\n }\n\n const { isOverDropZone } = useDropZone(chatViewEl, {\n dataTypes: computed(\n () => agentFileUpload.value?.allowedMimeTypes ?? [],\n ),\n onDrop: handleFileDrop,\n })\n</script>\n\n<template>\n <div\n ref=\"chatViewEl\"\n class=\"pk-chatbot-view-chat\"\n :class=\"{\n 'pk-chatbot-view-chat--dragover':\n isOverDropZone && agentFileUpload?.enabled,\n }\">\n <!-- #region messages -->\n <PkChatbotMessages\n class=\"flex flex-col flex-1 min-h-0 p-md overflow-y-auto\"\n :name=\"name\"\n :messages=\"messages\"\n :status=\"chat.status\"\n :error=\"chat.error\"\n :main-color=\"agentInterface?.mainColor\"\n :text-color=\"agentInterface?.textColor\"\n :revised-answers=\"revisedAnswers\"\n :actions=\"actions\"\n :logo=\"agentInterface?.logo\"\n :message-feedbacks=\"messageFeedbacks\"\n :feedback-message-id=\"feedbackDialogMessage?.id\"\n :feedback-loading=\"isFeedbackSubmitting\"\n :feedback-submitted=\"isFeedbackSubmitted\"\n :feedback-error=\"feedbackSubmitError\"\n @feedback-submit=\"onFeedbackSubmit($event)\"\n @feedback-close=\"feedbackDialogMessage = undefined\"\n @regenerate=\"regenerate\"\n @auto-retry=\"regenerate\"\n @reset-chat=\"startNewChat\"\n @show-info=\"emit('show-info', $event)\"\n @revise=\"emit('revise', $event)\"\n @upvote=\"onUpvote\"\n @downvote=\"onDownvote\"\n @feedback=\"onFeedback\">\n <template #tool-showContactForm=\"{ part }\">\n <PkToolShowContactForm\n :part\n :readonly=\"!baseUrl\"\n :submitted=\"isLeadSubmitted\"\n :loading=\"isLoadingSubmitLead\"\n :error=\"submitLeadError\"\n :privacy-policy-notice=\"agentInterface?.privacyPolicyNotice\"\n @submit=\"onLeadSubmit\" />\n </template>\n <template #tool-showSuggestedReply=\"{ part }\">\n <PkToolShowSuggestedReply\n :part\n @select=\"\n ($event) => {\n input = $event\n storeHandleSubmit()\n }\n \" />\n </template>\n <template #tool-showSources=\"{ part }\">\n <PkToolShowSources\n :part\n :on-expand-context=\"handleExpandSourceContext\"\n :on-download=\"handleDownloadSource\" />\n </template>\n <template #tool-showMultipleChoice=\"{ part }\">\n <transition mode=\"out-in\">\n <PkToolShowMultipleChoice\n :part\n @select=\"\n addToolOutput({\n tool: 'showMultipleChoice',\n toolCallId: (part as any).toolCallId,\n output: $event,\n })\n \" />\n </transition>\n </template>\n <template #tool-requestGeolocation=\"{ part }\">\n <PkToolRequestGeolocation\n :part\n :reverse-geocode=\"\n (lat: number, lon: number) =>\n apiClient.reverseGeocode(lat, lon)\n \"\n @result=\"\n addToolOutput({\n tool: 'requestGeolocation',\n toolCallId: (part as any).toolCallId,\n output: $event,\n })\n \" />\n </template>\n </PkChatbotMessages>\n <!-- #endregion -->\n\n <!-- #region input -->\n <div\n v-if=\"isConversationBlocked\"\n class=\"p-md border-t border-surface-3 text-center text-12 text-danger-darken-2 bg-surface-danger\">\n {{ $t('message.chatErrorConversationBlocked') }}\n </div>\n <PkChatbotInput\n v-else\n v-model=\"input\"\n v-model:pending-attachments=\"pendingAttachments\"\n :placeholder=\"inputMessagePlaceholder\"\n :dismissable-notice=\"\n dismissableNotice && chat.messages.length <= 1\n ? dismissableNotice\n : undefined\n \"\n :status=\"chat.status\"\n :max-message-length=\"agentInterface?.maxMessageLength\"\n :file-upload=\"agentFileUpload\"\n @stop-generation=\"stopGeneration\"\n @submit=\"storeHandleSubmit\"\n @file-select=\"handleFileSelect\" />\n <!-- #endregion -->\n <Transition>\n <div\n v-if=\"isOverDropZone && agentFileUpload?.enabled\"\n class=\"pk-chatbot-view-chat__drop-overlay\">\n <VvIcon\n name=\"ri:upload-cloud-2-line\"\n class=\"pk-chatbot-view-chat__drop-overlay-icon\" />\n <span>{{ $t('action.dropFile') }}</span>\n </div>\n </Transition>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-view-chat {\n position: relative;\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n\n &__drop-overlay {\n position: absolute;\n inset: var(--spacing-sm) var(--spacing-sm) var(--spacing-sm)\n var(--spacing-sm);\n z-index: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--spacing-xs);\n background-color: color-mix(\n in srgb,\n var(--color-surface) 85%,\n transparent\n );\n border-radius: var(--rounded-xl);\n border: var(--spacing-2) dashed var(--color-surface-5);\n pointer-events: none;\n color: var(--color-word-3);\n\n &-icon {\n font-size: var(--spacing-32);\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, useTemplateRef } from 'vue'\n import { useDropZone } from '@vueuse/core'\n import { storeToRefs } from 'pinia'\n import PkChatbotMessages from './PkChatbotMessages.vue'\n import PkChatbotInput from './PkChatbotInput.vue'\n import PkToolShowMultipleChoice from './PkToolShowMultipleChoice.vue'\n import PkToolShowContactForm from './PkToolShowContactForm.vue'\n import PkToolShowSuggestedReply from './PkToolShowSuggestedReply.vue'\n import PkToolShowSources from './PkToolShowSources.vue'\n import PkToolRequestGeolocation from './PkToolRequestGeolocation.vue'\n import { useLocalizedString } from '../composables/useLocalizedString'\n import { useChatbotStore } from 'composables'\n import type { UIChatMessage } from 'models'\n\n const props = defineProps<{ agentId: string }>()\n\n const emit = defineEmits<{\n 'show-info': [message: UIChatMessage]\n revise: [message: UIChatMessage]\n }>()\n\n const store = useChatbotStore(props.agentId)\n\n const {\n name,\n agentInterface,\n agentFileUpload,\n actions,\n revisedAnswers,\n messages,\n chat,\n messageFeedbacks,\n feedbackDialogMessage,\n isFeedbackSubmitting,\n isFeedbackSubmitted,\n feedbackSubmitError,\n isLeadSubmitted,\n isLoadingSubmitLead,\n submitLeadError,\n input,\n inputMessagePlaceholder,\n isConversationBlocked,\n baseUrl,\n pendingAttachments,\n apiClient,\n } = storeToRefs(store)\n\n const {\n handleSubmit: storeHandleSubmit,\n stopGeneration,\n regenerate,\n onUpvote,\n onDownvote,\n onFeedback,\n onFeedbackSubmit,\n onLeadSubmit,\n startNewChat,\n addToolOutput,\n handleFileSelect,\n } = store\n\n const dismissableNotice = useLocalizedString(\n () => agentInterface.value?.dismissableNotice,\n )\n\n const chatViewEl = useTemplateRef<HTMLDivElement>('chatViewEl')\n\n const handleExpandSourceContext = async (payload: {\n documentId: string\n chunkIndex: number\n }) => {\n const result = await apiClient.value.expandSourceContext(\n props.agentId,\n payload.documentId,\n payload.chunkIndex,\n )\n return result.content\n }\n\n const handleDownloadSource = async (documentId: string) => {\n const result = await apiClient.value.downloadSourceDocument(\n props.agentId,\n documentId,\n )\n window.open(result.downloadUrl, '_blank')\n }\n\n const handleFileDrop = (files: File[] | null) => {\n if (!agentFileUpload.value?.enabled || !files) {\n return\n }\n for (const file of files) {\n handleFileSelect(file)\n }\n }\n\n const { isOverDropZone } = useDropZone(chatViewEl, {\n dataTypes: computed(\n () => agentFileUpload.value?.allowedMimeTypes ?? [],\n ),\n onDrop: handleFileDrop,\n })\n</script>\n\n<template>\n <div\n ref=\"chatViewEl\"\n class=\"pk-chatbot-view-chat\"\n :class=\"{\n 'pk-chatbot-view-chat--dragover':\n isOverDropZone && agentFileUpload?.enabled,\n }\">\n <!-- #region messages -->\n <PkChatbotMessages\n class=\"flex flex-col flex-1 min-h-0 p-md overflow-y-auto\"\n :name=\"name\"\n :messages=\"messages\"\n :status=\"chat.status\"\n :error=\"chat.error\"\n :main-color=\"agentInterface?.mainColor\"\n :text-color=\"agentInterface?.textColor\"\n :revised-answers=\"revisedAnswers\"\n :actions=\"actions\"\n :logo=\"agentInterface?.logo\"\n :message-feedbacks=\"messageFeedbacks\"\n :feedback-message-id=\"feedbackDialogMessage?.id\"\n :feedback-loading=\"isFeedbackSubmitting\"\n :feedback-submitted=\"isFeedbackSubmitted\"\n :feedback-error=\"feedbackSubmitError\"\n @feedback-submit=\"onFeedbackSubmit($event)\"\n @feedback-close=\"feedbackDialogMessage = undefined\"\n @regenerate=\"regenerate\"\n @auto-retry=\"regenerate\"\n @reset-chat=\"startNewChat\"\n @show-info=\"emit('show-info', $event)\"\n @revise=\"emit('revise', $event)\"\n @upvote=\"onUpvote\"\n @downvote=\"onDownvote\"\n @feedback=\"onFeedback\">\n <template #tool-showContactForm=\"{ part }\">\n <PkToolShowContactForm\n :part\n :readonly=\"!baseUrl\"\n :submitted=\"isLeadSubmitted\"\n :loading=\"isLoadingSubmitLead\"\n :error=\"submitLeadError\"\n :privacy-policy-notice=\"agentInterface?.privacyPolicyNotice\"\n @submit=\"onLeadSubmit\" />\n </template>\n <template #tool-showSuggestedReply=\"{ part }\">\n <PkToolShowSuggestedReply\n :part\n @select=\"\n ($event) => {\n input = $event\n storeHandleSubmit()\n }\n \" />\n </template>\n <template #tool-showSources=\"{ part }\">\n <PkToolShowSources\n :part\n :on-expand-context=\"handleExpandSourceContext\"\n :on-download=\"handleDownloadSource\" />\n </template>\n <template #tool-showMultipleChoice=\"{ part }\">\n <transition mode=\"out-in\">\n <PkToolShowMultipleChoice\n :part\n @select=\"\n addToolOutput({\n tool: 'showMultipleChoice',\n toolCallId: (part as any).toolCallId,\n output: $event,\n })\n \" />\n </transition>\n </template>\n <template #tool-requestGeolocation=\"{ part }\">\n <PkToolRequestGeolocation\n :part\n :reverse-geocode=\"\n (lat: number, lon: number) =>\n apiClient.reverseGeocode(lat, lon)\n \"\n @result=\"\n addToolOutput({\n tool: 'requestGeolocation',\n toolCallId: (part as any).toolCallId,\n output: $event,\n })\n \" />\n </template>\n </PkChatbotMessages>\n <!-- #endregion -->\n\n <!-- #region input -->\n <div\n v-if=\"isConversationBlocked\"\n class=\"p-md border-t border-surface-3 text-center text-12 text-danger-darken-2 bg-surface-danger\">\n {{ $t('message.chatErrorConversationBlocked') }}\n </div>\n <PkChatbotInput\n v-else\n v-model=\"input\"\n v-model:pending-attachments=\"pendingAttachments\"\n :placeholder=\"inputMessagePlaceholder\"\n :dismissable-notice=\"\n dismissableNotice && chat.messages.length <= 1\n ? dismissableNotice\n : undefined\n \"\n :status=\"chat.status\"\n :max-message-length=\"agentInterface?.maxMessageLength\"\n :file-upload=\"agentFileUpload\"\n @stop-generation=\"stopGeneration\"\n @submit=\"storeHandleSubmit\"\n @file-select=\"handleFileSelect\" />\n <!-- #endregion -->\n <Transition>\n <div\n v-if=\"isOverDropZone && agentFileUpload?.enabled\"\n class=\"pk-chatbot-view-chat__drop-overlay\">\n <VvIcon\n name=\"ri:upload-cloud-2-line\"\n class=\"pk-chatbot-view-chat__drop-overlay-icon\" />\n <span>{{ $t('action.dropFile') }}</span>\n </div>\n </Transition>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-view-chat {\n position: relative;\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n\n &__drop-overlay {\n position: absolute;\n inset: var(--spacing-sm) var(--spacing-sm) var(--spacing-sm)\n var(--spacing-sm);\n z-index: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--spacing-xs);\n background-color: color-mix(\n in srgb,\n var(--color-surface) 85%,\n transparent\n );\n border-radius: var(--rounded-xl);\n border: var(--spacing-2) dashed var(--color-surface-5);\n pointer-events: none;\n color: var(--color-word-3);\n\n &-icon {\n font-size: var(--spacing-32);\n }\n }\n }\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"PkChatbotViewChat-EWotdJkz.js","names":["$t","$n","$t"],"sources":["../../../../packages/models/src/schema/Header.ts","../../../../packages/models/src/schema/Document.ts","../../../../packages/components/src/chat/PkToolShowMultipleChoice.vue","../../../../packages/components/src/chat/PkToolShowMultipleChoice.vue","../../../../packages/components/src/composables/useLocalizedString.ts","../../../../packages/components/src/chat/PkToolShowContactForm.vue","../../../../packages/components/src/chat/PkToolShowContactForm.vue","../../../../packages/components/src/chat/PkToolShowSuggestedReply.vue","../../../../packages/components/src/chat/PkToolShowSuggestedReply.vue","../../../../packages/components/src/chat/PkChunkPreview.vue","../../../../packages/components/src/chat/PkChunkPreview.vue","../../../../packages/components/src/chat/PkDocumentHeader.vue","../../../../packages/components/src/chat/PkDocumentHeader.vue","../../../../packages/components/src/chat/PkToolShowSources.vue","../../../../packages/components/src/chat/PkToolShowSources.vue","../../../../packages/components/src/chat/PkToolRequestGeolocation.vue","../../../../packages/components/src/chat/PkToolRequestGeolocation.vue","../../../../packages/components/src/chat/PkChatbotViewChat.vue","../../../../packages/components/src/chat/PkChatbotViewChat.vue"],"sourcesContent":["import * as z from 'zod'\n\nexport const HeaderSchema = z.object({\n key: z.string().optional(),\n value: z.string().optional(),\n})\n\nexport const HeadesSchema = z.array(HeaderSchema).transform((headers) => {\n return 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","import * as z from 'zod'\nimport { zodQs } 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.enum(BrowserEngine).optional(),\n headers: HeadesSchema.nullish(),\n})\n\nexport type ConversionOptions = z.infer<typeof ConversionOptionsSchema>\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 documents only) ===\n source: z\n .object({\n url: z.string(),\n lastScrapedAt: z.string(),\n })\n .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: z\n .union([z.number(), z.array(z.unknown())])\n .transform((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 // === 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})\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})\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']),\n ...zodQs.filters(['type', 'language', 'agentId', 'indexStatus']),\n ...zodQs.fullText(),\n ...zodQs.ids(),\n 'filter[similarity]': 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 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 })\n .superRefine((data, ctx) => {\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 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 agentIds: z.array(z.string()).min(1).optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\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>\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","<script setup lang=\"ts\">\n import { computed } from 'vue'\n\n type LegacyOption = { id: string; label: string; value: string }\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const emit = defineEmits<{\n select: [option: string]\n }>()\n\n const toolPart = computed(() => {\n return JSON.parse(JSON.stringify(props.part)) as {\n state?: string\n toolCallId?: string\n input?: {\n question: string\n options: string[] | LegacyOption[]\n }\n output?: string | LegacyOption\n }\n })\n\n /** Normalize options to string[] (supports legacy { label } objects) */\n const normalizedOptions = computed(() => {\n return (toolPart.value?.input?.options ?? []).map((o) =>\n typeof o === 'string' ? o : o.label,\n )\n })\n\n /** Normalize output to string (supports legacy { label } objects) */\n const normalizedOutput = computed(() => {\n const out = toolPart.value?.output\n if (!out) {\n return undefined\n }\n return typeof out === 'string' ? out : out.label\n })\n\n const toolState = computed(() => {\n return toolPart.value?.state || 'unknown'\n })\n\n const isInteractive = computed(() => {\n return toolState.value === 'input-available'\n })\n</script>\n\n<template>\n <div\n v-if=\"normalizedOptions.length\"\n :key=\"toolState\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-10 font-bold bg-surface-1 text-12 border-b border-surface-3 text-word-3\">\n {{ toolPart.input?.question }}\n </div>\n <div class=\"px-sm py-10\">\n <VvButtonGroup\n :key=\"normalizedOptions.length\"\n modifiers=\"vertical\"\n class=\"w-full\">\n <VvButton\n v-for=\"(option, index) in normalizedOptions\"\n :key=\"index\"\n modifiers=\"action-multiline\"\n class=\"whitespace-normal w-full\"\n :class=\"{\n pressed: option === normalizedOutput,\n }\"\n :disabled=\"!isInteractive\"\n :label=\"option\"\n @click.stop=\"emit('select', option)\" />\n </VvButtonGroup>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed } from 'vue'\n\n type LegacyOption = { id: string; label: string; value: string }\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const emit = defineEmits<{\n select: [option: string]\n }>()\n\n const toolPart = computed(() => {\n return JSON.parse(JSON.stringify(props.part)) as {\n state?: string\n toolCallId?: string\n input?: {\n question: string\n options: string[] | LegacyOption[]\n }\n output?: string | LegacyOption\n }\n })\n\n /** Normalize options to string[] (supports legacy { label } objects) */\n const normalizedOptions = computed(() => {\n return (toolPart.value?.input?.options ?? []).map((o) =>\n typeof o === 'string' ? o : o.label,\n )\n })\n\n /** Normalize output to string (supports legacy { label } objects) */\n const normalizedOutput = computed(() => {\n const out = toolPart.value?.output\n if (!out) {\n return undefined\n }\n return typeof out === 'string' ? out : out.label\n })\n\n const toolState = computed(() => {\n return toolPart.value?.state || 'unknown'\n })\n\n const isInteractive = computed(() => {\n return toolState.value === 'input-available'\n })\n</script>\n\n<template>\n <div\n v-if=\"normalizedOptions.length\"\n :key=\"toolState\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-10 font-bold bg-surface-1 text-12 border-b border-surface-3 text-word-3\">\n {{ toolPart.input?.question }}\n </div>\n <div class=\"px-sm py-10\">\n <VvButtonGroup\n :key=\"normalizedOptions.length\"\n modifiers=\"vertical\"\n class=\"w-full\">\n <VvButton\n v-for=\"(option, index) in normalizedOptions\"\n :key=\"index\"\n modifiers=\"action-multiline\"\n class=\"whitespace-normal w-full\"\n :class=\"{\n pressed: option === normalizedOutput,\n }\"\n :disabled=\"!isInteractive\"\n :label=\"option\"\n @click.stop=\"emit('select', option)\" />\n </VvButtonGroup>\n </div>\n </div>\n</template>\n","import { computed, toValue, type ComputedRef, type MaybeRefOrGetter } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport type { LocalizedString } from 'models'\n\nexport function useLocalizedString(\n value: MaybeRefOrGetter<LocalizedString | undefined>,\n fallbackKey: string,\n): ComputedRef<string>\nexport function useLocalizedString(\n value: MaybeRefOrGetter<LocalizedString | undefined>,\n): ComputedRef<string | undefined>\nexport function useLocalizedString(\n value: MaybeRefOrGetter<LocalizedString | undefined>,\n fallbackKey?: string,\n): ComputedRef<string | undefined> {\n const { locale, t, te } = useI18n({ useScope: 'global' })\n\n return computed(() => {\n const val = toValue(value)\n const fb =\n fallbackKey !== undefined && te(fallbackKey)\n ? t(fallbackKey)\n : undefined\n\n if (!val) {\n return fb\n }\n\n return val[locale.value] || fb\n })\n}\n","<script setup lang=\"ts\">\n import { computed, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { useForm } from '@volverjs/form-vue'\n import * as z from 'zod'\n import { useLocalStorage } from '@vueuse/core'\n import type { LocalizedString } from 'models'\n import { useLocalizedString } from '../composables/useLocalizedString'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const props = defineProps<{\n part: unknown\n submitted?: boolean\n loading?: boolean\n error?: string\n readonly?: boolean\n privacyPolicyNotice?: LocalizedString\n }>()\n\n const toolPart = computed(() => {\n const part = props.part as {\n type: string\n toolCallId: string\n input?: {\n name: string\n email: string\n phone?: string\n conversationContext?: Record<string, unknown>\n }\n }\n return part\n })\n\n const input = computed(() => toolPart.value.input)\n\n const localSubmitted = useLocalStorage<boolean>(\n computed(\n () =>\n `${toolPart.value.toolCallId}-${toolPart.value.type}-submitted`,\n ),\n false,\n )\n\n const LeadFormSchema = z.object({\n name: z.string().min(1).max(255).default(''),\n email: z.email().max(255).default(''),\n phone: z\n .string()\n .max(50)\n .regex(/^[+0-9\\s\\-.()]*$/, $t('validation.invalidPhoneNumber'))\n .optional(),\n })\n\n const emit = defineEmits<{\n submit: [data: Record<string, unknown>]\n }>()\n\n const { VvForm, VvFormField, formData } = useForm(LeadFormSchema, {\n lazyLoad: true,\n })\n\n // Pre-populate form with input values\n watch(\n input,\n (newInput) => {\n formData.value = {\n name: newInput?.name || '',\n email: newInput?.email || '',\n phone: newInput?.phone || '',\n }\n },\n { immediate: true },\n )\n\n watch(\n () => props.submitted,\n (submitted) => {\n if (submitted) {\n localSubmitted.value = true\n }\n },\n { immediate: true },\n )\n\n const isSubmitted = computed(() => {\n return props.submitted || localSubmitted.value\n })\n\n const submitLead = async (data: Record<string, unknown>): Promise<void> => {\n emit('submit', { ...data, metadata: input.value?.conversationContext })\n }\n\n const privacyNotice = useLocalizedString(\n () => props.privacyPolicyNotice,\n 'message.defaultPrivacyPolicyNotice',\n )\n</script>\n\n<template>\n <div class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8 min-h-40\">\n <VvIcon name=\"ri:send-plane-2-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{ $t('label.contactUs') }}</strong>\n </div>\n\n <Transition mode=\"out-in\">\n <div v-if=\"!isSubmitted\" class=\"p-sm\">\n <VvForm v-model=\"formData\" :readonly @submit=\"submitLead\">\n <VvFormField\n name=\"name\"\n type=\"text\"\n :label=\"$t('label.name')\"\n :placeholder=\"$t('placeholder.name')\"\n icon=\"ri:user-line\"\n modifiers=\"compact no-label\"\n class=\"mb-md\" />\n <VvFormField\n name=\"email\"\n type=\"email\"\n :label=\"$t('label.email')\"\n :placeholder=\"$t('placeholder.email')\"\n icon=\"ri:mail-line\"\n modifiers=\"compact no-label\"\n class=\"mb-md\" />\n <VvFormField\n name=\"phone\"\n type=\"tel\"\n :label=\"$t('label.phone')\"\n :placeholder=\"$t('placeholder.phone')\"\n icon=\"ri:phone-line\"\n class=\"mb-md\"\n modifiers=\"compact no-label\" />\n\n <div class=\"flex justify-between items-center gap-16 mt-xs\">\n <div\n class=\"text-smaller text-word-3 flex items-center gap-8\">\n <VvIcon\n name=\"ri:shield-check-line\"\n class=\"text-16 shrink-0\" />\n <PkStreamingMarkdown\n :markdown=\"privacyNotice\"\n class=\"wysiwyg\" />\n </div>\n <VvButton\n type=\"submit\"\n modifiers=\"primary\"\n :loading\n :disabled=\"loading || readonly\"\n icon-position=\"right\"\n class=\"shrink-0\"\n :label=\"$t('action.submit')\" />\n </div>\n </VvForm>\n </div>\n <div v-else class=\"p-sm\">\n <div class=\"flex items-center gap-sm\">\n <VvIcon\n name=\"ri:mail-check-line\"\n class=\"text-24 text-success\" />\n <div>\n <strong class=\"font-semibold block text-success\">\n {{ $t('message.leadSubmittedTitle') }}\n </strong>\n <p class=\"text-word-3\">\n {{ $t('message.leadSubmittedMessage') }}\n </p>\n </div>\n </div>\n </div>\n </Transition>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { useForm } from '@volverjs/form-vue'\n import * as z from 'zod'\n import { useLocalStorage } from '@vueuse/core'\n import type { LocalizedString } from 'models'\n import { useLocalizedString } from '../composables/useLocalizedString'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const props = defineProps<{\n part: unknown\n submitted?: boolean\n loading?: boolean\n error?: string\n readonly?: boolean\n privacyPolicyNotice?: LocalizedString\n }>()\n\n const toolPart = computed(() => {\n const part = props.part as {\n type: string\n toolCallId: string\n input?: {\n name: string\n email: string\n phone?: string\n conversationContext?: Record<string, unknown>\n }\n }\n return part\n })\n\n const input = computed(() => toolPart.value.input)\n\n const localSubmitted = useLocalStorage<boolean>(\n computed(\n () =>\n `${toolPart.value.toolCallId}-${toolPart.value.type}-submitted`,\n ),\n false,\n )\n\n const LeadFormSchema = z.object({\n name: z.string().min(1).max(255).default(''),\n email: z.email().max(255).default(''),\n phone: z\n .string()\n .max(50)\n .regex(/^[+0-9\\s\\-.()]*$/, $t('validation.invalidPhoneNumber'))\n .optional(),\n })\n\n const emit = defineEmits<{\n submit: [data: Record<string, unknown>]\n }>()\n\n const { VvForm, VvFormField, formData } = useForm(LeadFormSchema, {\n lazyLoad: true,\n })\n\n // Pre-populate form with input values\n watch(\n input,\n (newInput) => {\n formData.value = {\n name: newInput?.name || '',\n email: newInput?.email || '',\n phone: newInput?.phone || '',\n }\n },\n { immediate: true },\n )\n\n watch(\n () => props.submitted,\n (submitted) => {\n if (submitted) {\n localSubmitted.value = true\n }\n },\n { immediate: true },\n )\n\n const isSubmitted = computed(() => {\n return props.submitted || localSubmitted.value\n })\n\n const submitLead = async (data: Record<string, unknown>): Promise<void> => {\n emit('submit', { ...data, metadata: input.value?.conversationContext })\n }\n\n const privacyNotice = useLocalizedString(\n () => props.privacyPolicyNotice,\n 'message.defaultPrivacyPolicyNotice',\n )\n</script>\n\n<template>\n <div class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8 min-h-40\">\n <VvIcon name=\"ri:send-plane-2-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{ $t('label.contactUs') }}</strong>\n </div>\n\n <Transition mode=\"out-in\">\n <div v-if=\"!isSubmitted\" class=\"p-sm\">\n <VvForm v-model=\"formData\" :readonly @submit=\"submitLead\">\n <VvFormField\n name=\"name\"\n type=\"text\"\n :label=\"$t('label.name')\"\n :placeholder=\"$t('placeholder.name')\"\n icon=\"ri:user-line\"\n modifiers=\"compact no-label\"\n class=\"mb-md\" />\n <VvFormField\n name=\"email\"\n type=\"email\"\n :label=\"$t('label.email')\"\n :placeholder=\"$t('placeholder.email')\"\n icon=\"ri:mail-line\"\n modifiers=\"compact no-label\"\n class=\"mb-md\" />\n <VvFormField\n name=\"phone\"\n type=\"tel\"\n :label=\"$t('label.phone')\"\n :placeholder=\"$t('placeholder.phone')\"\n icon=\"ri:phone-line\"\n class=\"mb-md\"\n modifiers=\"compact no-label\" />\n\n <div class=\"flex justify-between items-center gap-16 mt-xs\">\n <div\n class=\"text-smaller text-word-3 flex items-center gap-8\">\n <VvIcon\n name=\"ri:shield-check-line\"\n class=\"text-16 shrink-0\" />\n <PkStreamingMarkdown\n :markdown=\"privacyNotice\"\n class=\"wysiwyg\" />\n </div>\n <VvButton\n type=\"submit\"\n modifiers=\"primary\"\n :loading\n :disabled=\"loading || readonly\"\n icon-position=\"right\"\n class=\"shrink-0\"\n :label=\"$t('action.submit')\" />\n </div>\n </VvForm>\n </div>\n <div v-else class=\"p-sm\">\n <div class=\"flex items-center gap-sm\">\n <VvIcon\n name=\"ri:mail-check-line\"\n class=\"text-24 text-success\" />\n <div>\n <strong class=\"font-semibold block text-success\">\n {{ $t('message.leadSubmittedTitle') }}\n </strong>\n <p class=\"text-word-3\">\n {{ $t('message.leadSubmittedMessage') }}\n </p>\n </div>\n </div>\n </div>\n </Transition>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, ref } from 'vue'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const emit = defineEmits<{\n select: [value: string]\n }>()\n\n const toolPart = computed(() => {\n return JSON.parse(JSON.stringify(props.part)) as {\n state?: string\n toolCallId?: string\n input?: {\n label: string\n prompt?: string\n }\n output?: string\n }\n })\n\n const clicked = ref(false)\n\n const isInteractive = computed(() => {\n return toolPart.value?.state === 'input-available' && !clicked.value\n })\n\n function handleClick() {\n if (!isInteractive.value) {\n return\n }\n clicked.value = true\n const value =\n toolPart.value?.input?.prompt ?? toolPart.value?.input?.label\n if (value) {\n emit('select', value)\n }\n }\n</script>\n\n<template>\n <div v-if=\"toolPart.input?.label\" class=\"pk-tool-suggested-reply\">\n <button\n type=\"button\"\n class=\"pk-tool-suggested-reply__link\"\n :class=\"{ 'is-clicked': clicked, 'is-disabled': !isInteractive }\"\n :disabled=\"!isInteractive\"\n @click.stop=\"handleClick\">\n <VvIcon\n name=\"ri:corner-down-right-line\"\n class=\"pk-tool-suggested-reply__icon\" />\n <span>{{ toolPart.input.label }}</span>\n </button>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-tool-suggested-reply {\n display: flex;\n align-items: center;\n\n &__link {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n background: none;\n border: none;\n padding: 0;\n font: inherit;\n font-size: 0.875em;\n text-decoration: underline;\n text-underline-offset: 2px;\n cursor: pointer;\n transition: opacity 0.15s ease;\n color: var(--color-word-3);\n transition: var(--transition-colors);\n\n &:hover:not(:disabled) {\n color: var(--color-word);\n }\n\n &.is-disabled {\n cursor: default;\n pointer-events: none;\n color: var(--color-word-5);\n }\n\n &.is-clicked {\n color: var(--color-word-5);\n text-decoration: none;\n }\n }\n\n &__icon {\n width: 1em;\n height: 1em;\n flex-shrink: 0;\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, ref } from 'vue'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const emit = defineEmits<{\n select: [value: string]\n }>()\n\n const toolPart = computed(() => {\n return JSON.parse(JSON.stringify(props.part)) as {\n state?: string\n toolCallId?: string\n input?: {\n label: string\n prompt?: string\n }\n output?: string\n }\n })\n\n const clicked = ref(false)\n\n const isInteractive = computed(() => {\n return toolPart.value?.state === 'input-available' && !clicked.value\n })\n\n function handleClick() {\n if (!isInteractive.value) {\n return\n }\n clicked.value = true\n const value =\n toolPart.value?.input?.prompt ?? toolPart.value?.input?.label\n if (value) {\n emit('select', value)\n }\n }\n</script>\n\n<template>\n <div v-if=\"toolPart.input?.label\" class=\"pk-tool-suggested-reply\">\n <button\n type=\"button\"\n class=\"pk-tool-suggested-reply__link\"\n :class=\"{ 'is-clicked': clicked, 'is-disabled': !isInteractive }\"\n :disabled=\"!isInteractive\"\n @click.stop=\"handleClick\">\n <VvIcon\n name=\"ri:corner-down-right-line\"\n class=\"pk-tool-suggested-reply__icon\" />\n <span>{{ toolPart.input.label }}</span>\n </button>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-tool-suggested-reply {\n display: flex;\n align-items: center;\n\n &__link {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n background: none;\n border: none;\n padding: 0;\n font: inherit;\n font-size: 0.875em;\n text-decoration: underline;\n text-underline-offset: 2px;\n cursor: pointer;\n transition: opacity 0.15s ease;\n color: var(--color-word-3);\n transition: var(--transition-colors);\n\n &:hover:not(:disabled) {\n color: var(--color-word);\n }\n\n &.is-disabled {\n cursor: default;\n pointer-events: none;\n color: var(--color-word-5);\n }\n\n &.is-clicked {\n color: var(--color-word-5);\n text-decoration: none;\n }\n }\n\n &__icon {\n width: 1em;\n height: 1em;\n flex-shrink: 0;\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { stripMarkdown } from 'utils'\n\n const props = defineProps<{\n content: string\n similarity?: number\n maxSimilarity?: number\n expanded: boolean\n }>()\n\n const similarityPercent = computed(() => {\n if (props.similarity == null) {\n return null\n }\n const max =\n props.maxSimilarity && props.maxSimilarity > 0\n ? props.maxSimilarity\n : 1\n return Math.round((props.similarity / max) * 100)\n })\n</script>\n\n<template>\n <VvIcon name=\"ri:text-snippet\" class=\"shrink-0 text-12 text-word-4\" />\n <span class=\"text-10 text-word-2 truncate flex-1\" :title=\"content\">\n {{ stripMarkdown(content) }}\n </span>\n <span v-if=\"similarityPercent != null\" class=\"text-10 text-word-4 shrink-0\">\n {{ similarityPercent }}%\n </span>\n <VvIcon\n :name=\"expanded ? 'ri:arrow-up-s-line' : 'ri:arrow-down-s-line'\"\n class=\"text-14 text-word-4 shrink-0\" />\n</template>\n","<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { stripMarkdown } from 'utils'\n\n const props = defineProps<{\n content: string\n similarity?: number\n maxSimilarity?: number\n expanded: boolean\n }>()\n\n const similarityPercent = computed(() => {\n if (props.similarity == null) {\n return null\n }\n const max =\n props.maxSimilarity && props.maxSimilarity > 0\n ? props.maxSimilarity\n : 1\n return Math.round((props.similarity / max) * 100)\n })\n</script>\n\n<template>\n <VvIcon name=\"ri:text-snippet\" class=\"shrink-0 text-12 text-word-4\" />\n <span class=\"text-10 text-word-2 truncate flex-1\" :title=\"content\">\n {{ stripMarkdown(content) }}\n </span>\n <span v-if=\"similarityPercent != null\" class=\"text-10 text-word-4 shrink-0\">\n {{ similarityPercent }}%\n </span>\n <VvIcon\n :name=\"expanded ? 'ri:arrow-up-s-line' : 'ri:arrow-down-s-line'\"\n class=\"text-14 text-word-4 shrink-0\" />\n</template>\n","<script setup lang=\"ts\">\n import type { DocumentType } from 'models'\n import { getTypeIcon } from 'models'\n import PkUrl from '../PkUrl.vue'\n\n defineProps<{\n type: string\n name: string\n url?: string\n filename?: string\n }>()\n</script>\n\n<template>\n <VvIcon\n :name=\"getTypeIcon(type as DocumentType)\"\n class=\"shrink-0 text-14 text-word-3\" />\n <div class=\"flex flex-col gap-2 min-w-0 flex-1\">\n <strong class=\"font-bold text-12 text-word-1 truncate block\">\n {{ name }}\n </strong>\n <span v-if=\"filename\" class=\"text-10 text-word-4 truncate\">\n {{ filename }}\n </span>\n <span\n v-if=\"url\"\n class=\"text-10 text-word-4 truncate flex items-center gap-4\">\n <VvIcon name=\"ri:link\" class=\"shrink-0 text-10\" />\n <PkUrl :url=\"url\" />\n </span>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import type { DocumentType } from 'models'\n import { getTypeIcon } from 'models'\n import PkUrl from '../PkUrl.vue'\n\n defineProps<{\n type: string\n name: string\n url?: string\n filename?: string\n }>()\n</script>\n\n<template>\n <VvIcon\n :name=\"getTypeIcon(type as DocumentType)\"\n class=\"shrink-0 text-14 text-word-3\" />\n <div class=\"flex flex-col gap-2 min-w-0 flex-1\">\n <strong class=\"font-bold text-12 text-word-1 truncate block\">\n {{ name }}\n </strong>\n <span v-if=\"filename\" class=\"text-10 text-word-4 truncate\">\n {{ filename }}\n </span>\n <span\n v-if=\"url\"\n class=\"text-10 text-word-4 truncate flex items-center gap-4\">\n <VvIcon name=\"ri:link\" class=\"shrink-0 text-10\" />\n <PkUrl :url=\"url\" />\n </span>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, ref, reactive } from 'vue'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n import PkChunkPreview from './PkChunkPreview.vue'\n import PkDocumentHeader from './PkDocumentHeader.vue'\n\n interface SourceItem {\n chunkId: string\n documentId: string\n documentName: string\n documentType: string\n language: string\n content: string\n chunkIndex?: number | null\n similarity?: number\n sourceUrl?: string\n sourceFilename?: string\n sourceDescription?: string\n sourceImageUrl?: string\n }\n\n const props = defineProps<{\n part: unknown\n onExpandContext?: (payload: {\n documentId: string\n chunkIndex: number\n }) => Promise<string>\n onDownload?: (documentId: string) => void\n }>()\n\n const toolPart = computed(() => {\n return props.part as {\n input?: {\n sources: SourceItem[]\n }\n }\n })\n\n const sources = computed(() => toolPart.value.input?.sources || [])\n\n const groupedSources = computed(() => {\n const groups = new Map<\n string,\n { document: SourceItem; chunks: SourceItem[] }\n >()\n for (const source of sources.value) {\n const existing = groups.get(source.documentId)\n if (existing) {\n existing.chunks.push(source)\n } else {\n groups.set(source.documentId, {\n document: source,\n chunks: [source],\n })\n }\n }\n return [...groups.values()]\n })\n\n const maxSimilarity = computed(() => {\n return Math.max(...sources.value.map((s) => s.similarity ?? 0), 0)\n })\n\n const expandedDocuments = reactive(new Set<string>())\n const expandedChunks = reactive(new Set<string>())\n const contextData = reactive(new Map<string, string>())\n const loadingContext = reactive(new Set<string>())\n\n const toggleDocument = (documentId: string) => {\n if (expandedDocuments.has(documentId)) {\n expandedDocuments.delete(documentId)\n } else {\n expandedDocuments.add(documentId)\n }\n }\n\n const toggleChunk = (chunkId: string) => {\n if (expandedChunks.has(chunkId)) {\n expandedChunks.delete(chunkId)\n } else {\n expandedChunks.add(chunkId)\n }\n }\n\n const handleExpandContext = async (source: SourceItem) => {\n if (source.chunkIndex == null || !props.onExpandContext) {\n return\n }\n loadingContext.add(source.chunkId)\n try {\n const content = await props.onExpandContext({\n documentId: source.documentId,\n chunkIndex: source.chunkIndex,\n })\n contextData.set(source.chunkId, content)\n } finally {\n loadingContext.delete(source.chunkId)\n }\n }\n\n const clearContext = (chunkId: string) => {\n contextData.delete(chunkId)\n }\n\n const showMore = ref(false)\n const visibleGroups = computed(() => {\n if (showMore.value) {\n return groupedSources.value\n }\n return groupedSources.value.slice(0, 3)\n })\n const hasMore = computed(() => groupedSources.value.length > 3)\n</script>\n\n<template>\n <div v-if=\"sources.length\" class=\"flex flex-col gap-xs w-full\">\n <div class=\"flex items-center gap-4 text-12 text-word-3 font-semibold\">\n <VvIcon name=\"ri:article-line\" class=\"text-14\" />\n {{ $t('label.sources') }}\n <span class=\"text-word-4 font-normal\">\n ({{ groupedSources.length }})\n </span>\n </div>\n\n <ul class=\"flex flex-col gap-xs\">\n <li\n v-for=\"group in visibleGroups\"\n :key=\"group.document.documentId\"\n class=\"border border-surface-3 rounded-lg overflow-hidden\">\n <!-- Document header -->\n <button\n class=\"flex items-center gap-8 p-8 w-full text-left hover:bg-surface-1 transition-colors cursor-pointer\"\n @click=\"toggleDocument(group.document.documentId)\">\n <PkDocumentHeader\n :type=\"group.document.documentType\"\n :name=\"group.document.documentName\"\n :url=\"group.document.sourceUrl\"\n :filename=\"group.document.sourceFilename\" />\n <div class=\"flex items-center gap-4 shrink-0\">\n <span\n v-if=\"group.chunks.length > 1\"\n class=\"text-10 text-word-4 bg-surface-2 rounded px-4 py-2\">\n {{ group.chunks.length }}\n </span>\n <span\n class=\"text-10 text-word-4 bg-surface-2 rounded px-4 py-2 uppercase\">\n {{ group.document.language }}\n </span>\n <VvIcon\n :name=\"\n expandedDocuments.has(group.document.documentId)\n ? 'ri:arrow-up-s-line'\n : 'ri:arrow-down-s-line'\n \"\n class=\"text-16 text-word-3\" />\n </div>\n </button>\n\n <!-- Expanded content -->\n <div\n v-if=\"expandedDocuments.has(group.document.documentId)\"\n class=\"border-t border-surface-3\">\n <PkStreamingMarkdown\n v-if=\"group.document.sourceDescription\"\n :markdown=\"group.document.sourceDescription\"\n class=\"px-8 py-4 text-10 text-word-3 bg-surface-1 border-b border-surface-3\" />\n\n <!-- Chunk excerpts -->\n <div\n v-for=\"chunk in group.chunks\"\n :key=\"chunk.chunkId\"\n class=\"border-b border-surface-3 last:border-b-0\">\n <button\n class=\"flex items-center gap-8 px-8 py-6 w-full text-left hover:bg-surface-1 transition-colors cursor-pointer\"\n @click=\"toggleChunk(chunk.chunkId)\">\n <PkChunkPreview\n :content=\"chunk.content\"\n :similarity=\"chunk.similarity\"\n :max-similarity=\"maxSimilarity\"\n :expanded=\"expandedChunks.has(chunk.chunkId)\" />\n </button>\n\n <!-- Expanded chunk content -->\n <div\n v-if=\"expandedChunks.has(chunk.chunkId)\"\n class=\"bg-surface-1 border-t border-surface-3\">\n <div class=\"p-8 text-10 text-word-3\">\n <transition mode=\"out-in\">\n <!-- Context expansion -->\n <PkStreamingMarkdown\n v-if=\"contextData.has(chunk.chunkId)\"\n :markdown=\"\n contextData.get(chunk.chunkId)!\n \"\n class=\"wysiwyg\" />\n\n <!-- Chunk content -->\n <PkStreamingMarkdown\n v-else\n :markdown=\"chunk.content\"\n class=\"wysiwyg\" />\n </transition>\n </div>\n\n <!-- Actions bar -->\n <div\n class=\"flex items-center gap-8 px-8 py-6 border-t border-surface-3 bg-surface\">\n <!-- Expand / collapse context -->\n <button\n v-if=\"\n onExpandContext &&\n chunk.chunkIndex != null &&\n !contextData.has(chunk.chunkId)\n \"\n class=\"text-10 text-word-3 hover:text-word flex items-center gap-4 cursor-pointer\"\n :disabled=\"\n loadingContext.has(chunk.chunkId)\n \"\n @click=\"handleExpandContext(chunk)\">\n <VvIcon\n :name=\"\n loadingContext.has(chunk.chunkId)\n ? 'line-md:loading-loop'\n : 'ri:expand-up-down-line'\n \"\n class=\"text-12\" />\n {{ $t('label.expandContext') }}\n </button>\n <button\n v-else-if=\"contextData.has(chunk.chunkId)\"\n class=\"text-10 text-word-3 hover:text-word-1 flex items-center gap-4 cursor-pointer\"\n @click=\"clearContext(chunk.chunkId)\">\n <VvIcon\n name=\"ri:collapse-vertical-line\"\n class=\"text-12\" />\n {{ $t('label.collapseContext') }}\n </button>\n\n <!-- Open source URL -->\n <a\n v-if=\"chunk.sourceUrl\"\n :href=\"chunk.sourceUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"text-10 text-word-3 hover:text-word-1 flex items-center gap-4 ml-auto\">\n <VvIcon\n name=\"ri:external-link-line\"\n class=\"text-12\" />\n {{ $t('label.openSource') }}\n </a>\n\n <!-- Download file -->\n <button\n v-if=\"\n onDownload &&\n chunk.documentType === 'file'\n \"\n class=\"text-10 text-word-3 hover:text-word-1 flex items-center gap-4 cursor-pointer\"\n :class=\"{\n 'ml-auto': !chunk.sourceUrl,\n }\"\n @click=\"onDownload(chunk.documentId)\">\n <VvIcon\n name=\"ri:download-line\"\n class=\"text-12\" />\n {{ $t('label.downloadFile') }}\n </button>\n </div>\n </div>\n </div>\n </div>\n </li>\n </ul>\n\n <!-- Show more -->\n <button\n v-if=\"hasMore\"\n class=\"text-12 text-word-3 cursor-pointer hover:underline flex items-center gap-4 mx-auto\"\n @click=\"showMore = !showMore\">\n <VvIcon\n :name=\"showMore ? 'ri:arrow-up-s-line' : 'ri:arrow-down-s-line'\"\n class=\"text-16\" />\n {{\n showMore\n ? $t('action.showLess')\n : $t('action.showMore', {\n count: groupedSources.length - 3,\n })\n }}\n </button>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, ref, reactive } from 'vue'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n import PkChunkPreview from './PkChunkPreview.vue'\n import PkDocumentHeader from './PkDocumentHeader.vue'\n\n interface SourceItem {\n chunkId: string\n documentId: string\n documentName: string\n documentType: string\n language: string\n content: string\n chunkIndex?: number | null\n similarity?: number\n sourceUrl?: string\n sourceFilename?: string\n sourceDescription?: string\n sourceImageUrl?: string\n }\n\n const props = defineProps<{\n part: unknown\n onExpandContext?: (payload: {\n documentId: string\n chunkIndex: number\n }) => Promise<string>\n onDownload?: (documentId: string) => void\n }>()\n\n const toolPart = computed(() => {\n return props.part as {\n input?: {\n sources: SourceItem[]\n }\n }\n })\n\n const sources = computed(() => toolPart.value.input?.sources || [])\n\n const groupedSources = computed(() => {\n const groups = new Map<\n string,\n { document: SourceItem; chunks: SourceItem[] }\n >()\n for (const source of sources.value) {\n const existing = groups.get(source.documentId)\n if (existing) {\n existing.chunks.push(source)\n } else {\n groups.set(source.documentId, {\n document: source,\n chunks: [source],\n })\n }\n }\n return [...groups.values()]\n })\n\n const maxSimilarity = computed(() => {\n return Math.max(...sources.value.map((s) => s.similarity ?? 0), 0)\n })\n\n const expandedDocuments = reactive(new Set<string>())\n const expandedChunks = reactive(new Set<string>())\n const contextData = reactive(new Map<string, string>())\n const loadingContext = reactive(new Set<string>())\n\n const toggleDocument = (documentId: string) => {\n if (expandedDocuments.has(documentId)) {\n expandedDocuments.delete(documentId)\n } else {\n expandedDocuments.add(documentId)\n }\n }\n\n const toggleChunk = (chunkId: string) => {\n if (expandedChunks.has(chunkId)) {\n expandedChunks.delete(chunkId)\n } else {\n expandedChunks.add(chunkId)\n }\n }\n\n const handleExpandContext = async (source: SourceItem) => {\n if (source.chunkIndex == null || !props.onExpandContext) {\n return\n }\n loadingContext.add(source.chunkId)\n try {\n const content = await props.onExpandContext({\n documentId: source.documentId,\n chunkIndex: source.chunkIndex,\n })\n contextData.set(source.chunkId, content)\n } finally {\n loadingContext.delete(source.chunkId)\n }\n }\n\n const clearContext = (chunkId: string) => {\n contextData.delete(chunkId)\n }\n\n const showMore = ref(false)\n const visibleGroups = computed(() => {\n if (showMore.value) {\n return groupedSources.value\n }\n return groupedSources.value.slice(0, 3)\n })\n const hasMore = computed(() => groupedSources.value.length > 3)\n</script>\n\n<template>\n <div v-if=\"sources.length\" class=\"flex flex-col gap-xs w-full\">\n <div class=\"flex items-center gap-4 text-12 text-word-3 font-semibold\">\n <VvIcon name=\"ri:article-line\" class=\"text-14\" />\n {{ $t('label.sources') }}\n <span class=\"text-word-4 font-normal\">\n ({{ groupedSources.length }})\n </span>\n </div>\n\n <ul class=\"flex flex-col gap-xs\">\n <li\n v-for=\"group in visibleGroups\"\n :key=\"group.document.documentId\"\n class=\"border border-surface-3 rounded-lg overflow-hidden\">\n <!-- Document header -->\n <button\n class=\"flex items-center gap-8 p-8 w-full text-left hover:bg-surface-1 transition-colors cursor-pointer\"\n @click=\"toggleDocument(group.document.documentId)\">\n <PkDocumentHeader\n :type=\"group.document.documentType\"\n :name=\"group.document.documentName\"\n :url=\"group.document.sourceUrl\"\n :filename=\"group.document.sourceFilename\" />\n <div class=\"flex items-center gap-4 shrink-0\">\n <span\n v-if=\"group.chunks.length > 1\"\n class=\"text-10 text-word-4 bg-surface-2 rounded px-4 py-2\">\n {{ group.chunks.length }}\n </span>\n <span\n class=\"text-10 text-word-4 bg-surface-2 rounded px-4 py-2 uppercase\">\n {{ group.document.language }}\n </span>\n <VvIcon\n :name=\"\n expandedDocuments.has(group.document.documentId)\n ? 'ri:arrow-up-s-line'\n : 'ri:arrow-down-s-line'\n \"\n class=\"text-16 text-word-3\" />\n </div>\n </button>\n\n <!-- Expanded content -->\n <div\n v-if=\"expandedDocuments.has(group.document.documentId)\"\n class=\"border-t border-surface-3\">\n <PkStreamingMarkdown\n v-if=\"group.document.sourceDescription\"\n :markdown=\"group.document.sourceDescription\"\n class=\"px-8 py-4 text-10 text-word-3 bg-surface-1 border-b border-surface-3\" />\n\n <!-- Chunk excerpts -->\n <div\n v-for=\"chunk in group.chunks\"\n :key=\"chunk.chunkId\"\n class=\"border-b border-surface-3 last:border-b-0\">\n <button\n class=\"flex items-center gap-8 px-8 py-6 w-full text-left hover:bg-surface-1 transition-colors cursor-pointer\"\n @click=\"toggleChunk(chunk.chunkId)\">\n <PkChunkPreview\n :content=\"chunk.content\"\n :similarity=\"chunk.similarity\"\n :max-similarity=\"maxSimilarity\"\n :expanded=\"expandedChunks.has(chunk.chunkId)\" />\n </button>\n\n <!-- Expanded chunk content -->\n <div\n v-if=\"expandedChunks.has(chunk.chunkId)\"\n class=\"bg-surface-1 border-t border-surface-3\">\n <div class=\"p-8 text-10 text-word-3\">\n <transition mode=\"out-in\">\n <!-- Context expansion -->\n <PkStreamingMarkdown\n v-if=\"contextData.has(chunk.chunkId)\"\n :markdown=\"\n contextData.get(chunk.chunkId)!\n \"\n class=\"wysiwyg\" />\n\n <!-- Chunk content -->\n <PkStreamingMarkdown\n v-else\n :markdown=\"chunk.content\"\n class=\"wysiwyg\" />\n </transition>\n </div>\n\n <!-- Actions bar -->\n <div\n class=\"flex items-center gap-8 px-8 py-6 border-t border-surface-3 bg-surface\">\n <!-- Expand / collapse context -->\n <button\n v-if=\"\n onExpandContext &&\n chunk.chunkIndex != null &&\n !contextData.has(chunk.chunkId)\n \"\n class=\"text-10 text-word-3 hover:text-word flex items-center gap-4 cursor-pointer\"\n :disabled=\"\n loadingContext.has(chunk.chunkId)\n \"\n @click=\"handleExpandContext(chunk)\">\n <VvIcon\n :name=\"\n loadingContext.has(chunk.chunkId)\n ? 'line-md:loading-loop'\n : 'ri:expand-up-down-line'\n \"\n class=\"text-12\" />\n {{ $t('label.expandContext') }}\n </button>\n <button\n v-else-if=\"contextData.has(chunk.chunkId)\"\n class=\"text-10 text-word-3 hover:text-word-1 flex items-center gap-4 cursor-pointer\"\n @click=\"clearContext(chunk.chunkId)\">\n <VvIcon\n name=\"ri:collapse-vertical-line\"\n class=\"text-12\" />\n {{ $t('label.collapseContext') }}\n </button>\n\n <!-- Open source URL -->\n <a\n v-if=\"chunk.sourceUrl\"\n :href=\"chunk.sourceUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"text-10 text-word-3 hover:text-word-1 flex items-center gap-4 ml-auto\">\n <VvIcon\n name=\"ri:external-link-line\"\n class=\"text-12\" />\n {{ $t('label.openSource') }}\n </a>\n\n <!-- Download file -->\n <button\n v-if=\"\n onDownload &&\n chunk.documentType === 'file'\n \"\n class=\"text-10 text-word-3 hover:text-word-1 flex items-center gap-4 cursor-pointer\"\n :class=\"{\n 'ml-auto': !chunk.sourceUrl,\n }\"\n @click=\"onDownload(chunk.documentId)\">\n <VvIcon\n name=\"ri:download-line\"\n class=\"text-12\" />\n {{ $t('label.downloadFile') }}\n </button>\n </div>\n </div>\n </div>\n </div>\n </li>\n </ul>\n\n <!-- Show more -->\n <button\n v-if=\"hasMore\"\n class=\"text-12 text-word-3 cursor-pointer hover:underline flex items-center gap-4 mx-auto\"\n @click=\"showMore = !showMore\">\n <VvIcon\n :name=\"showMore ? 'ri:arrow-up-s-line' : 'ri:arrow-down-s-line'\"\n class=\"text-16\" />\n {{\n showMore\n ? $t('action.showLess')\n : $t('action.showMore', {\n count: groupedSources.length - 3,\n })\n }}\n </button>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, onMounted } from 'vue'\n import { useI18n } from 'vue-i18n'\n\n import type { ReverseGeocodeFn } from 'utils/src/device-context'\n\n type GeolocationOutput =\n | {\n latitude: number\n longitude: number\n accuracy?: number\n city?: string\n }\n | { error: 'permission_denied' | 'position_unavailable' | 'timeout' }\n\n const props = defineProps<{\n part: unknown\n reverseGeocode?: ReverseGeocodeFn\n }>()\n\n const emit = defineEmits<{\n result: [output: GeolocationOutput]\n }>()\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const toolPart = computed(() => {\n return props.part as {\n state?: string\n input?: { reason?: string }\n output?: GeolocationOutput\n }\n })\n\n const state = computed(() => toolPart.value.state ?? 'unknown')\n\n const isOutputAvailable = computed(() => state.value === 'output-available')\n\n const successOutput = computed(() => {\n const out = toolPart.value.output\n if (!out || 'error' in out) {\n return undefined\n }\n return out\n })\n\n const errorOutput = computed(() => {\n const out = toolPart.value.output\n if (!out || !('error' in out)) {\n return undefined\n }\n return out\n })\n\n /** Maps GeolocationPositionError.code to a typed string */\n function mapGeolocationError(\n code: number,\n ): 'permission_denied' | 'position_unavailable' | 'timeout' {\n if (code === 1) {\n return 'permission_denied'\n }\n if (code === 3) {\n return 'timeout'\n }\n return 'position_unavailable'\n }\n\n onMounted(() => {\n if (state.value !== 'input-available') {\n return\n }\n\n if (!navigator.geolocation) {\n emit('result', { error: 'position_unavailable' })\n return\n }\n\n navigator.geolocation.getCurrentPosition(\n async (position) => {\n const { latitude, longitude, accuracy } = position.coords\n const city = props.reverseGeocode\n ? await props\n .reverseGeocode(latitude, longitude)\n .catch(() => undefined)\n : undefined\n emit('result', { latitude, longitude, accuracy, city })\n },\n (error) => {\n emit('result', { error: mapGeolocationError(error.code) })\n },\n { timeout: 15000 },\n )\n })\n</script>\n\n<template>\n <div\n class=\"flex items-center gap-6 text-12 text-word-3 border border-surface-3 rounded-xl px-sm py-10\">\n <!-- Loading state -->\n <template v-if=\"!isOutputAvailable\">\n <VvIcon name=\"line-md:loading-loop\" class=\"text-16\" />\n <span>{{ $t('messagePart.requestGeolocation') }}</span>\n </template>\n\n <!-- Success state -->\n <template v-else-if=\"successOutput\">\n <VvIcon name=\"ri:map-pin-line\" class=\"text-16\" />\n <span>\n {{\n $n(successOutput.latitude, {\n style: 'decimal',\n minimumFractionDigits: 5,\n maximumFractionDigits: 5,\n })\n }},\n {{\n $n(successOutput.longitude, {\n style: 'decimal',\n minimumFractionDigits: 5,\n maximumFractionDigits: 5,\n })\n }}\n <template v-if=\"successOutput.accuracy !== undefined\">\n (±{{\n $n(successOutput.accuracy, {\n style: 'unit',\n unit: 'meter',\n })\n }})\n </template>\n </span>\n </template>\n\n <!-- Error state -->\n <template v-else-if=\"errorOutput\">\n <span class=\"i-vv-alert-circle text-16 shrink-0 text-danger\" />\n <span>\n {{\n errorOutput.error === 'permission_denied'\n ? $t('message.geolocationPermissionDenied')\n : $t('message.geolocationUnavailable')\n }}\n </span>\n </template>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, onMounted } from 'vue'\n import { useI18n } from 'vue-i18n'\n\n import type { ReverseGeocodeFn } from 'utils/src/device-context'\n\n type GeolocationOutput =\n | {\n latitude: number\n longitude: number\n accuracy?: number\n city?: string\n }\n | { error: 'permission_denied' | 'position_unavailable' | 'timeout' }\n\n const props = defineProps<{\n part: unknown\n reverseGeocode?: ReverseGeocodeFn\n }>()\n\n const emit = defineEmits<{\n result: [output: GeolocationOutput]\n }>()\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const toolPart = computed(() => {\n return props.part as {\n state?: string\n input?: { reason?: string }\n output?: GeolocationOutput\n }\n })\n\n const state = computed(() => toolPart.value.state ?? 'unknown')\n\n const isOutputAvailable = computed(() => state.value === 'output-available')\n\n const successOutput = computed(() => {\n const out = toolPart.value.output\n if (!out || 'error' in out) {\n return undefined\n }\n return out\n })\n\n const errorOutput = computed(() => {\n const out = toolPart.value.output\n if (!out || !('error' in out)) {\n return undefined\n }\n return out\n })\n\n /** Maps GeolocationPositionError.code to a typed string */\n function mapGeolocationError(\n code: number,\n ): 'permission_denied' | 'position_unavailable' | 'timeout' {\n if (code === 1) {\n return 'permission_denied'\n }\n if (code === 3) {\n return 'timeout'\n }\n return 'position_unavailable'\n }\n\n onMounted(() => {\n if (state.value !== 'input-available') {\n return\n }\n\n if (!navigator.geolocation) {\n emit('result', { error: 'position_unavailable' })\n return\n }\n\n navigator.geolocation.getCurrentPosition(\n async (position) => {\n const { latitude, longitude, accuracy } = position.coords\n const city = props.reverseGeocode\n ? await props\n .reverseGeocode(latitude, longitude)\n .catch(() => undefined)\n : undefined\n emit('result', { latitude, longitude, accuracy, city })\n },\n (error) => {\n emit('result', { error: mapGeolocationError(error.code) })\n },\n { timeout: 15000 },\n )\n })\n</script>\n\n<template>\n <div\n class=\"flex items-center gap-6 text-12 text-word-3 border border-surface-3 rounded-xl px-sm py-10\">\n <!-- Loading state -->\n <template v-if=\"!isOutputAvailable\">\n <VvIcon name=\"line-md:loading-loop\" class=\"text-16\" />\n <span>{{ $t('messagePart.requestGeolocation') }}</span>\n </template>\n\n <!-- Success state -->\n <template v-else-if=\"successOutput\">\n <VvIcon name=\"ri:map-pin-line\" class=\"text-16\" />\n <span>\n {{\n $n(successOutput.latitude, {\n style: 'decimal',\n minimumFractionDigits: 5,\n maximumFractionDigits: 5,\n })\n }},\n {{\n $n(successOutput.longitude, {\n style: 'decimal',\n minimumFractionDigits: 5,\n maximumFractionDigits: 5,\n })\n }}\n <template v-if=\"successOutput.accuracy !== undefined\">\n (±{{\n $n(successOutput.accuracy, {\n style: 'unit',\n unit: 'meter',\n })\n }})\n </template>\n </span>\n </template>\n\n <!-- Error state -->\n <template v-else-if=\"errorOutput\">\n <span class=\"i-vv-alert-circle text-16 shrink-0 text-danger\" />\n <span>\n {{\n errorOutput.error === 'permission_denied'\n ? $t('message.geolocationPermissionDenied')\n : $t('message.geolocationUnavailable')\n }}\n </span>\n </template>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, useTemplateRef } from 'vue'\n import { useDropZone } from '@vueuse/core'\n import { storeToRefs } from 'pinia'\n import PkChatbotMessages from './PkChatbotMessages.vue'\n import PkChatbotInput from './PkChatbotInput.vue'\n import PkToolShowMultipleChoice from './PkToolShowMultipleChoice.vue'\n import PkToolShowContactForm from './PkToolShowContactForm.vue'\n import PkToolShowSuggestedReply from './PkToolShowSuggestedReply.vue'\n import PkToolShowSources from './PkToolShowSources.vue'\n import PkToolRequestGeolocation from './PkToolRequestGeolocation.vue'\n import { useLocalizedString } from '../composables/useLocalizedString'\n import { useChatbotStore } from 'composables'\n import type { UIChatMessage } from 'models'\n\n const props = defineProps<{ agentId: string }>()\n\n const emit = defineEmits<{\n 'show-info': [message: UIChatMessage]\n revise: [message: UIChatMessage]\n }>()\n\n const store = useChatbotStore(props.agentId)\n\n const {\n name,\n agentInterface,\n agentFileUpload,\n actions,\n revisedAnswers,\n messages,\n chat,\n messageFeedbacks,\n feedbackDialogMessage,\n isFeedbackSubmitting,\n isFeedbackSubmitted,\n feedbackSubmitError,\n isLeadSubmitted,\n isLoadingSubmitLead,\n submitLeadError,\n input,\n inputMessagePlaceholder,\n isConversationBlocked,\n baseUrl,\n pendingAttachments,\n apiClient,\n } = storeToRefs(store)\n\n const {\n handleSubmit: storeHandleSubmit,\n stopGeneration,\n regenerate,\n onUpvote,\n onDownvote,\n onFeedback,\n onFeedbackSubmit,\n onLeadSubmit,\n startNewChat,\n addToolOutput,\n handleFileSelect,\n } = store\n\n const dismissableNotice = useLocalizedString(\n () => agentInterface.value?.dismissableNotice,\n )\n\n const chatViewEl = useTemplateRef<HTMLDivElement>('chatViewEl')\n\n const handleExpandSourceContext = async (payload: {\n documentId: string\n chunkIndex: number\n }) => {\n const result = await apiClient.value.expandSourceContext(\n props.agentId,\n payload.documentId,\n payload.chunkIndex,\n )\n return result.content\n }\n\n const handleDownloadSource = async (documentId: string) => {\n const result = await apiClient.value.downloadSourceDocument(\n props.agentId,\n documentId,\n )\n window.open(result.downloadUrl, '_blank')\n }\n\n const handleFileDrop = (files: File[] | null) => {\n if (!agentFileUpload.value?.enabled || !files) {\n return\n }\n for (const file of files) {\n handleFileSelect(file)\n }\n }\n\n const { isOverDropZone } = useDropZone(chatViewEl, {\n dataTypes: computed(\n () => agentFileUpload.value?.allowedMimeTypes ?? [],\n ),\n onDrop: handleFileDrop,\n })\n</script>\n\n<template>\n <div\n ref=\"chatViewEl\"\n class=\"pk-chatbot-view-chat\"\n :class=\"{\n 'pk-chatbot-view-chat--dragover':\n isOverDropZone && agentFileUpload?.enabled,\n }\">\n <!-- #region messages -->\n <PkChatbotMessages\n class=\"flex flex-col flex-1 min-h-0 p-md overflow-y-auto\"\n :name=\"name\"\n :messages=\"messages\"\n :status=\"chat.status\"\n :error=\"chat.error\"\n :main-color=\"agentInterface?.mainColor\"\n :text-color=\"agentInterface?.textColor\"\n :revised-answers=\"revisedAnswers\"\n :actions=\"actions\"\n :logo=\"agentInterface?.logo\"\n :message-feedbacks=\"messageFeedbacks\"\n :feedback-message-id=\"feedbackDialogMessage?.id\"\n :feedback-loading=\"isFeedbackSubmitting\"\n :feedback-submitted=\"isFeedbackSubmitted\"\n :feedback-error=\"feedbackSubmitError\"\n @feedback-submit=\"onFeedbackSubmit($event)\"\n @feedback-close=\"feedbackDialogMessage = undefined\"\n @regenerate=\"regenerate\"\n @auto-retry=\"regenerate\"\n @reset-chat=\"startNewChat\"\n @show-info=\"emit('show-info', $event)\"\n @revise=\"emit('revise', $event)\"\n @upvote=\"onUpvote\"\n @downvote=\"onDownvote\"\n @feedback=\"onFeedback\">\n <template #tool-showContactForm=\"{ part }\">\n <PkToolShowContactForm\n :part\n :readonly=\"!baseUrl\"\n :submitted=\"isLeadSubmitted\"\n :loading=\"isLoadingSubmitLead\"\n :error=\"submitLeadError\"\n :privacy-policy-notice=\"agentInterface?.privacyPolicyNotice\"\n @submit=\"onLeadSubmit\" />\n </template>\n <template #tool-showSuggestedReply=\"{ part }\">\n <PkToolShowSuggestedReply\n :part\n @select=\"\n ($event) => {\n input = $event\n storeHandleSubmit()\n }\n \" />\n </template>\n <template #tool-showSources=\"{ part }\">\n <PkToolShowSources\n :part\n :on-expand-context=\"handleExpandSourceContext\"\n :on-download=\"handleDownloadSource\" />\n </template>\n <template #tool-showMultipleChoice=\"{ part }\">\n <transition mode=\"out-in\">\n <PkToolShowMultipleChoice\n :part\n @select=\"\n addToolOutput({\n tool: 'showMultipleChoice',\n toolCallId: (part as any).toolCallId,\n output: $event,\n })\n \" />\n </transition>\n </template>\n <template #tool-requestGeolocation=\"{ part }\">\n <PkToolRequestGeolocation\n :part\n :reverse-geocode=\"\n (lat: number, lon: number) =>\n apiClient.reverseGeocode(lat, lon)\n \"\n @result=\"\n addToolOutput({\n tool: 'requestGeolocation',\n toolCallId: (part as any).toolCallId,\n output: $event,\n })\n \" />\n </template>\n </PkChatbotMessages>\n <!-- #endregion -->\n\n <!-- #region input -->\n <div\n v-if=\"isConversationBlocked\"\n class=\"p-md border-t border-surface-3 text-center text-12 text-danger-darken-2 bg-surface-danger\">\n {{ $t('message.chatErrorConversationBlocked') }}\n </div>\n <PkChatbotInput\n v-else\n v-model=\"input\"\n v-model:pending-attachments=\"pendingAttachments\"\n :placeholder=\"inputMessagePlaceholder\"\n :dismissable-notice=\"\n dismissableNotice && chat.messages.length <= 1\n ? dismissableNotice\n : undefined\n \"\n :status=\"chat.status\"\n :max-message-length=\"agentInterface?.maxMessageLength\"\n :file-upload=\"agentFileUpload\"\n @stop-generation=\"stopGeneration\"\n @submit=\"storeHandleSubmit\"\n @file-select=\"handleFileSelect\" />\n <!-- #endregion -->\n <Transition>\n <div\n v-if=\"isOverDropZone && agentFileUpload?.enabled\"\n class=\"pk-chatbot-view-chat__drop-overlay\">\n <VvIcon\n name=\"ri:upload-cloud-2-line\"\n class=\"pk-chatbot-view-chat__drop-overlay-icon\" />\n <span>{{ $t('action.dropFile') }}</span>\n </div>\n </Transition>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-view-chat {\n position: relative;\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n\n &__drop-overlay {\n position: absolute;\n inset: var(--spacing-sm) var(--spacing-sm) var(--spacing-sm)\n var(--spacing-sm);\n z-index: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--spacing-xs);\n background-color: color-mix(\n in srgb,\n var(--color-surface) 85%,\n transparent\n );\n border-radius: var(--rounded-xl);\n border: var(--spacing-2) dashed var(--color-surface-5);\n pointer-events: none;\n color: var(--color-word-3);\n\n &-icon {\n font-size: var(--spacing-32);\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, useTemplateRef } from 'vue'\n import { useDropZone } from '@vueuse/core'\n import { storeToRefs } from 'pinia'\n import PkChatbotMessages from './PkChatbotMessages.vue'\n import PkChatbotInput from './PkChatbotInput.vue'\n import PkToolShowMultipleChoice from './PkToolShowMultipleChoice.vue'\n import PkToolShowContactForm from './PkToolShowContactForm.vue'\n import PkToolShowSuggestedReply from './PkToolShowSuggestedReply.vue'\n import PkToolShowSources from './PkToolShowSources.vue'\n import PkToolRequestGeolocation from './PkToolRequestGeolocation.vue'\n import { useLocalizedString } from '../composables/useLocalizedString'\n import { useChatbotStore } from 'composables'\n import type { UIChatMessage } from 'models'\n\n const props = defineProps<{ agentId: string }>()\n\n const emit = defineEmits<{\n 'show-info': [message: UIChatMessage]\n revise: [message: UIChatMessage]\n }>()\n\n const store = useChatbotStore(props.agentId)\n\n const {\n name,\n agentInterface,\n agentFileUpload,\n actions,\n revisedAnswers,\n messages,\n chat,\n messageFeedbacks,\n feedbackDialogMessage,\n isFeedbackSubmitting,\n isFeedbackSubmitted,\n feedbackSubmitError,\n isLeadSubmitted,\n isLoadingSubmitLead,\n submitLeadError,\n input,\n inputMessagePlaceholder,\n isConversationBlocked,\n baseUrl,\n pendingAttachments,\n apiClient,\n } = storeToRefs(store)\n\n const {\n handleSubmit: storeHandleSubmit,\n stopGeneration,\n regenerate,\n onUpvote,\n onDownvote,\n onFeedback,\n onFeedbackSubmit,\n onLeadSubmit,\n startNewChat,\n addToolOutput,\n handleFileSelect,\n } = store\n\n const dismissableNotice = useLocalizedString(\n () => agentInterface.value?.dismissableNotice,\n )\n\n const chatViewEl = useTemplateRef<HTMLDivElement>('chatViewEl')\n\n const handleExpandSourceContext = async (payload: {\n documentId: string\n chunkIndex: number\n }) => {\n const result = await apiClient.value.expandSourceContext(\n props.agentId,\n payload.documentId,\n payload.chunkIndex,\n )\n return result.content\n }\n\n const handleDownloadSource = async (documentId: string) => {\n const result = await apiClient.value.downloadSourceDocument(\n props.agentId,\n documentId,\n )\n window.open(result.downloadUrl, '_blank')\n }\n\n const handleFileDrop = (files: File[] | null) => {\n if (!agentFileUpload.value?.enabled || !files) {\n return\n }\n for (const file of files) {\n handleFileSelect(file)\n }\n }\n\n const { isOverDropZone } = useDropZone(chatViewEl, {\n dataTypes: computed(\n () => agentFileUpload.value?.allowedMimeTypes ?? [],\n ),\n onDrop: handleFileDrop,\n })\n</script>\n\n<template>\n <div\n ref=\"chatViewEl\"\n class=\"pk-chatbot-view-chat\"\n :class=\"{\n 'pk-chatbot-view-chat--dragover':\n isOverDropZone && agentFileUpload?.enabled,\n }\">\n <!-- #region messages -->\n <PkChatbotMessages\n class=\"flex flex-col flex-1 min-h-0 p-md overflow-y-auto\"\n :name=\"name\"\n :messages=\"messages\"\n :status=\"chat.status\"\n :error=\"chat.error\"\n :main-color=\"agentInterface?.mainColor\"\n :text-color=\"agentInterface?.textColor\"\n :revised-answers=\"revisedAnswers\"\n :actions=\"actions\"\n :logo=\"agentInterface?.logo\"\n :message-feedbacks=\"messageFeedbacks\"\n :feedback-message-id=\"feedbackDialogMessage?.id\"\n :feedback-loading=\"isFeedbackSubmitting\"\n :feedback-submitted=\"isFeedbackSubmitted\"\n :feedback-error=\"feedbackSubmitError\"\n @feedback-submit=\"onFeedbackSubmit($event)\"\n @feedback-close=\"feedbackDialogMessage = undefined\"\n @regenerate=\"regenerate\"\n @auto-retry=\"regenerate\"\n @reset-chat=\"startNewChat\"\n @show-info=\"emit('show-info', $event)\"\n @revise=\"emit('revise', $event)\"\n @upvote=\"onUpvote\"\n @downvote=\"onDownvote\"\n @feedback=\"onFeedback\">\n <template #tool-showContactForm=\"{ part }\">\n <PkToolShowContactForm\n :part\n :readonly=\"!baseUrl\"\n :submitted=\"isLeadSubmitted\"\n :loading=\"isLoadingSubmitLead\"\n :error=\"submitLeadError\"\n :privacy-policy-notice=\"agentInterface?.privacyPolicyNotice\"\n @submit=\"onLeadSubmit\" />\n </template>\n <template #tool-showSuggestedReply=\"{ part }\">\n <PkToolShowSuggestedReply\n :part\n @select=\"\n ($event) => {\n input = $event\n storeHandleSubmit()\n }\n \" />\n </template>\n <template #tool-showSources=\"{ part }\">\n <PkToolShowSources\n :part\n :on-expand-context=\"handleExpandSourceContext\"\n :on-download=\"handleDownloadSource\" />\n </template>\n <template #tool-showMultipleChoice=\"{ part }\">\n <transition mode=\"out-in\">\n <PkToolShowMultipleChoice\n :part\n @select=\"\n addToolOutput({\n tool: 'showMultipleChoice',\n toolCallId: (part as any).toolCallId,\n output: $event,\n })\n \" />\n </transition>\n </template>\n <template #tool-requestGeolocation=\"{ part }\">\n <PkToolRequestGeolocation\n :part\n :reverse-geocode=\"\n (lat: number, lon: number) =>\n apiClient.reverseGeocode(lat, lon)\n \"\n @result=\"\n addToolOutput({\n tool: 'requestGeolocation',\n toolCallId: (part as any).toolCallId,\n output: $event,\n })\n \" />\n </template>\n </PkChatbotMessages>\n <!-- #endregion -->\n\n <!-- #region input -->\n <div\n v-if=\"isConversationBlocked\"\n class=\"p-md border-t border-surface-3 text-center text-12 text-danger-darken-2 bg-surface-danger\">\n {{ $t('message.chatErrorConversationBlocked') }}\n </div>\n <PkChatbotInput\n v-else\n v-model=\"input\"\n v-model:pending-attachments=\"pendingAttachments\"\n :placeholder=\"inputMessagePlaceholder\"\n :dismissable-notice=\"\n dismissableNotice && chat.messages.length <= 1\n ? dismissableNotice\n : undefined\n \"\n :status=\"chat.status\"\n :max-message-length=\"agentInterface?.maxMessageLength\"\n :file-upload=\"agentFileUpload\"\n @stop-generation=\"stopGeneration\"\n @submit=\"storeHandleSubmit\"\n @file-select=\"handleFileSelect\" />\n <!-- #endregion -->\n <Transition>\n <div\n v-if=\"isOverDropZone && agentFileUpload?.enabled\"\n class=\"pk-chatbot-view-chat__drop-overlay\">\n <VvIcon\n name=\"ri:upload-cloud-2-line\"\n class=\"pk-chatbot-view-chat__drop-overlay-icon\" />\n <span>{{ $t('action.dropFile') }}</span>\n </div>\n </Transition>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-view-chat {\n position: relative;\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n\n &__drop-overlay {\n position: absolute;\n inset: var(--spacing-sm) var(--spacing-sm) var(--spacing-sm)\n var(--spacing-sm);\n z-index: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--spacing-xs);\n background-color: color-mix(\n in srgb,\n var(--color-surface) 85%,\n transparent\n );\n border-radius: var(--rounded-xl);\n border: var(--spacing-2) dashed var(--color-surface-5);\n pointer-events: none;\n color: var(--color-word-3);\n\n &-icon {\n font-size: var(--spacing-32);\n }\n }\n }\n</style>\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { t as e } from "./useChatbotStore-B9BUWM4O.js";
1
+ import { t as e } from "./useChatbotStore-ys9uGP5v.js";
2
2
  import { m as t, s as n } from "./src-DjRNH9vV.js";
3
3
  import { t as r } from "./PkRelativeTime-Bzh37jv5.js";
4
4
  import { Fragment as i, createElementBlock as a, createElementVNode as o, createVNode as s, defineComponent as c, normalizeClass as l, openBlock as u, renderList as d, toDisplayString as f, unref as p, withModifiers as m } from "vue";
@@ -37,4 +37,4 @@ var v = { class: "flex flex-col flex-1 min-h-0 overflow-y-auto p-md gap-sm relat
37
37
  //#endregion
38
38
  export { D as t };
39
39
 
40
- //# sourceMappingURL=PkChatbotViewConversations-DFv_8-8K.js.map
40
+ //# sourceMappingURL=PkChatbotViewConversations-Ct0TbDrg.js.map