@aglyn/plugins-ai 1.0.0-beta.244 → 1.0.0-beta.246
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/package.json +17 -17
- package/src/lib/activity/ai-activity-actions.js +3 -1
- package/src/lib/activity/ai-activity-actions.js.map +1 -1
- package/src/lib/components/ai-job-links.js +7 -0
- package/src/lib/components/ai-job-links.js.map +1 -1
- package/src/lib/components/ai-product-zones.d.ts +3 -1
- package/src/lib/components/ai-product-zones.js.map +1 -1
- package/src/lib/components/ai-products-hub-card.component.js +1 -1
- package/src/lib/components/ai-products-hub-card.component.js.map +1 -1
- package/src/lib/components/ai-products-proposals.component.js +17 -9
- package/src/lib/components/ai-products-proposals.component.js.map +1 -1
- package/src/lib/components/ai-site-start-card.component.js +6 -4
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/components/ai-upsell-dialog.component.js +1 -1
- package/src/lib/components/ai-upsell-dialog.component.js.map +1 -1
- package/src/lib/jobs/ai-build-capabilities.js +162 -2
- package/src/lib/jobs/ai-build-capabilities.js.map +1 -1
- package/src/lib/jobs/ai-job-build-step.d.ts +7 -0
- package/src/lib/jobs/ai-job-build-step.js +85 -16
- package/src/lib/jobs/ai-job-build-step.js.map +1 -1
- package/src/lib/jobs/ai-job-duplicate-step.d.ts +123 -0
- package/src/lib/jobs/ai-job-duplicate-step.js +269 -0
- package/src/lib/jobs/ai-job-duplicate-step.js.map +1 -0
- package/src/lib/jobs/ai-job-layout-language.js +13 -0
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-navigation-step.d.ts +157 -0
- package/src/lib/jobs/ai-job-navigation-step.js +439 -0
- package/src/lib/jobs/ai-job-navigation-step.js.map +1 -0
- package/src/lib/jobs/ai-job-page-language.d.ts +2 -1
- package/src/lib/jobs/ai-job-page-language.js +21 -5
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-sections.js +1 -1
- package/src/lib/jobs/ai-job-page-sections.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +4 -2
- package/src/lib/jobs/ai-job-plan-step.js +16 -7
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-products-step.d.ts +2 -2
- package/src/lib/jobs/ai-job-products-step.js +2 -2
- package/src/lib/jobs/ai-job-products-step.js.map +1 -1
- package/src/lib/jobs/ai-job-settings-step.d.ts +272 -0
- package/src/lib/jobs/ai-job-settings-step.js +695 -0
- package/src/lib/jobs/ai-job-settings-step.js.map +1 -0
- package/src/lib/jobs/ai-job-site-content.d.ts +20 -6
- package/src/lib/jobs/ai-job-site-content.js +28 -12
- package/src/lib/jobs/ai-job-site-content.js.map +1 -1
- package/src/lib/jobs/ai-job-site-datasets.d.ts +2 -0
- package/src/lib/jobs/ai-job-site-datasets.js +10 -3
- package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.d.ts +3 -1
- package/src/lib/jobs/ai-job-site-step.js +70 -10
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-site-publish.d.ts +62 -4
- package/src/lib/jobs/ai-site-publish.js +203 -56
- package/src/lib/jobs/ai-site-publish.js.map +1 -1
- package/src/lib/layout-language/ai-layout-compiler.d.ts +7 -4
- package/src/lib/layout-language/ai-layout-compiler.js +26 -25
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame-hollows.d.ts +41 -0
- package/src/lib/layout-language/ai-layout-frame-hollows.js +330 -0
- package/src/lib/layout-language/ai-layout-frame-hollows.js.map +1 -0
- package/src/lib/layout-language/ai-layout-frame.d.ts +18 -1
- package/src/lib/layout-language/ai-layout-frame.js +83 -13
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
- package/src/lib/layout-language/ai-layout-listings.d.ts +35 -0
- package/src/lib/layout-language/ai-layout-listings.js +34 -0
- package/src/lib/layout-language/ai-layout-listings.js.map +1 -1
- package/src/lib/layout-language/ai-layout-tree.d.ts +2 -0
- package/src/lib/layout-language/ai-layout-tree.js +17 -0
- package/src/lib/layout-language/ai-layout-tree.js.map +1 -1
- package/src/lib/model/ai-build-job.d.ts +23 -0
- package/src/lib/model/ai-build-job.js +102 -13
- package/src/lib/model/ai-build-job.js.map +1 -1
- package/src/lib/model/ai-build-plan.d.ts +25 -0
- package/src/lib/model/ai-build-plan.js +45 -1
- package/src/lib/model/ai-build-plan.js.map +1 -1
- package/src/lib/model/ai-credit-estimate.d.ts +52 -0
- package/src/lib/model/ai-credit-estimate.js +51 -0
- package/src/lib/model/ai-credit-estimate.js.map +1 -1
- package/src/lib/model/ai-job-activity.js +4 -1
- package/src/lib/model/ai-job-activity.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +10 -2
- package/src/lib/model/ai-jobs.types.js +4 -1
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-layout-menus.d.ts +104 -0
- package/src/lib/model/ai-layout-menus.js +518 -0
- package/src/lib/model/ai-layout-menus.js.map +1 -0
- package/src/lib/model/ai-products.d.ts +31 -1
- package/src/lib/model/ai-products.js +34 -1
- package/src/lib/model/ai-products.js.map +1 -1
- package/src/lib/model/ai-site-inventory.d.ts +15 -0
- package/src/lib/model/ai-site-inventory.js.map +1 -1
- package/src/lib/model/ai-site-job.d.ts +10 -0
- package/src/lib/model/ai-site-job.js +36 -9
- package/src/lib/model/ai-site-job.js.map +1 -1
- package/src/lib/model/ai-site-store-pages.js +1 -1
- package/src/lib/model/ai-site-store-pages.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +53 -0
- package/src/lib/runtime/ai-doctrine-validators.js +166 -25
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +7 -2
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-palette.generated.js +1 -1
- package/src/lib/runtime/ai-palette.generated.js.map +1 -1
- package/src/lib/runtime/ai-products-generation.d.ts +4 -2
- package/src/lib/runtime/ai-products-generation.js +12 -6
- package/src/lib/runtime/ai-products-generation.js.map +1 -1
- package/src/lib/runtime/site-inventory.d.ts +12 -0
- package/src/lib/runtime/site-inventory.js +29 -1
- package/src/lib/runtime/site-inventory.js.map +1 -1
- package/src/lib/server.js +12 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/testing/stand-in-dataset-index.js +37 -3
- package/src/lib/testing/stand-in-dataset-index.js.map +1 -1
- package/src/lib/tools/ai-products-tool.d.ts +3 -1
- package/src/lib/tools/ai-products-tool.js +15 -5
- package/src/lib/tools/ai-products-tool.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/testing/stand-in-dataset-index.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { visibleToHost } from '@aglyn/aglyn/app-utils/scope-tokens'\nimport {\n registerPluginRecordIndex,\n type PluginIndexedRecord,\n} from '@aglyn/aglyn/plugin-manager/plugin-record-index'\nimport { unregisterPluginServices } from '@aglyn/aglyn/plugin-manager/plugin-services'\n\n/**\n * The `dataset` index the plugin that keeps the workspace's datasets\n * publishes (AGL-3080), stood in over a spec's own Firestore double — this\n * plugin may not load the data plugin that registers the real one. It answers\n * in the shape the data plugin's `dataset-record-index.ts` documents: live\n * datasets only, narrowed to a site to those shared with it, each with its\n * fields (`{ id, name, type }` and a `customType` where one rides it, in\n * the dataset page's order) and its\n * `visibleTo`. What the data plugin itself answers is held in its own spec.\n */\n\nconst OWNER = 'data'\n\nconst str = (value: unknown): string => (typeof value === 'string' ? value.trim() : '')\n\n/** A field as a dataset document stores it, as far as this stand-in reads one. */\ninterface StoredField {\n name?: unknown\n type?: unknown\n customType?: unknown\n}\n\n/**\n * The fields a dataset document declares, in the Data page's order: its\n * model's, or for a dataset from before models, each name in `fields` as a\n * text field — the derivation the data plugin applies.\n */\nfunction storedFields(data: Record<string, unknown>): { order: string[]; fields: Record<string, StoredField> } {\n const model = data['model'] as { order?: unknown; fields?: unknown } | undefined\n if (model && Array.isArray(model.order) && model.order.length && model.fields && typeof model.fields === 'object') {\n return { order: model.order.map(String), fields: model.fields as Record<string, StoredField> }\n }\n const names = Array.isArray(data['fields']) ? data['fields'].map(String) : []\n const titled = (name: string) => {\n const words = name.replace(/_/g, ' ').trim()\n return words ? words.charAt(0).toUpperCase() + words.slice(1) : name\n }\n return {\n order: names,\n fields: Object.fromEntries(names.map((name) => [name, { name: titled(name), type: 'text' }])),\n }\n}\n\nfunction record(id: string, data: Record<string, unknown> | undefined): PluginIndexedRecord | null {\n if (!data || data['deletedAt'] != null) return null\n const model = storedFields(data)\n return {\n id,\n name: str(data['displayName']) || str(data['name']) || id,\n facts: {\n fields: model.order.map((fieldId) => ({\n id: fieldId,\n name: str(model.fields[fieldId]?.name) || fieldId,\n type: String(model.fields[fieldId]?.type ?? 'text'),\n ...(str(model.fields[fieldId]?.customType) ? { customType: str(model.fields[fieldId]?.customType) } : {}),\n })),\n visibleTo: Array.isArray(data['visibleTo']) ? data['visibleTo'] : [],\n },\n }\n}\n\n/** Registers it, reading through `firestore`. */\nexport function standInDatasetIndex(firestore: FirebaseFirestore.Firestore): void {\n const datasets = (orgId: string) => firestore.collection('orgs').doc(orgId).collection('datasets')\n const shared = (one: PluginIndexedRecord | null, hostId: string | null | undefined) =>\n one && (!hostId || visibleToHost(one.facts['visibleTo'] as string[], hostId)) ? one : null\n registerPluginRecordIndex(\n 'dataset',\n {\n async list({ orgId, hostId, limit }) {\n if (!orgId) return { records: [], truncated: false }\n const snapshot = await datasets(orgId).get()\n const records = snapshot.docs\n .map((doc) => shared(record(doc.id, doc.data()), hostId))\n .filter((one): one is PluginIndexedRecord => one !== null)\n return { records: records.slice(0, limit), truncated: records.length > limit }\n },\n async get({ orgId, hostId, id }) {\n if (!orgId) return null\n const snapshot = await datasets(orgId).doc(id).get()\n return snapshot.exists ? shared(record(snapshot.id, snapshot.data()), hostId) : null\n },\n },\n { pluginId: OWNER },\n )\n}\n\n/** Forgets it, so the next spec starts with nothing keeping datasets. */\nexport function removeStandInDatasetIndex(): void {\n unregisterPluginServices(OWNER)\n}\n"],"names":["visibleToHost","registerPluginRecordIndex","unregisterPluginServices","OWNER","str","value","trim","storedFields","data","model","Array","isArray","order","length","fields","map","String","names","titled","name","words","replace","charAt","toUpperCase","slice","Object","fromEntries","type","record","id","facts","fieldId","customType","visibleTo","standInDatasetIndex","firestore","datasets","orgId","collection","doc","shared","one","hostId","list","limit","records","truncated","snapshot","get","docs","filter","exists","pluginId","removeStandInDatasetIndex"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/testing/stand-in-dataset-index.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { visibleToHost } from '@aglyn/aglyn/app-utils/scope-tokens'\nimport {\n registerPluginRecordIndex,\n type PluginIndexedRecord,\n} from '@aglyn/aglyn/plugin-manager/plugin-record-index'\nimport { unregisterPluginServices } from '@aglyn/aglyn/plugin-manager/plugin-services'\n\n/**\n * The `dataset` index the plugin that keeps the workspace's datasets\n * publishes (AGL-3080), stood in over a spec's own Firestore double — this\n * plugin may not load the data plugin that registers the real one. It answers\n * in the shape the data plugin's `dataset-record-index.ts` documents: live\n * datasets only, narrowed to a site to those shared with it, each with its\n * fields (`{ id, name, type }` and a `customType` where one rides it, in\n * the dataset page's order) and its\n * `visibleTo`; narrowed to a site, the site's record page for it as\n * `recordPage` (`{ screenId, base, slugField }`, or `null`, AGL-3747) read off\n * `hosts/{hostId}/recordPages`. What the data plugin itself answers is held in\n * its own spec.\n */\n\nconst OWNER = 'data'\n\nconst str = (value: unknown): string => (typeof value === 'string' ? value.trim() : '')\n\n/** A field as a dataset document stores it, as far as this stand-in reads one. */\ninterface StoredField {\n name?: unknown\n type?: unknown\n customType?: unknown\n}\n\n/**\n * The fields a dataset document declares, in the Data page's order: its\n * model's, or for a dataset from before models, each name in `fields` as a\n * text field — the derivation the data plugin applies.\n */\nfunction storedFields(data: Record<string, unknown>): { order: string[]; fields: Record<string, StoredField> } {\n const model = data['model'] as { order?: unknown; fields?: unknown } | undefined\n if (model && Array.isArray(model.order) && model.order.length && model.fields && typeof model.fields === 'object') {\n return { order: model.order.map(String), fields: model.fields as Record<string, StoredField> }\n }\n const names = Array.isArray(data['fields']) ? data['fields'].map(String) : []\n const titled = (name: string) => {\n const words = name.replace(/_/g, ' ').trim()\n return words ? words.charAt(0).toUpperCase() + words.slice(1) : name\n }\n return {\n order: names,\n fields: Object.fromEntries(names.map((name) => [name, { name: titled(name), type: 'text' }])),\n }\n}\n\nfunction record(id: string, data: Record<string, unknown> | undefined): PluginIndexedRecord | null {\n if (!data || data['deletedAt'] != null) return null\n const model = storedFields(data)\n return {\n id,\n name: str(data['displayName']) || str(data['name']) || id,\n facts: {\n fields: model.order.map((fieldId) => ({\n id: fieldId,\n name: str(model.fields[fieldId]?.name) || fieldId,\n type: String(model.fields[fieldId]?.type ?? 'text'),\n ...(str(model.fields[fieldId]?.customType) ? { customType: str(model.fields[fieldId]?.customType) } : {}),\n })),\n visibleTo: Array.isArray(data['visibleTo']) ? data['visibleTo'] : [],\n },\n }\n}\n\n/** Registers it, reading through `firestore`. */\nexport function standInDatasetIndex(firestore: FirebaseFirestore.Firestore): void {\n const datasets = (orgId: string) => firestore.collection('orgs').doc(orgId).collection('datasets')\n const shared = (one: PluginIndexedRecord | null, hostId: string | null | undefined) =>\n one && (!hostId || visibleToHost(one.facts['visibleTo'] as string[], hostId)) ? one : null\n const recordPages = async (hostId: string) => {\n const snapshot = await firestore.collection('hosts').doc(hostId).collection('recordPages').get()\n const pages = new Map<string, { screenId: string; base: string; slugField: string }>()\n for (const doc of snapshot.docs) {\n const data = doc.data() ?? {}\n const base = str(data['base']).replace(/^\\/+|\\/+$/g, '')\n if (!str(data['datasetId']) || !base || !str(data['slugField']) || pages.has(str(data['datasetId']))) continue\n pages.set(str(data['datasetId']), { screenId: doc.id, base, slugField: str(data['slugField']) })\n }\n return pages\n }\n const withPages = async (records: PluginIndexedRecord[], hostId: string | null | undefined) => {\n if (!hostId || !records.length) return records\n const pages = await recordPages(hostId)\n return records.map((one) => ({ ...one, facts: { ...one.facts, recordPage: pages.get(one.id) ?? null } }))\n }\n registerPluginRecordIndex(\n 'dataset',\n {\n async list({ orgId, hostId, limit }) {\n if (!orgId) return { records: [], truncated: false }\n const snapshot = await datasets(orgId).get()\n const records = snapshot.docs\n .map((doc) => shared(record(doc.id, doc.data()), hostId))\n .filter((one): one is PluginIndexedRecord => one !== null)\n return { records: await withPages(records.slice(0, limit), hostId), truncated: records.length > limit }\n },\n async get({ orgId, hostId, id }) {\n if (!orgId) return null\n const snapshot = await datasets(orgId).doc(id).get()\n const one = snapshot.exists ? shared(record(snapshot.id, snapshot.data()), hostId) : null\n return one ? (await withPages([one], hostId))[0] : null\n },\n },\n { pluginId: OWNER },\n )\n}\n\n/** Forgets it, so the next spec starts with nothing keeping datasets. */\nexport function removeStandInDatasetIndex(): void {\n unregisterPluginServices(OWNER)\n}\n"],"names":["visibleToHost","registerPluginRecordIndex","unregisterPluginServices","OWNER","str","value","trim","storedFields","data","model","Array","isArray","order","length","fields","map","String","names","titled","name","words","replace","charAt","toUpperCase","slice","Object","fromEntries","type","record","id","facts","fieldId","customType","visibleTo","standInDatasetIndex","firestore","datasets","orgId","collection","doc","shared","one","hostId","recordPages","snapshot","get","pages","Map","docs","base","has","set","screenId","slugField","withPages","records","recordPage","list","limit","truncated","filter","exists","pluginId","removeStandInDatasetIndex"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,aAAa,QAAQ,sCAAqC;AACnE,SACEC,yBAAyB,QAEpB,kDAAiD;AACxD,SAASC,wBAAwB,QAAQ,8CAA6C;AAEtF;;;;;;;;;;;;CAYC,GAED,MAAMC,QAAQ;AAEd,MAAMC,MAAM,CAACC,QAA4B,OAAOA,UAAU,WAAWA,MAAMC,IAAI,KAAK;AASpF;;;;CAIC,GACD,SAASC,aAAaC,IAA6B;IACjD,MAAMC,QAAQD,IAAI,CAAC,QAAQ;IAC3B,IAAIC,SAASC,MAAMC,OAAO,CAACF,MAAMG,KAAK,KAAKH,MAAMG,KAAK,CAACC,MAAM,IAAIJ,MAAMK,MAAM,IAAI,OAAOL,MAAMK,MAAM,KAAK,UAAU;QACjH,OAAO;YAAEF,OAAOH,MAAMG,KAAK,CAACG,GAAG,CAACC;YAASF,QAAQL,MAAMK,MAAM;QAAgC;IAC/F;IACA,MAAMG,QAAQP,MAAMC,OAAO,CAACH,IAAI,CAAC,SAAS,IAAIA,IAAI,CAAC,SAAS,CAACO,GAAG,CAACC,UAAU,EAAE;IAC7E,MAAME,SAAS,CAACC;QACd,MAAMC,QAAQD,KAAKE,OAAO,CAAC,MAAM,KAAKf,IAAI;QAC1C,OAAOc,QAAQA,MAAME,MAAM,CAAC,GAAGC,WAAW,KAAKH,MAAMI,KAAK,CAAC,KAAKL;IAClE;IACA,OAAO;QACLP,OAAOK;QACPH,QAAQW,OAAOC,WAAW,CAACT,MAAMF,GAAG,CAAC,CAACI,OAAS;gBAACA;gBAAM;oBAAEA,MAAMD,OAAOC;oBAAOQ,MAAM;gBAAO;aAAE;IAC7F;AACF;AAEA,SAASC,OAAOC,EAAU,EAAErB,IAAyC;IACnE,IAAI,CAACA,QAAQA,IAAI,CAAC,YAAY,IAAI,MAAM,OAAO;IAC/C,MAAMC,QAAQF,aAAaC;IAC3B,OAAO;QACLqB;QACAV,MAAMf,IAAII,IAAI,CAAC,cAAc,KAAKJ,IAAII,IAAI,CAAC,OAAO,KAAKqB;QACvDC,OAAO;YACLhB,QAAQL,MAAMG,KAAK,CAACG,GAAG,CAAC,CAACgB;;oBAEbtB,uBACGA,wBACLA,wBAAuDA;uBAJ3B;oBACpCoB,IAAIE;oBACJZ,MAAMf,KAAIK,wBAAAA,MAAMK,MAAM,CAACiB,QAAQ,qBAArBtB,sBAAuBU,IAAI,KAAKY;oBAC1CJ,MAAMX,gBAAOP,yBAAAA,MAAMK,MAAM,CAACiB,QAAQ,qBAArBtB,uBAAuBkB,IAAI,mBAAI;mBACxCvB,KAAIK,yBAAAA,MAAMK,MAAM,CAACiB,QAAQ,qBAArBtB,uBAAuBuB,UAAU,IAAI;oBAAEA,YAAY5B,KAAIK,yBAAAA,MAAMK,MAAM,CAACiB,QAAQ,qBAArBtB,uBAAuBuB,UAAU;gBAAE,IAAI,CAAC;;YAEzGC,WAAWvB,MAAMC,OAAO,CAACH,IAAI,CAAC,YAAY,IAAIA,IAAI,CAAC,YAAY,GAAG,EAAE;QACtE;IACF;AACF;AAEA,+CAA+C,GAC/C,OAAO,SAAS0B,oBAAoBC,SAAsC;IACxE,MAAMC,WAAW,CAACC,QAAkBF,UAAUG,UAAU,CAAC,QAAQC,GAAG,CAACF,OAAOC,UAAU,CAAC;IACvF,MAAME,SAAS,CAACC,KAAiCC,SAC/CD,OAAQ,CAAA,CAACC,UAAU1C,cAAcyC,IAAIX,KAAK,CAAC,YAAY,EAAcY,OAAM,IAAKD,MAAM;IACxF,MAAME,cAAc,OAAOD;QACzB,MAAME,WAAW,MAAMT,UAAUG,UAAU,CAAC,SAASC,GAAG,CAACG,QAAQJ,UAAU,CAAC,eAAeO,GAAG;QAC9F,MAAMC,QAAQ,IAAIC;QAClB,KAAK,MAAMR,OAAOK,SAASI,IAAI,CAAE;gBAClBT;YAAb,MAAM/B,QAAO+B,YAAAA,IAAI/B,IAAI,cAAR+B,YAAc,CAAC;YAC5B,MAAMU,OAAO7C,IAAII,IAAI,CAAC,OAAO,EAAEa,OAAO,CAAC,cAAc;YACrD,IAAI,CAACjB,IAAII,IAAI,CAAC,YAAY,KAAK,CAACyC,QAAQ,CAAC7C,IAAII,IAAI,CAAC,YAAY,KAAKsC,MAAMI,GAAG,CAAC9C,IAAII,IAAI,CAAC,YAAY,IAAI;YACtGsC,MAAMK,GAAG,CAAC/C,IAAII,IAAI,CAAC,YAAY,GAAG;gBAAE4C,UAAUb,IAAIV,EAAE;gBAAEoB;gBAAMI,WAAWjD,IAAII,IAAI,CAAC,YAAY;YAAE;QAChG;QACA,OAAOsC;IACT;IACA,MAAMQ,YAAY,OAAOC,SAAgCb;QACvD,IAAI,CAACA,UAAU,CAACa,QAAQ1C,MAAM,EAAE,OAAO0C;QACvC,MAAMT,QAAQ,MAAMH,YAAYD;QAChC,OAAOa,QAAQxC,GAAG,CAAC,CAAC0B;gBAAsDK;mBAA7C,aAAKL;gBAAKX,OAAO,aAAKW,IAAIX,KAAK;oBAAE0B,UAAU,GAAEV,aAAAA,MAAMD,GAAG,CAACJ,IAAIZ,EAAE,aAAhBiB,aAAqB;;;;IACjG;IACA7C,0BACE,WACA;QACE,MAAMwD,MAAK,EAAEpB,KAAK,EAAEK,MAAM,EAAEgB,KAAK,EAAE;YACjC,IAAI,CAACrB,OAAO,OAAO;gBAAEkB,SAAS,EAAE;gBAAEI,WAAW;YAAM;YACnD,MAAMf,WAAW,MAAMR,SAASC,OAAOQ,GAAG;YAC1C,MAAMU,UAAUX,SAASI,IAAI,CAC1BjC,GAAG,CAAC,CAACwB,MAAQC,OAAOZ,OAAOW,IAAIV,EAAE,EAAEU,IAAI/B,IAAI,KAAKkC,SAChDkB,MAAM,CAAC,CAACnB,MAAoCA,QAAQ;YACvD,OAAO;gBAAEc,SAAS,MAAMD,UAAUC,QAAQ/B,KAAK,CAAC,GAAGkC,QAAQhB;gBAASiB,WAAWJ,QAAQ1C,MAAM,GAAG6C;YAAM;QACxG;QACA,MAAMb,KAAI,EAAER,KAAK,EAAEK,MAAM,EAAEb,EAAE,EAAE;YAC7B,IAAI,CAACQ,OAAO,OAAO;YACnB,MAAMO,WAAW,MAAMR,SAASC,OAAOE,GAAG,CAACV,IAAIgB,GAAG;YAClD,MAAMJ,MAAMG,SAASiB,MAAM,GAAGrB,OAAOZ,OAAOgB,SAASf,EAAE,EAAEe,SAASpC,IAAI,KAAKkC,UAAU;YACrF,OAAOD,MAAM,AAAC,CAAA,MAAMa,UAAU;gBAACb;aAAI,EAAEC,OAAM,CAAE,CAAC,EAAE,GAAG;QACrD;IACF,GACA;QAAEoB,UAAU3D;IAAM;AAEtB;AAEA,uEAAuE,GACvE,OAAO,SAAS4D;IACd7D,yBAAyBC;AAC3B"}
|
|
@@ -28,7 +28,9 @@ import type { AiGenerationCheckResult } from '../runtime/ai-doctrine';
|
|
|
28
28
|
* discounts, from a brief.
|
|
29
29
|
*
|
|
30
30
|
* Each schema is kept small, and no field is nullable: "none" is an empty
|
|
31
|
-
* string, an empty list or zero. A
|
|
31
|
+
* string, an empty list or zero. A catalog product's `price` is the one field
|
|
32
|
+
* no answer is refused for: code keeps it in range or drops it to the
|
|
33
|
+
* store's default (`aiCatalogPrice`). A strict schema accepts no length keyword,
|
|
32
34
|
* so every bound is stated in a description and enforced here. A check
|
|
33
35
|
* returns a value only when nothing in the answer is broken, and otherwise
|
|
34
36
|
* the violations and the parts at fault, for the generation call's one
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/ import { SEO_LISTING_FIELDS } from "@aglyn/aglyn/app-utils/seo-listing-fields";
|
|
17
|
-
import { AI_CATALOG_DESCRIPTION_MAX_CHARS, AI_CATALOG_OPTION_VALUE_MAX_CHARS, AI_CATALOG_OPTION_VALUES_MAX, AI_CATALOG_OPTIONS_MAX, AI_CATALOG_PHOTO_MAX_CHARS, AI_CATALOG_PRODUCTS, AI_CATALOG_TAGS_MAX, AI_CATEGORIES_MAX, AI_CATEGORY_NAME_MAX_CHARS, AI_DISCOUNT_CODE, AI_DISCOUNT_MAX_FIXED_USD, AI_DISCOUNT_MAX_PERCENT, AI_DISCOUNTS_MAX, AI_PRODUCT_CATEGORIES_MAX, AI_PRODUCT_DESCRIPTION_MAX_CHARS, AI_PRODUCT_NAME_MAX_CHARS, AI_PRODUCT_OPTION_NAME_MAX_CHARS, AI_PRODUCT_TAG_MAX_CHARS, AI_PRODUCT_TAGS_MAX, AI_PRODUCT_TYPES, AI_PROPOSAL_WHY_MAX_CHARS } from "../model/ai-products.js";
|
|
17
|
+
import { AI_CATALOG_DESCRIPTION_MAX_CHARS, AI_CATALOG_OPTION_VALUE_MAX_CHARS, AI_CATALOG_OPTION_VALUES_MAX, AI_CATALOG_OPTIONS_MAX, AI_CATALOG_PHOTO_MAX_CHARS, AI_CATALOG_PRICE_USD, AI_CATALOG_PRODUCTS, AI_CATALOG_TAGS_MAX, AI_CATEGORIES_MAX, AI_CATEGORY_NAME_MAX_CHARS, AI_DISCOUNT_CODE, AI_DISCOUNT_MAX_FIXED_USD, AI_DISCOUNT_MAX_PERCENT, AI_DISCOUNTS_MAX, AI_PRODUCT_CATEGORIES_MAX, AI_PRODUCT_DESCRIPTION_MAX_CHARS, AI_PRODUCT_NAME_MAX_CHARS, AI_PRODUCT_OPTION_NAME_MAX_CHARS, AI_PRODUCT_TAG_MAX_CHARS, AI_PRODUCT_TAGS_MAX, AI_PRODUCT_TYPES, AI_PROPOSAL_WHY_MAX_CHARS, aiCatalogPrice } from "../model/ai-products.js";
|
|
18
18
|
import { findInventedPrices, findStorefrontClaims, storefrontClaimViolations } from "../model/ai-storefront-claims.js";
|
|
19
19
|
import { detectOffVoiceCopy } from "../runtime/ai-doctrine-validators.js";
|
|
20
20
|
/**
|
|
@@ -28,7 +28,9 @@ import { detectOffVoiceCopy } from "../runtime/ai-doctrine-validators.js";
|
|
|
28
28
|
* discounts, from a brief.
|
|
29
29
|
*
|
|
30
30
|
* Each schema is kept small, and no field is nullable: "none" is an empty
|
|
31
|
-
* string, an empty list or zero. A
|
|
31
|
+
* string, an empty list or zero. A catalog product's `price` is the one field
|
|
32
|
+
* no answer is refused for: code keeps it in range or drops it to the
|
|
33
|
+
* store's default (`aiCatalogPrice`). A strict schema accepts no length keyword,
|
|
32
34
|
* so every bound is stated in a description and enforced here. A check
|
|
33
35
|
* returns a value only when nothing in the answer is broken, and otherwise
|
|
34
36
|
* the violations and the parts at fault, for the generation call's one
|
|
@@ -270,7 +272,8 @@ function fail(findings, at, code, message, value) {
|
|
|
270
272
|
'options',
|
|
271
273
|
'seoTitle',
|
|
272
274
|
'seoDescription',
|
|
273
|
-
'photo'
|
|
275
|
+
'photo',
|
|
276
|
+
'price'
|
|
274
277
|
],
|
|
275
278
|
properties: {
|
|
276
279
|
name: string(`Distinct within the list, at most ${AI_PRODUCT_NAME_MAX_CHARS} characters.`),
|
|
@@ -300,7 +303,11 @@ function fail(findings, at, code, message, value) {
|
|
|
300
303
|
},
|
|
301
304
|
seoTitle: string(`At most ${SEO_TITLE_MAX} characters.`),
|
|
302
305
|
seoDescription: string(`At most ${SEO_DESCRIPTION_MAX} characters.`),
|
|
303
|
-
photo: string(`What the product photo should show, in one sentence of at most ${AI_CATALOG_PHOTO_MAX_CHARS} characters.`)
|
|
306
|
+
photo: string(`What the product photo should show, in one sentence of at most ${AI_CATALOG_PHOTO_MAX_CHARS} characters.`),
|
|
307
|
+
price: {
|
|
308
|
+
type: 'number',
|
|
309
|
+
description: `Its suggested price in US dollars, from ${AI_CATALOG_PRICE_USD.min} to ${AI_CATALOG_PRICE_USD.max}.`
|
|
310
|
+
}
|
|
304
311
|
}
|
|
305
312
|
}
|
|
306
313
|
}
|
|
@@ -392,7 +399,10 @@ function fail(findings, at, code, message, value) {
|
|
|
392
399
|
options,
|
|
393
400
|
seoTitle,
|
|
394
401
|
seoDescription,
|
|
395
|
-
photo
|
|
402
|
+
photo,
|
|
403
|
+
// Kept by code, never re-asked (Zach, 2026-10-12): a price that is
|
|
404
|
+
// missing or out of range is `null`, and the store's default stands in.
|
|
405
|
+
price: aiCatalogPrice(entry['price'])
|
|
396
406
|
});
|
|
397
407
|
});
|
|
398
408
|
findings.violations.push(...claimViolations(samples, context.merchantWords), ...detectOffVoiceCopy(samples, null));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/tools/ai-products-tool.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { SEO_LISTING_FIELDS } from '@aglyn/aglyn/app-utils/seo-listing-fields'\nimport {\n AI_CATALOG_DESCRIPTION_MAX_CHARS,\n AI_CATALOG_OPTION_VALUE_MAX_CHARS,\n AI_CATALOG_OPTION_VALUES_MAX,\n AI_CATALOG_OPTIONS_MAX,\n AI_CATALOG_PHOTO_MAX_CHARS,\n AI_CATALOG_PRODUCTS,\n AI_CATALOG_TAGS_MAX,\n AI_CATEGORIES_MAX,\n AI_CATEGORY_NAME_MAX_CHARS,\n AI_DISCOUNT_CODE,\n AI_DISCOUNT_MAX_FIXED_USD,\n AI_DISCOUNT_MAX_PERCENT,\n AI_DISCOUNTS_MAX,\n AI_PRODUCT_CATEGORIES_MAX,\n AI_PRODUCT_DESCRIPTION_MAX_CHARS,\n AI_PRODUCT_NAME_MAX_CHARS,\n AI_PRODUCT_OPTION_NAME_MAX_CHARS,\n AI_PRODUCT_TAG_MAX_CHARS,\n AI_PRODUCT_TAGS_MAX,\n AI_PRODUCT_TYPES,\n AI_PROPOSAL_WHY_MAX_CHARS,\n type AiCatalogProduct,\n type AiCategoriesProposal,\n type AiDiscountKind,\n type AiProductCopy,\n type AiProductOption,\n type AiProductType,\n type AiProposedDiscount,\n} from '../model/ai-products'\nimport {\n findInventedPrices,\n findStorefrontClaims,\n storefrontClaimViolations,\n type AiStorefrontCopySample,\n} from '../model/ai-storefront-claims'\nimport type { AiTool } from '../providers/contract'\nimport type { AiGenerationCheckResult } from '../runtime/ai-doctrine'\nimport { detectOffVoiceCopy, type AiDoctrineViolation } from '../runtime/ai-doctrine-validators'\n\n/**\n * The strict tools commerce by AI answers through (AGL-2916), and the checks\n * that hold each answer to the commerce editor it proposes for.\n *\n * - `propose_product_copy` — one product's description, search listing, tags,\n * categories and option names.\n * - `propose_catalog` — a store's first products, from a brief.\n * - `propose_categories_and_discounts` — store categories and a first set of\n * discounts, from a brief.\n *\n * Each schema is kept small, and no field is nullable: \"none\" is an empty\n * string, an empty list or zero. A strict schema accepts no length keyword,\n * so every bound is stated in a description and enforced here. A check\n * returns a value only when nothing in the answer is broken, and otherwise\n * the violations and the parts at fault, for the generation call's one\n * re-ask.\n */\n\nexport const AI_PRODUCT_COPY_TOOL_NAME = 'propose_product_copy'\nexport const AI_CATALOG_TOOL_NAME = 'propose_catalog'\nexport const AI_CATEGORIES_TOOL_NAME = 'propose_categories_and_discounts'\n\nconst SEO_TITLE_MAX = SEO_LISTING_FIELDS.title.maxLength\nconst SEO_DESCRIPTION_MAX = SEO_LISTING_FIELDS.description.maxLength\n\nconst string = (description: string) => ({ type: 'string', description })\nconst strings = (description: string) => ({ type: 'array', items: { type: 'string' }, description })\n\n/* ------------------------------------------------------------------------ *\n * Shared reads\n * ------------------------------------------------------------------------ */\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\n/** One line: runs of white space folded to one space. */\nconst line = (value: unknown): string => (typeof value === 'string' ? value.replace(/\\s+/g, ' ').trim() : '')\n\n/** Paragraphs: spaces folded within a line, at most one blank line between paragraphs. */\nconst paragraphs = (value: unknown): string =>\n typeof value === 'string'\n ? value\n .replace(/\\r\\n?/g, '\\n')\n .split('\\n')\n .map((part) => part.replace(/[ \\t\\f\\v]+/g, ' ').trim())\n .join('\\n')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim()\n : ''\n\nconst MARKUP = /<\\/?[a-z][^>]*>/i\nconst MARKDOWN = /(^|\\n)\\s*#{1,6}\\s|\\*\\*[^*\\n]+\\*\\*|__[^_\\n]+__|!\\[[^\\]]*\\]\\(|\\[[^\\]]+\\]\\(https?:/\nconst EMOJI = /\\p{Extended_Pictographic}/u\nconst BRACKET = /[[\\]]/\nconst URL = /\\bhttps?:\\/\\/|\\bwww\\./i\n\ninterface Findings {\n violations: AiDoctrineViolation[]\n offending: Record<string, unknown>\n}\n\nfunction fail(findings: Findings, at: string, code: string, message: string, value: unknown): void {\n findings.violations.push({ rule: null, code, message, paths: [at] })\n if (!(at in findings.offending)) findings.offending[at] = value\n}\n\n/** A piece of copy a shopper reads: there, within its length, and plain text. */\nfunction checkCopyText(\n findings: Findings,\n at: string,\n raw: unknown,\n bounds: { label: string; max: number; multiline?: boolean; brackets?: boolean },\n): string {\n if (typeof raw !== 'string') {\n fail(findings, at, 'type', `${bounds.label} must be text.`, raw)\n return ''\n }\n const value = bounds.multiline ? paragraphs(raw) : line(raw)\n if (!value) {\n fail(findings, at, 'missing', `${bounds.label} is required.`, raw)\n return ''\n }\n if (value.length > bounds.max) {\n fail(findings, at, 'too-long', `${bounds.label} is ${value.length} characters; it may have ${bounds.max}.`, raw)\n }\n if (MARKUP.test(value) || MARKDOWN.test(value)) {\n fail(findings, at, 'markup', `${bounds.label} is plain text, with no markup or formatting marks.`, raw)\n }\n if (EMOJI.test(value)) fail(findings, at, 'emoji', `${bounds.label} holds no emoji.`, raw)\n if (URL.test(value)) fail(findings, at, 'link', `${bounds.label} holds no link.`, raw)\n if (bounds.brackets === false && BRACKET.test(value)) {\n fail(findings, at, 'bracket', `${bounds.label} is published as written, so it marks no missing fact in brackets.`, raw)\n }\n return value\n}\n\n/** Tags a shopper filters by: short, distinct, no `#`, no more than `max`. */\nfunction checkTags(findings: Findings, at: string, raw: unknown, max = AI_PRODUCT_TAGS_MAX): string[] {\n if (!Array.isArray(raw)) {\n fail(findings, at, 'type', 'Tags are a list of words or short phrases.', raw)\n return []\n }\n const seen = new Set<string>()\n const tags: string[] = []\n raw.forEach((entry, index) => {\n const tag = line(entry).replace(/^#+/, '').trim()\n if (!tag) return\n if (tag.length > AI_PRODUCT_TAG_MAX_CHARS || EMOJI.test(tag) || BRACKET.test(tag)) {\n fail(findings, `${at}[${index}]`, 'tag', `A tag is a plain word or phrase of at most ${AI_PRODUCT_TAG_MAX_CHARS} characters.`, entry)\n return\n }\n const key = tag.toLowerCase()\n if (seen.has(key)) return\n seen.add(key)\n tags.push(tag)\n })\n if (tags.length > max) {\n fail(findings, at, 'too-many', `A product carries at most ${max} tags.`, raw)\n }\n return tags\n}\n\n/** The claims and prices a set of copy may not make, as violations. */\nfunction claimViolations(samples: readonly AiStorefrontCopySample[], merchantWords: string): AiDoctrineViolation[] {\n return storefrontClaimViolations(\n findStorefrontClaims(samples, merchantWords),\n findInventedPrices(samples, merchantWords),\n )\n}\n\n/* ------------------------------------------------------------------------ *\n * One product's copy\n * ------------------------------------------------------------------------ */\n\nexport const AI_PRODUCT_COPY_TOOL: AiTool = {\n name: AI_PRODUCT_COPY_TOOL_NAME,\n description: 'Propose the storefront copy for one product. Every field is required.',\n strict: true,\n inputSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['description', 'seoTitle', 'seoDescription', 'tags', 'categoryIds', 'optionNames'],\n properties: {\n description: string(\n `The product description shoppers read, in short paragraphs, at most ${AI_PRODUCT_DESCRIPTION_MAX_CHARS} characters.`,\n ),\n seoTitle: string(`The search result headline, published as written, at most ${SEO_TITLE_MAX} characters.`),\n seoDescription: string(`The search result summary, at most ${SEO_DESCRIPTION_MAX} characters.`),\n tags: strings(`At most ${AI_PRODUCT_TAGS_MAX} tags, each at most ${AI_PRODUCT_TAG_MAX_CHARS} characters.`),\n categoryIds: strings(\n `At most ${AI_PRODUCT_CATEGORIES_MAX} category ids from the list you were given; empty when none fits.`,\n ),\n optionNames: strings(\n `One name per option the product has, in order, each at most ${AI_PRODUCT_OPTION_NAME_MAX_CHARS} characters; empty when it has none.`,\n ),\n },\n },\n}\n\nexport interface AiProductCopyCheckContext {\n /** The ids of the site's categories the request listed. */\n categoryIds: readonly string[]\n /** How many options the product has. */\n optionCount: number\n /** The merchant's own words about the product: its name, text and tags. */\n merchantWords: string\n}\n\n/**\n * A product copy answer held to the editor: every field written and within\n * its length, plain text, the categories the request listed, one distinct\n * name per option, and no claim or price the copy may not make.\n */\nexport function checkAiProductCopy(\n answer: Record<string, unknown>,\n context: AiProductCopyCheckContext,\n): AiGenerationCheckResult<AiProductCopy> {\n const findings: Findings = { violations: [], offending: {} }\n const description = checkCopyText(findings, 'description', answer['description'], {\n label: 'The description',\n max: AI_PRODUCT_DESCRIPTION_MAX_CHARS,\n multiline: true,\n })\n const seoTitle = checkCopyText(findings, 'seoTitle', answer['seoTitle'], {\n label: 'The search title',\n max: SEO_TITLE_MAX,\n brackets: false,\n })\n const seoDescription = checkCopyText(findings, 'seoDescription', answer['seoDescription'], {\n label: 'The search description',\n max: SEO_DESCRIPTION_MAX,\n brackets: false,\n })\n const tags = checkTags(findings, 'tags', answer['tags'])\n\n const allowed = new Set(context.categoryIds)\n const categoryIds: string[] = []\n const rawCategories = answer['categoryIds']\n if (!Array.isArray(rawCategories)) {\n fail(findings, 'categoryIds', 'type', 'Categories are a list of ids.', rawCategories)\n } else {\n for (const entry of rawCategories) {\n const id = line(entry)\n if (!id || categoryIds.includes(id)) continue\n if (!allowed.has(id)) {\n fail(findings, 'categoryIds', 'category-unknown', 'Use only the category ids you were given.', rawCategories)\n continue\n }\n categoryIds.push(id)\n }\n if (categoryIds.length > AI_PRODUCT_CATEGORIES_MAX) {\n fail(findings, 'categoryIds', 'too-many', `A product goes in at most ${AI_PRODUCT_CATEGORIES_MAX} categories.`, rawCategories)\n }\n }\n\n const optionNames: string[] = []\n const rawOptions = answer['optionNames']\n if (!Array.isArray(rawOptions)) {\n fail(findings, 'optionNames', 'type', 'Option names are a list.', rawOptions)\n } else {\n if (rawOptions.length !== context.optionCount) {\n fail(\n findings,\n 'optionNames',\n 'option-count',\n `The product has ${context.optionCount} ${context.optionCount === 1 ? 'option' : 'options'}; give one name for each.`,\n rawOptions,\n )\n }\n rawOptions.slice(0, context.optionCount).forEach((entry, index) => {\n const name = line(entry)\n if (!name || name.length > AI_PRODUCT_OPTION_NAME_MAX_CHARS || BRACKET.test(name) || EMOJI.test(name)) {\n fail(findings, `optionNames[${index}]`, 'option-name', `An option name is a plain word or phrase of at most ${AI_PRODUCT_OPTION_NAME_MAX_CHARS} characters.`, entry)\n }\n optionNames.push(name)\n })\n if (new Set(optionNames.map((name) => name.toLowerCase())).size !== optionNames.length) {\n fail(findings, 'optionNames', 'option-duplicate', 'Each option needs its own name.', rawOptions)\n }\n }\n\n const samples: AiStorefrontCopySample[] = [\n { at: 'description', text: description },\n { at: 'seoTitle', text: seoTitle },\n { at: 'seoDescription', text: seoDescription },\n ...tags.map((tag, index) => ({ at: `tags[${index}]`, text: tag })),\n ]\n findings.violations.push(\n ...claimViolations(samples, context.merchantWords),\n ...detectOffVoiceCopy(samples, null),\n )\n const value = findings.violations.length\n ? null\n : { description, seoTitle, seoDescription, tags, categoryIds, optionNames }\n return { value, violations: findings.violations, offending: findings.offending }\n}\n\n/* ------------------------------------------------------------------------ *\n * A store's first products\n * ------------------------------------------------------------------------ */\n\nexport const AI_CATALOG_TOOL: AiTool = {\n name: AI_CATALOG_TOOL_NAME,\n description: 'Propose the products of a new store, each a draft its owner completes. Every field is required.',\n strict: true,\n inputSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['products'],\n properties: {\n products: {\n type: 'array',\n description: `Between ${AI_CATALOG_PRODUCTS.min} and ${AI_CATALOG_PRODUCTS.max} products.`,\n items: {\n type: 'object',\n additionalProperties: false,\n required: ['name', 'type', 'description', 'tags', 'options', 'seoTitle', 'seoDescription', 'photo'],\n properties: {\n name: string(`Distinct within the list, at most ${AI_PRODUCT_NAME_MAX_CHARS} characters.`),\n type: { type: 'string', enum: [...AI_PRODUCT_TYPES] },\n description: string(`In short paragraphs, at most ${AI_CATALOG_DESCRIPTION_MAX_CHARS} characters.`),\n tags: strings(`At most ${AI_CATALOG_TAGS_MAX} tags, each at most ${AI_PRODUCT_TAG_MAX_CHARS} characters.`),\n options: {\n type: 'array',\n description: `The choices a shopper makes, at most ${AI_CATALOG_OPTIONS_MAX}; empty for a product with none.`,\n items: {\n type: 'object',\n additionalProperties: false,\n required: ['name', 'values'],\n properties: {\n name: string(`At most ${AI_PRODUCT_OPTION_NAME_MAX_CHARS} characters.`),\n values: strings(\n `At most ${AI_CATALOG_OPTION_VALUES_MAX} distinct values, each at most ${AI_CATALOG_OPTION_VALUE_MAX_CHARS} characters.`,\n ),\n },\n },\n },\n seoTitle: string(`At most ${SEO_TITLE_MAX} characters.`),\n seoDescription: string(`At most ${SEO_DESCRIPTION_MAX} characters.`),\n photo: string(`What the product photo should show, in one sentence of at most ${AI_CATALOG_PHOTO_MAX_CHARS} characters.`),\n },\n },\n },\n },\n },\n}\n\n/** A catalog answer held to the products editor and the storefront copy rules. */\nexport function checkAiCatalog(\n answer: Record<string, unknown>,\n context: { merchantWords: string },\n): AiGenerationCheckResult<AiCatalogProduct[]> {\n const findings: Findings = { violations: [], offending: {} }\n const raw = answer['products']\n if (!Array.isArray(raw)) {\n fail(findings, 'products', 'type', 'The products are a list.', raw)\n return { value: null, violations: findings.violations, offending: findings.offending }\n }\n if (raw.length < AI_CATALOG_PRODUCTS.min || raw.length > AI_CATALOG_PRODUCTS.max) {\n fail(findings, 'products', 'product-count', `Propose between ${AI_CATALOG_PRODUCTS.min} and ${AI_CATALOG_PRODUCTS.max} products.`, `${raw.length} products`)\n }\n const names = new Set<string>()\n const products: AiCatalogProduct[] = []\n const samples: AiStorefrontCopySample[] = []\n raw.slice(0, AI_CATALOG_PRODUCTS.max).forEach((entry, index) => {\n const at = `products[${index}]`\n if (!isRecord(entry)) {\n fail(findings, at, 'type', 'Each product is an object.', entry)\n return\n }\n const name = checkCopyText(findings, `${at}.name`, entry['name'], {\n label: 'A product name',\n max: AI_PRODUCT_NAME_MAX_CHARS,\n brackets: false,\n })\n if (name && names.has(name.toLowerCase())) {\n fail(findings, `${at}.name`, 'name-duplicate', 'Each product needs its own name.', entry['name'])\n }\n names.add(name.toLowerCase())\n const type = entry['type']\n if (!(AI_PRODUCT_TYPES as readonly unknown[]).includes(type)) {\n fail(findings, `${at}.type`, 'type', 'A product is physical, digital or a service.', type)\n }\n const description = checkCopyText(findings, `${at}.description`, entry['description'], {\n label: 'A product description',\n max: AI_CATALOG_DESCRIPTION_MAX_CHARS,\n multiline: true,\n })\n const tags = checkTags(findings, `${at}.tags`, entry['tags'], AI_CATALOG_TAGS_MAX)\n const options = checkCatalogOptions(findings, `${at}.options`, entry['options'])\n const seoTitle = checkCopyText(findings, `${at}.seoTitle`, entry['seoTitle'], {\n label: 'A search title',\n max: SEO_TITLE_MAX,\n brackets: false,\n })\n const seoDescription = checkCopyText(findings, `${at}.seoDescription`, entry['seoDescription'], {\n label: 'A search description',\n max: SEO_DESCRIPTION_MAX,\n brackets: false,\n })\n const photo = checkCopyText(findings, `${at}.photo`, entry['photo'], {\n label: 'What the photo shows',\n max: AI_CATALOG_PHOTO_MAX_CHARS,\n brackets: false,\n })\n samples.push(\n { at: `${at}.name`, text: name },\n { at: `${at}.description`, text: description },\n { at: `${at}.seoTitle`, text: seoTitle },\n { at: `${at}.seoDescription`, text: seoDescription },\n ...tags.map((tag, tagIndex) => ({ at: `${at}.tags[${tagIndex}]`, text: tag })),\n )\n products.push({\n name,\n type: type as AiProductType,\n description,\n tags,\n options,\n seoTitle,\n seoDescription,\n photo,\n })\n })\n findings.violations.push(...claimViolations(samples, context.merchantWords), ...detectOffVoiceCopy(samples, null))\n return {\n value: findings.violations.length ? null : products,\n violations: findings.violations,\n offending: findings.offending,\n }\n}\n\nfunction checkCatalogOptions(findings: Findings, at: string, raw: unknown): AiProductOption[] {\n if (!Array.isArray(raw)) {\n fail(findings, at, 'type', 'Options are a list.', raw)\n return []\n }\n if (raw.length > AI_CATALOG_OPTIONS_MAX) {\n fail(findings, at, 'too-many', `A proposed product has at most ${AI_CATALOG_OPTIONS_MAX} options.`, raw)\n }\n const options: AiProductOption[] = []\n raw.slice(0, AI_CATALOG_OPTIONS_MAX).forEach((entry, index) => {\n const here = `${at}[${index}]`\n const record = isRecord(entry) ? entry : {}\n const name = line(record['name'])\n if (!name || name.length > AI_PRODUCT_OPTION_NAME_MAX_CHARS || BRACKET.test(name)) {\n fail(findings, `${here}.name`, 'option-name', `An option name is a plain word or phrase of at most ${AI_PRODUCT_OPTION_NAME_MAX_CHARS} characters.`, record['name'])\n }\n const values = Array.isArray(record['values']) ? record['values'].map(line).filter(Boolean) : []\n if (!values.length || values.length > AI_CATALOG_OPTION_VALUES_MAX) {\n fail(findings, `${here}.values`, 'too-many', `An option has between 1 and ${AI_CATALOG_OPTION_VALUES_MAX} values.`, record['values'])\n }\n if (values.some((value) => value.length > AI_CATALOG_OPTION_VALUE_MAX_CHARS || BRACKET.test(value))) {\n fail(findings, `${here}.values`, 'option-values', `An option value is a plain word or phrase of at most ${AI_CATALOG_OPTION_VALUE_MAX_CHARS} characters.`, record['values'])\n }\n if (new Set(values.map((value) => value.toLowerCase())).size !== values.length) {\n fail(findings, `${here}.values`, 'option-values', 'An option’s values are all different.', record['values'])\n }\n options.push({ name, values: values.slice(0, AI_CATALOG_OPTION_VALUES_MAX) })\n })\n if (new Set(options.map((option) => option.name.toLowerCase())).size !== options.length) {\n fail(findings, at, 'option-duplicate', 'Each option needs its own name.', raw)\n }\n return options\n}\n\n/* ------------------------------------------------------------------------ *\n * Categories and discounts\n * ------------------------------------------------------------------------ */\n\nexport const AI_CATEGORIES_TOOL: AiTool = {\n name: AI_CATEGORIES_TOOL_NAME,\n description: 'Propose store categories and a first set of discounts, each created only if the owner accepts it. Every field is required.',\n strict: true,\n inputSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['categories', 'discounts'],\n properties: {\n categories: {\n type: 'array',\n description: `At most ${AI_CATEGORIES_MAX} categories; empty when the brief gives no reason for any.`,\n items: {\n type: 'object',\n additionalProperties: false,\n required: ['name', 'why'],\n properties: {\n name: string(`At most ${AI_CATEGORY_NAME_MAX_CHARS} characters.`),\n why: string(`One sentence of at most ${AI_PROPOSAL_WHY_MAX_CHARS} characters.`),\n },\n },\n },\n discounts: {\n type: 'array',\n description: `At most ${AI_DISCOUNTS_MAX} discounts; empty when the brief gives no reason for any.`,\n items: {\n type: 'object',\n additionalProperties: false,\n required: ['name', 'code', 'kind', 'value', 'minimumOrderUsd', 'why'],\n properties: {\n name: string(`At most ${AI_CATEGORY_NAME_MAX_CHARS} characters.`),\n code: string('The code a shopper types: 3 to 20 capital letters, digits, dashes or underscores; empty for a discount that applies on its own.'),\n kind: { type: 'string', enum: ['percent', 'fixed', 'free_shipping'] },\n value: {\n type: 'number',\n description: `percent: the percentage, 1 to ${AI_DISCOUNT_MAX_PERCENT}; fixed: dollars off, at most ${AI_DISCOUNT_MAX_FIXED_USD}; free_shipping: 0.`,\n },\n minimumOrderUsd: { type: 'number', description: 'The smallest order it applies to, in dollars; 0 for any order.' },\n why: string(`One sentence of at most ${AI_PROPOSAL_WHY_MAX_CHARS} characters.`),\n },\n },\n },\n },\n },\n}\n\n/** A categories answer held to the catalog and discount editors and the storefront copy rules. */\nexport function checkAiCategories(\n answer: Record<string, unknown>,\n context: { existingCategoryNames: readonly string[]; merchantWords: string },\n): AiGenerationCheckResult<Pick<AiCategoriesProposal, 'categories' | 'discounts'>> {\n const findings: Findings = { violations: [], offending: {} }\n const existing = new Set(context.existingCategoryNames.map((name) => line(name).toLowerCase()))\n const samples: AiStorefrontCopySample[] = []\n\n const categories: AiCategoriesProposal['categories'] = []\n const rawCategories = answer['categories']\n if (!Array.isArray(rawCategories)) {\n fail(findings, 'categories', 'type', 'Categories are a list.', rawCategories)\n } else {\n if (rawCategories.length > AI_CATEGORIES_MAX) {\n fail(findings, 'categories', 'too-many', `Propose at most ${AI_CATEGORIES_MAX} categories.`, `${rawCategories.length} categories`)\n }\n const seen = new Set<string>()\n rawCategories.slice(0, AI_CATEGORIES_MAX).forEach((entry, index) => {\n const at = `categories[${index}]`\n const record = isRecord(entry) ? entry : {}\n const name = checkCopyText(findings, `${at}.name`, record['name'], {\n label: 'A category name',\n max: AI_CATEGORY_NAME_MAX_CHARS,\n brackets: false,\n })\n const key = name.toLowerCase()\n if (name && existing.has(key)) {\n fail(findings, `${at}.name`, 'category-exists', `The store already has a category named ${name}.`, record['name'])\n } else if (name && seen.has(key)) {\n fail(findings, `${at}.name`, 'category-duplicate', 'Each category needs its own name.', record['name'])\n }\n seen.add(key)\n const why = checkCopyText(findings, `${at}.why`, record['why'], {\n label: 'Why a category helps',\n max: AI_PROPOSAL_WHY_MAX_CHARS,\n brackets: false,\n })\n samples.push({ at: `${at}.name`, text: name }, { at: `${at}.why`, text: why })\n categories.push({ name, why })\n })\n }\n\n const discounts: AiProposedDiscount[] = []\n const rawDiscounts = answer['discounts']\n if (!Array.isArray(rawDiscounts)) {\n fail(findings, 'discounts', 'type', 'Discounts are a list.', rawDiscounts)\n } else {\n if (rawDiscounts.length > AI_DISCOUNTS_MAX) {\n fail(findings, 'discounts', 'too-many', `Propose at most ${AI_DISCOUNTS_MAX} discounts.`, `${rawDiscounts.length} discounts`)\n }\n const codes = new Set<string>()\n rawDiscounts.slice(0, AI_DISCOUNTS_MAX).forEach((entry, index) => {\n const at = `discounts[${index}]`\n const record = isRecord(entry) ? entry : {}\n const name = checkCopyText(findings, `${at}.name`, record['name'], {\n label: 'A discount name',\n max: AI_CATEGORY_NAME_MAX_CHARS,\n brackets: false,\n })\n const typedCode = line(record['code']).toUpperCase()\n if (typedCode && !AI_DISCOUNT_CODE.test(typedCode)) {\n fail(findings, `${at}.code`, 'code', 'A code is 3 to 20 capital letters, digits, dashes or underscores.', record['code'])\n } else if (typedCode && codes.has(typedCode)) {\n fail(findings, `${at}.code`, 'code-duplicate', 'Each discount needs its own code.', record['code'])\n }\n if (typedCode) codes.add(typedCode)\n const kind = record['kind']\n const value = Number(record['value'])\n const minimum = Number(record['minimumOrderUsd'])\n let valuePct: number | null = null\n let valueCents: number | null = null\n if (kind === 'percent') {\n if (!Number.isInteger(value) || value < 1 || value > AI_DISCOUNT_MAX_PERCENT) {\n fail(findings, `${at}.value`, 'discount-value', `A percentage is a whole number from 1 to ${AI_DISCOUNT_MAX_PERCENT}.`, record['value'])\n }\n valuePct = value\n } else if (kind === 'fixed') {\n if (!Number.isFinite(value) || value <= 0 || value > AI_DISCOUNT_MAX_FIXED_USD) {\n fail(findings, `${at}.value`, 'discount-value', `An amount off is more than 0 and at most ${AI_DISCOUNT_MAX_FIXED_USD} dollars.`, record['value'])\n }\n valueCents = Math.round(value * 100)\n } else if (kind !== 'free_shipping') {\n fail(findings, `${at}.kind`, 'type', 'A discount is a percentage, an amount off or free shipping.', kind)\n }\n if (!Number.isFinite(minimum) || minimum < 0 || minimum > 10_000) {\n fail(findings, `${at}.minimumOrderUsd`, 'discount-minimum', 'A minimum order is between 0 and 10,000 dollars.', record['minimumOrderUsd'])\n }\n const why = checkCopyText(findings, `${at}.why`, record['why'], {\n label: 'Why a discount helps',\n max: AI_PROPOSAL_WHY_MAX_CHARS,\n brackets: false,\n })\n // The discount's own amount is stated in its fields, so only its name\n // and reason are read for a claim: \"15% off\" is the discount, not a price.\n samples.push({ at: `${at}.name`, text: name }, { at: `${at}.why`, text: why })\n discounts.push({\n name,\n code: typedCode || null,\n kind: kind as AiDiscountKind,\n valuePct,\n valueCents,\n minSubtotalCents: minimum > 0 ? Math.round(minimum * 100) : null,\n why,\n })\n })\n }\n\n if (!categories.length && !discounts.length && !findings.violations.length) {\n fail(findings, 'categories', 'empty', 'Propose at least one category or one discount.', answer)\n }\n findings.violations.push(\n ...storefrontClaimViolations(findStorefrontClaims(samples, context.merchantWords)),\n ...detectOffVoiceCopy(samples, null),\n )\n return {\n value: findings.violations.length ? null : { categories, discounts },\n violations: findings.violations,\n offending: findings.offending,\n }\n}\n"],"names":["SEO_LISTING_FIELDS","AI_CATALOG_DESCRIPTION_MAX_CHARS","AI_CATALOG_OPTION_VALUE_MAX_CHARS","AI_CATALOG_OPTION_VALUES_MAX","AI_CATALOG_OPTIONS_MAX","AI_CATALOG_PHOTO_MAX_CHARS","AI_CATALOG_PRODUCTS","AI_CATALOG_TAGS_MAX","AI_CATEGORIES_MAX","AI_CATEGORY_NAME_MAX_CHARS","AI_DISCOUNT_CODE","AI_DISCOUNT_MAX_FIXED_USD","AI_DISCOUNT_MAX_PERCENT","AI_DISCOUNTS_MAX","AI_PRODUCT_CATEGORIES_MAX","AI_PRODUCT_DESCRIPTION_MAX_CHARS","AI_PRODUCT_NAME_MAX_CHARS","AI_PRODUCT_OPTION_NAME_MAX_CHARS","AI_PRODUCT_TAG_MAX_CHARS","AI_PRODUCT_TAGS_MAX","AI_PRODUCT_TYPES","AI_PROPOSAL_WHY_MAX_CHARS","findInventedPrices","findStorefrontClaims","storefrontClaimViolations","detectOffVoiceCopy","AI_PRODUCT_COPY_TOOL_NAME","AI_CATALOG_TOOL_NAME","AI_CATEGORIES_TOOL_NAME","SEO_TITLE_MAX","title","maxLength","SEO_DESCRIPTION_MAX","description","string","type","strings","items","isRecord","value","Array","isArray","line","replace","trim","paragraphs","split","map","part","join","MARKUP","MARKDOWN","EMOJI","BRACKET","URL","fail","findings","at","code","message","violations","push","rule","paths","offending","checkCopyText","raw","bounds","label","multiline","length","max","test","brackets","checkTags","seen","Set","tags","forEach","entry","index","tag","key","toLowerCase","has","add","claimViolations","samples","merchantWords","AI_PRODUCT_COPY_TOOL","name","strict","inputSchema","additionalProperties","required","properties","seoTitle","seoDescription","categoryIds","optionNames","checkAiProductCopy","answer","context","allowed","rawCategories","id","includes","rawOptions","optionCount","slice","size","text","AI_CATALOG_TOOL","products","min","enum","options","values","photo","checkAiCatalog","names","checkCatalogOptions","tagIndex","here","record","filter","Boolean","some","option","AI_CATEGORIES_TOOL","categories","why","discounts","kind","minimumOrderUsd","checkAiCategories","existing","existingCategoryNames","rawDiscounts","codes","typedCode","toUpperCase","Number","minimum","valuePct","valueCents","isInteger","isFinite","Math","round","minSubtotalCents"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/tools/ai-products-tool.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { SEO_LISTING_FIELDS } from '@aglyn/aglyn/app-utils/seo-listing-fields'\nimport {\n AI_CATALOG_DESCRIPTION_MAX_CHARS,\n AI_CATALOG_OPTION_VALUE_MAX_CHARS,\n AI_CATALOG_OPTION_VALUES_MAX,\n AI_CATALOG_OPTIONS_MAX,\n AI_CATALOG_PHOTO_MAX_CHARS,\n AI_CATALOG_PRICE_USD,\n AI_CATALOG_PRODUCTS,\n AI_CATALOG_TAGS_MAX,\n AI_CATEGORIES_MAX,\n AI_CATEGORY_NAME_MAX_CHARS,\n AI_DISCOUNT_CODE,\n AI_DISCOUNT_MAX_FIXED_USD,\n AI_DISCOUNT_MAX_PERCENT,\n AI_DISCOUNTS_MAX,\n AI_PRODUCT_CATEGORIES_MAX,\n AI_PRODUCT_DESCRIPTION_MAX_CHARS,\n AI_PRODUCT_NAME_MAX_CHARS,\n AI_PRODUCT_OPTION_NAME_MAX_CHARS,\n AI_PRODUCT_TAG_MAX_CHARS,\n AI_PRODUCT_TAGS_MAX,\n AI_PRODUCT_TYPES,\n AI_PROPOSAL_WHY_MAX_CHARS,\n aiCatalogPrice,\n type AiCatalogProduct,\n type AiCategoriesProposal,\n type AiDiscountKind,\n type AiProductCopy,\n type AiProductOption,\n type AiProductType,\n type AiProposedDiscount,\n} from '../model/ai-products'\nimport {\n findInventedPrices,\n findStorefrontClaims,\n storefrontClaimViolations,\n type AiStorefrontCopySample,\n} from '../model/ai-storefront-claims'\nimport type { AiTool } from '../providers/contract'\nimport type { AiGenerationCheckResult } from '../runtime/ai-doctrine'\nimport { detectOffVoiceCopy, type AiDoctrineViolation } from '../runtime/ai-doctrine-validators'\n\n/**\n * The strict tools commerce by AI answers through (AGL-2916), and the checks\n * that hold each answer to the commerce editor it proposes for.\n *\n * - `propose_product_copy` — one product's description, search listing, tags,\n * categories and option names.\n * - `propose_catalog` — a store's first products, from a brief.\n * - `propose_categories_and_discounts` — store categories and a first set of\n * discounts, from a brief.\n *\n * Each schema is kept small, and no field is nullable: \"none\" is an empty\n * string, an empty list or zero. A catalog product's `price` is the one field\n * no answer is refused for: code keeps it in range or drops it to the\n * store's default (`aiCatalogPrice`). A strict schema accepts no length keyword,\n * so every bound is stated in a description and enforced here. A check\n * returns a value only when nothing in the answer is broken, and otherwise\n * the violations and the parts at fault, for the generation call's one\n * re-ask.\n */\n\nexport const AI_PRODUCT_COPY_TOOL_NAME = 'propose_product_copy'\nexport const AI_CATALOG_TOOL_NAME = 'propose_catalog'\nexport const AI_CATEGORIES_TOOL_NAME = 'propose_categories_and_discounts'\n\nconst SEO_TITLE_MAX = SEO_LISTING_FIELDS.title.maxLength\nconst SEO_DESCRIPTION_MAX = SEO_LISTING_FIELDS.description.maxLength\n\nconst string = (description: string) => ({ type: 'string', description })\nconst strings = (description: string) => ({ type: 'array', items: { type: 'string' }, description })\n\n/* ------------------------------------------------------------------------ *\n * Shared reads\n * ------------------------------------------------------------------------ */\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\n/** One line: runs of white space folded to one space. */\nconst line = (value: unknown): string => (typeof value === 'string' ? value.replace(/\\s+/g, ' ').trim() : '')\n\n/** Paragraphs: spaces folded within a line, at most one blank line between paragraphs. */\nconst paragraphs = (value: unknown): string =>\n typeof value === 'string'\n ? value\n .replace(/\\r\\n?/g, '\\n')\n .split('\\n')\n .map((part) => part.replace(/[ \\t\\f\\v]+/g, ' ').trim())\n .join('\\n')\n .replace(/\\n{3,}/g, '\\n\\n')\n .trim()\n : ''\n\nconst MARKUP = /<\\/?[a-z][^>]*>/i\nconst MARKDOWN = /(^|\\n)\\s*#{1,6}\\s|\\*\\*[^*\\n]+\\*\\*|__[^_\\n]+__|!\\[[^\\]]*\\]\\(|\\[[^\\]]+\\]\\(https?:/\nconst EMOJI = /\\p{Extended_Pictographic}/u\nconst BRACKET = /[[\\]]/\nconst URL = /\\bhttps?:\\/\\/|\\bwww\\./i\n\ninterface Findings {\n violations: AiDoctrineViolation[]\n offending: Record<string, unknown>\n}\n\nfunction fail(findings: Findings, at: string, code: string, message: string, value: unknown): void {\n findings.violations.push({ rule: null, code, message, paths: [at] })\n if (!(at in findings.offending)) findings.offending[at] = value\n}\n\n/** A piece of copy a shopper reads: there, within its length, and plain text. */\nfunction checkCopyText(\n findings: Findings,\n at: string,\n raw: unknown,\n bounds: { label: string; max: number; multiline?: boolean; brackets?: boolean },\n): string {\n if (typeof raw !== 'string') {\n fail(findings, at, 'type', `${bounds.label} must be text.`, raw)\n return ''\n }\n const value = bounds.multiline ? paragraphs(raw) : line(raw)\n if (!value) {\n fail(findings, at, 'missing', `${bounds.label} is required.`, raw)\n return ''\n }\n if (value.length > bounds.max) {\n fail(findings, at, 'too-long', `${bounds.label} is ${value.length} characters; it may have ${bounds.max}.`, raw)\n }\n if (MARKUP.test(value) || MARKDOWN.test(value)) {\n fail(findings, at, 'markup', `${bounds.label} is plain text, with no markup or formatting marks.`, raw)\n }\n if (EMOJI.test(value)) fail(findings, at, 'emoji', `${bounds.label} holds no emoji.`, raw)\n if (URL.test(value)) fail(findings, at, 'link', `${bounds.label} holds no link.`, raw)\n if (bounds.brackets === false && BRACKET.test(value)) {\n fail(findings, at, 'bracket', `${bounds.label} is published as written, so it marks no missing fact in brackets.`, raw)\n }\n return value\n}\n\n/** Tags a shopper filters by: short, distinct, no `#`, no more than `max`. */\nfunction checkTags(findings: Findings, at: string, raw: unknown, max = AI_PRODUCT_TAGS_MAX): string[] {\n if (!Array.isArray(raw)) {\n fail(findings, at, 'type', 'Tags are a list of words or short phrases.', raw)\n return []\n }\n const seen = new Set<string>()\n const tags: string[] = []\n raw.forEach((entry, index) => {\n const tag = line(entry).replace(/^#+/, '').trim()\n if (!tag) return\n if (tag.length > AI_PRODUCT_TAG_MAX_CHARS || EMOJI.test(tag) || BRACKET.test(tag)) {\n fail(findings, `${at}[${index}]`, 'tag', `A tag is a plain word or phrase of at most ${AI_PRODUCT_TAG_MAX_CHARS} characters.`, entry)\n return\n }\n const key = tag.toLowerCase()\n if (seen.has(key)) return\n seen.add(key)\n tags.push(tag)\n })\n if (tags.length > max) {\n fail(findings, at, 'too-many', `A product carries at most ${max} tags.`, raw)\n }\n return tags\n}\n\n/** The claims and prices a set of copy may not make, as violations. */\nfunction claimViolations(samples: readonly AiStorefrontCopySample[], merchantWords: string): AiDoctrineViolation[] {\n return storefrontClaimViolations(\n findStorefrontClaims(samples, merchantWords),\n findInventedPrices(samples, merchantWords),\n )\n}\n\n/* ------------------------------------------------------------------------ *\n * One product's copy\n * ------------------------------------------------------------------------ */\n\nexport const AI_PRODUCT_COPY_TOOL: AiTool = {\n name: AI_PRODUCT_COPY_TOOL_NAME,\n description: 'Propose the storefront copy for one product. Every field is required.',\n strict: true,\n inputSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['description', 'seoTitle', 'seoDescription', 'tags', 'categoryIds', 'optionNames'],\n properties: {\n description: string(\n `The product description shoppers read, in short paragraphs, at most ${AI_PRODUCT_DESCRIPTION_MAX_CHARS} characters.`,\n ),\n seoTitle: string(`The search result headline, published as written, at most ${SEO_TITLE_MAX} characters.`),\n seoDescription: string(`The search result summary, at most ${SEO_DESCRIPTION_MAX} characters.`),\n tags: strings(`At most ${AI_PRODUCT_TAGS_MAX} tags, each at most ${AI_PRODUCT_TAG_MAX_CHARS} characters.`),\n categoryIds: strings(\n `At most ${AI_PRODUCT_CATEGORIES_MAX} category ids from the list you were given; empty when none fits.`,\n ),\n optionNames: strings(\n `One name per option the product has, in order, each at most ${AI_PRODUCT_OPTION_NAME_MAX_CHARS} characters; empty when it has none.`,\n ),\n },\n },\n}\n\nexport interface AiProductCopyCheckContext {\n /** The ids of the site's categories the request listed. */\n categoryIds: readonly string[]\n /** How many options the product has. */\n optionCount: number\n /** The merchant's own words about the product: its name, text and tags. */\n merchantWords: string\n}\n\n/**\n * A product copy answer held to the editor: every field written and within\n * its length, plain text, the categories the request listed, one distinct\n * name per option, and no claim or price the copy may not make.\n */\nexport function checkAiProductCopy(\n answer: Record<string, unknown>,\n context: AiProductCopyCheckContext,\n): AiGenerationCheckResult<AiProductCopy> {\n const findings: Findings = { violations: [], offending: {} }\n const description = checkCopyText(findings, 'description', answer['description'], {\n label: 'The description',\n max: AI_PRODUCT_DESCRIPTION_MAX_CHARS,\n multiline: true,\n })\n const seoTitle = checkCopyText(findings, 'seoTitle', answer['seoTitle'], {\n label: 'The search title',\n max: SEO_TITLE_MAX,\n brackets: false,\n })\n const seoDescription = checkCopyText(findings, 'seoDescription', answer['seoDescription'], {\n label: 'The search description',\n max: SEO_DESCRIPTION_MAX,\n brackets: false,\n })\n const tags = checkTags(findings, 'tags', answer['tags'])\n\n const allowed = new Set(context.categoryIds)\n const categoryIds: string[] = []\n const rawCategories = answer['categoryIds']\n if (!Array.isArray(rawCategories)) {\n fail(findings, 'categoryIds', 'type', 'Categories are a list of ids.', rawCategories)\n } else {\n for (const entry of rawCategories) {\n const id = line(entry)\n if (!id || categoryIds.includes(id)) continue\n if (!allowed.has(id)) {\n fail(findings, 'categoryIds', 'category-unknown', 'Use only the category ids you were given.', rawCategories)\n continue\n }\n categoryIds.push(id)\n }\n if (categoryIds.length > AI_PRODUCT_CATEGORIES_MAX) {\n fail(findings, 'categoryIds', 'too-many', `A product goes in at most ${AI_PRODUCT_CATEGORIES_MAX} categories.`, rawCategories)\n }\n }\n\n const optionNames: string[] = []\n const rawOptions = answer['optionNames']\n if (!Array.isArray(rawOptions)) {\n fail(findings, 'optionNames', 'type', 'Option names are a list.', rawOptions)\n } else {\n if (rawOptions.length !== context.optionCount) {\n fail(\n findings,\n 'optionNames',\n 'option-count',\n `The product has ${context.optionCount} ${context.optionCount === 1 ? 'option' : 'options'}; give one name for each.`,\n rawOptions,\n )\n }\n rawOptions.slice(0, context.optionCount).forEach((entry, index) => {\n const name = line(entry)\n if (!name || name.length > AI_PRODUCT_OPTION_NAME_MAX_CHARS || BRACKET.test(name) || EMOJI.test(name)) {\n fail(findings, `optionNames[${index}]`, 'option-name', `An option name is a plain word or phrase of at most ${AI_PRODUCT_OPTION_NAME_MAX_CHARS} characters.`, entry)\n }\n optionNames.push(name)\n })\n if (new Set(optionNames.map((name) => name.toLowerCase())).size !== optionNames.length) {\n fail(findings, 'optionNames', 'option-duplicate', 'Each option needs its own name.', rawOptions)\n }\n }\n\n const samples: AiStorefrontCopySample[] = [\n { at: 'description', text: description },\n { at: 'seoTitle', text: seoTitle },\n { at: 'seoDescription', text: seoDescription },\n ...tags.map((tag, index) => ({ at: `tags[${index}]`, text: tag })),\n ]\n findings.violations.push(\n ...claimViolations(samples, context.merchantWords),\n ...detectOffVoiceCopy(samples, null),\n )\n const value = findings.violations.length\n ? null\n : { description, seoTitle, seoDescription, tags, categoryIds, optionNames }\n return { value, violations: findings.violations, offending: findings.offending }\n}\n\n/* ------------------------------------------------------------------------ *\n * A store's first products\n * ------------------------------------------------------------------------ */\n\nexport const AI_CATALOG_TOOL: AiTool = {\n name: AI_CATALOG_TOOL_NAME,\n description: 'Propose the products of a new store, each a draft its owner completes. Every field is required.',\n strict: true,\n inputSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['products'],\n properties: {\n products: {\n type: 'array',\n description: `Between ${AI_CATALOG_PRODUCTS.min} and ${AI_CATALOG_PRODUCTS.max} products.`,\n items: {\n type: 'object',\n additionalProperties: false,\n required: ['name', 'type', 'description', 'tags', 'options', 'seoTitle', 'seoDescription', 'photo', 'price'],\n properties: {\n name: string(`Distinct within the list, at most ${AI_PRODUCT_NAME_MAX_CHARS} characters.`),\n type: { type: 'string', enum: [...AI_PRODUCT_TYPES] },\n description: string(`In short paragraphs, at most ${AI_CATALOG_DESCRIPTION_MAX_CHARS} characters.`),\n tags: strings(`At most ${AI_CATALOG_TAGS_MAX} tags, each at most ${AI_PRODUCT_TAG_MAX_CHARS} characters.`),\n options: {\n type: 'array',\n description: `The choices a shopper makes, at most ${AI_CATALOG_OPTIONS_MAX}; empty for a product with none.`,\n items: {\n type: 'object',\n additionalProperties: false,\n required: ['name', 'values'],\n properties: {\n name: string(`At most ${AI_PRODUCT_OPTION_NAME_MAX_CHARS} characters.`),\n values: strings(\n `At most ${AI_CATALOG_OPTION_VALUES_MAX} distinct values, each at most ${AI_CATALOG_OPTION_VALUE_MAX_CHARS} characters.`,\n ),\n },\n },\n },\n seoTitle: string(`At most ${SEO_TITLE_MAX} characters.`),\n seoDescription: string(`At most ${SEO_DESCRIPTION_MAX} characters.`),\n photo: string(`What the product photo should show, in one sentence of at most ${AI_CATALOG_PHOTO_MAX_CHARS} characters.`),\n price: {\n type: 'number',\n description: `Its suggested price in US dollars, from ${AI_CATALOG_PRICE_USD.min} to ${AI_CATALOG_PRICE_USD.max}.`,\n },\n },\n },\n },\n },\n },\n}\n\n/** A catalog answer held to the products editor and the storefront copy rules. */\nexport function checkAiCatalog(\n answer: Record<string, unknown>,\n context: { merchantWords: string },\n): AiGenerationCheckResult<AiCatalogProduct[]> {\n const findings: Findings = { violations: [], offending: {} }\n const raw = answer['products']\n if (!Array.isArray(raw)) {\n fail(findings, 'products', 'type', 'The products are a list.', raw)\n return { value: null, violations: findings.violations, offending: findings.offending }\n }\n if (raw.length < AI_CATALOG_PRODUCTS.min || raw.length > AI_CATALOG_PRODUCTS.max) {\n fail(findings, 'products', 'product-count', `Propose between ${AI_CATALOG_PRODUCTS.min} and ${AI_CATALOG_PRODUCTS.max} products.`, `${raw.length} products`)\n }\n const names = new Set<string>()\n const products: AiCatalogProduct[] = []\n const samples: AiStorefrontCopySample[] = []\n raw.slice(0, AI_CATALOG_PRODUCTS.max).forEach((entry, index) => {\n const at = `products[${index}]`\n if (!isRecord(entry)) {\n fail(findings, at, 'type', 'Each product is an object.', entry)\n return\n }\n const name = checkCopyText(findings, `${at}.name`, entry['name'], {\n label: 'A product name',\n max: AI_PRODUCT_NAME_MAX_CHARS,\n brackets: false,\n })\n if (name && names.has(name.toLowerCase())) {\n fail(findings, `${at}.name`, 'name-duplicate', 'Each product needs its own name.', entry['name'])\n }\n names.add(name.toLowerCase())\n const type = entry['type']\n if (!(AI_PRODUCT_TYPES as readonly unknown[]).includes(type)) {\n fail(findings, `${at}.type`, 'type', 'A product is physical, digital or a service.', type)\n }\n const description = checkCopyText(findings, `${at}.description`, entry['description'], {\n label: 'A product description',\n max: AI_CATALOG_DESCRIPTION_MAX_CHARS,\n multiline: true,\n })\n const tags = checkTags(findings, `${at}.tags`, entry['tags'], AI_CATALOG_TAGS_MAX)\n const options = checkCatalogOptions(findings, `${at}.options`, entry['options'])\n const seoTitle = checkCopyText(findings, `${at}.seoTitle`, entry['seoTitle'], {\n label: 'A search title',\n max: SEO_TITLE_MAX,\n brackets: false,\n })\n const seoDescription = checkCopyText(findings, `${at}.seoDescription`, entry['seoDescription'], {\n label: 'A search description',\n max: SEO_DESCRIPTION_MAX,\n brackets: false,\n })\n const photo = checkCopyText(findings, `${at}.photo`, entry['photo'], {\n label: 'What the photo shows',\n max: AI_CATALOG_PHOTO_MAX_CHARS,\n brackets: false,\n })\n samples.push(\n { at: `${at}.name`, text: name },\n { at: `${at}.description`, text: description },\n { at: `${at}.seoTitle`, text: seoTitle },\n { at: `${at}.seoDescription`, text: seoDescription },\n ...tags.map((tag, tagIndex) => ({ at: `${at}.tags[${tagIndex}]`, text: tag })),\n )\n products.push({\n name,\n type: type as AiProductType,\n description,\n tags,\n options,\n seoTitle,\n seoDescription,\n photo,\n // Kept by code, never re-asked (Zach, 2026-10-12): a price that is\n // missing or out of range is `null`, and the store's default stands in.\n price: aiCatalogPrice(entry['price']),\n })\n })\n findings.violations.push(...claimViolations(samples, context.merchantWords), ...detectOffVoiceCopy(samples, null))\n return {\n value: findings.violations.length ? null : products,\n violations: findings.violations,\n offending: findings.offending,\n }\n}\n\nfunction checkCatalogOptions(findings: Findings, at: string, raw: unknown): AiProductOption[] {\n if (!Array.isArray(raw)) {\n fail(findings, at, 'type', 'Options are a list.', raw)\n return []\n }\n if (raw.length > AI_CATALOG_OPTIONS_MAX) {\n fail(findings, at, 'too-many', `A proposed product has at most ${AI_CATALOG_OPTIONS_MAX} options.`, raw)\n }\n const options: AiProductOption[] = []\n raw.slice(0, AI_CATALOG_OPTIONS_MAX).forEach((entry, index) => {\n const here = `${at}[${index}]`\n const record = isRecord(entry) ? entry : {}\n const name = line(record['name'])\n if (!name || name.length > AI_PRODUCT_OPTION_NAME_MAX_CHARS || BRACKET.test(name)) {\n fail(findings, `${here}.name`, 'option-name', `An option name is a plain word or phrase of at most ${AI_PRODUCT_OPTION_NAME_MAX_CHARS} characters.`, record['name'])\n }\n const values = Array.isArray(record['values']) ? record['values'].map(line).filter(Boolean) : []\n if (!values.length || values.length > AI_CATALOG_OPTION_VALUES_MAX) {\n fail(findings, `${here}.values`, 'too-many', `An option has between 1 and ${AI_CATALOG_OPTION_VALUES_MAX} values.`, record['values'])\n }\n if (values.some((value) => value.length > AI_CATALOG_OPTION_VALUE_MAX_CHARS || BRACKET.test(value))) {\n fail(findings, `${here}.values`, 'option-values', `An option value is a plain word or phrase of at most ${AI_CATALOG_OPTION_VALUE_MAX_CHARS} characters.`, record['values'])\n }\n if (new Set(values.map((value) => value.toLowerCase())).size !== values.length) {\n fail(findings, `${here}.values`, 'option-values', 'An option’s values are all different.', record['values'])\n }\n options.push({ name, values: values.slice(0, AI_CATALOG_OPTION_VALUES_MAX) })\n })\n if (new Set(options.map((option) => option.name.toLowerCase())).size !== options.length) {\n fail(findings, at, 'option-duplicate', 'Each option needs its own name.', raw)\n }\n return options\n}\n\n/* ------------------------------------------------------------------------ *\n * Categories and discounts\n * ------------------------------------------------------------------------ */\n\nexport const AI_CATEGORIES_TOOL: AiTool = {\n name: AI_CATEGORIES_TOOL_NAME,\n description: 'Propose store categories and a first set of discounts, each created only if the owner accepts it. Every field is required.',\n strict: true,\n inputSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['categories', 'discounts'],\n properties: {\n categories: {\n type: 'array',\n description: `At most ${AI_CATEGORIES_MAX} categories; empty when the brief gives no reason for any.`,\n items: {\n type: 'object',\n additionalProperties: false,\n required: ['name', 'why'],\n properties: {\n name: string(`At most ${AI_CATEGORY_NAME_MAX_CHARS} characters.`),\n why: string(`One sentence of at most ${AI_PROPOSAL_WHY_MAX_CHARS} characters.`),\n },\n },\n },\n discounts: {\n type: 'array',\n description: `At most ${AI_DISCOUNTS_MAX} discounts; empty when the brief gives no reason for any.`,\n items: {\n type: 'object',\n additionalProperties: false,\n required: ['name', 'code', 'kind', 'value', 'minimumOrderUsd', 'why'],\n properties: {\n name: string(`At most ${AI_CATEGORY_NAME_MAX_CHARS} characters.`),\n code: string('The code a shopper types: 3 to 20 capital letters, digits, dashes or underscores; empty for a discount that applies on its own.'),\n kind: { type: 'string', enum: ['percent', 'fixed', 'free_shipping'] },\n value: {\n type: 'number',\n description: `percent: the percentage, 1 to ${AI_DISCOUNT_MAX_PERCENT}; fixed: dollars off, at most ${AI_DISCOUNT_MAX_FIXED_USD}; free_shipping: 0.`,\n },\n minimumOrderUsd: { type: 'number', description: 'The smallest order it applies to, in dollars; 0 for any order.' },\n why: string(`One sentence of at most ${AI_PROPOSAL_WHY_MAX_CHARS} characters.`),\n },\n },\n },\n },\n },\n}\n\n/** A categories answer held to the catalog and discount editors and the storefront copy rules. */\nexport function checkAiCategories(\n answer: Record<string, unknown>,\n context: { existingCategoryNames: readonly string[]; merchantWords: string },\n): AiGenerationCheckResult<Pick<AiCategoriesProposal, 'categories' | 'discounts'>> {\n const findings: Findings = { violations: [], offending: {} }\n const existing = new Set(context.existingCategoryNames.map((name) => line(name).toLowerCase()))\n const samples: AiStorefrontCopySample[] = []\n\n const categories: AiCategoriesProposal['categories'] = []\n const rawCategories = answer['categories']\n if (!Array.isArray(rawCategories)) {\n fail(findings, 'categories', 'type', 'Categories are a list.', rawCategories)\n } else {\n if (rawCategories.length > AI_CATEGORIES_MAX) {\n fail(findings, 'categories', 'too-many', `Propose at most ${AI_CATEGORIES_MAX} categories.`, `${rawCategories.length} categories`)\n }\n const seen = new Set<string>()\n rawCategories.slice(0, AI_CATEGORIES_MAX).forEach((entry, index) => {\n const at = `categories[${index}]`\n const record = isRecord(entry) ? entry : {}\n const name = checkCopyText(findings, `${at}.name`, record['name'], {\n label: 'A category name',\n max: AI_CATEGORY_NAME_MAX_CHARS,\n brackets: false,\n })\n const key = name.toLowerCase()\n if (name && existing.has(key)) {\n fail(findings, `${at}.name`, 'category-exists', `The store already has a category named ${name}.`, record['name'])\n } else if (name && seen.has(key)) {\n fail(findings, `${at}.name`, 'category-duplicate', 'Each category needs its own name.', record['name'])\n }\n seen.add(key)\n const why = checkCopyText(findings, `${at}.why`, record['why'], {\n label: 'Why a category helps',\n max: AI_PROPOSAL_WHY_MAX_CHARS,\n brackets: false,\n })\n samples.push({ at: `${at}.name`, text: name }, { at: `${at}.why`, text: why })\n categories.push({ name, why })\n })\n }\n\n const discounts: AiProposedDiscount[] = []\n const rawDiscounts = answer['discounts']\n if (!Array.isArray(rawDiscounts)) {\n fail(findings, 'discounts', 'type', 'Discounts are a list.', rawDiscounts)\n } else {\n if (rawDiscounts.length > AI_DISCOUNTS_MAX) {\n fail(findings, 'discounts', 'too-many', `Propose at most ${AI_DISCOUNTS_MAX} discounts.`, `${rawDiscounts.length} discounts`)\n }\n const codes = new Set<string>()\n rawDiscounts.slice(0, AI_DISCOUNTS_MAX).forEach((entry, index) => {\n const at = `discounts[${index}]`\n const record = isRecord(entry) ? entry : {}\n const name = checkCopyText(findings, `${at}.name`, record['name'], {\n label: 'A discount name',\n max: AI_CATEGORY_NAME_MAX_CHARS,\n brackets: false,\n })\n const typedCode = line(record['code']).toUpperCase()\n if (typedCode && !AI_DISCOUNT_CODE.test(typedCode)) {\n fail(findings, `${at}.code`, 'code', 'A code is 3 to 20 capital letters, digits, dashes or underscores.', record['code'])\n } else if (typedCode && codes.has(typedCode)) {\n fail(findings, `${at}.code`, 'code-duplicate', 'Each discount needs its own code.', record['code'])\n }\n if (typedCode) codes.add(typedCode)\n const kind = record['kind']\n const value = Number(record['value'])\n const minimum = Number(record['minimumOrderUsd'])\n let valuePct: number | null = null\n let valueCents: number | null = null\n if (kind === 'percent') {\n if (!Number.isInteger(value) || value < 1 || value > AI_DISCOUNT_MAX_PERCENT) {\n fail(findings, `${at}.value`, 'discount-value', `A percentage is a whole number from 1 to ${AI_DISCOUNT_MAX_PERCENT}.`, record['value'])\n }\n valuePct = value\n } else if (kind === 'fixed') {\n if (!Number.isFinite(value) || value <= 0 || value > AI_DISCOUNT_MAX_FIXED_USD) {\n fail(findings, `${at}.value`, 'discount-value', `An amount off is more than 0 and at most ${AI_DISCOUNT_MAX_FIXED_USD} dollars.`, record['value'])\n }\n valueCents = Math.round(value * 100)\n } else if (kind !== 'free_shipping') {\n fail(findings, `${at}.kind`, 'type', 'A discount is a percentage, an amount off or free shipping.', kind)\n }\n if (!Number.isFinite(minimum) || minimum < 0 || minimum > 10_000) {\n fail(findings, `${at}.minimumOrderUsd`, 'discount-minimum', 'A minimum order is between 0 and 10,000 dollars.', record['minimumOrderUsd'])\n }\n const why = checkCopyText(findings, `${at}.why`, record['why'], {\n label: 'Why a discount helps',\n max: AI_PROPOSAL_WHY_MAX_CHARS,\n brackets: false,\n })\n // The discount's own amount is stated in its fields, so only its name\n // and reason are read for a claim: \"15% off\" is the discount, not a price.\n samples.push({ at: `${at}.name`, text: name }, { at: `${at}.why`, text: why })\n discounts.push({\n name,\n code: typedCode || null,\n kind: kind as AiDiscountKind,\n valuePct,\n valueCents,\n minSubtotalCents: minimum > 0 ? Math.round(minimum * 100) : null,\n why,\n })\n })\n }\n\n if (!categories.length && !discounts.length && !findings.violations.length) {\n fail(findings, 'categories', 'empty', 'Propose at least one category or one discount.', answer)\n }\n findings.violations.push(\n ...storefrontClaimViolations(findStorefrontClaims(samples, context.merchantWords)),\n ...detectOffVoiceCopy(samples, null),\n )\n return {\n value: findings.violations.length ? null : { categories, discounts },\n violations: findings.violations,\n offending: findings.offending,\n }\n}\n"],"names":["SEO_LISTING_FIELDS","AI_CATALOG_DESCRIPTION_MAX_CHARS","AI_CATALOG_OPTION_VALUE_MAX_CHARS","AI_CATALOG_OPTION_VALUES_MAX","AI_CATALOG_OPTIONS_MAX","AI_CATALOG_PHOTO_MAX_CHARS","AI_CATALOG_PRICE_USD","AI_CATALOG_PRODUCTS","AI_CATALOG_TAGS_MAX","AI_CATEGORIES_MAX","AI_CATEGORY_NAME_MAX_CHARS","AI_DISCOUNT_CODE","AI_DISCOUNT_MAX_FIXED_USD","AI_DISCOUNT_MAX_PERCENT","AI_DISCOUNTS_MAX","AI_PRODUCT_CATEGORIES_MAX","AI_PRODUCT_DESCRIPTION_MAX_CHARS","AI_PRODUCT_NAME_MAX_CHARS","AI_PRODUCT_OPTION_NAME_MAX_CHARS","AI_PRODUCT_TAG_MAX_CHARS","AI_PRODUCT_TAGS_MAX","AI_PRODUCT_TYPES","AI_PROPOSAL_WHY_MAX_CHARS","aiCatalogPrice","findInventedPrices","findStorefrontClaims","storefrontClaimViolations","detectOffVoiceCopy","AI_PRODUCT_COPY_TOOL_NAME","AI_CATALOG_TOOL_NAME","AI_CATEGORIES_TOOL_NAME","SEO_TITLE_MAX","title","maxLength","SEO_DESCRIPTION_MAX","description","string","type","strings","items","isRecord","value","Array","isArray","line","replace","trim","paragraphs","split","map","part","join","MARKUP","MARKDOWN","EMOJI","BRACKET","URL","fail","findings","at","code","message","violations","push","rule","paths","offending","checkCopyText","raw","bounds","label","multiline","length","max","test","brackets","checkTags","seen","Set","tags","forEach","entry","index","tag","key","toLowerCase","has","add","claimViolations","samples","merchantWords","AI_PRODUCT_COPY_TOOL","name","strict","inputSchema","additionalProperties","required","properties","seoTitle","seoDescription","categoryIds","optionNames","checkAiProductCopy","answer","context","allowed","rawCategories","id","includes","rawOptions","optionCount","slice","size","text","AI_CATALOG_TOOL","products","min","enum","options","values","photo","price","checkAiCatalog","names","checkCatalogOptions","tagIndex","here","record","filter","Boolean","some","option","AI_CATEGORIES_TOOL","categories","why","discounts","kind","minimumOrderUsd","checkAiCategories","existing","existingCategoryNames","rawDiscounts","codes","typedCode","toUpperCase","Number","minimum","valuePct","valueCents","isInteger","isFinite","Math","round","minSubtotalCents"],"mappings":"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"}
|