@designcrowd/library.brand-page 6.2.3 → 6.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/src/{CreatedOnBrandCrowd-de-de-Cn0M-eZ1.js → CreatedOnBrandCrowd-de-de-ystrO2LW.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-DRLMSDZr.js → CreatedOnBrandCrowd-en-us-BU7hNzTZ.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-BglTu73U.js → CreatedOnBrandCrowd-es-es-CbuxneQ3.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-Bj6YZ_el.js → CreatedOnBrandCrowd-fr-ca-BuNUGOFr.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-Bj6YZ_el.js → CreatedOnBrandCrowd-fr-fr-BuNUGOFr.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-DEoOmQ1F.js → CreatedOnBrandCrowd-pt-br-BehL88mc.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-DEoOmQ1F.js → CreatedOnBrandCrowd-pt-pt-BehL88mc.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-BZ7gTt4Z.js → CreatedOnDcom-de-de-CMxjFZt9.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-CD6Km5sH.js → CreatedOnDcom-en-us-2Cf6WBvx.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-CNpZHvEl.js → CreatedOnDcom-es-es-CATNnbTq.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-URS-ydJ1.js → CreatedOnDcom-fr-ca-DQtMfB-a.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-D2AVeA3H.js → CreatedOnDcom-fr-fr-C1_FWOQf.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-C32frnFs.js → CreatedOnDcom-pt-br-C0QOCW0L.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-TDYGjRXS.js → CreatedOnDcom-pt-pt-lHD-p6o4.js} +1 -1
- package/lib/src/brand-page/models/brand-page-context.model.d.ts +5 -0
- package/lib/src/brand-page/models/brand-page-context.model.js +8 -1
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +21 -0
- package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +21 -0
- package/lib/src/brand-page-maker/components/preview/Preview.mixin.d.ts +7 -0
- package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +21 -0
- package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +22 -1
- package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +21 -0
- package/lib/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.mixin.d.ts +21 -0
- package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +21 -0
- package/lib/src/brand-page-maker/components/upgrade-to-premium-button/UpgradeToPremiumButton.mixin.d.ts +21 -0
- package/lib/src/brand-page-maker/composables/ai-chat/ai-builder-experiment.d.ts +10 -0
- package/lib/src/brand-page-maker/composables/ai-chat/ai-builder-experiment.js +11 -0
- package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +14 -4
- package/lib/src/brand-page-maker/stores/ai-thread/ai-website-builder-thread-store.d.ts +9 -2
- package/lib/src/brand-page-maker/stores/ai-thread/ai-website-builder-thread-store.js +20 -0
- package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.d.ts +21 -0
- package/lib/src/clients/ai-assistant-client.d.ts +1 -0
- package/lib/src/clients/ai-assistant-client.js +1 -0
- package/lib/src/index.mjs +224 -223
- package/lib/src/{lib-Dm9AuOJL.js → lib-CqHUUPUW.js} +21920 -21691
- package/lib/src/metadata-builder/builders/global-font-propagation.d.ts +41 -0
- package/lib/src/metadata-builder/builders/global-font-propagation.js +146 -0
- package/lib/src/metadata-builder/builders/global-styles-builder.js +29 -1
- package/lib/src/metadata-builder/builders/header-builder.js +8 -0
- package/lib/src/metadata-builder/builders/reorder-pages-builder.d.ts +13 -0
- package/lib/src/metadata-builder/builders/reorder-pages-builder.js +49 -0
- package/lib/src/metadata-builder/builders/section-builders/index.d.ts +1 -0
- package/lib/src/metadata-builder/builders/section-builders/index.js +1 -0
- package/lib/src/metadata-builder/builders/section-builders/support-me-builder.d.ts +8 -0
- package/lib/src/metadata-builder/builders/section-builders/support-me-builder.js +25 -0
- package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +5 -2
- package/lib/src/metadata-builder/builders/section-field-maps.js +15 -0
- package/lib/src/metadata-builder/builders/section-field-utils.d.ts +6 -1
- package/lib/src/metadata-builder/builders/section-field-utils.js +48 -12
- package/lib/src/metadata-builder/builders/section-rules/support-me.rules.d.ts +2 -0
- package/lib/src/metadata-builder/builders/section-rules/support-me.rules.js +17 -0
- package/lib/src/metadata-builder/helpers/rte.helpers.d.ts +9 -0
- package/lib/src/metadata-builder/helpers/rte.helpers.js +60 -1
- package/lib/src/metadata-builder/metadata-executor.js +3 -1
- package/lib/src/metadata-builder/models.d.ts +2 -0
- package/lib/src/metadata-builder/models.js +2 -0
- package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +1 -0
- package/lib/src/metadata-builder/parsers/ai-toolcall-parser.js +4 -0
- package/lib/src/metadata-builder/parsers/section-tool-arguments.d.ts +14 -2
- package/lib/src/shared/content-settings/components/GenericTextInput.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/email-field/EmailField.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +21 -0
- package/lib/src/shared/content-settings/components/tel-field/TelField.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/text-field/TextField.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/textarea-field/TextareaField.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/url-field/UrlField.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/youtube-video-field/YoutubeVideoField.mixin.d.ts +1 -1
- package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +21 -0
- package/lib/src/shared/page-settings/components/delete-page-modal/DeletePageModal.mixin.d.ts +1 -1
- package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +21 -0
- package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +21 -0
- package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +28 -0
- package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +21 -0
- package/lib/src/shared/style-settings/button-style-preset.d.ts +12 -0
- package/lib/src/shared/style-settings/button-style-preset.js +39 -0
- package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +21 -0
- package/lib/src/shared/style-settings/store/style-settings-store.js +6 -32
- package/lib/src/utils/minify-brand-page-metadata.d.ts +9 -0
- package/lib/src/utils/minify-brand-page-metadata.js +23 -1
- package/package.json +1 -12
- package/src/brand-page/models/brand-page-context.model.ts +14 -1
- package/src/brand-page-maker/components/ai-website-builder/AiWebsiteBuilder.vue +1 -1
- package/src/brand-page-maker/composables/ai-chat/ai-builder-experiment.test.ts +82 -0
- package/src/brand-page-maker/composables/ai-chat/ai-builder-experiment.ts +19 -0
- package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +18 -4
- package/src/brand-page-maker/stores/ai-thread/ai-website-builder-thread-store.ts +30 -0
- package/src/clients/ai-assistant-client.ts +1 -0
- package/src/metadata-builder/builders/global-font-propagation.test.ts +401 -0
- package/src/metadata-builder/builders/global-font-propagation.ts +238 -0
- package/src/metadata-builder/builders/global-styles-builder.test.ts +107 -0
- package/src/metadata-builder/builders/global-styles-builder.ts +38 -1
- package/src/metadata-builder/builders/header-builder.test.ts +45 -0
- package/src/metadata-builder/builders/header-builder.ts +20 -0
- package/src/metadata-builder/builders/reorder-pages-builder.ts +80 -0
- package/src/metadata-builder/builders/section-builders/index.ts +1 -0
- package/src/metadata-builder/builders/section-builders/support-me-builder.test.ts +177 -0
- package/src/metadata-builder/builders/section-builders/support-me-builder.ts +43 -0
- package/src/metadata-builder/builders/section-builders/text-section-builder.ts +5 -2
- package/src/metadata-builder/builders/section-field-maps.ts +18 -0
- package/src/metadata-builder/builders/section-field-utils.test.ts +83 -0
- package/src/metadata-builder/builders/section-field-utils.ts +69 -18
- package/src/metadata-builder/builders/section-rules/support-me.rules.ts +39 -0
- package/src/metadata-builder/helpers/rte.helpers.ts +82 -1
- package/src/metadata-builder/metadata-executor.ts +3 -0
- package/src/metadata-builder/models.ts +2 -0
- package/src/metadata-builder/parsers/ai-toolcall-parser.ts +4 -0
- package/src/metadata-builder/parsers/section-tool-arguments.ts +14 -1
- package/src/shared/style-settings/button-style-preset.test.ts +67 -0
- package/src/shared/style-settings/button-style-preset.ts +56 -0
- package/src/shared/style-settings/store/style-settings-store.ts +9 -38
- package/src/utils/minify-brand-page-metadata.test.ts +166 -1
- package/src/utils/minify-brand-page-metadata.ts +31 -1
|
@@ -224,7 +224,13 @@ const minifyContent = (content, editor, assets) => {
|
|
|
224
224
|
})),
|
|
225
225
|
}),
|
|
226
226
|
...(includeStyle(c.textStyle) && { textStyle: c.textStyle }),
|
|
227
|
-
|
|
227
|
+
// A text section keeps its band on the flat `backgroundColor` key — as a
|
|
228
|
+
// `{ backgroundColor }` object or a bare string — not on `backgroundStyle`,
|
|
229
|
+
// so the shared helper saw nothing and the AI never knew the band (BP-6081).
|
|
230
|
+
...includeBackgroundStyle(c.backgroundStyle ??
|
|
231
|
+
(typeof c.backgroundColor === 'string'
|
|
232
|
+
? { backgroundColor: c.backgroundColor }
|
|
233
|
+
: c.backgroundColor)),
|
|
228
234
|
};
|
|
229
235
|
case 'profile':
|
|
230
236
|
return {
|
|
@@ -359,11 +365,18 @@ const minifyContent = (content, editor, assets) => {
|
|
|
359
365
|
case 'logo':
|
|
360
366
|
return base;
|
|
361
367
|
case 'request-payment':
|
|
368
|
+
return {
|
|
369
|
+
...base,
|
|
370
|
+
...st('title', c.title, editor),
|
|
371
|
+
...st('description', c.description, editor),
|
|
372
|
+
};
|
|
362
373
|
case 'support-me':
|
|
363
374
|
return {
|
|
364
375
|
...base,
|
|
365
376
|
...st('title', c.title, editor),
|
|
366
377
|
...st('description', c.description, editor),
|
|
378
|
+
...st('successMessage', c.successMessage, editor),
|
|
379
|
+
...(includeString(c.displayStyle) && { displayStyle: c.displayStyle }),
|
|
367
380
|
};
|
|
368
381
|
default:
|
|
369
382
|
return base;
|
|
@@ -387,6 +400,15 @@ const minifyFooter = (footer, logoAssetKey) => {
|
|
|
387
400
|
url: l.url || '',
|
|
388
401
|
}))
|
|
389
402
|
: undefined,
|
|
403
|
+
backgroundStyle: footer.backgroundStyle?.backgroundColor
|
|
404
|
+
? { backgroundColor: footer.backgroundStyle.backgroundColor }
|
|
405
|
+
: undefined,
|
|
406
|
+
copyrightStyle: footer.copyrightStyle?.color
|
|
407
|
+
? { color: footer.copyrightStyle.color }
|
|
408
|
+
: undefined,
|
|
409
|
+
iconStyle: footer.iconStyle?.fill
|
|
410
|
+
? { fill: footer.iconStyle.fill }
|
|
411
|
+
: undefined,
|
|
390
412
|
};
|
|
391
413
|
};
|
|
392
414
|
// Fully opaque (100) is the default, so it's omitted to keep the AI payload small.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@designcrowd/library.brand-page",
|
|
3
3
|
"description": "A collection of Maker/Designer applications",
|
|
4
|
-
"version": "6.2.
|
|
4
|
+
"version": "6.2.4",
|
|
5
5
|
"author": "Design.com Eng",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"type": "module",
|
|
@@ -48,10 +48,6 @@
|
|
|
48
48
|
"copy:css": "copyfiles -fF ./public/css/global.css ./public/css/reset.css ./lib/src/css/",
|
|
49
49
|
"test": "vitest run",
|
|
50
50
|
"test:watch": "vitest watch",
|
|
51
|
-
"test:e2e": "vitest run --reporter=basic -c vitest.e2e.config.ts",
|
|
52
|
-
"test:e2e:watch": "vitest watch --reporter=basic -c vitest.e2e.config.ts",
|
|
53
|
-
"docker:test:e2e": "docker-compose -f docker-compose-coverage.yml build e2e && docker-compose -f docker-compose-coverage.yml run e2e",
|
|
54
|
-
"docker:test:e2e:env": "docker-compose -f docker-compose-coverage.yml build e2e-test-env && docker-compose -f docker-compose-coverage.yml run e2e-test-env",
|
|
55
51
|
"coverage": "echo \"To be migrated to vitest\"",
|
|
56
52
|
"storybook": "npm run clean:vite && npm run storybook:css && npm run storybook:themes && npm run storybook:start",
|
|
57
53
|
"storybook:themes": "node .storybook/tailwind.themes.cjs",
|
|
@@ -63,10 +59,6 @@
|
|
|
63
59
|
"watch": "npm run clean:lib && run-p watch:lib watch:css build:bp:typings",
|
|
64
60
|
"watch:lib": "NODE_ENV=development npm run build:bp:vite -- --watch",
|
|
65
61
|
"watch:css": "NODE_ENV=development nodemon --config nodemon.css.json",
|
|
66
|
-
"cy:run:local": "cypress run --browser chrome --headless --config \"baseUrl=http://localhost:8080\"",
|
|
67
|
-
"cy:run:ci": "cypress run --browser chrome --headless --config \"baseUrl=https://maker.designcrowd.ninja\"",
|
|
68
|
-
"cy:report": "npx junit-merge -o ./cypress/results/report.xml ./cypress/results/*.xml",
|
|
69
|
-
"cy:open": "cypress open",
|
|
70
62
|
"pre-push": "npm run test"
|
|
71
63
|
},
|
|
72
64
|
"dependencies": {
|
|
@@ -152,7 +144,6 @@
|
|
|
152
144
|
},
|
|
153
145
|
"devDependencies": {
|
|
154
146
|
"@faker-js/faker": "8.4.0",
|
|
155
|
-
"@frsource/cypress-plugin-visual-regression-diff": "3.3.10",
|
|
156
147
|
"@nuxt/test-utils": "4.0.0",
|
|
157
148
|
"@nuxt/types": "2.18.1",
|
|
158
149
|
"@nuxt/typescript-build": "3.0.2",
|
|
@@ -193,11 +184,9 @@
|
|
|
193
184
|
"cors": "2.8.6",
|
|
194
185
|
"cross-env": "7.0.3",
|
|
195
186
|
"css-loader": "6.9.1",
|
|
196
|
-
"cypress": "13.6.3",
|
|
197
187
|
"eslint": "8.56.0",
|
|
198
188
|
"eslint-config-prettier": "9.1.0",
|
|
199
189
|
"eslint-friendly-formatter": "4.0.1",
|
|
200
|
-
"eslint-plugin-cypress": "2.15.1",
|
|
201
190
|
"eslint-plugin-prettier": "5.5.5",
|
|
202
191
|
"eslint-plugin-vue": "9.21.1",
|
|
203
192
|
"file-loader": "6.2.0",
|
|
@@ -46,12 +46,16 @@ export interface AbTestResult {
|
|
|
46
46
|
isExcluded: boolean;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
const AB_TEST_KEYS = {
|
|
49
|
+
export const AB_TEST_KEYS = {
|
|
50
50
|
BP_3926_FREEMIUM_WATERMARK: 'bc-bp-3926-freemium-cta-in-website-editor',
|
|
51
|
+
// V1 (control) vs V2 (variation-1) AI website builder, sent by bc-net in the editor
|
|
52
|
+
// payload at load. Key must match `Bp6136V2AiBuilderStrategy.CampaignKey`.
|
|
53
|
+
BP_6136_V2_AI_BUILDER: 'bc-bp-6136-v2-ai-builder',
|
|
51
54
|
};
|
|
52
55
|
|
|
53
56
|
export interface AbTest {
|
|
54
57
|
bp_3926_freemium_watermark?: AbTestResult;
|
|
58
|
+
bp_6136_v2_ai_builder?: AbTestResult;
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
export const MEDIA_SIZES = {
|
|
@@ -132,5 +136,14 @@ export const getAbTestResults = (abtestKeyValues: AbTest): AbTest => {
|
|
|
132
136
|
);
|
|
133
137
|
}
|
|
134
138
|
|
|
139
|
+
// AB Test - V1 vs V2 AI website builder
|
|
140
|
+
|
|
141
|
+
if (abtestKeyValues[AB_TEST_KEYS.BP_6136_V2_AI_BUILDER]) {
|
|
142
|
+
abTests.bp_6136_v2_ai_builder = getValueType(
|
|
143
|
+
AB_TEST_KEYS.BP_6136_V2_AI_BUILDER,
|
|
144
|
+
abtestKeyValues[AB_TEST_KEYS.BP_6136_V2_AI_BUILDER],
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
135
148
|
return abTests;
|
|
136
149
|
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { createPinia, setActivePinia } from 'pinia';
|
|
3
|
+
import { aiBuilderAgentTypeForArm } from './ai-builder-experiment';
|
|
4
|
+
import { getAbTestResults } from '../../../brand-page/models/brand-page-context.model';
|
|
5
|
+
import { useAiWebsiteBuilderThreadStore } from '../../stores';
|
|
6
|
+
|
|
7
|
+
// Must match `Bp6136V2AiBuilderStrategy` in bc-net and the LaunchDarkly flag.
|
|
8
|
+
const CAMPAIGN = 'bc-bp-6136-v2-ai-builder';
|
|
9
|
+
|
|
10
|
+
// The arm arrives as the raw bc-net campaign string, so go through the real parser.
|
|
11
|
+
const armFor = (value?: string) =>
|
|
12
|
+
getAbTestResults(value ? ({ [CAMPAIGN]: value } as never) : {})
|
|
13
|
+
.bp_6136_v2_ai_builder;
|
|
14
|
+
|
|
15
|
+
describe('BP-6136 arm to AI builder agent type', () => {
|
|
16
|
+
it('variation-1 gets the V2 builder', () => {
|
|
17
|
+
expect(aiBuilderAgentTypeForArm(armFor('bp-6136-variation-1'))).toBe(
|
|
18
|
+
'website_builder_v2',
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('control stays on V1', () => {
|
|
23
|
+
expect(aiBuilderAgentTypeForArm(armFor('bp-6136-control'))).toBe(
|
|
24
|
+
'website_builder',
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('excluded stays on V1', () => {
|
|
29
|
+
expect(aiBuilderAgentTypeForArm(armFor('bp-6136-excluded'))).toBe(
|
|
30
|
+
'website_builder',
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('no arm at all (pre-purchase, AI tab off, older bc-net) stays on V1', () => {
|
|
35
|
+
expect(aiBuilderAgentTypeForArm(armFor(undefined))).toBe('website_builder');
|
|
36
|
+
expect(aiBuilderAgentTypeForArm(undefined)).toBe('website_builder');
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe('thread store agent type', () => {
|
|
41
|
+
beforeEach(() => {
|
|
42
|
+
setActivePinia(createPinia());
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('starts on V1, the production default', () => {
|
|
46
|
+
expect(useAiWebsiteBuilderThreadStore().agentType).toBe('website_builder');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('switching before any thread exists keeps the pending prompt and does not reset', () => {
|
|
50
|
+
const threadStore = useAiWebsiteBuilderThreadStore();
|
|
51
|
+
|
|
52
|
+
threadStore.promptText = 'draft the user is typing';
|
|
53
|
+
|
|
54
|
+
threadStore.setAgentType('website_builder_v2');
|
|
55
|
+
|
|
56
|
+
expect(threadStore.agentType).toBe('website_builder_v2');
|
|
57
|
+
expect(threadStore.promptText).toBe('draft the user is typing');
|
|
58
|
+
expect(threadStore.resetToken).toBe(0);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('switching under a running thread drops that thread', () => {
|
|
62
|
+
const threadStore = useAiWebsiteBuilderThreadStore();
|
|
63
|
+
|
|
64
|
+
threadStore.threadId = 'thread-on-v1';
|
|
65
|
+
|
|
66
|
+
threadStore.setAgentType('website_builder_v2');
|
|
67
|
+
|
|
68
|
+
expect(threadStore.threadId).toBeNull();
|
|
69
|
+
expect(threadStore.resetToken).toBe(1);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('setting the same agent again is a no-op', () => {
|
|
73
|
+
const threadStore = useAiWebsiteBuilderThreadStore();
|
|
74
|
+
|
|
75
|
+
threadStore.threadId = 'thread-on-v1';
|
|
76
|
+
|
|
77
|
+
threadStore.setAgentType('website_builder');
|
|
78
|
+
|
|
79
|
+
expect(threadStore.threadId).toBe('thread-on-v1');
|
|
80
|
+
expect(threadStore.resetToken).toBe(0);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AbTestResult } from '../../../brand-page/models/brand-page-context.model';
|
|
2
|
+
import {
|
|
3
|
+
AI_ASSISTANT_AGENT_TYPES,
|
|
4
|
+
type AiAssistantAgentType,
|
|
5
|
+
} from '../../../clients/ai-assistant-client';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A/B test: control keeps the V1 AI website builder, variation-1 gets V2.
|
|
9
|
+
*
|
|
10
|
+
* bc-net (WebsiteMakerInteractor) buckets post-purchase users who get the AI tab at
|
|
11
|
+
* editor load and sends the arm in `abTests`. No arm, control and excluded all stay
|
|
12
|
+
* on V1, so a missing value is today's production behaviour.
|
|
13
|
+
*/
|
|
14
|
+
export const aiBuilderAgentTypeForArm = (
|
|
15
|
+
arm: AbTestResult | undefined,
|
|
16
|
+
): AiAssistantAgentType =>
|
|
17
|
+
arm?.isVariation
|
|
18
|
+
? AI_ASSISTANT_AGENT_TYPES.WEBSITE_BUILDER_V2
|
|
19
|
+
: AI_ASSISTANT_AGENT_TYPES.WEBSITE_BUILDER;
|
|
@@ -3,7 +3,6 @@ import type { BrandPageModel } from '../../../brand-page/models';
|
|
|
3
3
|
import { getCurrentLocale } from '../../../composables/useTranslate';
|
|
4
4
|
import {
|
|
5
5
|
getInstance as getAiAssistantClient,
|
|
6
|
-
AI_ASSISTANT_AGENT_TYPES,
|
|
7
6
|
type AiAssistantResponse,
|
|
8
7
|
type AiAssistantToolResult,
|
|
9
8
|
type AiAssistantToolCall,
|
|
@@ -38,6 +37,7 @@ import { useHistoryStore } from '../../stores/history/history-store';
|
|
|
38
37
|
import { useUndoRedoFlag } from '../useUndoRedoFlag';
|
|
39
38
|
import { useBrandPageMakerUserStore } from '../../stores/user/user-store';
|
|
40
39
|
import { useAiMetadataBuilder } from './useAiMetadataBuilder';
|
|
40
|
+
import { aiBuilderAgentTypeForArm } from './ai-builder-experiment';
|
|
41
41
|
import {
|
|
42
42
|
pickErrorMessage,
|
|
43
43
|
pickWsErrorMessage,
|
|
@@ -529,6 +529,16 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
|
|
|
529
529
|
? 'premium'
|
|
530
530
|
: 'free';
|
|
531
531
|
|
|
532
|
+
if (!aiThreadStore.threadId) {
|
|
533
|
+
// The A/B arm bc-net bucketed at editor load decides which builder owns the
|
|
534
|
+
// new thread; the message and tool-result calls below reuse it.
|
|
535
|
+
aiThreadStore.setAgentType(
|
|
536
|
+
aiBuilderAgentTypeForArm(
|
|
537
|
+
containerStore.abTests.bp_6136_v2_ai_builder,
|
|
538
|
+
),
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
|
|
532
542
|
let buildResponse;
|
|
533
543
|
|
|
534
544
|
if (!aiThreadStore.threadId) {
|
|
@@ -536,7 +546,7 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
|
|
|
536
546
|
message,
|
|
537
547
|
websiteContext,
|
|
538
548
|
websiteSnapshot: snapshotStore.snapshotBase64 || undefined,
|
|
539
|
-
agentType:
|
|
549
|
+
agentType: aiThreadStore.agentType,
|
|
540
550
|
userPlan,
|
|
541
551
|
connectionId,
|
|
542
552
|
...buildAttributionFields(),
|
|
@@ -548,7 +558,7 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
|
|
|
548
558
|
message,
|
|
549
559
|
websiteContext,
|
|
550
560
|
websiteSnapshot: snapshotStore.snapshotBase64 || undefined,
|
|
551
|
-
agentType:
|
|
561
|
+
agentType: aiThreadStore.agentType,
|
|
552
562
|
userPlan,
|
|
553
563
|
connectionId,
|
|
554
564
|
...buildAttributionFields(),
|
|
@@ -752,11 +762,15 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
|
|
|
752
762
|
retryCount,
|
|
753
763
|
});
|
|
754
764
|
|
|
765
|
+
// Tool submissions must go to the SAME agent that ran the thread
|
|
766
|
+
// (AI QA 2026-07-05 T19: a mismatched agentType routes tool results
|
|
767
|
+
// to a service with no state for the thread and fails the build).
|
|
768
|
+
// The thread store holds this thread's agent (A/B arm: V1 control, V2 variation-1).
|
|
755
769
|
const submitResult = await client.submitToolResultsBuildAsync(
|
|
756
770
|
aiThreadStore.threadId!,
|
|
757
771
|
{
|
|
758
772
|
toolCalls: toolResults,
|
|
759
|
-
agentType:
|
|
773
|
+
agentType: aiThreadStore.agentType,
|
|
760
774
|
connectionId,
|
|
761
775
|
retryCount,
|
|
762
776
|
userPlan,
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { defineStore } from 'pinia';
|
|
2
2
|
import { ref } from 'vue';
|
|
3
|
+
import {
|
|
4
|
+
AI_ASSISTANT_AGENT_TYPES,
|
|
5
|
+
type AiAssistantAgentType,
|
|
6
|
+
} from '../../../clients/ai-assistant-client';
|
|
3
7
|
|
|
4
8
|
export const useAiWebsiteBuilderThreadStore = defineStore(
|
|
5
9
|
'aiWebsiteBuilderThread',
|
|
@@ -14,6 +18,14 @@ export const useAiWebsiteBuilderThreadStore = defineStore(
|
|
|
14
18
|
const promptText = ref<string>('');
|
|
15
19
|
const stopGeneration = ref<(() => void) | null>(null);
|
|
16
20
|
|
|
21
|
+
// Which builder this thread talks to. V1 (control) is the default, what production
|
|
22
|
+
// runs today; the chat composable sets V2 for the variation-1 arm when a thread
|
|
23
|
+
// starts (aiBuilderAgentTypeForArm). Every send site reads it, because tool results
|
|
24
|
+
// must reach the agent that owns the thread (AI QA 2026-07-05 T19).
|
|
25
|
+
const agentType = ref<AiAssistantAgentType>(
|
|
26
|
+
AI_ASSISTANT_AGENT_TYPES.WEBSITE_BUILDER,
|
|
27
|
+
);
|
|
28
|
+
|
|
17
29
|
// Bumped on every reset so consumers (useAiWebsiteBuilderChat) can react
|
|
18
30
|
// without watching `messages`, which would loop with its own deep watch.
|
|
19
31
|
const resetToken = ref<number>(0);
|
|
@@ -35,6 +47,22 @@ export const useAiWebsiteBuilderThreadStore = defineStore(
|
|
|
35
47
|
resetToken.value += 1;
|
|
36
48
|
};
|
|
37
49
|
|
|
50
|
+
const setAgentType = (type: AiAssistantAgentType) => {
|
|
51
|
+
if (agentType.value === type) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const hadThread = threadId.value !== null;
|
|
56
|
+
|
|
57
|
+
agentType.value = type;
|
|
58
|
+
|
|
59
|
+
// V1 and V2 threads are not interchangeable, so a thread already running on
|
|
60
|
+
// the other agent is dropped. Before the first prompt there is nothing to drop.
|
|
61
|
+
if (hadThread) {
|
|
62
|
+
reset();
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
38
66
|
return {
|
|
39
67
|
threadId,
|
|
40
68
|
runId,
|
|
@@ -45,6 +73,8 @@ export const useAiWebsiteBuilderThreadStore = defineStore(
|
|
|
45
73
|
buildSectionsCompleted,
|
|
46
74
|
promptText,
|
|
47
75
|
stopGeneration,
|
|
76
|
+
agentType,
|
|
77
|
+
setAgentType,
|
|
48
78
|
resetToken,
|
|
49
79
|
reset,
|
|
50
80
|
};
|