@designcrowd/library.brand-page 5.17.28 → 5.18.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 (380) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-CJZpKPNH.js → CreatedOnBrandCrowd-de-de-xmkupPus.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-DkIa7iEb.js → CreatedOnBrandCrowd-en-us-Ck7EdTtb.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-CE2p6XHz.js → CreatedOnBrandCrowd-es-es-BC8sJuDH.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-BBjOZS3M.js → CreatedOnBrandCrowd-fr-ca-CN-UBe1q.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-BBjOZS3M.js → CreatedOnBrandCrowd-fr-fr-CN-UBe1q.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-Dayzl4BZ.js → CreatedOnBrandCrowd-pt-br-CajQyNkx.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-Dayzl4BZ.js → CreatedOnBrandCrowd-pt-pt-CajQyNkx.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-CFzDqfCb.js → CreatedOnDcom-de-de-BRCNMmDq.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-C2jIPBDY.js → CreatedOnDcom-en-us-BzQDtZhc.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-qejpzqho.js → CreatedOnDcom-es-es-D-qAM4Cd.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-DMO9Ld7K.js → CreatedOnDcom-fr-ca-CZ1irFOc.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-BFWN9qTP.js → CreatedOnDcom-fr-fr-Gb5BCF0N.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-CneD3ghF.js → CreatedOnDcom-pt-br-CAQV0q6o.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-Cg1B7s0o.js → CreatedOnDcom-pt-pt-D6tQdQFh.js} +1 -1
  15. package/lib/src/brand-page/components/image-gallery/ImageGalleryModal.mixin.js +2 -2
  16. package/lib/src/brand-page/models/brand-page-context.model.d.ts +0 -2
  17. package/lib/src/brand-page/models/brand-page-context.model.js +1 -11
  18. package/lib/src/brand-page/models/index.d.ts +1 -0
  19. package/lib/src/brand-page/models/index.js +1 -0
  20. package/lib/src/brand-page/utils/color.util.js +23 -3
  21. package/lib/src/brand-page/utils/raygun.util.d.ts +5 -1
  22. package/lib/src/brand-page/utils/raygun.util.js +7 -2
  23. package/lib/src/brand-page/utils/svg-color.util.js +1 -2
  24. package/lib/src/brand-page/utils/view-model.util.js +1 -1
  25. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +1 -31
  26. package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.js +0 -2
  27. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +2 -31
  28. package/lib/src/brand-page-maker/components/preview/Preview.mixin.d.ts +0 -14
  29. package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +0 -28
  30. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +0 -28
  31. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +0 -28
  32. package/lib/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.mixin.d.ts +0 -28
  33. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +0 -28
  34. package/lib/src/brand-page-maker/components/upgrade-to-premium-button/UpgradeToPremiumButton.mixin.d.ts +0 -28
  35. package/lib/src/brand-page-maker/composables/ai-chat/aiErrorCopy.d.ts +35 -0
  36. package/lib/src/brand-page-maker/composables/ai-chat/aiErrorCopy.js +108 -0
  37. package/lib/src/brand-page-maker/composables/ai-chat/{useAiChat.d.ts → types.d.ts} +5 -13
  38. package/lib/src/brand-page-maker/composables/ai-chat/types.js +1 -0
  39. package/lib/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.d.ts +19 -0
  40. package/lib/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.js +1 -0
  41. package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.d.ts +1 -1
  42. package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +488 -82
  43. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +5 -5
  44. package/lib/src/brand-page-maker/composables/useEventTracker.d.ts +6 -16
  45. package/lib/src/brand-page-maker/composables/useEventTracker.js +19 -21
  46. package/lib/src/brand-page-maker/constants/sidebar-constant.d.ts +0 -1
  47. package/lib/src/brand-page-maker/constants/sidebar-constant.js +7 -15
  48. package/lib/src/brand-page-maker/convertors/image-aspect-ratio.convertor.js +2 -2
  49. package/lib/src/brand-page-maker/convertors/text-size-value.convertor.js +3 -1
  50. package/lib/src/brand-page-maker/stores/ai-checkpoint/ai-checkpoint-store.d.ts +30660 -0
  51. package/lib/src/brand-page-maker/stores/ai-checkpoint/ai-checkpoint-store.js +34 -0
  52. package/lib/src/brand-page-maker/stores/ai-thread/ai-website-builder-thread-store.d.ts +1 -1
  53. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.d.ts +0 -28
  54. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +42 -2
  55. package/lib/src/brand-page-maker/stores/index.d.ts +1 -1
  56. package/lib/src/brand-page-maker/stores/index.js +1 -1
  57. package/lib/src/brand-page-maker/stores/user/user-store.js +0 -1
  58. package/lib/src/bundled-translations-CnareLWC.js +175 -0
  59. package/lib/src/bundled-translations.de-DE-2Ys7epLO.js +175 -0
  60. package/lib/src/bundled-translations.es-ES-Cjp-G8rT.js +175 -0
  61. package/lib/src/bundled-translations.fr-CA-CsaW4Oae.js +175 -0
  62. package/lib/src/bundled-translations.fr-FR-DIT2dd8J.js +175 -0
  63. package/lib/src/bundled-translations.pt-BR-BamoBpDW.js +175 -0
  64. package/lib/src/bundled-translations.pt-PT-C9A4hY_e.js +175 -0
  65. package/lib/src/bundles/bundled-translations.de-DE.json +1 -20
  66. package/lib/src/bundles/bundled-translations.es-ES.json +1 -20
  67. package/lib/src/bundles/bundled-translations.fr-CA.json +1 -20
  68. package/lib/src/bundles/bundled-translations.fr-FR.json +1 -20
  69. package/lib/src/bundles/bundled-translations.json +1 -20
  70. package/lib/src/bundles/bundled-translations.pt-BR.json +1 -20
  71. package/lib/src/bundles/bundled-translations.pt-PT.json +1 -20
  72. package/lib/src/clients/ai-assistant-client.d.ts +30 -29
  73. package/lib/src/clients/ai-assistant-client.js +16 -16
  74. package/lib/src/clients/design-template-client.d.ts +0 -2
  75. package/lib/src/clients/design-template-client.js +0 -38
  76. package/lib/src/clients/websocket-gateway-client.d.ts +9 -1
  77. package/lib/src/composables/useTranslate.d.ts +2 -1
  78. package/lib/src/composables/useTranslate.js +2 -1
  79. package/lib/src/constants/ui.d.ts +0 -1
  80. package/lib/src/css/library.brand-page-brandCrowd.min.css +225 -134
  81. package/lib/src/css/library.brand-page-brandPage.min.css +227 -121
  82. package/lib/src/css/library.brand-page-designCom.min.css +225 -134
  83. package/lib/src/css/library.brand-page-preview.min.css +225 -118
  84. package/lib/src/index.d.ts +1 -1
  85. package/lib/src/index.mjs +1 -1
  86. package/lib/src/{lib-33w_DBny.js → lib-CSRUPpSo.js} +30887 -29395
  87. package/lib/src/metadata-builder/ai-metadata-executor.d.ts +21 -0
  88. package/lib/src/metadata-builder/ai-metadata-executor.js +56 -3
  89. package/lib/src/metadata-builder/builders/add-page-builder.d.ts +2 -4
  90. package/lib/src/metadata-builder/builders/add-page-builder.js +5 -8
  91. package/lib/src/metadata-builder/builders/footer-builder.d.ts +11 -0
  92. package/lib/src/metadata-builder/builders/footer-builder.js +151 -0
  93. package/lib/src/metadata-builder/builders/global-styles-builder.d.ts +15 -0
  94. package/lib/src/metadata-builder/builders/global-styles-builder.js +129 -0
  95. package/lib/src/metadata-builder/builders/header-builder.d.ts +11 -0
  96. package/lib/src/metadata-builder/builders/header-builder.js +167 -0
  97. package/lib/src/metadata-builder/builders/rename-page-builder.d.ts +12 -0
  98. package/lib/src/metadata-builder/builders/rename-page-builder.js +49 -0
  99. package/lib/src/metadata-builder/builders/section-builders/about-section-builder.d.ts +2 -0
  100. package/lib/src/metadata-builder/builders/section-builders/about-section-builder.js +44 -4
  101. package/lib/src/metadata-builder/builders/section-builders/banner-section-builder.d.ts +2 -0
  102. package/lib/src/metadata-builder/builders/section-builders/banner-section-builder.js +70 -6
  103. package/lib/src/metadata-builder/builders/section-builders/base-section-builder.d.ts +36 -4
  104. package/lib/src/metadata-builder/builders/section-builders/base-section-builder.js +102 -12
  105. package/lib/src/metadata-builder/builders/section-builders/booking-section-builder.d.ts +8 -0
  106. package/lib/src/metadata-builder/builders/section-builders/booking-section-builder.js +50 -0
  107. package/lib/src/metadata-builder/builders/section-builders/button-section-builder.d.ts +2 -0
  108. package/lib/src/metadata-builder/builders/section-builders/button-section-builder.js +5 -1
  109. package/lib/src/metadata-builder/builders/section-builders/contact-form-builder.d.ts +2 -0
  110. package/lib/src/metadata-builder/builders/section-builders/contact-form-builder.js +47 -3
  111. package/lib/src/metadata-builder/builders/section-builders/delete-section-builder.d.ts +2 -1
  112. package/lib/src/metadata-builder/builders/section-builders/delete-section-builder.js +5 -2
  113. package/lib/src/metadata-builder/builders/section-builders/divider-section-builder.d.ts +2 -0
  114. package/lib/src/metadata-builder/builders/section-builders/divider-section-builder.js +11 -1
  115. package/lib/src/metadata-builder/builders/section-builders/image-gallery-builder.d.ts +2 -0
  116. package/lib/src/metadata-builder/builders/section-builders/image-gallery-builder.js +52 -13
  117. package/lib/src/metadata-builder/builders/section-builders/images-section-builder.d.ts +2 -0
  118. package/lib/src/metadata-builder/builders/section-builders/images-section-builder.js +47 -17
  119. package/lib/src/metadata-builder/builders/section-builders/index.d.ts +1 -0
  120. package/lib/src/metadata-builder/builders/section-builders/index.js +1 -0
  121. package/lib/src/metadata-builder/builders/section-builders/mailing-list-builder.d.ts +2 -0
  122. package/lib/src/metadata-builder/builders/section-builders/mailing-list-builder.js +20 -2
  123. package/lib/src/metadata-builder/builders/section-builders/mailing-list-section-builder.d.ts +2 -0
  124. package/lib/src/metadata-builder/builders/section-builders/mailing-list-section-builder.js +20 -2
  125. package/lib/src/metadata-builder/builders/section-builders/profile-section-builder.d.ts +2 -0
  126. package/lib/src/metadata-builder/builders/section-builders/profile-section-builder.js +36 -2
  127. package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.d.ts +2 -0
  128. package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.js +70 -27
  129. package/lib/src/metadata-builder/builders/section-builders/social-links-builder.d.ts +2 -0
  130. package/lib/src/metadata-builder/builders/section-builders/social-links-builder.js +7 -2
  131. package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.d.ts +2 -0
  132. package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.js +91 -26
  133. package/lib/src/metadata-builder/builders/section-builders/text-section-builder.d.ts +2 -0
  134. package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +69 -31
  135. package/lib/src/metadata-builder/builders/section-content-factory.d.ts +2 -2
  136. package/lib/src/metadata-builder/builders/section-content-factory.js +8 -2
  137. package/lib/src/metadata-builder/builders/section-field-maps.js +30 -2
  138. package/lib/src/metadata-builder/builders/section-field-utils.d.ts +46 -7
  139. package/lib/src/metadata-builder/builders/section-field-utils.js +86 -62
  140. package/lib/src/metadata-builder/builders/section-rules/about-section.rules.d.ts +2 -0
  141. package/lib/src/metadata-builder/builders/section-rules/about-section.rules.js +20 -0
  142. package/lib/src/metadata-builder/builders/section-rules/add-page.rules.d.ts +7 -0
  143. package/lib/src/metadata-builder/builders/section-rules/add-page.rules.js +8 -0
  144. package/lib/src/metadata-builder/builders/section-rules/banner-section.rules.d.ts +2 -0
  145. package/lib/src/metadata-builder/builders/section-rules/banner-section.rules.js +27 -0
  146. package/lib/src/metadata-builder/builders/section-rules/booking-section.rules.d.ts +2 -0
  147. package/lib/src/metadata-builder/builders/section-rules/booking-section.rules.js +16 -0
  148. package/lib/src/metadata-builder/builders/section-rules/button-section.rules.d.ts +2 -0
  149. package/lib/src/metadata-builder/builders/section-rules/button-section.rules.js +13 -0
  150. package/lib/src/metadata-builder/builders/section-rules/contact-form.rules.d.ts +2 -0
  151. package/lib/src/metadata-builder/builders/section-rules/contact-form.rules.js +16 -0
  152. package/lib/src/metadata-builder/builders/section-rules/divider-section.rules.d.ts +2 -0
  153. package/lib/src/metadata-builder/builders/section-rules/divider-section.rules.js +7 -0
  154. package/lib/src/metadata-builder/builders/section-rules/footer.rules.d.ts +4 -0
  155. package/lib/src/metadata-builder/builders/section-rules/footer.rules.js +5 -0
  156. package/lib/src/metadata-builder/builders/section-rules/global-styles.rules.d.ts +6 -0
  157. package/lib/src/metadata-builder/builders/section-rules/global-styles.rules.js +26 -0
  158. package/lib/src/metadata-builder/builders/section-rules/header.rules.d.ts +4 -0
  159. package/lib/src/metadata-builder/builders/section-rules/header.rules.js +41 -0
  160. package/lib/src/metadata-builder/builders/section-rules/image-gallery.rules.d.ts +2 -0
  161. package/lib/src/metadata-builder/builders/section-rules/image-gallery.rules.js +10 -0
  162. package/lib/src/metadata-builder/builders/section-rules/images-section.rules.d.ts +2 -0
  163. package/lib/src/metadata-builder/builders/section-rules/images-section.rules.js +31 -0
  164. package/lib/src/metadata-builder/builders/section-rules/mailing-list.rules.d.ts +2 -0
  165. package/lib/src/metadata-builder/builders/section-rules/mailing-list.rules.js +11 -0
  166. package/lib/src/metadata-builder/builders/section-rules/profile.rules.d.ts +2 -0
  167. package/lib/src/metadata-builder/builders/section-rules/profile.rules.js +14 -0
  168. package/lib/src/metadata-builder/builders/section-rules/rename-page.rules.d.ts +7 -0
  169. package/lib/src/metadata-builder/builders/section-rules/rename-page.rules.js +8 -0
  170. package/lib/src/metadata-builder/builders/section-rules/shapes-section.rules.d.ts +2 -0
  171. package/lib/src/metadata-builder/builders/section-rules/shapes-section.rules.js +27 -0
  172. package/lib/src/metadata-builder/builders/section-rules/social-links.rules.d.ts +2 -0
  173. package/lib/src/metadata-builder/builders/section-rules/social-links.rules.js +9 -0
  174. package/lib/src/metadata-builder/builders/section-rules/testimonial-section.rules.d.ts +7 -0
  175. package/lib/src/metadata-builder/builders/section-rules/testimonial-section.rules.js +26 -0
  176. package/lib/src/metadata-builder/builders/section-rules/text-section.rules.d.ts +2 -0
  177. package/lib/src/metadata-builder/builders/section-rules/text-section.rules.js +14 -0
  178. package/lib/src/metadata-builder/builders/shape-color-utils.d.ts +26 -0
  179. package/lib/src/metadata-builder/builders/shape-color-utils.js +52 -0
  180. package/lib/src/metadata-builder/builders/undo-builder.d.ts +48 -0
  181. package/lib/src/metadata-builder/builders/undo-builder.js +58 -0
  182. package/lib/src/metadata-builder/builders/update-content-text-style-builder.js +5 -1
  183. package/lib/src/metadata-builder/helpers/rte.helpers.d.ts +15 -4
  184. package/lib/src/metadata-builder/helpers/rte.helpers.js +24 -10
  185. package/lib/src/metadata-builder/metadata-executor.d.ts +2 -1
  186. package/lib/src/metadata-builder/metadata-executor.js +32 -5
  187. package/lib/src/metadata-builder/models.d.ts +26 -1
  188. package/lib/src/metadata-builder/models.js +14 -1
  189. package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +144 -0
  190. package/lib/src/metadata-builder/parsers/ai-toolcall-parser.js +17 -0
  191. package/lib/src/metadata-builder/parsers/section-tool-arguments.d.ts +113 -24
  192. package/lib/src/metadata-builder/parsers/section-tool-arguments.js +5 -1
  193. package/lib/src/metadata-builder/sanitizers/rte-schema-check.d.ts +22 -0
  194. package/lib/src/metadata-builder/sanitizers/rte-schema-check.js +84 -0
  195. package/lib/src/metadata-builder/sanitizers/sanitizer-rules.d.ts +47 -0
  196. package/lib/src/metadata-builder/sanitizers/sanitizer-rules.js +60 -0
  197. package/lib/src/metadata-builder/sanitizers/section-args-validator.d.ts +41 -0
  198. package/lib/src/metadata-builder/sanitizers/section-args-validator.js +274 -0
  199. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +2 -1
  200. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.js +2 -16
  201. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.stories.js +0 -1
  202. package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +2 -1
  203. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +2 -3
  204. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +0 -4
  205. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.js +6 -8
  206. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +0 -28
  207. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +2 -1
  208. package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +0 -28
  209. package/lib/src/shared/navigation-style-settings/store/index.js +1 -0
  210. package/lib/src/shared/page-navigation/store/page-navigation-store.js +1 -20
  211. package/lib/src/shared/page-navigation/utils/nav-order-utils.d.ts +3 -0
  212. package/lib/src/shared/page-navigation/utils/nav-order-utils.js +20 -0
  213. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +2 -30
  214. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +0 -28
  215. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +2 -43
  216. package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +0 -30
  217. package/lib/src/shared/side-bar/components/SideBarTabButton.mixin.d.ts +2 -3
  218. package/lib/src/shared/side-bar/store/side-bar-store.d.ts +0 -12
  219. package/lib/src/shared/side-bar/store/side-bar-store.js +0 -7
  220. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +2 -29
  221. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +2 -1
  222. package/lib/src/utils/build-asset-manifest.d.ts +26 -0
  223. package/lib/src/utils/build-asset-manifest.js +114 -0
  224. package/lib/src/utils/minify-brand-page-metadata.d.ts +49 -1
  225. package/lib/src/utils/minify-brand-page-metadata.js +216 -129
  226. package/package.json +1 -1
  227. package/src/brand-page/components/banner-section/BannerSection.vue +1 -1
  228. package/src/brand-page/components/contact-form/ContactForm.vue +29 -26
  229. package/src/brand-page/components/image-gallery/ImageGalleryModal.mixin.ts +6 -2
  230. package/src/brand-page/components/text-media-section/TextMediaSection.vue +1 -5
  231. package/src/brand-page/models/brand-page-context.model.ts +1 -25
  232. package/src/brand-page/models/index.ts +1 -0
  233. package/src/brand-page/utils/color.util.test.ts +48 -0
  234. package/src/brand-page/utils/color.util.ts +29 -4
  235. package/src/brand-page/utils/raygun.util.ts +11 -2
  236. package/src/brand-page/utils/svg-color.util.ts +1 -3
  237. package/src/brand-page/utils/view-model.util.ts +1 -4
  238. package/src/brand-page-maker/components/ai-text-edit/AiChatbox.vue +2 -2
  239. package/src/brand-page-maker/components/ai-text-edit/AiProgressFeed.vue +162 -0
  240. package/src/brand-page-maker/components/ai-text-edit/TextBubble.vue +57 -5
  241. package/src/brand-page-maker/components/ai-text-edit/i18n/generate-ai.de-DE.json +0 -20
  242. package/src/brand-page-maker/components/ai-text-edit/i18n/generate-ai.es-ES.json +0 -20
  243. package/src/brand-page-maker/components/ai-text-edit/i18n/generate-ai.fr-CA.json +0 -20
  244. package/src/brand-page-maker/components/ai-text-edit/i18n/generate-ai.fr-FR.json +0 -20
  245. package/src/brand-page-maker/components/ai-text-edit/i18n/generate-ai.json +0 -20
  246. package/src/brand-page-maker/components/ai-text-edit/i18n/generate-ai.pt-BR.json +0 -20
  247. package/src/brand-page-maker/components/ai-text-edit/i18n/generate-ai.pt-PT.json +0 -20
  248. package/src/brand-page-maker/components/ai-website-builder/AiWebsiteBuilder.vue +1 -2
  249. package/src/brand-page-maker/components/ai-website-builder/i18n/ai-website-builder.de-DE.json +3 -0
  250. package/src/brand-page-maker/components/ai-website-builder/i18n/ai-website-builder.es-ES.json +3 -0
  251. package/src/brand-page-maker/components/ai-website-builder/i18n/ai-website-builder.fr-CA.json +3 -0
  252. package/src/brand-page-maker/components/ai-website-builder/i18n/ai-website-builder.fr-FR.json +3 -0
  253. package/src/brand-page-maker/components/ai-website-builder/i18n/ai-website-builder.json +3 -0
  254. package/src/brand-page-maker/components/ai-website-builder/i18n/ai-website-builder.pt-BR.json +3 -0
  255. package/src/brand-page-maker/components/ai-website-builder/i18n/ai-website-builder.pt-PT.json +3 -0
  256. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.vue +3 -28
  257. package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.ts +0 -2
  258. package/src/brand-page-maker/composables/ai-chat/aiErrorCopy.test.ts +229 -0
  259. package/src/brand-page-maker/composables/ai-chat/aiErrorCopy.ts +164 -0
  260. package/src/brand-page-maker/composables/ai-chat/types.ts +49 -0
  261. package/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.ts +20 -0
  262. package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +651 -94
  263. package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +9 -9
  264. package/src/brand-page-maker/composables/useEventTracker.ts +31 -25
  265. package/src/brand-page-maker/constants/sidebar-constant.ts +7 -15
  266. package/src/brand-page-maker/convertors/image-aspect-ratio.convertor.ts +2 -2
  267. package/src/brand-page-maker/convertors/text-size-value.convertor.ts +3 -3
  268. package/src/brand-page-maker/stores/ai-checkpoint/ai-checkpoint-store.ts +54 -0
  269. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +76 -0
  270. package/src/brand-page-maker/stores/index.ts +1 -1
  271. package/src/brand-page-maker/stores/user/user-store.ts +0 -1
  272. package/src/bundles/bundled-translations.de-DE.json +1 -20
  273. package/src/bundles/bundled-translations.es-ES.json +1 -20
  274. package/src/bundles/bundled-translations.fr-CA.json +1 -20
  275. package/src/bundles/bundled-translations.fr-FR.json +1 -20
  276. package/src/bundles/bundled-translations.json +1 -20
  277. package/src/bundles/bundled-translations.pt-BR.json +1 -20
  278. package/src/bundles/bundled-translations.pt-PT.json +1 -20
  279. package/src/clients/ai-assistant-client.ts +59 -46
  280. package/src/clients/design-template-client.ts +0 -66
  281. package/src/clients/websocket-gateway-client.ts +17 -1
  282. package/src/composables/useTranslate.ts +3 -0
  283. package/src/constants/ui.ts +0 -1
  284. package/src/lib.ts +1 -0
  285. package/src/metadata-builder/ai-metadata-executor.ts +94 -1
  286. package/src/metadata-builder/builders/add-page-builder.ts +9 -13
  287. package/src/metadata-builder/builders/footer-builder.test.ts +76 -0
  288. package/src/metadata-builder/builders/footer-builder.ts +226 -0
  289. package/src/metadata-builder/builders/global-styles-builder.ts +187 -0
  290. package/src/metadata-builder/builders/header-builder.test.ts +106 -0
  291. package/src/metadata-builder/builders/header-builder.ts +254 -0
  292. package/src/metadata-builder/builders/rename-page-builder.ts +79 -0
  293. package/src/metadata-builder/builders/section-builders/about-section-builder.ts +73 -5
  294. package/src/metadata-builder/builders/section-builders/banner-section-builder.ts +112 -7
  295. package/src/metadata-builder/builders/section-builders/base-section-builder.ts +149 -11
  296. package/src/metadata-builder/builders/section-builders/booking-section-builder.ts +87 -0
  297. package/src/metadata-builder/builders/section-builders/button-section-builder.ts +6 -1
  298. package/src/metadata-builder/builders/section-builders/contact-form-builder.ts +74 -4
  299. package/src/metadata-builder/builders/section-builders/delete-section-builder.ts +15 -1
  300. package/src/metadata-builder/builders/section-builders/divider-section-builder.ts +13 -1
  301. package/src/metadata-builder/builders/section-builders/image-gallery-builder.ts +91 -31
  302. package/src/metadata-builder/builders/section-builders/images-section-builder.ts +102 -48
  303. package/src/metadata-builder/builders/section-builders/index.ts +1 -0
  304. package/src/metadata-builder/builders/section-builders/mailing-list-builder.ts +38 -2
  305. package/src/metadata-builder/builders/section-builders/mailing-list-section-builder.ts +38 -2
  306. package/src/metadata-builder/builders/section-builders/profile-section-builder.ts +55 -3
  307. package/src/metadata-builder/builders/section-builders/shapes-section-builder.ts +170 -77
  308. package/src/metadata-builder/builders/section-builders/social-links-builder.test.ts +119 -0
  309. package/src/metadata-builder/builders/section-builders/social-links-builder.ts +13 -2
  310. package/src/metadata-builder/builders/section-builders/testimonial-section-builder.ts +178 -57
  311. package/src/metadata-builder/builders/section-builders/text-section-builder.ts +130 -30
  312. package/src/metadata-builder/builders/section-content-factory.ts +15 -2
  313. package/src/metadata-builder/builders/section-field-maps.ts +34 -1
  314. package/src/metadata-builder/builders/section-field-utils.ts +131 -72
  315. package/src/metadata-builder/builders/section-rules/about-section.rules.ts +38 -0
  316. package/src/metadata-builder/builders/section-rules/add-page.rules.ts +17 -0
  317. package/src/metadata-builder/builders/section-rules/banner-section.rules.ts +49 -0
  318. package/src/metadata-builder/builders/section-rules/booking-section.rules.ts +34 -0
  319. package/src/metadata-builder/builders/section-rules/button-section.rules.ts +22 -0
  320. package/src/metadata-builder/builders/section-rules/contact-form.rules.ts +30 -0
  321. package/src/metadata-builder/builders/section-rules/divider-section.rules.ts +17 -0
  322. package/src/metadata-builder/builders/section-rules/footer.rules.ts +21 -0
  323. package/src/metadata-builder/builders/section-rules/global-styles.rules.ts +44 -0
  324. package/src/metadata-builder/builders/section-rules/header.rules.ts +75 -0
  325. package/src/metadata-builder/builders/section-rules/image-gallery.rules.ts +22 -0
  326. package/src/metadata-builder/builders/section-rules/images-section.rules.ts +55 -0
  327. package/src/metadata-builder/builders/section-rules/mailing-list.rules.ts +21 -0
  328. package/src/metadata-builder/builders/section-rules/profile.rules.ts +27 -0
  329. package/src/metadata-builder/builders/section-rules/rename-page.rules.ts +17 -0
  330. package/src/metadata-builder/builders/section-rules/shapes-section.rules.ts +51 -0
  331. package/src/metadata-builder/builders/section-rules/social-links.rules.ts +27 -0
  332. package/src/metadata-builder/builders/section-rules/testimonial-section.rules.ts +48 -0
  333. package/src/metadata-builder/builders/section-rules/text-section.rules.ts +28 -0
  334. package/src/metadata-builder/builders/shape-color-utils.test.ts +115 -0
  335. package/src/metadata-builder/builders/shape-color-utils.ts +75 -0
  336. package/src/metadata-builder/builders/undo-builder.ts +105 -0
  337. package/src/metadata-builder/builders/update-content-text-style-builder.ts +4 -1
  338. package/src/metadata-builder/helpers/rte.helpers.ts +27 -13
  339. package/src/metadata-builder/metadata-executor.ts +42 -2
  340. package/src/metadata-builder/models.ts +39 -1
  341. package/src/metadata-builder/parsers/ai-toolcall-parser.ts +152 -0
  342. package/src/metadata-builder/parsers/section-tool-arguments.ts +138 -24
  343. package/src/metadata-builder/sanitizers/__tests__/section-args-validator.test.ts +659 -0
  344. package/src/metadata-builder/sanitizers/rte-schema-check.ts +99 -0
  345. package/src/metadata-builder/sanitizers/sanitizer-rules.ts +97 -0
  346. package/src/metadata-builder/sanitizers/section-args-validator.ts +445 -0
  347. package/src/shared/content-settings/components/content-settings/ContentSettings.mixin.ts +10 -16
  348. package/src/shared/content-settings/components/content-settings/ContentSettings.stories.ts +0 -1
  349. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.ts +6 -10
  350. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.vue +1 -23
  351. package/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.vue +0 -15
  352. package/src/shared/content-settings/components/text-items-field/TextItemsField.vue +0 -15
  353. package/src/shared/navigation-style-settings/store/index.ts +5 -0
  354. package/src/shared/page-navigation/store/page-navigation-store.ts +4 -31
  355. package/src/shared/page-navigation/utils/nav-order-utils.ts +32 -0
  356. package/src/shared/side-bar/components/SideBar.vue +14 -1
  357. package/src/shared/side-bar/store/side-bar-store.ts +0 -20
  358. package/src/utils/build-asset-manifest.ts +153 -0
  359. package/src/utils/minify-brand-page-metadata.ts +362 -130
  360. package/lib/src/brand-page-maker/composables/ai-chat/useAiChat.js +0 -368
  361. package/lib/src/brand-page-maker/composables/ai-chat/useAiTextEditPrompts.d.ts +0 -18
  362. package/lib/src/brand-page-maker/composables/ai-chat/useAiTextEditPrompts.js +0 -144
  363. package/lib/src/brand-page-maker/stores/ai-thread/ai-thread-store.d.ts +0 -155
  364. package/lib/src/brand-page-maker/stores/ai-thread/ai-thread-store.js +0 -25
  365. package/lib/src/brand-page-maker/utils/mixpanel.util.d.ts +0 -1
  366. package/lib/src/brand-page-maker/utils/mixpanel.util.js +0 -29
  367. package/lib/src/bundled-translations-CNK7l6_v.js +0 -173
  368. package/lib/src/bundled-translations.de-DE-BLE4_y0H.js +0 -173
  369. package/lib/src/bundled-translations.es-ES-thO9osbg.js +0 -173
  370. package/lib/src/bundled-translations.fr-CA-BZkhiNgU.js +0 -173
  371. package/lib/src/bundled-translations.fr-FR-bhDLPKgZ.js +0 -173
  372. package/lib/src/bundled-translations.pt-BR-CI9a5Bq1.js +0 -173
  373. package/lib/src/bundled-translations.pt-PT-DBoErBaq.js +0 -173
  374. package/src/brand-page-maker/components/ai-text-edit/AiTextEdit.vue +0 -154
  375. package/src/brand-page-maker/composables/ai-chat/useAiChat.ts +0 -562
  376. package/src/brand-page-maker/composables/ai-chat/useAiTextEditPrompts.ts +0 -196
  377. package/src/brand-page-maker/stores/ai-thread/ai-thread-store.ts +0 -31
  378. package/src/brand-page-maker/utils/mixpanel.util.ts +0 -42
  379. package/src/shared/content-settings/components/generate-ai-button/GenerateAiButton.vue +0 -114
  380. package/src/shared/content-settings/components/generate-ai-modal/GenerateAiModal.vue +0 -761
@@ -1,39 +1,66 @@
1
1
  import { ref, computed, watch, nextTick, onUnmounted } from 'vue';
2
+ import type { BrandPageModel } from '../../../brand-page/models';
2
3
  import {
3
4
  getInstance as getAiAssistantClient,
4
5
  AI_ASSISTANT_AGENT_TYPES,
5
- buildWebsiteBuilderMessage,
6
6
  type AiAssistantResponse,
7
7
  type AiAssistantToolResult,
8
8
  type AiAssistantToolCall,
9
+ type LogoContext,
10
+ type UserPlan,
9
11
  } from '../../../clients/ai-assistant-client';
12
+ import { FabricRenderClient } from '../../../clients/fabric-render-client';
13
+ import { parseLogoThemeToCssStyles } from '../../../brand-page/utils/style.util';
14
+ import { AI_ASSISTANT_TOOL_NAMES } from '../../../metadata-builder/parsers/ai-toolcall-parser';
10
15
  import {
11
16
  WebSocketGatewayClient,
12
17
  type WebSocketMessage,
18
+ type PlanItem,
13
19
  } from '../../../clients/websocket-gateway-client';
14
20
  import { minifyBrandPageMetadata } from '../../../utils/minify-brand-page-metadata';
15
- import { useSnapshotStore, useAiWebsiteBuilderThreadStore } from '../../stores';
21
+ import { buildAssetManifest } from '../../../utils/build-asset-manifest';
22
+ import { usePageNavigationStore } from '../../../shared/page-navigation/store/page-navigation-store';
23
+ import { navigateToPageByPageId } from '../../routing';
24
+ import {
25
+ useSnapshotStore,
26
+ useAiWebsiteBuilderThreadStore,
27
+ useAiCheckpointStore,
28
+ useBrandPageContainerStore,
29
+ useUiStore,
30
+ } from '../../stores';
16
31
  import { useBrandPageMakerStore } from '../../stores';
32
+ import { useBrandPageMakerUserStore } from '../../stores/user/user-store';
17
33
  import { useAiMetadataBuilder } from './useAiMetadataBuilder';
34
+ import {
35
+ pickErrorMessage,
36
+ pickWsErrorMessage,
37
+ buildSubmitErrorReport,
38
+ } from './aiErrorCopy';
39
+ import raygunUtil from '../../../brand-page/utils/raygun.util';
40
+ import { useEventTracker, AI_CTA_LOCATIONS } from '../useEventTracker';
18
41
  import { Logger } from '../../../metadata-builder/logger';
19
42
  import type {
20
43
  UseAiChatResult,
21
44
  ThreadMessage,
22
45
  TextThreadMessage,
23
46
  SendMessageOptions,
24
- } from './useAiChat';
47
+ } from './types';
25
48
 
26
49
  const BUILD_TIMEOUT_MS = 600000;
27
50
 
28
51
  const aiLogger = new Logger();
29
52
  let activeBuildWsClient: WebSocketGatewayClient | null = null;
30
- const MAX_TOOL_CALL_ITERATIONS = 5;
31
53
 
32
54
  export function useAiWebsiteBuilderChat(): UseAiChatResult {
33
55
  const aiThreadStore = useAiWebsiteBuilderThreadStore();
34
56
  const snapshotStore = useSnapshotStore();
35
57
  const brandPageMakerStore = useBrandPageMakerStore();
58
+ const containerStore = useBrandPageContainerStore();
59
+ const userStore = useBrandPageMakerUserStore();
60
+ const uiStore = useUiStore();
36
61
  const aiMetadataBuilder = useAiMetadataBuilder(aiLogger);
62
+ const checkpointStore = useAiCheckpointStore();
63
+ const eventTracker = useEventTracker();
37
64
 
38
65
  const hasStoredMessages = aiThreadStore.messages.length > 0;
39
66
  const threadItems = ref<ThreadMessage[]>(
@@ -49,6 +76,50 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
49
76
  } as TextThreadMessage,
50
77
  ],
51
78
  );
79
+
80
+ // ---------------------------------------------------------------------------
81
+ // Undo snapshot lifecycle (WL9) — reuses the existing `checkpointStore`,
82
+ // which stores pre-prompt BrandPageModel snapshots keyed by user message id.
83
+ //
84
+ // Capture rule: one checkpoint per user prompt, but ONLY when the response
85
+ // contains at least one non-undo tool call. Conversational responses and
86
+ // pure-undo responses leave checkpoint state untouched. This is handled
87
+ // inside `applyToolCallsAsync`, which is idempotent per user prompt thanks
88
+ // to the `hasCheckpoint(userMessageId)` guard — so multi-turn retry flows
89
+ // (where `applyToolCallsAsync` may run multiple times for one user prompt)
90
+ // only create the checkpoint on the first change-producing response.
91
+ //
92
+ // Restore rule: the UndoBuilder calls `undoHandler` which reverts to the
93
+ // latest checkpoint. `checkpointStore.revertToCheckpoint` splices away the
94
+ // target plus all subsequent entries in one step — exactly the pop-and-
95
+ // cleanup semantics we want.
96
+ //
97
+ // User-facing feedback comes from the AI pipeline's AIMessage content
98
+ // (e.g., "Reverted your last change.", server-side Gate 1 refusals for
99
+ // empty history) — NOT from this handler. Server-side Gate 1 already
100
+ // refuses undo when the conversation has no prior change-producing action,
101
+ // so a null return here is a defensive no-op rather than a normal path.
102
+ // ---------------------------------------------------------------------------
103
+
104
+ /**
105
+ * Resolver invoked by the UndoBuilder at execute time.
106
+ *
107
+ * Pops the latest checkpoint and returns its model; returns `null` when
108
+ * no checkpoint exists (defensive — server-side Gate 1 should prevent
109
+ * undo from reaching this handler on an empty history). The UndoBuilder
110
+ * surfaces the null case as a tool error, which the caller may log; no
111
+ * thread-level UI bubble is appended here.
112
+ */
113
+ const undoHandler = (): BrandPageModel | null => {
114
+ const { checkpoints } = checkpointStore;
115
+
116
+ if (checkpoints.length === 0) return null;
117
+
118
+ const latest = checkpoints[checkpoints.length - 1];
119
+
120
+ return checkpointStore.revertToCheckpoint(latest.userMessageId);
121
+ };
122
+
52
123
  const isProcessing = computed({
53
124
  get: () => aiThreadStore.isProcessing,
54
125
  set: (value: boolean) => {
@@ -99,8 +170,31 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
99
170
  const connectionId = await wsClient.connect();
100
171
 
101
172
  wsClient.onDisconnect(() => {
173
+ // Only report when a build was actively in flight. Idle disconnects
174
+ // (page reload, server restart with no user-visible build) would
175
+ // otherwise flood Raygun with non-actionable noise.
176
+ const wasBuildInFlight = aiThreadStore.isBuildInProgress;
177
+
102
178
  activeBuildWsClient = null;
103
179
  addServiceUnavailableBubble();
180
+
181
+ if (wasBuildInFlight) {
182
+ const err = new Error(
183
+ 'There was a disruption in the connection while building your website. Please try again.',
184
+ );
185
+
186
+ raygunUtil.safeSendRaygunError(err, {
187
+ tags: [
188
+ 'feature:ai-website-builder',
189
+ 'failure:websocket_disconnect',
190
+ 'stage:in_flight_build',
191
+ ],
192
+ customData: {
193
+ build_id: aiThreadStore.buildId ?? null,
194
+ thread_id: aiThreadStore.threadId ?? null,
195
+ },
196
+ });
197
+ }
104
198
  });
105
199
 
106
200
  activeBuildWsClient = wsClient;
@@ -108,30 +202,216 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
108
202
  return connectionId;
109
203
  };
110
204
 
111
- const buildMessage = (userPrompt: string) => {
112
- const minified = minifyBrandPageMetadata(brandPageMakerStore.brandPageData);
205
+ const USER_PROMPT_PARAM_MAX_LENGTH = 100;
206
+
207
+ const appendUserPromptParam = (
208
+ rawUrl: string,
209
+ userPrompt: string,
210
+ ): string => {
211
+ try {
212
+ const url = new URL(rawUrl);
213
+ const trimmed = userPrompt.trim().slice(0, USER_PROMPT_PARAM_MAX_LENGTH);
214
+
215
+ if (trimmed) {
216
+ url.searchParams.set('user_prompt', trimmed);
217
+ }
218
+
219
+ return url.toString();
220
+ } catch {
221
+ return rawUrl;
222
+ }
223
+ };
224
+
225
+ const fetchLogoContext = async (
226
+ logoDraftToken: string | undefined,
227
+ ): Promise<LogoContext | undefined> => {
228
+ if (!logoDraftToken) return undefined;
113
229
 
114
- return buildWebsiteBuilderMessage(userPrompt, minified);
230
+ const client = FabricRenderClient.getInstance();
231
+
232
+ if (!client) return undefined;
233
+
234
+ const attributes =
235
+ await client.getLogoAttributesByLogoDraftTokenAsync(logoDraftToken);
236
+
237
+ if (!attributes?.logoTheme) return undefined;
238
+
239
+ const { logoTextColor, logoBackgroundColor } = parseLogoThemeToCssStyles(
240
+ attributes.logoTheme,
241
+ );
242
+
243
+ const context: LogoContext = {};
244
+
245
+ if (logoTextColor.rgb) context.logoTextColor = logoTextColor.rgb;
246
+
247
+ if (logoBackgroundColor.rgb)
248
+ context.logoBackgroundColor = logoBackgroundColor.rgb;
249
+
250
+ return Object.keys(context).length > 0 ? context : undefined;
115
251
  };
116
252
 
117
- const applyToolCallsAsync = async (response: AiAssistantResponse) => {
253
+ const buildMessagePayload = async (userPrompt: string) => {
254
+ const brandPageData = brandPageMakerStore.brandPageData;
255
+ const headerLogoDraftToken =
256
+ brandPageData.pageHeaderDesktop?.logoImage?.logoDraftToken ??
257
+ uiStore.logoDraftToken;
258
+ const [assets, logoContext] = await Promise.all([
259
+ buildAssetManifest(brandPageData),
260
+ fetchLogoContext(headerLogoDraftToken),
261
+ ]);
262
+ const pageNavigationStore = usePageNavigationStore();
263
+ const currentPageId = pageNavigationStore.activePageId;
264
+
265
+ const websiteContext = {
266
+ metadata: minifyBrandPageMetadata(brandPageData, assets),
267
+ ...(assets.length > 0 && { assets }),
268
+ websiteTemplateToken: containerStore.designTemplateToken,
269
+ ...(containerStore.designDraftToken && {
270
+ websiteDraftToken: containerStore.designDraftToken,
271
+ }),
272
+ ...(currentPageId && { activeContext: { currentPageId } }),
273
+ ...(brandPageMakerStore.businessName && {
274
+ businessName: brandPageMakerStore.businessName,
275
+ }),
276
+ ...(logoContext && { logoContext }),
277
+ };
278
+
279
+ return { message: userPrompt, websiteContext };
280
+ };
281
+
282
+ /**
283
+ * Per-page vacant-slot queue for the current build session.
284
+ *
285
+ * When the AI pipeline emits a CREATE batch, sections are processed in
286
+ * planned order. If any CREATE fails validation, it returns through the
287
+ * retry loop as a fresh CREATE tool call carrying no `move_before_content_id`
288
+ * — the backend cannot supply one because it never sees the frontend-
289
+ * assigned content ids. Without a hint, the retried section is pushed to
290
+ * the bottom of the page (see BaseSectionBuilder.createContent).
291
+ *
292
+ * To preserve position, we track "vacant slots" per page: each failure
293
+ * records a `null` placeholder; the first subsequent successful CREATE on
294
+ * the same page anchors that placeholder by stamping its own content id.
295
+ * A retry CREATE on that page pops the oldest anchored placeholder and
296
+ * injects `move_before_content_id`, so the splice lands at the planned
297
+ * index. Multiple interleaved failures are handled FIFO, matching the
298
+ * planner-ascending order in which the retry batch is emitted.
299
+ *
300
+ * The map is build-scoped and reset at the start of every `callApiBuildAsync`.
301
+ */
302
+ type VacantSlotMap = Map<string, (string | null)[]>;
303
+
304
+ const applyToolCallsAsync = async (
305
+ response: AiAssistantResponse,
306
+ userMessageId: string,
307
+ vacantSlots: VacantSlotMap,
308
+ ) => {
118
309
  let aiMessage: string | null = response.message || '';
119
310
  const modelToUpdate = brandPageMakerStore.brandPageData;
311
+ const preCallModel = modelToUpdate;
312
+
313
+ // Conditional per-prompt checkpoint creation. Guarded by:
314
+ // - has at least one non-undo tool call (skip conversational + pure-undo
315
+ // responses — nothing worth reverting to),
316
+ // - no checkpoint exists yet for this user prompt (idempotent across the
317
+ // multi-turn retry flow, which calls applyToolCallsAsync multiple
318
+ // times for the same userMessageId).
319
+ const hasChangeProducingToolCall = (response.toolCalls ?? []).some(
320
+ (tc) => tc.function !== AI_ASSISTANT_TOOL_NAMES.UNDO,
321
+ );
322
+
323
+ if (
324
+ hasChangeProducingToolCall &&
325
+ !checkpointStore.hasCheckpoint(userMessageId)
326
+ ) {
327
+ checkpointStore.createCheckpoint(userMessageId, preCallModel);
328
+ }
329
+
330
+ // PRE-PASS: for each create-mode section tool call on a page with a
331
+ // pending anchored vacant slot, splice `move_before_content_id` into
332
+ // the wire arguments so the executor places the section at the planned
333
+ // index instead of the end of the page. We rewrite the JSON string
334
+ // because parseToolCalls owns the parse step downstream.
335
+ const enrichedToolCalls = (response.toolCalls ?? []).map((tc) => {
336
+ try {
337
+ const args = JSON.parse(tc.arguments) as Record<string, unknown>;
338
+ const mode = args.mode;
339
+ const pageId = args.page_id as string | undefined;
340
+
341
+ if (
342
+ mode === 'create' &&
343
+ pageId &&
344
+ !args.move_before_content_id &&
345
+ (vacantSlots.get(pageId)?.length ?? 0) > 0
346
+ ) {
347
+ const slots = vacantSlots.get(pageId)!;
348
+ const anchorIdx = slots.findIndex((a) => a !== null);
349
+
350
+ if (anchorIdx !== -1) {
351
+ const anchor = slots[anchorIdx];
352
+
353
+ slots.splice(anchorIdx, 1);
354
+ args.move_before_content_id = anchor;
355
+
356
+ return { ...tc, arguments: JSON.stringify(args) };
357
+ }
358
+ }
359
+ } catch {
360
+ // Malformed arguments — leave as-is; parseToolCalls will surface the error.
361
+ }
362
+
363
+ return tc;
364
+ });
120
365
 
121
366
  const updateResult = await aiMetadataBuilder.applyAiToolCallsAsync(
122
367
  modelToUpdate,
123
- response.toolCalls || [],
368
+ enrichedToolCalls,
369
+ {
370
+ undoHandler,
371
+ eventTracker,
372
+ },
124
373
  );
125
374
 
126
375
  const toolResults: AiAssistantToolResult[] = updateResult.results.map(
127
- (x) => {
376
+ (x, i) => {
128
377
  return {
129
378
  toolId: x.toolId,
130
379
  success: x.errors && x.errors.length > 0 ? 'failed' : 'success',
380
+ name: enrichedToolCalls[i]?.function,
381
+ errorMessage: x.errors?.length ? x.errors.join('; ') : undefined,
131
382
  };
132
383
  },
133
384
  );
134
385
 
386
+ // POST-PASS: walk this batch's create-mode results in plan order.
387
+ // - Failure → append `null` to the page's vacant queue. Anchor unknown
388
+ // until a later successful CREATE on the same page binds it.
389
+ // - Success → if the page has any pending `null` placeholders from
390
+ // earlier failures in this batch, bind the FIRST one to this new
391
+ // content id. The retry batch will pop it in plan order, which
392
+ // matches the backend's ascending-`order` retry emission.
393
+ updateResult.parsedToolCalls.forEach((parsed, i) => {
394
+ const args = parsed.arguments as { mode?: string; page_id?: string };
395
+
396
+ if (args.mode !== 'create' || !args.page_id) return;
397
+
398
+ const result = updateResult.results[i];
399
+ const pageId = args.page_id;
400
+ const slots = vacantSlots.get(pageId) ?? [];
401
+
402
+ if (result.errors && result.errors.length > 0) {
403
+ slots.push(null);
404
+ } else if (result.contentId) {
405
+ const nullIdx = slots.indexOf(null);
406
+
407
+ if (nullIdx !== -1) {
408
+ slots[nullIdx] = result.contentId;
409
+ }
410
+ }
411
+
412
+ vacantSlots.set(pageId, slots);
413
+ });
414
+
135
415
  updateResult.parsedToolCalls.forEach((toolCall) => {
136
416
  const args = toolCall.arguments as any;
137
417
 
@@ -140,15 +420,25 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
140
420
  }
141
421
  });
142
422
 
143
- console.log(
144
- 'updateResult.model',
145
- JSON.parse(JSON.stringify(updateResult.model)),
146
- );
147
-
148
423
  await brandPageMakerStore.initialiseStoresByBrandPageModelAsync(
149
424
  updateResult.model,
150
425
  );
151
426
 
427
+ // AI tool calls can regenerate the active page's slug (e.g. rename_page
428
+ // recomputes pageSlug from the new title). The in-memory maker router's
429
+ // currentRoute still holds the pre-change slug, so the preview's
430
+ // slug-keyed page lookup (findNavItemByRelativePath) misses and silently
431
+ // falls back to pages[0]. Re-push by the stable pageId — which survives
432
+ // any rename — to refresh routeStore.currentRoute.params to the new slug
433
+ // and keep the preview on the page the user was editing. Unconditional:
434
+ // a push to an unchanged slug is a no-op, and an empty activePageId (e.g.
435
+ // initial load) is a safe early-return inside navigateToPageByPageId.
436
+ const pageNavigationStore = usePageNavigationStore();
437
+
438
+ if (pageNavigationStore.activePageId) {
439
+ navigateToPageByPageId(pageNavigationStore.activePageId);
440
+ }
441
+
152
442
  await nextTick();
153
443
 
154
444
  // Re-capture snapshot so subsequent messages reflect the updated page
@@ -163,23 +453,28 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
163
453
 
164
454
  const callApiBuildAsync = async (
165
455
  userPrompt: string,
166
- ): Promise<{ text: string | null; langChainUrl?: string }> => {
456
+ userMessageId: string,
457
+ ): Promise<{ text: string | null; isError?: boolean }> => {
167
458
  const connectionId = await ensureConnectedAsync();
168
459
  const wsClient = activeBuildWsClient!;
169
460
 
170
461
  try {
171
462
  const client = getAiAssistantClient();
172
- const message = buildMessage(userPrompt);
463
+ const { message, websiteContext } = await buildMessagePayload(userPrompt);
173
464
 
174
- wsClient.sendHeartbeat();
465
+ const userPlan: UserPlan = userStore.hasPremiumSubscription
466
+ ? 'premium'
467
+ : 'free';
175
468
 
176
469
  let buildResponse;
177
470
 
178
471
  if (!aiThreadStore.threadId) {
179
472
  buildResponse = await client.createWebsiteThreadBuildAsync({
180
473
  message,
474
+ websiteContext,
181
475
  websiteSnapshot: snapshotStore.snapshotBase64 || undefined,
182
476
  agentType: AI_ASSISTANT_AGENT_TYPES.WEBSITE_BUILDER,
477
+ userPlan,
183
478
  connectionId,
184
479
  });
185
480
  } else {
@@ -187,8 +482,10 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
187
482
  aiThreadStore.threadId,
188
483
  {
189
484
  message,
485
+ websiteContext,
190
486
  websiteSnapshot: snapshotStore.snapshotBase64 || undefined,
191
487
  agentType: AI_ASSISTANT_AGENT_TYPES.WEBSITE_BUILDER,
488
+ userPlan,
192
489
  connectionId,
193
490
  },
194
491
  );
@@ -199,15 +496,45 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
199
496
  aiThreadStore.isBuildInProgress = true;
200
497
  aiThreadStore.buildSectionsCompleted = 0;
201
498
 
202
- const langChainUrl = buildResponse.langChainUrl;
203
-
204
499
  wsClient.setBuildActive(true);
205
500
  wsClient.startResponseHeartbeat();
206
501
 
207
- return new Promise<{ text: string | null; langChainUrl?: string }>(
502
+ const withTypingMessage = (
503
+ fn: (msg: TextThreadMessage) => void,
504
+ ): void => {
505
+ const typingId = currentTypingMessageId.value;
506
+
507
+ if (!typingId) return;
508
+
509
+ const idx = threadItems.value.findIndex((m) => m.id === typingId);
510
+
511
+ if (idx !== -1) fn(threadItems.value[idx] as TextThreadMessage);
512
+ };
513
+
514
+ // Surface the thread URL on the agent bubble as soon as the API returns
515
+ // it, so the button is available while the build is still streaming and
516
+ // is preserved if the build later errors or times out.
517
+ if (buildResponse.langChainUrl) {
518
+ const url = appendUserPromptParam(
519
+ buildResponse.langChainUrl,
520
+ userPrompt,
521
+ );
522
+
523
+ withTypingMessage((m) => {
524
+ m.langChainUrl = url;
525
+ });
526
+ }
527
+
528
+ return new Promise<{ text: string | null; isError?: boolean }>(
208
529
  (resolve, reject) => {
209
530
  let settled = false;
531
+ let retryCount = 0;
532
+ let lastAiMessage: string | null = null;
210
533
  let handler: ((msg: WebSocketMessage) => void) | null = null;
534
+ // Vacant-slot queue scoped to this build session. Persists across
535
+ // retry rounds so a failed CREATE returns to its planned slot via
536
+ // a synthesised `move_before_content_id`.
537
+ const vacantSlots: VacantSlotMap = new Map();
211
538
 
212
539
  const finishBuild = () => {
213
540
  aiThreadStore.isBuildInProgress = false;
@@ -228,59 +555,261 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
228
555
  handler = (msg: WebSocketMessage) => {
229
556
  if (settled) return;
230
557
 
231
- if (msg.buildId !== aiThreadStore.buildId) return;
558
+ try {
559
+ if (msg.buildId !== aiThreadStore.buildId) return;
232
560
 
233
- if (isStopped.value) {
234
- settled = true;
235
- clearTimeout(timeout);
236
- finishBuild();
237
- resolve({ text: null });
561
+ if (isStopped.value) {
562
+ settled = true;
563
+ clearTimeout(timeout);
564
+ finishBuild();
565
+ resolve({ text: null });
238
566
 
239
- return;
240
- }
567
+ return;
568
+ }
241
569
 
242
- if (msg.type === 'build_complete') {
243
- settled = true;
244
- clearTimeout(timeout);
245
-
246
- const toolCalls = (msg.toolCalls || []) as AiAssistantToolCall[];
247
- const aiResponse: AiAssistantResponse = {
248
- threadId: aiThreadStore.threadId || '',
249
- toolCalls,
250
- message: msg.message || null,
251
- type: 'tool_calls',
252
- totalPaidToolCalls: 0,
253
- timestamp: Date.now(),
254
- };
255
-
256
- (async () => {
257
- try {
258
- if (toolCalls.length > 0) {
259
- await applyToolCallsAsync(aiResponse);
260
- }
570
+ if (msg.type === 'chat_started' && msg.message) {
571
+ withTypingMessage((m) => {
572
+ m.initialMessage = msg.message;
573
+ });
261
574
 
262
- finishBuild();
263
- await snapshotStore.refreshSnapshotAsync();
264
- resolve({
265
- text:
266
- aiResponse.message || 'Your website has been updated.',
267
- langChainUrl,
268
- });
269
- } catch (err) {
270
- aiLogger.log('build_complete apply error', { err });
271
- finishBuild();
272
- resolve({ text: 'An error occurred applying changes.' });
273
- }
274
- })();
275
- }
575
+ return;
576
+ }
577
+
578
+ if (msg.type === 'plan_announced' && msg.items) {
579
+ withTypingMessage((m) => {
580
+ if (!m.planItems) m.planItems = msg.items as PlanItem[];
581
+ });
276
582
 
277
- if (msg.type === 'build_error') {
278
- settled = true;
279
- clearTimeout(timeout);
280
- finishBuild();
281
- resolve({
282
- text: msg.error || 'An error occurred during the build.',
583
+ return;
584
+ }
585
+
586
+ if (msg.type === 'item_complete' && msg.itemId) {
587
+ const itemId = msg.itemId;
588
+
589
+ withTypingMessage((m) => {
590
+ if (!m.completedItemIds?.includes(itemId)) {
591
+ m.completedItemIds = [
592
+ ...(m.completedItemIds ?? []),
593
+ itemId,
594
+ ];
595
+ }
596
+ });
597
+
598
+ return;
599
+ }
600
+
601
+ if (msg.type === 'server_response') {
602
+ const toolCalls = (msg.toolCalls ||
603
+ []) as AiAssistantToolCall[];
604
+ const aiResponse: AiAssistantResponse = {
605
+ threadId: aiThreadStore.threadId || '',
606
+ toolCalls,
607
+ message: msg.message || null,
608
+ type: 'tool_calls',
609
+ totalPaidToolCalls: 0,
610
+ timestamp: Date.now(),
611
+ };
612
+
613
+ (async () => {
614
+ try {
615
+ // No tool calls = build cycle complete (success, max retries, or no retryable sections)
616
+ if (toolCalls.length === 0) {
617
+ // Defence-in-depth: a server_response with no toolCalls AND
618
+ // no message text is a degenerate response — it means the
619
+ // backend graph reached END without producing anything
620
+ // actionable. The server-side fix in stream_with_push now
621
+ // converts this to a build_error frame, but if a future
622
+ // regression slips through we must NOT show "Your website
623
+ // has been updated" — that hides real failures from users
624
+ // and from monitoring.
625
+ const hasMeaningfulMessage = Boolean(
626
+ aiResponse.message || lastAiMessage,
627
+ );
628
+
629
+ if (!hasMeaningfulMessage) {
630
+ raygunUtil.safeSendRaygunError(
631
+ new Error(
632
+ 'AI build server_response had empty toolCalls and empty message',
633
+ ),
634
+ {
635
+ tags: [
636
+ 'feature:ai-website-builder',
637
+ 'failure:degenerate_server_response',
638
+ ],
639
+ customData: {
640
+ build_id: aiThreadStore.buildId ?? null,
641
+ thread_id: aiThreadStore.threadId ?? null,
642
+ },
643
+ },
644
+ );
645
+ settled = true;
646
+ clearTimeout(timeout);
647
+ finishBuild();
648
+ resolve({
649
+ text: 'Something went wrong while updating your website. Please try again.',
650
+ isError: true,
651
+ });
652
+
653
+ return;
654
+ }
655
+
656
+ settled = true;
657
+ clearTimeout(timeout);
658
+ finishBuild();
659
+ await snapshotStore.refreshSnapshotAsync();
660
+ resolve({
661
+ text: aiResponse.message || lastAiMessage || '',
662
+ });
663
+
664
+ return;
665
+ }
666
+
667
+ // Tool calls present — apply locally and submit results back
668
+ const { toolResults, aiMessage } =
669
+ await applyToolCallsAsync(
670
+ aiResponse,
671
+ userMessageId,
672
+ vacantSlots,
673
+ );
674
+
675
+ lastAiMessage = aiMessage;
676
+
677
+ // Submit all tool results (success + failure) so the AI pipeline
678
+ // persists ToolMessages matching every tool_call in the conversation.
679
+ const failedResults = toolResults.filter(
680
+ (tr) => tr.success !== 'success',
681
+ );
682
+
683
+ aiLogger.log('tool submission for results', {
684
+ total: toolResults.length,
685
+ failed: failedResults.length,
686
+ failedResults,
687
+ retryCount,
688
+ });
689
+
690
+ const submitResult =
691
+ await client.submitToolResultsBuildAsync(
692
+ aiThreadStore.threadId!,
693
+ {
694
+ toolCalls: toolResults,
695
+ agentType: AI_ASSISTANT_AGENT_TYPES.WEBSITE_BUILDER,
696
+ connectionId,
697
+ retryCount,
698
+ userPlan,
699
+ },
700
+ );
701
+
702
+ if (failedResults.length === 0) {
703
+ settled = true;
704
+ clearTimeout(timeout);
705
+ finishBuild();
706
+ resolve({
707
+ text: aiMessage || 'Your website has been updated.',
708
+ });
709
+
710
+ return;
711
+ }
712
+
713
+ // Update buildId so the handler matches subsequent WS messages
714
+ if (submitResult.buildId) {
715
+ aiThreadStore.buildId = submitResult.buildId;
716
+ }
717
+
718
+ // eslint-disable-next-line no-plusplus
719
+ retryCount++;
720
+ } catch (err) {
721
+ aiLogger.log('server_response apply error', { err });
722
+ // Client-side apply failure (metadata builder, tool-call parser,
723
+ // missing field, etc.) — server thinks the build succeeded but we
724
+ // couldn't materialise the changes. Mark the chat bubble as an
725
+ // error so the user sees the real outcome, and report to Raygun
726
+ // so the failure is visible in monitoring (the server didn't see it).
727
+ raygunUtil.safeSendRaygunError(
728
+ err instanceof Error
729
+ ? err
730
+ : new Error('AI apply failed: non-Error thrown'),
731
+ {
732
+ tags: [
733
+ 'feature:ai-website-builder',
734
+ 'failure:apply_error',
735
+ 'stage:client_apply',
736
+ ],
737
+ customData: {
738
+ thread_id: aiThreadStore.threadId ?? null,
739
+ build_id: aiThreadStore.buildId ?? null,
740
+ },
741
+ },
742
+ );
743
+ settled = true;
744
+ clearTimeout(timeout);
745
+ finishBuild();
746
+ resolve({
747
+ text: "I couldn't apply those changes to your website. Please try again.",
748
+ isError: true,
749
+ });
750
+ }
751
+ })();
752
+
753
+ return;
754
+ }
755
+
756
+ if (msg.type === 'server_error' || msg.type === 'build_error') {
757
+ settled = true;
758
+ clearTimeout(timeout);
759
+ finishBuild();
760
+
761
+ // Backend already reports the underlying pipeline failure to
762
+ // Raygun via its structured handler (stage:run_build /
763
+ // stage:section_builder / etc. with full Python traceback).
764
+ // We report the frontend's RECEIPT of the error frame as a
765
+ // separate signal — distinct tag, distinct grouping. This
766
+ // gives triangulation: both sides have entry → normal crash;
767
+ // frontend only → backend Raygun outage; backend only → WS
768
+ // frame didn't reach client (different bug shape).
769
+ const wsMsg = msg as {
770
+ type: string;
771
+ code?: string;
772
+ message?: string;
773
+ error?: string;
774
+ buildId?: string;
775
+ };
776
+
777
+ raygunUtil.safeSendRaygunError(
778
+ new Error(
779
+ `AI build ${wsMsg.type}: ${wsMsg.code ?? wsMsg.error ?? 'unknown'}`,
780
+ ),
781
+ {
782
+ tags: [
783
+ 'feature:ai-website-builder',
784
+ 'failure:websocket_error_received',
785
+ `frame_type:${wsMsg.type}`,
786
+ ],
787
+ customData: {
788
+ code: wsMsg.code ?? null,
789
+ message: wsMsg.message ?? null,
790
+ error: wsMsg.error ?? null,
791
+ build_id: wsMsg.buildId ?? null,
792
+ thread_id: aiThreadStore.threadId ?? null,
793
+ },
794
+ },
795
+ );
796
+
797
+ resolve({ text: pickWsErrorMessage(msg), isError: true });
798
+
799
+ return;
800
+ }
801
+ } catch (err) {
802
+ aiLogger.log('Unexpected error in WS message handler', {
803
+ err,
804
+ type: msg.type,
283
805
  });
806
+
807
+ if (!settled) {
808
+ settled = true;
809
+ clearTimeout(timeout);
810
+ finishBuild();
811
+ resolve({ text: 'An error occurred during the build.' });
812
+ }
284
813
  }
285
814
  };
286
815
 
@@ -300,6 +829,8 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
300
829
 
301
830
  if (!text?.trim() && (!images || images.length === 0)) return;
302
831
 
832
+ eventTracker.sendAiSendPromptEvent(AI_CTA_LOCATIONS.AI_BUILDER_TAB);
833
+
303
834
  isStopped.value = false;
304
835
  aiThreadStore.isProcessing = true;
305
836
 
@@ -322,6 +853,12 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
322
853
 
323
854
  threadItems.value.push(userMessage);
324
855
 
856
+ // Checkpoint creation is now conditional and happens inside
857
+ // `applyToolCallsAsync` — it fires only when the response carries at
858
+ // least one change-producing tool call, and only once per user prompt
859
+ // (idempotent across the multi-turn retry flow). See the "Undo snapshot
860
+ // lifecycle (WL9)" block near the top of this composable.
861
+
325
862
  const agentMessageId = (Date.now() + 1).toString();
326
863
 
327
864
  currentTypingMessageId.value = agentMessageId;
@@ -340,7 +877,7 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
340
877
  aiLogger.startGroup();
341
878
  aiLogger.log('sendMessageAsync', { messageOptions });
342
879
 
343
- const result = await callApiBuildAsync(text || '');
880
+ const result = await callApiBuildAsync(text || '', userMessage.id);
344
881
 
345
882
  if (isStopped.value) return;
346
883
 
@@ -352,7 +889,13 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
352
889
  if (result.text) {
353
890
  threadItems.value[messageIndex].text = result.text;
354
891
  threadItems.value[messageIndex].isTyping = false;
355
- threadItems.value[messageIndex].langChainUrl = result.langChainUrl;
892
+
893
+ // Honour the isError flag set by error paths in callApiBuildAsync
894
+ // (apply-failure catch, server_error / build_error WS frames).
895
+ // Without this, error text would render as a normal AI reply.
896
+ if (result.isError) {
897
+ threadItems.value[messageIndex].isError = true;
898
+ }
356
899
  } else {
357
900
  threadItems.value[messageIndex].text =
358
901
  'Failed to apply changes. Please try again.';
@@ -374,11 +917,22 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
374
917
  if (messageIndex !== -1) {
375
918
  threadItems.value[messageIndex].text = isConnectionError
376
919
  ? SERVICE_UNAVAILABLE_MESSAGE
377
- : error?.response?.data?.error ||
378
- 'An error occurred. Please try again.';
920
+ : pickErrorMessage(error);
379
921
  threadItems.value[messageIndex].isTyping = false;
380
922
  threadItems.value[messageIndex].isError = true;
381
923
  }
924
+
925
+ // REL 1 item (4): report request-path failures to Raygun so we can
926
+ // see network / proxy / upstream errors separately from pipeline
927
+ // failures (which are reported server-side via build_error).
928
+ const report = buildSubmitErrorReport(error, { stage: 'submit' });
929
+
930
+ if (report) {
931
+ raygunUtil.safeSendRaygunError(report.error, {
932
+ tags: report.tags,
933
+ customData: report.customData,
934
+ });
935
+ }
382
936
  } finally {
383
937
  currentTypingMessageId.value = null;
384
938
  isProcessing.value = false;
@@ -386,8 +940,6 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
386
940
  // was destroyed (tab switch) and the writable computed setter is inert.
387
941
  aiThreadStore.isProcessing = false;
388
942
  }
389
-
390
- console.log('aiLogger', aiLogger);
391
943
  };
392
944
 
393
945
  const deleteMessage = (messageId: string) => {
@@ -399,6 +951,8 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
399
951
  };
400
952
 
401
953
  const stopGenerationAsync = async () => {
954
+ eventTracker.sendAiStopGenerationEvent(AI_CTA_LOCATIONS.AI_BUILDER_TAB);
955
+
402
956
  isStopped.value = true;
403
957
  aiThreadStore.isBuildInProgress = false;
404
958
 
@@ -418,31 +972,34 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
418
972
 
419
973
  aiThreadStore.stopGeneration = stopGenerationAsync;
420
974
 
421
- onUnmounted(() => {
422
- if (aiThreadStore.stopGeneration === stopGenerationAsync) {
423
- aiThreadStore.stopGeneration = null;
424
- }
425
- });
426
-
427
975
  const formattedMessages = computed(() => {
428
976
  const initialMessageCount = hasStoredMessages
429
977
  ? aiThreadStore.messages.length
430
978
  : 1;
431
979
 
432
- return threadItems.value.map((msg, index) => ({
433
- type: msg.type,
434
- props: {
435
- ...(msg.type === 'text' && { text: msg.text }),
436
- ...(msg.type === 'image' && { images: msg.images, text: msg.text }),
437
- isUser: msg.role === 'user',
438
- isAi: msg.role === 'agent',
439
- showIcon: msg.role === 'agent',
440
- isTyping: msg.isTyping,
441
- isResponse: index >= 1,
442
- disableAnimation: index < initialMessageCount,
443
- langChainUrl: msg.langChainUrl,
444
- } as Record<string, unknown>,
445
- }));
980
+ return threadItems.value.map((msg, index) => {
981
+ return {
982
+ type: msg.type,
983
+ props: {
984
+ ...(msg.type === 'text' && { text: msg.text }),
985
+ ...(msg.type === 'image' && { images: msg.images, text: msg.text }),
986
+ isUser: msg.role === 'user',
987
+ isAi: msg.role === 'agent',
988
+ showIcon: msg.role === 'agent',
989
+ isTyping: msg.isTyping,
990
+ isResponse: index >= 1,
991
+ disableAnimation: index < initialMessageCount,
992
+ langChainUrl: msg.langChainUrl,
993
+ ...(msg.type === 'text' &&
994
+ msg.isTyping && {
995
+ initialMessage: (msg as TextThreadMessage).initialMessage,
996
+ planItems: (msg as TextThreadMessage).planItems ?? [],
997
+ completedItemIds:
998
+ (msg as TextThreadMessage).completedItemIds ?? [],
999
+ }),
1000
+ } as Record<string, unknown>,
1001
+ };
1002
+ });
446
1003
  });
447
1004
 
448
1005
  return {