@designcrowd/library.brand-page 5.17.6 → 5.17.7

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 (172) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-BI2KuOEF.js → CreatedOnBrandCrowd-de-de-BUQFMhZb.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-BYLJCjLJ.js → CreatedOnBrandCrowd-en-us-QS-5r4XI.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-Y_D6cuGE.js → CreatedOnBrandCrowd-es-es-CP2iH-n0.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-CqCBRjYh.js → CreatedOnBrandCrowd-fr-ca-qfD4NmQZ.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-CqCBRjYh.js → CreatedOnBrandCrowd-fr-fr-qfD4NmQZ.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-Bt0YF6DA.js → CreatedOnBrandCrowd-pt-br-CfmaB7zE.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-Bt0YF6DA.js → CreatedOnBrandCrowd-pt-pt-CfmaB7zE.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-CEk8FBEG.js → CreatedOnDcom-de-de-BxSUWfGN.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-DWw4Tm2L.js → CreatedOnDcom-en-us-CSeUdR6v.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-DpG-8o98.js → CreatedOnDcom-es-es-g7rCfAtP.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-CEla7RmR.js → CreatedOnDcom-fr-ca-Bh_BTb-O.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-DRXeVTlV.js → CreatedOnDcom-fr-fr-Clgd_Ujm.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-Bzu_phZc.js → CreatedOnDcom-pt-br-Dlgk0myX.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-DWax8Er7.js → CreatedOnDcom-pt-pt-B14APfrn.js} +1 -1
  15. package/lib/src/brand-page/models/brand-page-context.model.d.ts +2 -1
  16. package/lib/src/brand-page/models/brand-page-context.model.js +5 -0
  17. package/lib/src/brand-page/models/index.d.ts +1 -0
  18. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +62 -2
  19. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +1 -0
  20. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +60 -2
  21. package/lib/src/brand-page-maker/components/preview/Preview.mixin.d.ts +30 -1
  22. package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +60 -2
  23. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +60 -2
  24. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +60 -2
  25. package/lib/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.mixin.d.ts +60 -2
  26. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +60 -2
  27. package/lib/src/brand-page-maker/components/upgrade-to-premium-button/UpgradeToPremiumButton.mixin.d.ts +60 -2
  28. package/lib/src/brand-page-maker/composables/ai-chat/useAiChat.js +3 -1
  29. package/lib/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.d.ts +1 -1
  30. package/lib/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.js +6 -6
  31. package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.d.ts +2 -0
  32. package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +258 -0
  33. package/lib/src/brand-page-maker/constants/sidebar-constant.d.ts +1 -0
  34. package/lib/src/brand-page-maker/constants/sidebar-constant.js +8 -0
  35. package/lib/src/brand-page-maker/stores/ai-thread/ai-website-builder-thread-store.d.ts +16 -0
  36. package/lib/src/brand-page-maker/stores/ai-thread/ai-website-builder-thread-store.js +14 -0
  37. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.d.ts +62 -3
  38. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +2 -0
  39. package/lib/src/brand-page-maker/stores/index.d.ts +1 -0
  40. package/lib/src/brand-page-maker/stores/index.js +1 -0
  41. package/lib/src/brand-page-maker/stores/snapshot/snapshot-store.d.ts +2 -0
  42. package/lib/src/brand-page-maker/stores/snapshot/snapshot-store.js +9 -0
  43. package/lib/src/clients/ai-assistant-client.d.ts +8 -0
  44. package/lib/src/clients/ai-assistant-client.js +11 -1
  45. package/lib/src/composables/useSnapshot.js +33 -0
  46. package/lib/src/css/library.brand-page-brandCrowd.min.css +19 -6
  47. package/lib/src/css/library.brand-page-brandPage.min.css +19 -6
  48. package/lib/src/css/library.brand-page-designCom.min.css +19 -6
  49. package/lib/src/css/library.brand-page-preview.min.css +19 -6
  50. package/lib/src/index.d.ts +1 -0
  51. package/lib/src/index.mjs +42 -41
  52. package/lib/src/{lib-DODSa6QK.js → lib-pOkCQP0J.js} +28820 -26841
  53. package/lib/src/lib.js +1 -0
  54. package/lib/src/metadata-builder/ai-metadata-executor.d.ts +1 -1
  55. package/lib/src/metadata-builder/ai-metadata-executor.js +68 -7
  56. package/lib/src/metadata-builder/builders/add-page-builder.d.ts +14 -0
  57. package/lib/src/metadata-builder/builders/add-page-builder.js +66 -0
  58. package/lib/src/metadata-builder/builders/remove-page-builder.d.ts +13 -0
  59. package/lib/src/metadata-builder/builders/remove-page-builder.js +50 -0
  60. package/lib/src/metadata-builder/builders/section-builders/about-section-builder.d.ts +6 -0
  61. package/lib/src/metadata-builder/builders/section-builders/about-section-builder.js +17 -0
  62. package/lib/src/metadata-builder/builders/section-builders/banner-section-builder.d.ts +6 -0
  63. package/lib/src/metadata-builder/builders/section-builders/banner-section-builder.js +25 -0
  64. package/lib/src/metadata-builder/builders/section-builders/base-section-builder.d.ts +40 -0
  65. package/lib/src/metadata-builder/builders/section-builders/base-section-builder.js +108 -0
  66. package/lib/src/metadata-builder/builders/section-builders/button-section-builder.d.ts +6 -0
  67. package/lib/src/metadata-builder/builders/section-builders/button-section-builder.js +16 -0
  68. package/lib/src/metadata-builder/builders/section-builders/contact-form-builder.d.ts +6 -0
  69. package/lib/src/metadata-builder/builders/section-builders/contact-form-builder.js +27 -0
  70. package/lib/src/metadata-builder/builders/section-builders/delete-section-builder.d.ts +13 -0
  71. package/lib/src/metadata-builder/builders/section-builders/delete-section-builder.js +37 -0
  72. package/lib/src/metadata-builder/builders/section-builders/divider-section-builder.d.ts +6 -0
  73. package/lib/src/metadata-builder/builders/section-builders/divider-section-builder.js +16 -0
  74. package/lib/src/metadata-builder/builders/section-builders/image-gallery-builder.d.ts +6 -0
  75. package/lib/src/metadata-builder/builders/section-builders/image-gallery-builder.js +76 -0
  76. package/lib/src/metadata-builder/builders/section-builders/image-section-builder.d.ts +6 -0
  77. package/lib/src/metadata-builder/builders/section-builders/image-section-builder.js +16 -0
  78. package/lib/src/metadata-builder/builders/section-builders/images-section-builder.d.ts +6 -0
  79. package/lib/src/metadata-builder/builders/section-builders/images-section-builder.js +158 -0
  80. package/lib/src/metadata-builder/builders/section-builders/index.d.ts +17 -0
  81. package/lib/src/metadata-builder/builders/section-builders/index.js +17 -0
  82. package/lib/src/metadata-builder/builders/section-builders/mailing-list-builder.d.ts +6 -0
  83. package/lib/src/metadata-builder/builders/section-builders/mailing-list-builder.js +17 -0
  84. package/lib/src/metadata-builder/builders/section-builders/mailing-list-section-builder.d.ts +6 -0
  85. package/lib/src/metadata-builder/builders/section-builders/mailing-list-section-builder.js +16 -0
  86. package/lib/src/metadata-builder/builders/section-builders/move-section-builder.d.ts +15 -0
  87. package/lib/src/metadata-builder/builders/section-builders/move-section-builder.js +62 -0
  88. package/lib/src/metadata-builder/builders/section-builders/profile-section-builder.d.ts +6 -0
  89. package/lib/src/metadata-builder/builders/section-builders/profile-section-builder.js +16 -0
  90. package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.d.ts +6 -0
  91. package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.js +162 -0
  92. package/lib/src/metadata-builder/builders/section-builders/social-links-builder.d.ts +6 -0
  93. package/lib/src/metadata-builder/builders/section-builders/social-links-builder.js +50 -0
  94. package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.d.ts +6 -0
  95. package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.js +133 -0
  96. package/lib/src/metadata-builder/builders/section-builders/text-section-builder.d.ts +6 -0
  97. package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +154 -0
  98. package/lib/src/metadata-builder/builders/section-content-factory.d.ts +3 -0
  99. package/lib/src/metadata-builder/builders/section-content-factory.js +13 -0
  100. package/lib/src/metadata-builder/builders/section-field-maps.d.ts +12 -0
  101. package/lib/src/metadata-builder/builders/section-field-maps.js +180 -0
  102. package/lib/src/metadata-builder/builders/section-field-utils.d.ts +11 -0
  103. package/lib/src/metadata-builder/builders/section-field-utils.js +109 -0
  104. package/lib/src/metadata-builder/helpers/rte.helpers.d.ts +6 -0
  105. package/lib/src/metadata-builder/helpers/rte.helpers.js +16 -1
  106. package/lib/src/metadata-builder/metadata-executor.js +71 -1
  107. package/lib/src/metadata-builder/models.d.ts +54 -0
  108. package/lib/src/metadata-builder/models.js +58 -0
  109. package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +51 -3
  110. package/lib/src/metadata-builder/parsers/ai-toolcall-parser.js +110 -13
  111. package/lib/src/metadata-builder/parsers/section-tool-arguments.d.ts +285 -0
  112. package/lib/src/metadata-builder/parsers/section-tool-arguments.js +7 -0
  113. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +60 -2
  114. package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +60 -2
  115. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +60 -2
  116. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +60 -2
  117. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +90 -3
  118. package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +61 -2
  119. package/lib/src/shared/side-bar/components/SideBar.mixin.js +6 -0
  120. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +60 -2
  121. package/lib/src/utils/minify-brand-page-metadata.d.ts +22 -0
  122. package/lib/src/utils/minify-brand-page-metadata.js +344 -0
  123. package/package.json +1 -1
  124. package/src/brand-page/models/brand-page-context.model.ts +12 -3
  125. package/src/brand-page/models/index.ts +1 -0
  126. package/src/brand-page-maker/components/ai-website-builder/AiWebsiteBuilder.vue +80 -0
  127. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +4 -0
  128. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.vue +9 -2
  129. package/src/brand-page-maker/composables/ai-chat/useAiChat.ts +4 -1
  130. package/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.ts +6 -6
  131. package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +363 -0
  132. package/src/brand-page-maker/constants/sidebar-constant.ts +8 -0
  133. package/src/brand-page-maker/stores/ai-thread/ai-website-builder-thread-store.ts +19 -0
  134. package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.ts +3 -1
  135. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +4 -0
  136. package/src/brand-page-maker/stores/index.ts +1 -0
  137. package/src/brand-page-maker/stores/snapshot/snapshot-store.ts +12 -0
  138. package/src/clients/ai-assistant-client.ts +17 -1
  139. package/src/composables/useSnapshot.ts +47 -0
  140. package/src/lib.ts +4 -0
  141. package/src/metadata-builder/ai-metadata-executor.ts +116 -26
  142. package/src/metadata-builder/builders/add-page-builder.ts +98 -0
  143. package/src/metadata-builder/builders/remove-page-builder.ts +83 -0
  144. package/src/metadata-builder/builders/section-builders/about-section-builder.ts +28 -0
  145. package/src/metadata-builder/builders/section-builders/banner-section-builder.ts +45 -0
  146. package/src/metadata-builder/builders/section-builders/base-section-builder.ts +160 -0
  147. package/src/metadata-builder/builders/section-builders/button-section-builder.ts +24 -0
  148. package/src/metadata-builder/builders/section-builders/contact-form-builder.ts +43 -0
  149. package/src/metadata-builder/builders/section-builders/delete-section-builder.ts +63 -0
  150. package/src/metadata-builder/builders/section-builders/divider-section-builder.ts +27 -0
  151. package/src/metadata-builder/builders/section-builders/image-gallery-builder.ts +111 -0
  152. package/src/metadata-builder/builders/section-builders/image-section-builder.ts +24 -0
  153. package/src/metadata-builder/builders/section-builders/images-section-builder.ts +223 -0
  154. package/src/metadata-builder/builders/section-builders/index.ts +21 -0
  155. package/src/metadata-builder/builders/section-builders/mailing-list-builder.ts +29 -0
  156. package/src/metadata-builder/builders/section-builders/mailing-list-section-builder.ts +27 -0
  157. package/src/metadata-builder/builders/section-builders/move-section-builder.ts +100 -0
  158. package/src/metadata-builder/builders/section-builders/profile-section-builder.ts +27 -0
  159. package/src/metadata-builder/builders/section-builders/shapes-section-builder.ts +231 -0
  160. package/src/metadata-builder/builders/section-builders/social-links-builder.ts +79 -0
  161. package/src/metadata-builder/builders/section-builders/testimonial-section-builder.ts +194 -0
  162. package/src/metadata-builder/builders/section-builders/text-section-builder.ts +234 -0
  163. package/src/metadata-builder/builders/section-content-factory.ts +20 -0
  164. package/src/metadata-builder/builders/section-field-maps.ts +235 -0
  165. package/src/metadata-builder/builders/section-field-utils.ts +157 -0
  166. package/src/metadata-builder/helpers/rte.helpers.ts +23 -1
  167. package/src/metadata-builder/metadata-executor.ts +96 -4
  168. package/src/metadata-builder/models.ts +62 -0
  169. package/src/metadata-builder/parsers/ai-toolcall-parser.ts +141 -17
  170. package/src/metadata-builder/parsers/section-tool-arguments.ts +417 -0
  171. package/src/shared/side-bar/components/SideBar.mixin.ts +10 -0
  172. package/src/utils/minify-brand-page-metadata.ts +407 -0
@@ -52,12 +52,14 @@ const AB_TEST_KEYS = {
52
52
  'bc-bp-4572-ai-text-generation-post-purchase',
53
53
  BP_4964_AI_TEXT_GENERATION_IMPROVEMENT:
54
54
  'bc-bp-4964-ai-text-improvement-post-purchase-on-website',
55
+ BP_5245_AI_WEBSITE_ASSISTANT: 'bc-bp-5245-ai-website-assistant',
55
56
  };
56
57
 
57
58
  export interface AbTest {
58
59
  bp_3926_freemium_watermark?: AbTestResult;
59
60
  bp_4572_ai_text_generation_post_purchase?: AbTestResult;
60
61
  bp_4964_ai_text_generation_improvement?: AbTestResult;
62
+ bp_5245_ai_website_assistant?: AbTestResult;
61
63
  }
62
64
 
63
65
  export const MEDIA_SIZES = {
@@ -119,9 +121,7 @@ export const getValueType = (
119
121
  };
120
122
  };
121
123
 
122
- export const getAbTestResults = (
123
- abtestKeyValues: Record<string, string>,
124
- ): AbTest => {
124
+ export const getAbTestResults = (abtestKeyValues: AbTest): AbTest => {
125
125
  const abTests: AbTest = {};
126
126
 
127
127
  // AB Test for BP-3926 - Freemium Watermark Variation
@@ -151,5 +151,14 @@ export const getAbTestResults = (
151
151
  );
152
152
  }
153
153
 
154
+ // AB Test for BP-5245 - AI Website Assistant
155
+
156
+ if (abtestKeyValues[AB_TEST_KEYS.BP_5245_AI_WEBSITE_ASSISTANT]) {
157
+ abTests.bp_5245_ai_website_assistant = getValueType(
158
+ AB_TEST_KEYS.BP_5245_AI_WEBSITE_ASSISTANT,
159
+ abtestKeyValues[AB_TEST_KEYS.BP_5245_AI_WEBSITE_ASSISTANT],
160
+ );
161
+ }
162
+
154
163
  return abTests;
155
164
  };
@@ -447,6 +447,7 @@ export interface TextMediaItem extends ImageItem {
447
447
 
448
448
  export interface TextShapeItem extends TextMediaItem {
449
449
  colorReplacements: ColorReplacement[];
450
+ keepColor?: boolean;
450
451
  aspectRatio?: number | null;
451
452
  }
452
453
 
@@ -0,0 +1,80 @@
1
+ <template>
2
+ <div class="ai-container">
3
+ <div class="tw-px-5">
4
+ <SideBarSettingsHeader
5
+ title="AI Website Builder"
6
+ :show-back-button="true"
7
+ @on-back="onBack"
8
+ />
9
+ </div>
10
+ <AiChatbox
11
+ v-model="promptText"
12
+ :messages="formattedMessages"
13
+ :disabled="isProcessing"
14
+ class="tw-flex-1 tw-overflow-hidden tw-px-5"
15
+ @send="onSendMessage"
16
+ @stop-generation="onStopGeneration"
17
+ />
18
+ </div>
19
+ </template>
20
+
21
+ <script setup lang="ts">
22
+ import { ref, onMounted } from 'vue';
23
+ import SideBarSettingsHeader from '../../../shared/common/SideBarSettingsHeader.vue';
24
+ import AiChatbox from '../ai-text-edit/AiChatbox.vue';
25
+ import { useUiSideBarStore } from '../../../shared/side-bar/store';
26
+ import { useSnapshotStore } from '../../stores';
27
+ import { SIDE_BAR_TAB_NAMES } from '../../constants';
28
+ import { useAiWebsiteBuilderChat } from '../../composables/ai-chat/useAiWebsiteBuilderChat';
29
+
30
+ const sideBarStore = useUiSideBarStore();
31
+ const snapshotStore = useSnapshotStore();
32
+
33
+ const emit = defineEmits<{
34
+ back: [];
35
+ 'capture-preview-snapshot': [];
36
+ }>();
37
+
38
+ const promptText = ref(
39
+ 'Update banner title to "This is awesome" and add a contact form to a new page',
40
+ );
41
+
42
+ const {
43
+ isProcessing,
44
+ sendMessageAsync,
45
+ formattedMessages,
46
+ stopGenerationAsync,
47
+ } = useAiWebsiteBuilderChat();
48
+
49
+ const onBack = () => {
50
+ sideBarStore.setSelectedTabName({
51
+ tabName: SIDE_BAR_TAB_NAMES.CONTENT_SETTINGS,
52
+ });
53
+ emit('back');
54
+ };
55
+
56
+ const onSendMessage = async (text: string) => {
57
+ await sendMessageAsync({ text });
58
+ };
59
+
60
+ const onStopGeneration = async () => {
61
+ await stopGenerationAsync();
62
+ };
63
+
64
+ defineExpose({
65
+ stopGenerationAsync,
66
+ });
67
+
68
+ onMounted(() => {
69
+ snapshotStore.clearSnapshot();
70
+ setTimeout(() => {
71
+ emit('capture-preview-snapshot');
72
+ }, 50);
73
+ });
74
+ </script>
75
+ <style>
76
+ .ai-container {
77
+ height: calc(100vh - 90px);
78
+ @apply tw-flex tw-flex-col tw--mx-5;
79
+ }
80
+ </style>
@@ -296,6 +296,10 @@ export default defineComponent({
296
296
 
297
297
  fontLoaderUtil.loadAllFonts();
298
298
 
299
+ this.snapshotStore.registerCaptureCallback(() =>
300
+ this.handleCaptureSnapshot(),
301
+ );
302
+
299
303
  this.setUiScreenSizeModeBasedOnDeviceWidth();
300
304
 
301
305
  if (this.isBrandPageOrIsBrandContact) {
@@ -175,8 +175,9 @@ import { UI_DEVICE_MODES, UI_SCREENSIZE_MODES } from '@shared/models';
175
175
  import { useLocalisedRouteStore } from '@brand-page-maker/stores/route/localised-route-store';
176
176
  import { useBrandPageMakerStore } from '@brand-page-maker/stores/brandpage-maker/brandpage-maker-store';
177
177
  import AiTextEdit from '../ai-text-edit/AiTextEdit.vue';
178
+ import AiWebsiteBuilder from '../ai-website-builder/AiWebsiteBuilder.vue';
178
179
  import AiActionButtons from '../ai-text-edit/AiActionButtons.vue';
179
- import { useAiThreadStore } from '../../stores';
180
+ import { useAiThreadStore, useAiWebsiteBuilderThreadStore } from '../../stores';
180
181
  import { useEventTracker } from '../../composables/useEventTracker';
181
182
 
182
183
  export default {
@@ -186,6 +187,7 @@ export default {
186
187
  ActionBar,
187
188
  AdminBackgroundSettings,
188
189
  AiTextEdit,
190
+ AiWebsiteBuilder,
189
191
  AiActionButtons,
190
192
  BackgroundSettings: BrandPageBackgroundSettings,
191
193
  BrandPageSettings,
@@ -210,12 +212,17 @@ export default {
210
212
  const localisedRouteStore = useLocalisedRouteStore();
211
213
  const brandPageMakerStore = useBrandPageMakerStore();
212
214
  const aiThreadStore = useAiThreadStore();
215
+ const aiWebsiteBuilderThreadStore = useAiWebsiteBuilderThreadStore();
213
216
  const eventTracker = useEventTracker();
214
217
 
215
218
  return {
216
219
  ...BrandPageMakerMixin.setup(props, context),
217
220
  brandCrowdUrl: computed(() => localisedRouteStore.localisedBaseUrl),
218
- isAiProcessing: computed(() => aiThreadStore.isProcessing),
221
+ isAiProcessing: computed(
222
+ () =>
223
+ aiThreadStore.isProcessing ||
224
+ aiWebsiteBuilderThreadStore.isProcessing,
225
+ ),
219
226
  isBrandPageLoaded: computed(() => brandPageMakerStore.isBrandPageLoaded),
220
227
  eventTracker,
221
228
  };
@@ -179,7 +179,7 @@ export function useAiChat(options: UseAiChatOptions): UseAiChatResult {
179
179
  );
180
180
 
181
181
  updateResult.parsedToolCalls.forEach((toolCall) => {
182
- const { message } = toolCall.arguments;
182
+ const message = toolCall.arguments.message as string | undefined;
183
183
 
184
184
  if (message) {
185
185
  aiMessage = aiMessage ? `${aiMessage} ${message}` : message;
@@ -193,6 +193,9 @@ export function useAiChat(options: UseAiChatOptions): UseAiChatResult {
193
193
  // Allow Vue to process reactive updates
194
194
  await nextTick();
195
195
 
196
+ // Re-capture snapshot so subsequent messages reflect the updated page
197
+ await snapshotStore.refreshSnapshotAsync();
198
+
196
199
  return {
197
200
  shouldContinue: toolResults.length > 0 && aiThreadStore.runId !== null,
198
201
  toolResults,
@@ -1,7 +1,7 @@
1
1
  import type { BrandPageModel } from 'src/lib';
2
- import { executeAiToolUseAsync } from '../../../metadata-builder/ai-metadata-executor';
2
+ import { executeToolCallsAsync } from '../../../metadata-builder/ai-metadata-executor';
3
3
  import {
4
- parseAiToolcall,
4
+ parseToolCalls,
5
5
  type ParsedToolCall,
6
6
  } from '../../../metadata-builder/parsers/ai-toolcall-parser';
7
7
  import type { AiAssistantToolCall } from '../../../clients/ai-assistant-client';
@@ -25,19 +25,19 @@ export function useAiMetadataBuilder(logger: Logger) {
25
25
  aiAssistantToolCall: AiAssistantToolCall[],
26
26
  options: {
27
27
  maxCharacters?: number;
28
- },
28
+ } = {},
29
29
  ): Promise<AiMetadataBuilderResult> => {
30
30
  try {
31
- const requests = parseAiToolcall(aiAssistantToolCall);
31
+ const parsed = parseToolCalls(aiAssistantToolCall);
32
32
 
33
- const result = await executeAiToolUseAsync(model, requests, {
33
+ const result = await executeToolCallsAsync(model, parsed, {
34
34
  ...options,
35
35
  logger,
36
36
  });
37
37
 
38
38
  return {
39
39
  model: result.model,
40
- parsedToolCalls: requests,
40
+ parsedToolCalls: parsed,
41
41
  results: result.results.map((x) => {
42
42
  return {
43
43
  toolId: x.request.id,
@@ -0,0 +1,363 @@
1
+ import { ref, computed, watch, nextTick } from 'vue';
2
+ import {
3
+ getInstance as getAiAssistantClient,
4
+ AI_ASSISTANT_AGENT_TYPES,
5
+ buildWebsiteBuilderMessage,
6
+ type AiAssistantResponse,
7
+ type AiAssistantToolResult,
8
+ } from '../../../clients/ai-assistant-client';
9
+ import { minifyBrandPageMetadata } from '../../../utils/minify-brand-page-metadata';
10
+ import { useSnapshotStore, useAiWebsiteBuilderThreadStore } from '../../stores';
11
+ import { useBrandPageMakerStore } from '../../stores';
12
+ import { useUiPageSettingsStore } from '../../../shared/page-settings/store';
13
+ import { useAiMetadataBuilder } from './useAiMetadataBuilder';
14
+ import { Logger } from '../../../metadata-builder/logger';
15
+ import type {
16
+ UseAiChatResult,
17
+ ThreadMessage,
18
+ TextThreadMessage,
19
+ SendMessageOptions,
20
+ } from './useAiChat';
21
+
22
+ const MAX_TOOL_CALL_ITERATIONS = 5;
23
+
24
+ const aiLogger = new Logger();
25
+
26
+ export function useAiWebsiteBuilderChat(): UseAiChatResult {
27
+ const aiThreadStore = useAiWebsiteBuilderThreadStore();
28
+ const snapshotStore = useSnapshotStore();
29
+ const brandPageMakerStore = useBrandPageMakerStore();
30
+ const pageSettingsStore = useUiPageSettingsStore();
31
+ const aiMetadataBuilder = useAiMetadataBuilder(aiLogger);
32
+
33
+ const hasStoredMessages = aiThreadStore.messages.length > 0;
34
+ const threadItems = ref<ThreadMessage[]>(
35
+ aiThreadStore.messages.length > 0
36
+ ? aiThreadStore.messages
37
+ : [
38
+ {
39
+ id: '1',
40
+ type: 'text',
41
+ role: 'agent',
42
+ text: 'What changes would you like to make to your website?',
43
+ timestamp: new Date(),
44
+ } as TextThreadMessage,
45
+ ],
46
+ );
47
+ const isProcessing = ref(false);
48
+
49
+ watch(isProcessing, (newValue) => {
50
+ aiThreadStore.isProcessing = newValue;
51
+ });
52
+
53
+ watch(
54
+ threadItems,
55
+ (newMessages) => {
56
+ aiThreadStore.messages = newMessages;
57
+ },
58
+ { deep: true },
59
+ );
60
+
61
+ const currentTypingMessageId = ref<string | null>(null);
62
+ const isStopped = ref(false);
63
+ const generatedText = ref<string | null>(null);
64
+ const generatedStyle = ref<BrandPageCssStyle | null>(null);
65
+
66
+ const buildMessage = (userPrompt: string) => {
67
+ const minified = minifyBrandPageMetadata(brandPageMakerStore.brandPageData);
68
+
69
+ return buildWebsiteBuilderMessage(userPrompt, minified);
70
+ };
71
+
72
+ const applyToolCallsAsync = async (response: AiAssistantResponse) => {
73
+ let aiMessage: string | null = response.message || '';
74
+ const modelToUpdate = brandPageMakerStore.brandPageData;
75
+
76
+ const updateResult = await aiMetadataBuilder.applyAiToolCallsAsync(
77
+ modelToUpdate,
78
+ response.toolCalls || [],
79
+ );
80
+
81
+ const toolResults: AiAssistantToolResult[] = updateResult.results.map(
82
+ (x) => {
83
+ return {
84
+ toolId: x.toolId,
85
+ success: x.errors && x.errors.length > 0 ? 'failed' : 'success',
86
+ };
87
+ },
88
+ );
89
+
90
+ updateResult.parsedToolCalls.forEach((toolCall) => {
91
+ const args = toolCall.arguments as any;
92
+
93
+ if (args.message) {
94
+ aiMessage = aiMessage ? `${aiMessage} ${args.message}` : args.message;
95
+ }
96
+ });
97
+
98
+ console.log(
99
+ 'updateResult.model',
100
+ JSON.parse(JSON.stringify(updateResult.model)),
101
+ );
102
+
103
+ await brandPageMakerStore.initialiseStoresByBrandPageModelAsync(
104
+ updateResult.model,
105
+ );
106
+
107
+ await nextTick();
108
+
109
+ // Re-capture snapshot so subsequent messages reflect the updated page
110
+ await snapshotStore.refreshSnapshotAsync();
111
+
112
+ return {
113
+ shouldContinue: toolResults.length > 0 && aiThreadStore.runId !== null,
114
+ toolResults,
115
+ aiMessage,
116
+ };
117
+ };
118
+
119
+ const submitToolResults = async (toolResults: AiAssistantToolResult[]) => {
120
+ if (!aiThreadStore.threadId || !aiThreadStore.runId || !toolResults.length)
121
+ return null;
122
+
123
+ const client = getAiAssistantClient();
124
+ const { response } = await client.submitWebsiteToolCallOutputAsync(
125
+ aiThreadStore.threadId,
126
+ {
127
+ runId: aiThreadStore.runId,
128
+ toolCalls: toolResults,
129
+ agentType: AI_ASSISTANT_AGENT_TYPES.WEBSITE_BUILDER,
130
+ websiteSnapshot: snapshotStore.snapshotBase64 || undefined,
131
+ },
132
+ );
133
+
134
+ return response;
135
+ };
136
+
137
+ const callApiAsync = async (userPrompt: string): Promise<string | null> => {
138
+ generatedText.value = null;
139
+ generatedStyle.value = null;
140
+
141
+ const client = getAiAssistantClient();
142
+
143
+ let aiAssistantResponse: AiAssistantResponse = {} as AiAssistantResponse;
144
+
145
+ if (!aiThreadStore.threadId) {
146
+ const { response } = await client.createWebsiteThreadAndSendMessageAsync({
147
+ message: buildMessage(userPrompt || ''),
148
+ websiteSnapshot: snapshotStore.snapshotBase64 || undefined,
149
+ agentType: AI_ASSISTANT_AGENT_TYPES.WEBSITE_BUILDER,
150
+ });
151
+
152
+ aiAssistantResponse = response;
153
+ aiThreadStore.threadId = response.threadId;
154
+ aiThreadStore.runId = response.runId || null;
155
+ } else {
156
+ const { response } = await client.sendWebsiteMessageAsync(
157
+ aiThreadStore.threadId!,
158
+ {
159
+ message: buildMessage(userPrompt),
160
+ websiteSnapshot: snapshotStore.snapshotBase64 || undefined,
161
+ agentType: AI_ASSISTANT_AGENT_TYPES.WEBSITE_BUILDER,
162
+ },
163
+ );
164
+
165
+ aiAssistantResponse = response;
166
+ }
167
+
168
+ aiLogger.log('callApiAsync response', { aiAssistantResponse });
169
+
170
+ if (isStopped.value) return null;
171
+
172
+ const handledResponse = await handleAiResponseAsync(aiAssistantResponse);
173
+
174
+ return (
175
+ handledResponse.aiMessage ||
176
+ 'I was unable to make the changes. Please try again.'
177
+ );
178
+ };
179
+
180
+ const handleToolResponseAsync = async (
181
+ response: AiAssistantResponse,
182
+ ): Promise<{ aiMessage: string | null }> => {
183
+ let { shouldContinue, toolResults, aiMessage } =
184
+ await applyToolCallsAsync(response);
185
+
186
+ let iterations = 0;
187
+
188
+ while (shouldContinue && iterations < MAX_TOOL_CALL_ITERATIONS) {
189
+ if (isStopped.value) return { aiMessage: '' };
190
+
191
+ const nextResponse = await submitToolResults(toolResults);
192
+
193
+ aiLogger.log('handleToolResponseAsync submitToolResults', {
194
+ toolResults,
195
+ nextResponse,
196
+ });
197
+
198
+ if (!nextResponse) break;
199
+
200
+ const retryResult = await applyToolCallsAsync(nextResponse);
201
+
202
+ shouldContinue = retryResult.shouldContinue;
203
+ toolResults = retryResult.toolResults;
204
+ aiMessage = retryResult.aiMessage || aiMessage;
205
+ iterations += 1;
206
+ }
207
+
208
+ return { aiMessage };
209
+ };
210
+
211
+ const handleAiResponseAsync = async (
212
+ response: AiAssistantResponse,
213
+ ): Promise<{ aiMessage: string | null }> => {
214
+ const aiMessageResult: string | null = response.message || '';
215
+
216
+ if (response.toolCalls && response.toolCalls.length > 0) {
217
+ const toolResult = await handleToolResponseAsync(response);
218
+
219
+ // Todo: For now dont show tool result message as it is not functional
220
+ // aiMessageResult = toolResult.aiMessage || aiMessageResult;
221
+
222
+ aiLogger.log('handleAiResponseAsync toolResult', { toolResult });
223
+ }
224
+
225
+ return { aiMessage: aiMessageResult };
226
+ };
227
+
228
+ const sendMessageAsync = async (messageOptions: SendMessageOptions) => {
229
+ const { text, images } = messageOptions;
230
+
231
+ if (!text?.trim() && (!images || images.length === 0)) return;
232
+
233
+ isStopped.value = false;
234
+ isProcessing.value = true;
235
+
236
+ const userMessage: ThreadMessage = images
237
+ ? {
238
+ id: Date.now().toString(),
239
+ type: 'image' as const,
240
+ role: 'user' as const,
241
+ images,
242
+ text,
243
+ timestamp: new Date(),
244
+ }
245
+ : {
246
+ id: Date.now().toString(),
247
+ type: 'text' as const,
248
+ role: 'user' as const,
249
+ text: text || '',
250
+ timestamp: new Date(),
251
+ };
252
+
253
+ threadItems.value.push(userMessage);
254
+
255
+ const agentMessageId = (Date.now() + 1).toString();
256
+
257
+ currentTypingMessageId.value = agentMessageId;
258
+ const agentMessage: TextThreadMessage = {
259
+ id: agentMessageId,
260
+ type: 'text' as const,
261
+ role: 'agent' as const,
262
+ text: '',
263
+ isTyping: true,
264
+ timestamp: new Date(),
265
+ };
266
+
267
+ threadItems.value.push(agentMessage);
268
+
269
+ try {
270
+ aiLogger.log('sendMessageAsync', { messageOptions });
271
+
272
+ const responseText: string | null = await callApiAsync(text || '');
273
+
274
+ if (isStopped.value) return;
275
+
276
+ const messageIndex = threadItems.value.findIndex(
277
+ (msg) => msg.id === agentMessageId,
278
+ );
279
+
280
+ if (messageIndex !== -1) {
281
+ if (responseText) {
282
+ threadItems.value[messageIndex].text = responseText;
283
+ threadItems.value[messageIndex].isTyping = false;
284
+ } else {
285
+ threadItems.value[messageIndex].text =
286
+ 'Failed to apply changes. Please try again.';
287
+ threadItems.value[messageIndex].isTyping = false;
288
+ threadItems.value[messageIndex].isError = true;
289
+ }
290
+ }
291
+ } catch (error: any) {
292
+ if (isStopped.value) return;
293
+
294
+ const messageIndex = threadItems.value.findIndex(
295
+ (msg) => msg.id === agentMessageId,
296
+ );
297
+
298
+ if (messageIndex !== -1) {
299
+ threadItems.value[messageIndex].text =
300
+ error?.response?.data?.error ||
301
+ 'An error occurred. Please try again.';
302
+ threadItems.value[messageIndex].isTyping = false;
303
+ threadItems.value[messageIndex].isError = true;
304
+ }
305
+ } finally {
306
+ currentTypingMessageId.value = null;
307
+ isProcessing.value = false;
308
+ }
309
+
310
+ console.log('aiLogger', aiLogger);
311
+ };
312
+
313
+ const deleteMessage = (messageId: string) => {
314
+ const index = threadItems.value.findIndex((msg) => msg.id === messageId);
315
+
316
+ if (index !== -1) {
317
+ threadItems.value.splice(index, 1);
318
+ }
319
+ };
320
+
321
+ const stopGenerationAsync = async () => {
322
+ isStopped.value = true;
323
+
324
+ if (currentTypingMessageId.value) {
325
+ deleteMessage(currentTypingMessageId.value);
326
+ currentTypingMessageId.value = null;
327
+ }
328
+
329
+ isProcessing.value = false;
330
+ };
331
+
332
+ const formattedMessages = computed(() => {
333
+ const initialMessageCount = hasStoredMessages
334
+ ? aiThreadStore.messages.length
335
+ : 1;
336
+
337
+ return threadItems.value.map((msg, index) => ({
338
+ type: msg.type,
339
+ props: {
340
+ ...(msg.type === 'text' && { text: msg.text }),
341
+ ...(msg.type === 'image' && { images: msg.images, text: msg.text }),
342
+ isUser: msg.role === 'user',
343
+ isAi: msg.role === 'agent',
344
+ showIcon: msg.role === 'agent',
345
+ isTyping: msg.isTyping,
346
+ isResponse: index >= 1,
347
+ disableAnimation: index < initialMessageCount,
348
+ } as Record<string, unknown>,
349
+ }));
350
+ });
351
+
352
+ return {
353
+ threadItems,
354
+ isProcessing,
355
+ currentTypingMessageId,
356
+ generatedText,
357
+ generatedStyle,
358
+ sendMessageAsync,
359
+ deleteMessage,
360
+ stopGenerationAsync,
361
+ formattedMessages,
362
+ };
363
+ }
@@ -12,6 +12,7 @@ export const SIDE_BAR_TAB_NAMES = {
12
12
  STYLE_SETTINGS: 'StyleSettings',
13
13
  BRANDPAGE_SETTINGS: 'BrandPageSettings',
14
14
  AI_TEXT_EDIT: 'AiTextEdit',
15
+ AI_WEBSITE_BUILDER: 'AiWebsiteBuilder',
15
16
  };
16
17
 
17
18
  export const DEFAULT_SIDE_BAR_TABS = (): SideBarTab[] => [
@@ -45,6 +46,13 @@ export const DEFAULT_SIDE_BAR_TABS = (): SideBarTab[] => [
45
46
  accessibleDisplayName: 'AI Text Edit',
46
47
  isVisible: false,
47
48
  },
49
+ {
50
+ name: SIDE_BAR_TAB_NAMES.AI_WEBSITE_BUILDER,
51
+ displayName: 'AI Builder',
52
+ iconName: 'ai',
53
+ accessibleDisplayName: 'AI Website Builder',
54
+ isVisible: true,
55
+ },
48
56
  {
49
57
  name: SIDE_BAR_TAB_NAMES.BACKGROUND_SETTINGS,
50
58
  displayName: constantsTr(`backgroundDisplayName`),
@@ -0,0 +1,19 @@
1
+ import { defineStore } from 'pinia';
2
+ import { ref } from 'vue';
3
+
4
+ export const useAiWebsiteBuilderThreadStore = defineStore(
5
+ 'aiWebsiteBuilderThread',
6
+ () => {
7
+ const threadId = ref<string | null>(null);
8
+ const runId = ref<string | null>(null);
9
+ const messages = ref<any[]>([]);
10
+ const isProcessing = ref<boolean>(false);
11
+
12
+ return {
13
+ threadId,
14
+ runId,
15
+ messages,
16
+ isProcessing,
17
+ };
18
+ },
19
+ );
@@ -22,6 +22,7 @@ import {
22
22
  SENSITIVE_CONTENT_TYPES,
23
23
  getAbTestResults,
24
24
  getValueType,
25
+ type AbTest,
25
26
  type LogoContent,
26
27
  } from '@brand-page';
27
28
  import { isLogoContent } from '@brand-page/utils';
@@ -88,7 +89,7 @@ export interface BrandPageContainerState {
88
89
  eventButtonLocation?: string;
89
90
  websiteUpsellModalViewModel?: any;
90
91
  showPublishOptionModal?: boolean; // select an option modal on publish
91
- abTests: Record<string, string>;
92
+ abTests: AbTest;
92
93
  isSubsequentPublish: boolean;
93
94
  isContextualUpgradeModalVisible: boolean;
94
95
  contextualUpgradeType: WebsiteContextUpgradeType | undefined;
@@ -241,6 +242,7 @@ export const useBrandPageContainerStore = defineStore('brandPageContainer', {
241
242
  this.makerFonts = payload.makerFonts || [];
242
243
  this.showPublishOptionModal = payload.showPublishOptionModal;
243
244
  this.abTests = getAbTestResults(payload.abTests || {});
245
+
244
246
  this.isSubsequentPublish = payload.isSubsequentPublish;
245
247
  this.requestVerificationToken = payload.requestVerificationToken;
246
248
 
@@ -759,6 +759,10 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
759
759
  async initialiseStoresByBrandPageModelAsync(
760
760
  brandPageModel: BrandPageModel,
761
761
  ) {
762
+ const pageNavigationStore = usePageNavigationStore();
763
+
764
+ pageNavigationStore.setNav({ nav: brandPageModel.nav });
765
+
762
766
  this.initialisePagesForCurrentPage({
763
767
  pages: brandPageModel.pages,
764
768
  sections: {
@@ -13,3 +13,4 @@ export * from './logo-store';
13
13
  export * from './video';
14
14
  export * from './snapshot/snapshot-store';
15
15
  export * from './ai-thread/ai-thread-store';
16
+ export * from './ai-thread/ai-website-builder-thread-store';